'use socket.io client in dart in different places with a single instance
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
Solution 1:[1]
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.
Solution 2:[2]
Yes, Of course, that is possible. You can make one singleton service and access it on a global level. When you need to ensure only a single instance of a class is created, and you want to provide a global point of access to it, the Singleton design pattern can be of great help.
class SocketSingleton {
Socket _socket;
SocketSingleton._privateConstructor();
static final SocketSingleton _instance =
SocketSingleton._privateConstructor();
static SocketSingleton get instance => _instance;
static SocketSingleton get socket => _socket;
initSocket() {
_socket = SocketApi().init();
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Kishan Busa |