import 'dart:async'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:network_info_plus/network_info_plus.dart'; import 'package:shelf/shelf.dart'; import 'package:shelf/shelf_io.dart' as io; import 'package:shelf_web_socket/shelf_web_socket.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import 'package:bus_infotainment/backend/modules/info_module.dart'; import 'package:bus_infotainment/utils/delegates.dart'; class NetworkingModule extends InfoModule { // Host websocket server String host = "ws://0.0.0.0:8080"; HttpServer? _server; WebSocketChannel? _channel; // Store connected WebSocket channels final List _connectedClients = []; EventDelegate? onMessageReceived = EventDelegate(); NetworkingModule() { _refresh(); refreshTimer(); } Future startWebSocketServer() async { try { var handler = webSocketHandler((WebSocketChannel webSocket) { _connectedClients.add(webSocket); // Add the client to the list print('Client connected: ${webSocket}'); // Log client connection webSocket.stream.listen((message) { // Handle messages from the client here print('Received message: $message'); // Forward message to all clients except the sender for (var client in _connectedClients) { if (client != webSocket) { client.sink.add(message); } } _onMessageReceived(message); }, onDone: () { _connectedClients.remove(webSocket); // Remove client on disconnect print('Client disconnected: ${webSocket}'); // Log client disconnection }); }); _server = await io.serve(handler, InternetAddress.anyIPv4, 8080); print('WebSocket server started at ${_server?.address.address}:${_server?.port}'); return true; } catch (e) { print('Failed to start WebSocket server: $e'); return false; } } bool stopWebSocketServer() { if (_server == null) { throw Exception('WebSocket server is not running'); } try { for (var client in _connectedClients) { client.sink.close(); } _connectedClients.clear(); _server?.close(force: true); _server = null; print('WebSocket server stopped'); return true; } catch (e) { print('Failed to stop WebSocket server: $e'); return false; } } Future connectToWebSocketServer(String url) async { try { _channel = await WebSocketChannel.connect(Uri.parse(url)); _channel?.stream.listen((message) { // Handle messages from the server here print('Received message from server: $message'); _onMessageReceived(message); }); print('Connected to WebSocket server at $url'); return true; } catch (e) { print('Failed to connect to WebSocket server: $e'); return false; } } bool disconnectFromWebSocketServer() { if (_channel == null) { throw Exception('No active WebSocket connection'); } try { _channel?.sink.close(); _channel = null; print('Disconnected from WebSocket server'); return true; } catch (e) { print('Failed to disconnect from WebSocket server: $e'); return false; } } bool sendMessage(String message) { // If hosting a server, send message to all clients if (_server != null) { return sendMessageToClients(message); } if (_channel == null) { throw Exception('No active WebSocket connection'); } try { _channel?.sink.add(message); print('Sent message: $message'); return true; } catch (e) { print('Failed to send message: $e'); return false; } } bool sendMessageToClients(String message) { if (_connectedClients.isEmpty) { print('No clients connected'); return false; } try { for (var client in _connectedClients) { client.sink.add(message); } print('Sent message to all clients: $message'); return true; } catch (e) { print('Failed to send message to clients: $e'); return false; } } void _onMessageReceived(String message) { // Notify all listeners that a message has been received. onMessageReceived?.trigger(message); } // Useful boilerplate String _localIP = ""; String get localIP => _localIP; Timer refreshTimer() => Timer.periodic(const Duration(seconds: 10), (timer) { if (kIsWeb) return; _refresh(); }); Future _refresh() async { print("Refreshing network info..."); { // Update the local IP address // First try NetworkInfo _localIP = (await NetworkInfo().getWifiIP()) ?? ""; // If null, try NetworkInterface // Only look for ethernet. Wifi would have been found by NetworkInfo if (_localIP.isEmpty) { for (var interface in await NetworkInterface.list()) { if (!interface.name.toLowerCase().contains("eth") || interface.name.contains(" ")) { continue; } for (var addr in interface.addresses) { print('Interface ${interface.name} has address ${addr.address}'); if (addr.type == InternetAddressType.IPv4 && !addr.isLoopback) { _localIP = addr.address; break; } } } } } } }