/// Browser WebSocket client library for the Angel framework. library angel_websocket.browser; import 'dart:async'; import 'dart:html'; import 'package:angel_client/angel_client.dart'; import 'package:angel_http_exception/angel_http_exception.dart'; import 'package:http/browser_client.dart' as http; import 'package:web_socket_channel/web_socket_channel.dart'; import 'package:web_socket_channel/html.dart'; import 'base_websocket_client.dart'; export 'angel_websocket.dart'; final RegExp _straySlashes = new RegExp(r"(^/)|(/+$)"); /// Queries an Angel server via WebSockets. class WebSockets extends BaseWebSocketClient { final List _services = []; WebSockets(String path) : super(new http.BrowserClient(), path); @override Future close() { for (var service in _services) { service.close(); } return super.close(); } @override Stream authenticateViaPopup(String url, {String eventName: 'token', String errorMessage}) { var ctrl = new StreamController(); var wnd = window.open(url, 'angel_client_auth_popup'); Timer t; StreamSubscription sub; t = new Timer.periodic(new Duration(milliseconds: 500), (timer) { if (!ctrl.isClosed) { if (wnd.closed) { ctrl.addError(new AngelHttpException.notAuthenticated( message: errorMessage ?? 'Authentication via popup window failed.')); ctrl.close(); timer.cancel(); sub?.cancel(); } } else timer.cancel(); }); sub = window.on[eventName ?? 'token'].listen((e) { if (!ctrl.isClosed) { ctrl.add((e as CustomEvent).detail); t.cancel(); ctrl.close(); sub.cancel(); } }); return ctrl.stream; } @override Future getConnectedWebSocket() { var socket = new WebSocket(authToken?.isNotEmpty == true ? '$basePath?token=$authToken' : basePath); var completer = new Completer(); socket ..onOpen.listen((_) { if (!completer.isCompleted) return completer.complete(new HtmlWebSocketChannel(socket)); }) ..onError.listen((e) { var err = e as ErrorEvent; if (!completer.isCompleted) return completer.completeError(err.error); }); return completer.future; } @override BrowserWebSocketsService service(String path, {Type type, AngelDeserializer deserializer}) { String uri = path.replaceAll(_straySlashes, ''); return new BrowserWebSocketsService(socket, this, uri, deserializer: deserializer); } } class BrowserWebSocketsService extends WebSocketsService { final Type type; BrowserWebSocketsService(WebSocketChannel socket, Angel app, String uri, {this.type, AngelDeserializer deserializer}) : super(socket, app, uri, deserializer: deserializer); }