import 'dart:html'; import 'dart:convert'; import 'dart:async'; // Import for handling Completers class Backend { static WebSocket? _socket; static String? _url; static String? _username; static Map _pendingActions = {}; static Map>> _chatControllers = {}; static int _nextNonce = 0; // Tracking nonce for each action static StreamController> _packetStreamController = StreamController.broadcast(); static void setup(String url) { _url = url; connect(); } static void auth(String username, String password) { _socket!.send(json.encode({'username': username, 'password': password})); _username = username; } static void connect() { _socket = WebSocket(_url!); _socket!.onOpen.listen((event) { print('Connected to the WebSocket server'); }); _socket!.onError.listen((event) { print('Error: $event'); _reconnect(); }); _socket!.onClose.listen((event) { print('Disconnected. Attempting to reconnect...'); _reconnect(); }); _socket!.onMessage.listen((event) { _handleIncomingMessage(event.data); }); } static void _reconnect() { Future.delayed(Duration(seconds: 5), () { connect(); }); } static Future sendAction(String action, Map body) { int nonce = _nextNonce++; Completer completer = Completer(); _pendingActions[nonce] = completer; final packet = { 'action': action, 'nonce': nonce, 'body': body, }; _socket!.send(json.encode(packet)); return completer.future.then((response) { _pendingActions.remove(nonce); // Clean up the mapping return response; }); } static void _handleIncomingMessage(String data) { var jsonData = json.decode(data); print("Incoming Packet: $jsonData"); if (jsonData['nonce'] != null) { int nonce = jsonData['nonce']; if (_pendingActions.containsKey(nonce)) { // Complete the response _pendingActions[nonce]!.complete(jsonData); } else { print("Orphan response for action nonce $nonce"); } } else if (jsonData['action'] == 'chat-message') { int chatId = jsonData['chatId']; final controller = _chatControllers[chatId]; if (controller != null && !controller.isClosed) { controller.add(jsonData); } else { print("No active listeners for chatId $chatId"); } } else { _packetStreamController.add(jsonData); } } static Stream> chatMessages(int chatId) { if (!_chatControllers.containsKey(chatId) || _chatControllers[chatId]!.isClosed) { _chatControllers[chatId] = StreamController>.broadcast(); } return _chatControllers[chatId]!.stream; } static void removeChatListener(int chatId) { final controller = _chatControllers.remove(chatId); if (controller != null && !controller.isClosed) { controller.close(); } } static void ping() { if (_socket!= null && _socket!.readyState == WebSocket.OPEN) { final data = json.encode({'path': 'ping'}); _socket!.send(data); print('Ping sent: $data'); } } }