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
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.