// ignore_for_file: avoid_print, prefer_final_fields import 'dart:io'; import 'package:protobuf/protobuf.dart'; import 'packets/message_common.pb.dart'; import 'ws_protobuf_client.dart'; abstract class WsProtobufServer { List _clientList = []; bool _started = false; HttpServer? _server; final String _host; final int _port; final SecurityContext? _securityContext; final WsProtobufClient Function(WebSocket) _createNewClient; bool get started => _started; bool get isSecure => _securityContext != null; /// Plain WebSocket server (ws://). WsProtobufServer(this._host, this._port, this._createNewClient) : _securityContext = null; /// Secure WebSocket server (wss://). /// /// [securityContext] must have a certificate and private key loaded: /// ```dart /// final ctx = SecurityContext() /// ..useCertificateChain('server.crt') /// ..usePrivateKey('server.key'); /// final server = MyServer.secure('0.0.0.0', 443, ctx, (ws) => MyClient(ws)); /// ``` WsProtobufServer.secure( this._host, this._port, SecurityContext securityContext, this._createNewClient) : _securityContext = securityContext; Future start() async { final ctx = _securityContext; if (ctx != null) { _server = await HttpServer.bindSecure(_host, _port, ctx); } else { _server = await HttpServer.bind(_host, _port); } _started = true; _server!.listen((HttpRequest request) async { if (WebSocketTransformer.isUpgradeRequest(request)) { final ws = await WebSocketTransformer.upgrade(request); _onClientWebSocket(ws); } }); return Future.value(); } void _onClientWebSocket(WebSocket ws) { var client = _createNewClient(ws); client.addDisconnectListener(onDisconnectedClient); client.addListener((_) => onClientHeartBeat(client)); _clientList.add(client); onClientConnected(client); } // implement in child void onClientConnected(WsProtobufClient client); void onClientHeartBeat(WsProtobufClient client) {} void onDisconnectedClient(WsProtobufClient client) { _clientList.remove(client); client.dispose(); print('WS Client disconnected'); } Future broadcast(T data) async { for (var client in _clientList) { await client.send(data); } return Future.value(); } Future stop() async { await _server?.close(force: true); _started = false; return Future.value(); } }