使用 socket.io client in dart 在不同地方使用单个实例

use socket.io client in dart in different places with a single instance

我使用 Bloc 和存储库, 我将在项目的不同地方使用套接字。 每个 api 包都有自己的事件,但共享同一个套接字。 我想连接一次并在多个地方和包中使用它。 这可能吗?

// use socket in multiple files 
final socket = SocketApi().init();

在 javascript 我会导出 { socket }

包:https://pub.dev/packages/socket_io_client


更新:即使套接字是静态的,也可以多次调用和连接套接字初始化函数,并检查它是否已经连接

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 ***');
    },
  );
}

这是我多次调用 socketApi.init() 的结果,已连接的套接字永远不会打印出来,而是创建一个新连接

这是我的依赖文件

要实现所需的功能,您需要为 Socket IO 插件创建一个 class,它将与 SocketIO 包的代码进行所有交互,并且您还需要创建一个工厂构造函数,因此使用相同的 SocketApi 对象整个应用程序。

工厂构造函数示例。

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

用法

SocketApi socketApi = SocketApi();

您可以了解有关工厂构造函数的更多信息here

是的,当然可以。您可以制作一个单例服务并在全球范围内访问它。当您需要确保只创建 class 的单个实例,并且您希望提供对其的全局访问点时,单例设计模式会很有帮助。

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();
  }
}