platform/packages/websocket/lib/browser.dart

112 lines
3.1 KiB
Dart
Raw Normal View History

2016-12-23 20:57:46 +00:00
/// Browser WebSocket client library for the Angel framework.
2021-05-15 07:19:35 +00:00
library angel3_websocket.browser;
2016-12-23 20:57:46 +00:00
2016-07-21 01:36:16 +00:00
import 'dart:async';
import 'dart:html';
2021-05-15 07:19:35 +00:00
import 'package:angel3_client/angel3_client.dart';
2017-02-12 03:06:40 +00:00
import 'package:http/browser_client.dart' as http;
2016-12-23 20:57:46 +00:00
import 'package:web_socket_channel/web_socket_channel.dart';
import 'package:web_socket_channel/html.dart';
import 'base_websocket_client.dart';
2021-05-15 07:19:35 +00:00
export 'angel3_websocket.dart';
2016-07-21 01:36:16 +00:00
2021-04-10 15:12:43 +00:00
final RegExp _straySlashes = RegExp(r'(^/)|(/+$)');
2016-07-21 01:36:16 +00:00
2016-12-23 20:57:46 +00:00
/// Queries an Angel server via WebSockets.
class WebSockets extends BaseWebSocketClient {
2017-06-30 23:09:03 +00:00
final List<BrowserWebSocketsService> _services = [];
2017-03-02 03:54:58 +00:00
WebSockets(baseUrl,
2021-04-26 00:47:32 +00:00
{bool reconnectOnClose = true, Duration? reconnectInterval})
2021-02-21 02:47:23 +00:00
: super(http.BrowserClient(), baseUrl,
reconnectOnClose: reconnectOnClose,
reconnectInterval: reconnectInterval);
2016-09-18 01:35:16 +00:00
2017-03-02 03:54:58 +00:00
@override
Future close() {
for (var service in _services) {
service.close();
}
return super.close();
}
@override
Stream<String> authenticateViaPopup(String url,
2021-04-26 00:47:32 +00:00
{String eventName = 'token', String? errorMessage}) {
2021-02-21 02:47:23 +00:00
var ctrl = StreamController<String>();
2017-03-02 03:54:58 +00:00
var wnd = window.open(url, 'angel_client_auth_popup');
2017-04-23 18:40:30 +00:00
Timer t;
2021-04-26 00:47:32 +00:00
StreamSubscription<Event>? sub;
2021-02-21 02:47:23 +00:00
t = Timer.periodic(Duration(milliseconds: 500), (timer) {
2017-04-23 18:40:30 +00:00
if (!ctrl.isClosed) {
2021-07-10 04:32:42 +00:00
if (wnd.closed == true) {
2021-02-21 02:47:23 +00:00
ctrl.addError(AngelHttpException.notAuthenticated(
2017-03-02 03:54:58 +00:00
message:
2017-09-24 04:37:58 +00:00
errorMessage ?? 'Authentication via popup window failed.'));
2017-03-02 03:54:58 +00:00
ctrl.close();
2017-04-23 18:40:30 +00:00
timer.cancel();
2017-06-03 18:13:38 +00:00
sub?.cancel();
2017-03-02 03:54:58 +00:00
}
2021-04-10 15:12:43 +00:00
} else {
2017-04-23 18:40:30 +00:00
timer.cancel();
2021-04-10 15:12:43 +00:00
}
2017-04-23 18:40:30 +00:00
});
2021-04-26 00:47:32 +00:00
sub = window.on[eventName].listen((e) {
2017-04-23 18:40:30 +00:00
if (!ctrl.isClosed) {
2018-07-10 16:54:55 +00:00
ctrl.add((e as CustomEvent).detail.toString());
2017-04-23 18:40:30 +00:00
t.cancel();
ctrl.close();
2021-07-10 04:32:42 +00:00
sub?.cancel();
2017-04-23 18:40:30 +00:00
}
});
2017-03-02 03:54:58 +00:00
return ctrl.stream;
}
2016-07-21 01:36:16 +00:00
@override
2016-12-23 20:57:46 +00:00
Future<WebSocketChannel> getConnectedWebSocket() {
2019-01-06 02:41:46 +00:00
var url = websocketUri;
if (authToken?.isNotEmpty == true) {
url = url.replace(
2021-04-26 00:47:32 +00:00
queryParameters: Map<String, String?>.from(url.queryParameters)
2019-01-06 02:41:46 +00:00
..['token'] = authToken);
}
2021-02-21 02:47:23 +00:00
var socket = WebSocket(url.toString());
var completer = Completer<WebSocketChannel>();
2016-07-21 01:36:16 +00:00
2016-12-23 20:57:46 +00:00
socket
..onOpen.listen((_) {
2021-04-10 15:12:43 +00:00
if (!completer.isCompleted) {
2021-02-21 02:47:23 +00:00
return completer.complete(HtmlWebSocketChannel(socket));
2021-04-10 15:12:43 +00:00
}
2016-12-23 20:57:46 +00:00
})
2017-09-24 04:37:58 +00:00
..onError.listen((e) {
2021-04-10 15:12:43 +00:00
if (!completer.isCompleted) {
2021-04-26 00:47:32 +00:00
return completer.completeError(e is ErrorEvent ? e.error! : e);
2021-04-10 15:12:43 +00:00
}
2016-12-23 20:57:46 +00:00
});
2016-07-21 01:36:16 +00:00
2016-12-23 20:57:46 +00:00
return completer.future;
2016-07-21 01:36:16 +00:00
}
@override
2021-04-26 00:47:32 +00:00
Service<Id, Data> service<Id, Data>(String path,
{Type? type, AngelDeserializer<Data>? deserializer}) {
2021-04-10 15:12:43 +00:00
var uri = path.replaceAll(_straySlashes, '');
2021-02-21 02:47:23 +00:00
return BrowserWebSocketsService<Id, Data>(socket, this, uri,
2021-04-26 00:47:32 +00:00
deserializer: deserializer) as Service<Id, Data>;
2016-07-21 01:36:16 +00:00
}
}
2018-10-21 08:15:51 +00:00
class BrowserWebSocketsService<Id, Data> extends WebSocketsService<Id, Data> {
2021-04-26 00:47:32 +00:00
final Type? type;
2016-07-21 01:36:16 +00:00
2023-12-24 01:52:57 +00:00
BrowserWebSocketsService(super.socket, WebSockets super.app, super.uri,
{this.type, super.deserializer});
2016-07-21 01:36:16 +00:00
}