use socket.io client in dart in different places with a single instance
To achieve your required functionality you will need to create one class for Socket IO plugin which will do all the interections with SocketIO package's code and also you will need to create one factory constructor so use same SocketApi object across the application.
Example of factory constructor.
class SocketApi {
// A static private instance to access _socketApi from inside class only
static final SocketApi _socketApi = SocketApi._internal();
// An internal private constructor to access it for only once for static instance of class.
SocketApi._internal();
// Factry constructor to retutn same static instance everytime you create any object.
factory SocketApi() {
return _socketApi;
}
// All socket related functions.
}
Usage
SocketApi socketApi = SocketApi();
You can learn more about factory constructor here.
Amine Da.
Intern at Microsoft. Working with : WPF, Universal apps 10 and .net .
Updated on January 04, 2023Comments
-
Amine Da. over 1 year
I use Bloc and repositories, I'm going to use the socket in different places in the project. each api package has its own events but shares the same socket. I want to connect once and use it in multiple places and packages. Is that possible?
// use socket in multiple files final socket = SocketApi().init();
In javascript I would export { socket }
package : https://pub.dev/packages/socket_io_client
UPDATE: socket init function can be called and connects multiple times even if the socket is static and checking if it's already connected
import 'dart:async'; import 'package:ngi_api/ngi_api.export.dart'; import 'package:socket_io_client/socket_io_client.dart' as IO; class StreamSocketController<T> { StreamSocketController() { print('Init Stream controller ${T.toString()}'); } final _socketResponse = StreamController<T>(); void Function(T) get addResponse => _socketResponse.sink.add; Stream<T> get getResponse => _socketResponse.stream; void dispose() { _socketResponse.close(); } } class SocketApi { // Factry constructor to retutn same static instance everytime you create any object. factory SocketApi() { return _socketApi; } // An internal private constructor to access it for only once for static instance of class. SocketApi._internal(); static void init() { print('socket init connected: ${socket.connected}'); if (socket.connected == false) { socket.connect(); socket.on('server:connected', (dynamic data) { print( 'socket instance created and connected', ); socket.emit( 'user:connected', <dynamic, dynamic>{'user': Environment.user}, ); }); socket.on('unauthorized', (dynamic data) { print('Unauthorized'); }); socket.onError( (dynamic error) => {print(error), print('socket error')}, ); socket.onDisconnect((dynamic data) { print('socket instance disconnected'); }); } else { print('socket instance already connected'); } } // A static private instance to access _socketApi from inside class only static final SocketApi _socketApi = SocketApi._internal(); static IO.Socket socket = IO.io( TcFleetTunEnvironment.socketURL, IO.OptionBuilder() .setTransports(['websocket']) .disableAutoConnect() .enableForceNewConnection() .setTimeout(5000) .setReconnectionDelay(10000) .enableReconnection() .setQuery( <dynamic, dynamic>{'token': Environment.token}, ) .build(), ); // All socket related functions. static Stream<Asset> getAsset() async* { final streamSocket = StreamSocketController<Asset>(); try { socket.on('newMsg', (dynamic data) { try { streamSocket .addResponse(Asset.fromJson(data as Map<String, dynamic>)); } catch (e, stackTrace) { print('Exception newMsg'); print(e); print(stackTrace); print(data); } }); yield* streamSocket.getResponse.take(20); } catch (e) { print('Exception getAsset'); print(e); } finally { print('Stream controller asset closed'); socket.off('newMsg'); streamSocket.dispose(); } } } //main void main() async { SocketApi.init(); SocketApi.init(); SocketApi.getAsset().listen( (Asset data) { print('Asset.1: ${data.name}'); }, cancelOnError: false, onError: print, onDone: () { print('*** asset.1 stream controller Done ***'); }, ); }
this is the result if i call socketApi.init() multiple times, socket already connected never gets printed , instead a new connection is created
This is my dependencies file
-
Amine Da. about 2 yearsmakes sense , thank you. I'll try to make a factory constructor.
-
Amine Da. about 2 yearsI'm getting this error though, A value of type 'Socket' can't be returned from the constructor 'SocketService' because it has a return type of 'SocketService'
-
Amine Da. about 2 yearsshould i put the socket connection inside the internal constructor ? I'm not sure where should i connect to the socket. i'll update my question with some code
-
Devarsh Ranpara about 2 yearsHi, I have checked out your implementation, and seems like there is not any issues in your factory constructor. Althogh you should create one method for initialize the socket and you should not put it inside the internal constructor. Let me know if you still face any issues.
-
Amine Da. about 2 yearsShould the internal constructor stay empty? is it just made for caching the instance? What's the point of the internal constructor if i shouldn't initialize the socket in it?
-
Devarsh Ranpara about 2 yearsInternal constructor can have code, but it should not have expensive calls. Creating a new function for init would be best practice for this kind of scenarios.
-
Amine Da. about 2 yearsI did create a function for init , but that made creating more than one socket instance possible. should the function init be private and static? but that means i need to call it inside the constructor
-
Devarsh Ranpara about 2 yearsDoes creating init function solved your issue? You need to use constructor only for providing instance of class and use init method for socket connection, you can check in init method, is connection is already there you can avoid execution of whole Soekct.
-
Amine Da. about 2 yearssocket init function can be called and connects multiple times even if the socket is static and checking if it's already connected. I updated the code and output. PLZ take a look and if you notice an error, can you update your answer with some code? thanks in advance
-
Devarsh Ranpara almost 2 yearsOkay I will try to run this code and get back to you, can you tell me which plugin you are using with version. Your code does not look nullsafe, so Flutter version will be appriciated as well.
-
Amine Da. almost 2 yearsmy code is null safe I'm using the latest dart and flutter version, I updated my post with yaml file