// ignore_for_file: prefer_final_fields import 'dart:async'; import 'dart:io'; import 'package:protobuf/protobuf.dart'; import 'packets/message_common.pb.dart'; import 'protobuf_client.dart'; abstract class ProtobufServer { List _clientList = []; bool _started = false; ServerSocket? _server; SecureServerSocket? _secureServer; final String _host; final int _port; final SecurityContext? _securityContext; final ProtobufClient Function(Socket) _createNewClient; bool get started => _started; bool get isSecure => _securityContext != null; /// Plain TCP server. ProtobufServer(this._host, this._port, this._createNewClient) : _securityContext = null; /// SSL/TLS server. /// /// [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', 9090, ctx, (s) => MyClient(s)); /// ``` ProtobufServer.secure(this._host, this._port, SecurityContext securityContext, this._createNewClient) : _securityContext = securityContext; Future start() async { final securityContext = _securityContext; if (securityContext != null) { _secureServer = await SecureServerSocket.bind(_host, _port, securityContext); _started = true; _secureServer?.listen(_onClientSocket); } else { _server = await ServerSocket.bind(_host, _port); _started = true; _server?.listen(_onClientSocket); } return Future.value(); } void _onClientSocket(Socket socket) { var client = _createNewClient(socket); client.addDisconnectListener(onDisconnectedClient); client.addListener((_) => onClientHeartBeat(client)); _clientList.add(client); onClientConnected(client); } // implement in child void onClientConnected(ProtobufClient client); void onClientHeartBeat(ProtobufClient client) {} void onDisconnectedClient(ProtobufClient client) { _clientList.remove(client); unawaited(client.close()); } Future broadcast(T data) async { for (var client in _clientList) { await client.send(data); } return Future.value(); } Future stop() async { final clients = List.from(_clientList); _clientList.clear(); await _server?.close(); await _secureServer?.close(); for (final client in clients) { await client.close(); } _started = false; return Future.value(); } }