You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
4.1 KiB
144 lines
4.1 KiB
2 years ago
|
// ignore_for_file: public_member_api_docs
|
||
|
|
||
|
library nextcloud_push_proxy;
|
||
|
|
||
|
import 'dart:async';
|
||
|
import 'dart:convert';
|
||
|
import 'dart:io';
|
||
|
|
||
|
import 'package:shelf/shelf.dart';
|
||
|
import 'package:shelf/shelf_io.dart';
|
||
|
import 'package:shelf_router/shelf_router.dart';
|
||
|
|
||
|
/// Implements the listening part of a Nextcloud push proxy
|
||
|
class NextcloudPushProxy {
|
||
|
HttpServer? _server;
|
||
|
|
||
|
late StreamController<PushProxyDevice> _onNewDeviceController;
|
||
|
late StreamController<PushProxyNotification> _onNewNotificationController;
|
||
|
|
||
|
Stream<PushProxyDevice>? _onNewDeviceStream;
|
||
|
Stream<PushProxyNotification>? _onNewNotificationStream;
|
||
|
|
||
|
/// Listens for new devices
|
||
|
Stream<PushProxyDevice> get onNewDevice {
|
||
|
if (_onNewDeviceStream == null) {
|
||
|
throw Exception('Server not created');
|
||
|
}
|
||
|
return _onNewDeviceStream!;
|
||
|
}
|
||
|
|
||
|
/// Listens for new notifications
|
||
|
Stream<PushProxyNotification> get onNewNotification {
|
||
|
if (_onNewNotificationStream == null) {
|
||
|
throw Exception('Server not created');
|
||
|
}
|
||
|
return _onNewNotificationStream!;
|
||
|
}
|
||
|
|
||
|
late final _router = Router()
|
||
|
..post('/devices', _devicesHandler)
|
||
|
..post('/notifications', _notificationsHandler);
|
||
|
|
||
|
Future<Response> _devicesHandler(Request request) async {
|
||
|
final data = Uri(query: await request.readAsString()).queryParameters;
|
||
|
_onNewDeviceController.add(
|
||
|
PushProxyDevice(
|
||
|
pushToken: data['pushToken']!,
|
||
|
deviceIdentifier: data['deviceIdentifier']!,
|
||
|
deviceIdentifierSignature: data['deviceIdentifierSignature']!,
|
||
|
userPublicKey: data['userPublicKey']!,
|
||
|
),
|
||
|
);
|
||
|
return Response.ok('');
|
||
|
}
|
||
|
|
||
|
Future<Response> _notificationsHandler(Request request) async {
|
||
|
final data = Uri(query: await request.readAsString()).queryParameters;
|
||
|
for (final notification in data.values) {
|
||
|
final notificationData = json.decode(notification) as Map<String, dynamic>;
|
||
|
_onNewNotificationController.add(
|
||
|
PushProxyNotification(
|
||
|
deviceIdentifier: notificationData['deviceIdentifier']! as String,
|
||
|
pushTokenHash: notificationData['pushTokenHash']! as String,
|
||
|
subject: notificationData['subject']! as String,
|
||
|
signature: notificationData['signature']! as String,
|
||
|
priority: notificationData['priority']! as String,
|
||
|
type: notificationData['type']! as String,
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
return Response.ok('');
|
||
|
}
|
||
|
|
||
|
/// Creates a server listening on the [port]
|
||
|
Future create({
|
||
|
final bool logging = true,
|
||
|
final int port = 8080,
|
||
|
}) async {
|
||
|
if (_server != null) {
|
||
|
throw Exception('Server already created');
|
||
|
}
|
||
|
|
||
|
_onNewDeviceController = StreamController<PushProxyDevice>();
|
||
|
_onNewNotificationController = StreamController<PushProxyNotification>();
|
||
|
_onNewDeviceStream = _onNewDeviceController.stream.asBroadcastStream();
|
||
|
_onNewNotificationStream = _onNewNotificationController.stream.asBroadcastStream();
|
||
|
|
||
|
var handler = Cascade().add(_router).handler;
|
||
|
if (logging) {
|
||
|
handler = logRequests().addHandler(handler);
|
||
|
}
|
||
|
final server = await serve(
|
||
|
handler,
|
||
|
InternetAddress.anyIPv4,
|
||
|
port,
|
||
|
);
|
||
|
server.autoCompress = true;
|
||
|
|
||
|
_server = server;
|
||
|
}
|
||
|
|
||
|
/// Closes the server
|
||
|
Future close() async {
|
||
|
if (_server != null) {
|
||
|
await _server!.close();
|
||
|
_server = null;
|
||
|
await _onNewDeviceController.close();
|
||
|
await _onNewNotificationController.close();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class PushProxyDevice {
|
||
|
PushProxyDevice({
|
||
|
required this.pushToken,
|
||
|
required this.deviceIdentifier,
|
||
|
required this.deviceIdentifierSignature,
|
||
|
required this.userPublicKey,
|
||
|
});
|
||
|
|
||
|
final String pushToken;
|
||
|
final String deviceIdentifier;
|
||
|
final String deviceIdentifierSignature;
|
||
|
final String userPublicKey;
|
||
|
}
|
||
|
|
||
|
class PushProxyNotification {
|
||
|
PushProxyNotification({
|
||
|
required this.deviceIdentifier,
|
||
|
required this.pushTokenHash,
|
||
|
required this.subject,
|
||
|
required this.signature,
|
||
|
required this.priority,
|
||
|
required this.type,
|
||
|
});
|
||
|
|
||
|
final String deviceIdentifier;
|
||
|
final String pushTokenHash;
|
||
|
final String subject;
|
||
|
final String signature;
|
||
|
final String priority;
|
||
|
final String type;
|
||
|
}
|