import 'dart:async'; import 'dart:developer'; import 'package:taafee_mobile/core/errors/custom_exception.dart'; import 'package:socket_io_client/socket_io_client.dart'; import './event.dart'; import './extension.dart'; class SocketIO { // @attributes final String uri; Function()? onConnect; Function()? onDisconnect; Function()? onConnecting; Function()? onError; Map extraHeaders = {}; // @constructors SocketIO({ required this.uri, this.onConnect, this.onConnecting, this.onError, this.onDisconnect, }); // @privates Socket? _socket; // suggest late instead of nullable bool _initialized = false; Status _status = Status.notConnected; final Map _socketOptions = { 'transports': ['websocket'], 'autoConnect': true, }; // @getters bool get initialized => _initialized; Status get status => _status; // @methods Future boot() async { init(); await connect(); } Future restart() async { _assertInitialized(); await disconnect(); await boot(); } void init() { _socketOptions["extraHeaders"] = extraHeaders; _socket = io(uri, _socketOptions); _initialized = true; } Future connect() async { _assertInitialized(); _status = Status.connecting; onConnecting?.call(); await _socket!.connectAsync().timeout(const Duration(seconds: 10), onTimeout: () { onError?.call(); throw GenericException( type: ExceptionType.connectionError, errorMessage: "You Have no Internet Connection", ); }); onConnect?.call(); _status = Status.connected; } void setOnDisconnect(Function() trigger) { onDisconnect = trigger; _socket?.onDisconnect((_) => trigger()); } void setOnConnect(Function() trigger) { onConnect = trigger; _socket?.onConnect((data) => trigger()); } void setOnConnectionError(Function() trigger) { onError = trigger; _socket?.onerror((_) => trigger()); } void setOnConnecting(Function() trigger) { onConnecting = trigger; _socket?.onerror((_) => trigger()); } Future disconnect() async { _assertInitialized(); await _socket!.disconnectAsync(); // suggest onDisconnect?.call(); _status = Status.notConnected; } Future emit(Event event, {bool reciveDataOnError = false}) async { _assertInitialized(); dynamic ack = {}; try { ack = await _socket!.emitAsync(event.name, event.body); if (ack["status"] == "failed") { if (reciveDataOnError) { return ack; } throw badRequestException[ ack["error"]["name"] ?? "INTERNAL_SERVER_ERROR"] ?? GenericException( type: ExceptionType.internalServerException, ); } } catch (e) { if (e is GenericException) { rethrow; } throw GenericException( type: ExceptionType.internalServerException, ); } return ack["data"]; } void listen(String eventName, Function(dynamic) handler) { // there is no need to check if initialized here, it is just registering a handler. _socket!.on(eventName, (data) { log('event:$eventName'); handler(data); }); } void setAuthentication(String token) { extraHeaders["authorization"] = token; } void _assertInitialized() { if (!initialized) { throw Exception("Object is not initialized, do call .init() method"); } } void clearListeners() { _socket?.clearListeners(); } } enum Status { connected, connecting, notConnected }