From 585f3f71abdbf73c9abee5cf73d8886cd67cf3a1 Mon Sep 17 00:00:00 2001 From: kechankrisna Date: Tue, 24 Feb 2026 15:28:58 +0700 Subject: [PATCH 1/5] feat: improve for dart 3 --- CHANGELOG.md | 25 ++++++++ analysis_options.yaml | 2 +- lib/socket_io.dart | 2 +- lib/src/adapter/adapter.dart | 19 +++--- lib/src/client.dart | 9 +-- lib/src/engine/server.dart | 6 +- lib/src/engine/socket.dart | 6 +- .../engine/transport/polling_transport.dart | 20 +++--- lib/src/engine/transport/transports.dart | 4 +- .../engine/transport/websocket_transport.dart | 5 +- lib/src/namespace.dart | 6 +- lib/src/server.dart | 61 +++++++------------ lib/src/socket.dart | 12 ++-- lib/src/util/event_emitter.dart | 26 ++++---- pubspec.yaml | 14 ++--- test/socket.test.dart | 4 +- 16 files changed, 111 insertions(+), 110 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef03978..fc19781 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +## 2.0.0 + +**Breaking Changes — Dart 3 upgrade:** + +* Raised SDK constraint to `>=3.0.0 <4.0.0` +* Upgraded `stream` to `^4.0.0` (Dart 3 compatible) +* Upgraded `socket_io_common` to `^3.0.0` (Socket.IO v4.7+ protocol, Dart 3) + * All internal `src/` imports replaced with `package:socket_io_common/socket_io_common.dart` + * `ERROR` packet-type constant renamed to `CONNECT_ERROR` (protocol v5 alignment) + * `PacketParser.decodePayload` is now synchronous (returns `List`); callback pattern removed + * `PacketParser.encodePayload` no longer accepts `supportsBinary` parameter + * `PacketParser.decodePacket` second parameter is now positional `binaryType` (not `utf8decode`) +* Upgraded `uuid` to `^4.0.0` +* Replaced retired `pedantic` dev-dependency with `lints: ^3.0.0` +* Updated `analysis_options.yaml` to include `package:lints/recommended.yaml` + +**Bug Fixes (Dart 3 soundness):** + +* `namespace.dart`: Fixed JS-style boolean truthiness check `if (err)` → `if (err != null)` +* `namespace.dart`: Fixed JS-style `||` null-coalesce `err.data || err.message` → `err.data ?? err.message` +* `server.dart`: Fixed JS-style `if (err)` → `if (err != null)` in `set()` authorization callback +* `server.dart`: Fixed JS-style `&&` truthiness `oldSettings[key] && engine![...]` → null checks +* `engine/server.dart`: Fixed null-safety in `abortConnection` — `ServerErrorMessages[code]` is `String?` +* `polling_transport.dart`: Added null guard for `maxHttpBufferSize` comparison + ## 1.0.1 **Bug Fix:** diff --git a/analysis_options.yaml b/analysis_options.yaml index 80bb834..91bd51c 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -2,7 +2,7 @@ # # The commented part below is just for inspiration. Read the guide here: # https://www.dartlang.org/guides/language/analysis-options -include: package:pedantic/analysis_options.yaml +include: package:lints/recommended.yaml analyzer: # exclude: # - path/to/excluded/files/** diff --git a/lib/socket_io.dart b/lib/socket_io.dart index d8148d5..37fe978 100644 --- a/lib/socket_io.dart +++ b/lib/socket_io.dart @@ -7,5 +7,5 @@ export 'src/engine/transport/jsonp_transport.dart' show JSONPTransport; export 'src/engine/transport/polling_transport.dart' show PollingTransport; export 'src/engine/transport/websocket_transport.dart' show WebSocketTransport; -export 'package:socket_io_common/src/engine/parser/parser.dart' +export 'package:socket_io_common/socket_io_common.dart' show PacketParser; diff --git a/lib/src/adapter/adapter.dart b/lib/src/adapter/adapter.dart index 4d4a08f..6ba7777 100644 --- a/lib/src/adapter/adapter.dart +++ b/lib/src/adapter/adapter.dart @@ -10,7 +10,7 @@ /// Copyright (C) 2017 Potix Corporation. All Rights Reserved. import 'dart:async'; import 'package:socket_io/src/namespace.dart'; -import 'package:socket_io_common/src/parser/parser.dart'; +import 'package:socket_io_common/socket_io_common.dart'; import 'package:socket_io/src/util/event_emitter.dart'; abstract class Adapter { @@ -128,8 +128,8 @@ class _MemoryStoreAdapter extends EventEmitter implements Adapter { var socket; packet['nsp'] = nsp.name; - encoder.encode(packet, (encodedPackets) { - if (rooms.isNotEmpty) { + var encodedPackets = encoder.encode(packet); + if (rooms.isNotEmpty) { for (var i = 0; i < rooms.length; i++) { var room = this.rooms[rooms[i]]; if (room == null) continue; @@ -146,17 +146,14 @@ class _MemoryStoreAdapter extends EventEmitter implements Adapter { } } } else { - for (var id in sids.keys) { - if (except.contains(id)) continue; - socket = nsp.connected[id]; - if (socket != null) socket.packet(encodedPackets, packetOpts); - } + for (var id in sids.keys) { + if (except.contains(id)) continue; + socket = nsp.connected[id]; + if (socket != null) socket.packet(encodedPackets, packetOpts); } - }); + } } - /// Gets a list of clients by sid. - /// /// @param {Array} explicit set of rooms to check. /// @param {Function} callback /// @api public diff --git a/lib/src/client.dart b/lib/src/client.dart index 745ebd5..604206e 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -11,7 +11,7 @@ import 'package:logging/logging.dart'; import 'package:socket_io/src/engine/socket.dart'; -import 'package:socket_io_common/src/parser/parser.dart'; +import 'package:socket_io_common/socket_io_common.dart'; import 'package:socket_io/src/server.dart'; class Client { @@ -55,7 +55,7 @@ class Client { _logger.fine('connecting to namespace $name'); if (!server.nsps.containsKey(name)) { packet({ - 'type': ERROR, + 'type': CONNECT_ERROR, 'nsp': name, 'data': 'Invalid namespace' }); @@ -140,10 +140,7 @@ class Client { _logger.fine('writing packet $packet'); if (opts['preEncoded'] != true) { // not broadcasting, need to encode - encoder.encode(packet, (encodedPackets) { - // encode, then write results to engine - writeToEngine(encodedPackets); - }); + writeToEngine(encoder.encode(packet)); } else { // a broadcast pre-encodes a packet writeToEngine(packet); diff --git a/lib/src/engine/server.dart b/lib/src/engine/server.dart index 4c552bb..d563532 100644 --- a/lib/src/engine/server.dart +++ b/lib/src/engine/server.dart @@ -428,9 +428,9 @@ class Server extends Engine { static void abortConnection(SocketConnect connect, code) { var socket = connect.websocket; if (socket?.readyState == HttpStatus.ok) { - var message = ServerErrorMessages.containsKey(code) - ? ServerErrorMessages[code] - : code; + final String message = ServerErrorMessages.containsKey(code) + ? (ServerErrorMessages[code] ?? '') + : '$code'; var length = utf8.encode(message).length; socket!.add('HTTP/1.1 400 Bad Request\r\n' 'Connection: close\r\n' diff --git a/lib/src/engine/socket.dart b/lib/src/engine/socket.dart index 34e56ad..dbf46d4 100644 --- a/lib/src/engine/socket.dart +++ b/lib/src/engine/socket.dart @@ -314,10 +314,8 @@ class Socket extends EventEmitter { var onDrain = (_) { if (sentCallbackFn.isNotEmpty) { var seqFn = sentCallbackFn[0]; - if (seqFn is Function) { - _logger.fine('executing send callback'); - seqFn(transport); - } + _logger.fine('executing send callback'); + seqFn(transport); /// else if (Array.isArray(seqFn)) { /// _logger.fine('executing batch send callback'); diff --git a/lib/src/engine/transport/polling_transport.dart b/lib/src/engine/transport/polling_transport.dart index 397aad8..6e796d7 100644 --- a/lib/src/engine/transport/polling_transport.dart +++ b/lib/src/engine/transport/polling_transport.dart @@ -13,7 +13,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:logging/logging.dart'; import 'package:socket_io/src/engine/connect.dart'; -import 'package:socket_io_common/src/engine/parser/parser.dart'; +import 'package:socket_io_common/socket_io_common.dart'; import 'package:socket_io/src/engine/transport/transports.dart'; class PollingTransport extends Transport { @@ -136,7 +136,8 @@ class PollingTransport extends Transport { contentLength = chunks.length; } - if (contentLength > self.maxHttpBufferSize) { + if (self.maxHttpBufferSize != null && + contentLength > self.maxHttpBufferSize!) { chunks = ''; connect.close(); } @@ -180,18 +181,15 @@ class PollingTransport extends Transport { messageHandler!.handle(this, data); } else { var self = this; - var callback = (packet, [foo, bar]) { + var packets = PacketParser.decodePayload(data, null); + for (var packet in (packets is List ? packets : [packets])) { if ('close' == packet['type']) { _logger.fine('got xhr close packet'); self.onClose(); - return false; + break; } - - self.onPacket(packet); - return true; - }; - - PacketParser.decodePayload(data, callback: callback); + self.onPacket(packet as Map); + } } } @@ -225,7 +223,7 @@ class PollingTransport extends Transport { } var self = this; - PacketParser.encodePayload(packets, supportsBinary: supportsBinary == true, + PacketParser.encodePayload(packets, callback: (data) { var compress = packets.any((packet) { var opt = packet['options']; diff --git a/lib/src/engine/transport/transports.dart b/lib/src/engine/transport/transports.dart index 910e8d3..2b5b42b 100644 --- a/lib/src/engine/transport/transports.dart +++ b/lib/src/engine/transport/transports.dart @@ -10,7 +10,7 @@ /// Copyright (C) 2017 Potix Corporation. All Rights Reserved. import 'package:logging/logging.dart'; import 'package:socket_io/src/engine/connect.dart'; -import 'package:socket_io_common/src/engine/parser/parser.dart'; +import 'package:socket_io_common/socket_io_common.dart'; import 'package:socket_io/src/engine/transport/jsonp_transport.dart'; import 'package:socket_io/src/engine/transport/websocket_transport.dart'; import 'package:socket_io/src/engine/transport/xhr_transport.dart'; @@ -95,7 +95,7 @@ abstract class Transport extends EventEmitter { if (messageHandler != null) { messageHandler!.handle(this, data); } else { - onPacket(PacketParser.decodePacket(data, utf8decode: true)); + onPacket(PacketParser.decodePacket(data, null) as Map); } } diff --git a/lib/src/engine/transport/websocket_transport.dart b/lib/src/engine/transport/websocket_transport.dart index 4a23115..0de4d52 100644 --- a/lib/src/engine/transport/websocket_transport.dart +++ b/lib/src/engine/transport/websocket_transport.dart @@ -11,7 +11,7 @@ import 'dart:async'; /// /// Copyright (C) 2017 Potix Corporation. All Rights Reserved. import 'package:logging/logging.dart'; -import 'package:socket_io_common/src/engine/parser/parser.dart'; +import 'package:socket_io_common/socket_io_common.dart'; import 'package:socket_io/src/engine/transport/transports.dart'; class WebSocketTransport extends Transport { @@ -60,7 +60,8 @@ class WebSocketTransport extends Transport { for (var i = 0; i < packets.length; i++) { var packet = packets[i]; PacketParser.encodePacket(packet, - supportsBinary: supportsBinary, callback: (_) => send(_, packet)); + supportsBinary: supportsBinary ?? false, + callback: (_) => send(_, packet)); } } diff --git a/lib/src/namespace.dart b/lib/src/namespace.dart index 192325a..c25a078 100644 --- a/lib/src/namespace.dart +++ b/lib/src/namespace.dart @@ -12,7 +12,7 @@ import 'dart:async'; import 'package:logging/logging.dart'; import 'package:socket_io/src/adapter/adapter.dart'; import 'package:socket_io/src/client.dart'; -import 'package:socket_io_common/src/parser/parser.dart'; +import 'package:socket_io_common/socket_io_common.dart'; import 'package:socket_io/src/server.dart'; import 'package:socket_io/src/socket.dart'; import 'package:socket_io/src/util/event_emitter.dart'; @@ -83,7 +83,7 @@ class Namespace extends EventEmitter { int index, List fns, Socket socket, Function fn) { return fns[index](socket, (err) { // upon error, short-circuit - if (err) return fn(err); + if (err != null) return fn(err); // if no middleware left, summon callback if (fns.length <= index + 1) return fn(null); @@ -125,7 +125,7 @@ class Namespace extends EventEmitter { // don't use Timer.run() here scheduleMicrotask(() { if ('open' == client.conn.readyState) { - if (err != null) return socket.error(err.data || err.message); + if (err != null) return socket.error(err.data ?? err.message); // track socket self.sockets.add(socket); diff --git a/lib/src/server.dart b/lib/src/server.dart index ba71551..9ed8ddb 100644 --- a/lib/src/server.dart +++ b/lib/src/server.dart @@ -14,11 +14,9 @@ import 'package:logging/logging.dart'; import 'package:socket_io/src/client.dart'; import 'package:socket_io/src/engine/engine.dart'; import 'package:socket_io/src/namespace.dart'; -import 'package:socket_io_common/src/parser/parser.dart'; +import 'package:socket_io_common/socket_io_common.dart'; import 'package:stream/stream.dart'; -import 'namespace.dart'; - /// Socket.IO client source. /// Old settings for backwards compatibility Map oldSettings = { @@ -140,7 +138,7 @@ class Server { if ('authorization' == key && val != null) { use((socket, next) { val(socket.request, (err, authorized) { - if (err) { + if (err != null) { return next(Exception(err)); } ; @@ -155,7 +153,7 @@ class Server { origins(val); } else if ('resource' == key) { path(val); - } else if (oldSettings[key] && engine![oldSettings[key]]) { + } else if (oldSettings[key] != null && engine![oldSettings[key]] != null) { engine![oldSettings[key]] = val; } else { _logger.severe('Option $key is not valid. Please refer to the README.'); @@ -254,50 +252,37 @@ class Server { //// response.close(); //// }); - var completer = Completer(); var connectPacket = {'type': CONNECT, 'nsp': '/'}; - encoder.encode(connectPacket, (encodedPacket) { - // the CONNECT packet will be merged with Engine.IO handshake, - // to reduce the number of round trips - opts!['initialPacket'] = encodedPacket; - - _logger.fine('creating engine.io instance with opts $opts'); - // initialize engine - engine = Engine.attach(server, opts); + // the CONNECT packet will be merged with Engine.IO handshake, + // to reduce the number of round trips + opts['initialPacket'] = encoder.encode(connectPacket); - // attach static file serving -// if (self._serveClient) self.attachServe(srv); + _logger.fine('creating engine.io instance with opts $opts'); + // initialize engine + engine = Engine.attach(server, opts); - // Export http server - httpServer = server; + // Export http server + httpServer = server; - // bind to engine events - bind(engine!); + // bind to engine events + bind(engine!); - completer.complete(); - }); - await completer.future; -// }); } else { var connectPacket = {'type': CONNECT, 'nsp': '/'}; - encoder.encode(connectPacket, (encodedPacket) { - // the CONNECT packet will be merged with Engine.IO handshake, - // to reduce the number of round trips - opts!['initialPacket'] = encodedPacket; + // the CONNECT packet will be merged with Engine.IO handshake, + // to reduce the number of round trips + opts['initialPacket'] = encoder.encode(connectPacket); - _logger.fine('creating engine.io instance with opts $opts'); - // initialize engine - engine = Engine.attach(srv, opts); + _logger.fine('creating engine.io instance with opts $opts'); + // initialize engine + engine = Engine.attach(srv, opts); - // attach static file serving -// if (self._serveClient) self.attachServe(srv); + // Export http server + httpServer = srv; - // Export http server - httpServer = srv; + // bind to engine events + bind(engine!); - // bind to engine events - bind(engine!); - }); } return this; diff --git a/lib/src/socket.dart b/lib/src/socket.dart index 016c08a..99eae80 100644 --- a/lib/src/socket.dart +++ b/lib/src/socket.dart @@ -11,7 +11,7 @@ import 'dart:io'; import 'package:socket_io/src/adapter/adapter.dart'; import 'package:socket_io/src/client.dart'; -import 'package:socket_io_common/src/parser/parser.dart'; +import 'package:socket_io_common/socket_io_common.dart'; import 'package:socket_io/src/namespace.dart'; import 'package:socket_io/src/server.dart'; import 'package:socket_io/src/util/event_emitter.dart'; @@ -297,7 +297,7 @@ class Socket extends EventEmitter { ondisconnect(); break; - case ERROR: + case CONNECT_ERROR: emit('error', packet['data']); } } @@ -349,10 +349,10 @@ class Socket extends EventEmitter { /// /// @api private void onack(packet) { - Function ack = acks.remove(packet['id']); - if (ack is Function) { + dynamic ackFn = acks.remove(packet['id']); + if (ackFn is Function) { // debug('calling ack %s with %j', packet.id, packet.data); - Function.apply(ack, packet['data']); + Function.apply(ackFn, packet['data']); } else { // debug('bad ack %s', packet.id); } @@ -401,7 +401,7 @@ class Socket extends EventEmitter { /// @param {Object} error object /// @api private void error(err) { - packet({'type': ERROR, 'data': err}); + packet({'type': CONNECT_ERROR, 'data': err}); } /// Disconnects this client. diff --git a/lib/src/util/event_emitter.dart b/lib/src/util/event_emitter.dart index 7c8b66e..36617af 100644 --- a/lib/src/util/event_emitter.dart +++ b/lib/src/util/event_emitter.dart @@ -16,12 +16,12 @@ typedef EventHandler = dynamic Function(T data); /// Generic event emitting and handling. class EventEmitter { /// Mapping of events to a list of event handlers - Map> _events = - HashMap>(); + Map> _events = + HashMap>(); /// Mapping of events to a list of one-time event handlers - Map> _eventsOnce = - HashMap>(); + Map> _eventsOnce = + HashMap>(); /// This function triggers all the handlers currently listening /// to [event] and passes them [data]. @@ -29,32 +29,32 @@ class EventEmitter { final list0 = _events[event]; // todo: try to optimize this. Maybe remember the off() handlers and remove later? // handler might be off() inside handler; make a copy first - final list = list0 != null ? List.from(list0) : null; + final list = list0 != null ? List.from(list0) : null; list?.forEach((handler) { handler(data); }); - _eventsOnce.remove(event)?.forEach((EventHandler handler) { + _eventsOnce.remove(event)?.forEach((Function handler) { handler(data); }); } /// This function binds the [handler] as a listener to the [event] - void on(String event, EventHandler handler) { - _events.putIfAbsent(event, () => []); + void on(String event, EventHandler handler) { + _events.putIfAbsent(event, () => []); _events[event]!.add(handler); } /// This function binds the [handler] as a listener to the first /// occurrence of the [event]. When [handler] is called once, /// it is removed. - void once(String event, EventHandler handler) { - _eventsOnce.putIfAbsent(event, () => []); + void once(String event, EventHandler handler) { + _eventsOnce.putIfAbsent(event, () => []); _eventsOnce[event]!.add(handler); } /// This function attempts to unbind the [handler] from the [event] - void off(String event, [EventHandler? handler]) { + void off(String event, [Function? handler]) { if (handler != null) { _events[event]?.remove(handler); _eventsOnce[event]?.remove(handler); @@ -72,8 +72,8 @@ class EventEmitter { /// This function unbinds all the handlers for all the events. void clearListeners() { - _events = HashMap>(); - _eventsOnce = HashMap>(); + _events = HashMap>(); + _eventsOnce = HashMap>(); } /// Returns whether the event has registered. diff --git a/pubspec.yaml b/pubspec.yaml index b42d222..b422c8b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,19 +2,19 @@ name: socket_io description: > Port of JS/Node library Socket.io. It enables real-time, bidirectional and event-based communication cross-platform. -version: 1.0.1 +version: 2.0.0 homepage: https://www.zkoss.org repository: https://github.com/rikulo/socket.io-dart issue_tracker: https://github.com/rikulo/socket.io-dart/issues environment: - sdk: '>=2.12.0 <3.0.0' + sdk: '>=3.0.0 <4.0.0' dependencies: - stream: ^3.0.0 - socket_io_common: ^1.0.1 - uuid: ^3.0.4 + stream: ^4.0.0 + socket_io_common: ^3.0.0 + uuid: ^4.0.0 logging: ^1.0.0 dev_dependencies: - test: ^1.16.8 - pedantic: ^1.11.0 + test: ^1.24.0 + lints: ^3.0.0 diff --git a/test/socket.test.dart b/test/socket.test.dart index bc9b5f1..918f902 100644 --- a/test/socket.test.dart +++ b/test/socket.test.dart @@ -17,14 +17,14 @@ void main() { test('Start standalone server', () async { var io = Server(); var nsp = io.of('/some'); - nsp.on('connection', (client) { + nsp.on('connection', (Socket client) { print('connection /some'); client.on('msg', (data) { print('data from /some => $data'); client.emit('fromServer', 'ok 2'); }); }); - io.on('connection', (client) { + io.on('connection', (Socket client) { print('connection default namespace'); client.on('msg', (data) { print('data from default => $data'); From ba6a9e6fce4fefd78a09b3e71fa6c25f84ed1c1a Mon Sep 17 00:00:00 2001 From: kechankrisna Date: Tue, 24 Feb 2026 15:33:18 +0700 Subject: [PATCH 2/5] chore: rename the package as _plus --- README.md | 2 +- example/README.md | 2 +- lib/src/adapter/adapter.dart | 4 ++-- lib/src/client.dart | 4 ++-- lib/src/engine/engine.dart | 4 ++-- lib/src/engine/server.dart | 8 ++++---- lib/src/engine/socket.dart | 8 ++++---- lib/src/engine/transport/jsonp_transport.dart | 4 ++-- lib/src/engine/transport/polling_transport.dart | 4 ++-- lib/src/engine/transport/transports.dart | 10 +++++----- lib/src/engine/transport/websocket_transport.dart | 2 +- lib/src/engine/transport/xhr_transport.dart | 4 ++-- lib/src/namespace.dart | 10 +++++----- lib/src/server.dart | 6 +++--- lib/src/socket.dart | 10 +++++----- pubspec.yaml | 8 +++----- test/socket.test.dart | 2 +- 17 files changed, 45 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index b578007..b6be9f2 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Port of awesome JavaScript Node.js library - [Socket.io v2.0.1](https://github.c ## Usage ```dart -import 'package:socket_io/socket_io.dart'; +import 'package:socket_io_plus/socket_io.dart'; main() { var io = new Server(); diff --git a/example/README.md b/example/README.md index 756fa64..0f793ee 100644 --- a/example/README.md +++ b/example/README.md @@ -5,7 +5,7 @@ Port of awesome JavaScript Node.js library - [Socket.io v2.0.1](https://github.c ## Usage ```dart -import 'package:socket_io/socket_io.dart'; +import 'package:socket_io_plus/socket_io.dart'; main() { var io = new Server(); diff --git a/lib/src/adapter/adapter.dart b/lib/src/adapter/adapter.dart index 6ba7777..453b8d4 100644 --- a/lib/src/adapter/adapter.dart +++ b/lib/src/adapter/adapter.dart @@ -9,9 +9,9 @@ /// /// Copyright (C) 2017 Potix Corporation. All Rights Reserved. import 'dart:async'; -import 'package:socket_io/src/namespace.dart'; +import 'package:socket_io_plus/src/namespace.dart'; import 'package:socket_io_common/socket_io_common.dart'; -import 'package:socket_io/src/util/event_emitter.dart'; +import 'package:socket_io_plus/src/util/event_emitter.dart'; abstract class Adapter { Map nsps = {}; diff --git a/lib/src/client.dart b/lib/src/client.dart index 604206e..eb35a59 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -10,9 +10,9 @@ /// Copyright (C) 2017 Potix Corporation. All Rights Reserved. import 'package:logging/logging.dart'; -import 'package:socket_io/src/engine/socket.dart'; +import 'package:socket_io_plus/src/engine/socket.dart'; import 'package:socket_io_common/socket_io_common.dart'; -import 'package:socket_io/src/server.dart'; +import 'package:socket_io_plus/src/server.dart'; class Client { Server server; diff --git a/lib/src/engine/engine.dart b/lib/src/engine/engine.dart index a2672d7..d4ee045 100644 --- a/lib/src/engine/engine.dart +++ b/lib/src/engine/engine.dart @@ -8,8 +8,8 @@ /// 16/02/2017, Created by jumperchen /// /// Copyright (C) 2017 Potix Corporation. All Rights Reserved. -import 'package:socket_io/src/engine/server.dart'; -import 'package:socket_io/src/util/event_emitter.dart'; +import 'package:socket_io_plus/src/engine/server.dart'; +import 'package:socket_io_plus/src/util/event_emitter.dart'; class Engine extends EventEmitter { static Engine attach(server, [Map? options]) { diff --git a/lib/src/engine/server.dart b/lib/src/engine/server.dart index d563532..019dab7 100644 --- a/lib/src/engine/server.dart +++ b/lib/src/engine/server.dart @@ -11,10 +11,10 @@ import 'dart:convert'; import 'dart:io' hide Socket; import 'package:logging/logging.dart'; -import 'package:socket_io/src/engine/connect.dart'; -import 'package:socket_io/src/engine/engine.dart'; -import 'package:socket_io/src/engine/socket.dart'; -import 'package:socket_io/src/engine/transport/transports.dart'; +import 'package:socket_io_plus/src/engine/connect.dart'; +import 'package:socket_io_plus/src/engine/engine.dart'; +import 'package:socket_io_plus/src/engine/socket.dart'; +import 'package:socket_io_plus/src/engine/transport/transports.dart'; import 'package:stream/stream.dart'; import 'package:uuid/uuid.dart'; diff --git a/lib/src/engine/socket.dart b/lib/src/engine/socket.dart index dbf46d4..6ec046f 100644 --- a/lib/src/engine/socket.dart +++ b/lib/src/engine/socket.dart @@ -12,10 +12,10 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:logging/logging.dart'; -import 'package:socket_io/src/engine/connect.dart'; -import 'package:socket_io/src/engine/server.dart'; -import 'package:socket_io/src/engine/transport/transports.dart'; -import 'package:socket_io/src/util/event_emitter.dart'; +import 'package:socket_io_plus/src/engine/connect.dart'; +import 'package:socket_io_plus/src/engine/server.dart'; +import 'package:socket_io_plus/src/engine/transport/transports.dart'; +import 'package:socket_io_plus/src/util/event_emitter.dart'; /// Client class (abstract). /// diff --git a/lib/src/engine/transport/jsonp_transport.dart b/lib/src/engine/transport/jsonp_transport.dart index 86df83e..e1e396b 100644 --- a/lib/src/engine/transport/jsonp_transport.dart +++ b/lib/src/engine/transport/jsonp_transport.dart @@ -9,8 +9,8 @@ /// /// Copyright (C) 2017 Potix Corporation. All Rights Reserved. import 'dart:convert'; -import 'package:socket_io/src/engine/connect.dart'; -import 'package:socket_io/src/engine/transport/polling_transport.dart'; +import 'package:socket_io_plus/src/engine/connect.dart'; +import 'package:socket_io_plus/src/engine/transport/polling_transport.dart'; class JSONPTransport extends PollingTransport { late String head; diff --git a/lib/src/engine/transport/polling_transport.dart b/lib/src/engine/transport/polling_transport.dart index 6e796d7..57c255e 100644 --- a/lib/src/engine/transport/polling_transport.dart +++ b/lib/src/engine/transport/polling_transport.dart @@ -12,9 +12,9 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:logging/logging.dart'; -import 'package:socket_io/src/engine/connect.dart'; +import 'package:socket_io_plus/src/engine/connect.dart'; import 'package:socket_io_common/socket_io_common.dart'; -import 'package:socket_io/src/engine/transport/transports.dart'; +import 'package:socket_io_plus/src/engine/transport/transports.dart'; class PollingTransport extends Transport { @override diff --git a/lib/src/engine/transport/transports.dart b/lib/src/engine/transport/transports.dart index 2b5b42b..d25f520 100644 --- a/lib/src/engine/transport/transports.dart +++ b/lib/src/engine/transport/transports.dart @@ -9,12 +9,12 @@ /// /// Copyright (C) 2017 Potix Corporation. All Rights Reserved. import 'package:logging/logging.dart'; -import 'package:socket_io/src/engine/connect.dart'; +import 'package:socket_io_plus/src/engine/connect.dart'; import 'package:socket_io_common/socket_io_common.dart'; -import 'package:socket_io/src/engine/transport/jsonp_transport.dart'; -import 'package:socket_io/src/engine/transport/websocket_transport.dart'; -import 'package:socket_io/src/engine/transport/xhr_transport.dart'; -import 'package:socket_io/src/util/event_emitter.dart'; +import 'package:socket_io_plus/src/engine/transport/jsonp_transport.dart'; +import 'package:socket_io_plus/src/engine/transport/websocket_transport.dart'; +import 'package:socket_io_plus/src/engine/transport/xhr_transport.dart'; +import 'package:socket_io_plus/src/util/event_emitter.dart'; class Transports { static List upgradesTo(String from) { diff --git a/lib/src/engine/transport/websocket_transport.dart b/lib/src/engine/transport/websocket_transport.dart index 0de4d52..7865513 100644 --- a/lib/src/engine/transport/websocket_transport.dart +++ b/lib/src/engine/transport/websocket_transport.dart @@ -12,7 +12,7 @@ import 'dart:async'; /// Copyright (C) 2017 Potix Corporation. All Rights Reserved. import 'package:logging/logging.dart'; import 'package:socket_io_common/socket_io_common.dart'; -import 'package:socket_io/src/engine/transport/transports.dart'; +import 'package:socket_io_plus/src/engine/transport/transports.dart'; class WebSocketTransport extends Transport { static final Logger _logger = diff --git a/lib/src/engine/transport/xhr_transport.dart b/lib/src/engine/transport/xhr_transport.dart index 33dfeba..91ac7ea 100644 --- a/lib/src/engine/transport/xhr_transport.dart +++ b/lib/src/engine/transport/xhr_transport.dart @@ -8,8 +8,8 @@ /// 22/02/2017, Created by jumperchen /// /// Copyright (C) 2017 Potix Corporation. All Rights Reserved. -import 'package:socket_io/src/engine/connect.dart'; -import 'package:socket_io/src/engine/transport/polling_transport.dart'; +import 'package:socket_io_plus/src/engine/connect.dart'; +import 'package:socket_io_plus/src/engine/transport/polling_transport.dart'; class XHRTransport extends PollingTransport { XHRTransport(SocketConnect connect) : super(connect); diff --git a/lib/src/namespace.dart b/lib/src/namespace.dart index c25a078..7e93c7c 100644 --- a/lib/src/namespace.dart +++ b/lib/src/namespace.dart @@ -10,12 +10,12 @@ /// Copyright (C) 2017 Potix Corporation. All Rights Reserved. import 'dart:async'; import 'package:logging/logging.dart'; -import 'package:socket_io/src/adapter/adapter.dart'; -import 'package:socket_io/src/client.dart'; +import 'package:socket_io_plus/src/adapter/adapter.dart'; +import 'package:socket_io_plus/src/client.dart'; import 'package:socket_io_common/socket_io_common.dart'; -import 'package:socket_io/src/server.dart'; -import 'package:socket_io/src/socket.dart'; -import 'package:socket_io/src/util/event_emitter.dart'; +import 'package:socket_io_plus/src/server.dart'; +import 'package:socket_io_plus/src/socket.dart'; +import 'package:socket_io_plus/src/util/event_emitter.dart'; /// Blacklisted events. diff --git a/lib/src/server.dart b/lib/src/server.dart index 9ed8ddb..edc8841 100644 --- a/lib/src/server.dart +++ b/lib/src/server.dart @@ -11,9 +11,9 @@ import 'dart:async'; import 'dart:io'; import 'package:logging/logging.dart'; -import 'package:socket_io/src/client.dart'; -import 'package:socket_io/src/engine/engine.dart'; -import 'package:socket_io/src/namespace.dart'; +import 'package:socket_io_plus/src/client.dart'; +import 'package:socket_io_plus/src/engine/engine.dart'; +import 'package:socket_io_plus/src/namespace.dart'; import 'package:socket_io_common/socket_io_common.dart'; import 'package:stream/stream.dart'; diff --git a/lib/src/socket.dart b/lib/src/socket.dart index 99eae80..d77d06a 100644 --- a/lib/src/socket.dart +++ b/lib/src/socket.dart @@ -9,12 +9,12 @@ /// /// Copyright (C) 2017 Potix Corporation. All Rights Reserved. import 'dart:io'; -import 'package:socket_io/src/adapter/adapter.dart'; -import 'package:socket_io/src/client.dart'; +import 'package:socket_io_plus/src/adapter/adapter.dart'; +import 'package:socket_io_plus/src/client.dart'; import 'package:socket_io_common/socket_io_common.dart'; -import 'package:socket_io/src/namespace.dart'; -import 'package:socket_io/src/server.dart'; -import 'package:socket_io/src/util/event_emitter.dart'; +import 'package:socket_io_plus/src/namespace.dart'; +import 'package:socket_io_plus/src/server.dart'; +import 'package:socket_io_plus/src/util/event_emitter.dart'; /// Module exports. // diff --git a/pubspec.yaml b/pubspec.yaml index b422c8b..c6d4fa3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,11 +1,9 @@ -name: socket_io +name: socket_io_plus description: > Port of JS/Node library Socket.io. It enables real-time, bidirectional and - event-based communication cross-platform. + event-based communication cross-platform. Dart 3 compatible fork. version: 2.0.0 -homepage: https://www.zkoss.org -repository: https://github.com/rikulo/socket.io-dart -issue_tracker: https://github.com/rikulo/socket.io-dart/issues +homepage: https://pub.dev/packages/socket_io_plus environment: sdk: '>=3.0.0 <4.0.0' diff --git a/test/socket.test.dart b/test/socket.test.dart index 918f902..6bea01d 100644 --- a/test/socket.test.dart +++ b/test/socket.test.dart @@ -10,7 +10,7 @@ /// Copyright (C) 2017 Potix Corporation. All Rights Reserved. import 'package:test/test.dart'; -import 'package:socket_io/socket_io.dart'; +import 'package:socket_io_plus/socket_io.dart'; void main() { group('Socket IO', () { From 12c310d76dfe82f3dde85edeb40151cffc7d70fd Mon Sep 17 00:00:00 2001 From: kechankrisna Date: Tue, 24 Feb 2026 15:41:56 +0700 Subject: [PATCH 3/5] chore: improve doc --- README.md | 216 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 155 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index b6be9f2..0313c38 100644 --- a/README.md +++ b/README.md @@ -1,96 +1,190 @@ -# socket.io-dart +# socket_io_plus -Port of awesome JavaScript Node.js library - [Socket.io v2.0.1](https://github.com/socketio/socket.io) - in Dart +A Dart 3 compatible port of the [Socket.IO](https://socket.io) server library. +Real-time, bidirectional, event-based communication — fully null-safe and ready for modern Dart. -## Usage +[![pub package](https://img.shields.io/pub/v/socket_io_plus.svg)](https://pub.dev/packages/socket_io_plus) +[![Dart SDK](https://img.shields.io/badge/Dart-%3E%3D3.0.0-blue)](https://dart.dev) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) + +--- + +## Features + +- Full Dart 3 null-safety support +- WebSocket and XHR/JSONP polling transports +- Namespace (multiplexing) support +- Room-based broadcasting +- In-memory socket adapter +- Compatible with the official [socket_io_client](https://pub.dev/packages/socket_io_client) and JS Socket.IO clients + +--- + +## Installation + +Add to your `pubspec.yaml`: + +```yaml +dependencies: + socket_io_plus: ^2.0.0 +``` + +Then run: + +```sh +dart pub get +``` + +--- + +## Quick Start + +### Server (Dart) ```dart import 'package:socket_io_plus/socket_io.dart'; -main() { - var io = new Server(); - var nsp = io.of('/some'); - nsp.on('connection', (client) { - print('connection /some'); - client.on('msg', (data) { - print('data from /some => $data'); - client.emit('fromServer', "ok 2"); - }); +void main() async { + final io = Server(); + + // Default namespace + io.on('connection', (Socket client) { + print('Client connected: ${client.id}'); + + client.on('msg', (data) { + print('Message from client: $data'); + client.emit('fromServer', 'ok'); }); - io.on('connection', (client) { - print('connection default namespace'); - client.on('msg', (data) { - print('data from default => $data'); - client.emit('fromServer', "ok"); - }); - }); - io.listen(3000); + + client.on('disconnect', (_) { + print('Client disconnected: ${client.id}'); + }); + }); + + // Custom namespace + final nsp = io.of('/chat'); + nsp.on('connection', (Socket client) { + print('Client connected to /chat'); + + client.on('message', (data) { + // Broadcast to everyone in the namespace + nsp.emit('broadcastMessage', data); + }); + }); + + await io.listen(3000); + print('Server running on port 3000'); } ``` +### Client — JavaScript + ```js -// JS client -var socket = io('http://localhost:3000'); -socket.on('connect', function(){console.log('connect')}); -socket.on('event', function(data){console.log(data)}); -socket.on('disconnect', function(){console.log('disconnect')}); -socket.on('fromServer', function(e){console.log(e)}); +const socket = io('http://localhost:3000'); + +socket.on('connect', () => console.log('connected')); +socket.on('fromServer', (data) => console.log('from server:', data)); +socket.on('disconnect', () => console.log('disconnected')); + +socket.emit('msg', 'hello'); ``` +### Client — Dart + ```dart -// Dart client import 'package:socket_io_client/socket_io_client.dart' as IO; -IO.Socket socket = IO.io('http://localhost:3000'); -socket.on('connect', (_) { - print('connect'); - socket.emit('msg', 'test'); +void main() { + final socket = IO.io('http://localhost:3000'); + + socket.on('connect', (_) { + print('connected'); + socket.emit('msg', 'hello from Dart'); + }); + + socket.on('fromServer', (data) => print('from server: $data')); + socket.on('disconnect', (_) => print('disconnected')); +} +``` + +--- + +## Rooms + +Sockets can join and leave named rooms. Broadcast to all members of a room: + +```dart +io.on('connection', (Socket client) { + client.join('room1'); + + client.on('msg', (data) { + // Emit to all sockets in 'room1' + io.to('room1').emit('roomMessage', data); + }); }); -socket.on('event', (data) => print(data)); -socket.on('disconnect', (_) => print('disconnect')); -socket.on('fromServer', (_) => print(_)); ``` -## Multiplexing support +--- -Same as Socket.IO, this project allows you to create several Namespaces, which will act as separate communication channels but will share the same underlying connection. +## Namespaces -## Room support +Create separate communication channels that share the same underlying connection: -Within each Namespace, you can define arbitrary channels, called Rooms, that sockets can join and leave. You can then broadcast to any given room, reaching every socket that has joined it. +```dart +final admin = io.of('/admin'); +admin.on('connection', (Socket client) { + client.emit('welcome', 'You are in the admin namespace'); +}); +``` -## Transports support - Refers to [engine.io](https://github.com/socketio/engine.io) +--- -- `polling`: XHR / JSONP polling transport. -- `websocket`: WebSocket transport. +## Transports + +Powered by Engine.IO, two transports are supported: + +| Transport | Description | +|-------------|------------------------------------------------| +| `polling` | XHR / JSONP long-polling (HTTP fallback) | +| `websocket` | Full-duplex WebSocket connection | + +Clients start with polling and upgrade to WebSocket automatically when available. + +--- + +## Migration from `socket_io` + +This package is a Dart 3 compatible fork of [`socket_io`](https://pub.dev/packages/socket_io). To migrate: + +1. Replace `socket_io` with `socket_io_plus` in `pubspec.yaml` +2. Update all imports: + +```dart +// Before +import 'package:socket_io/socket_io.dart'; + +// After +import 'package:socket_io_plus/socket_io.dart'; +``` -## Adapters support +No other code changes are required. -* Default socket.io in-memory adapter class. Refers to [socket.io-adapter](https://github.com/socketio/socket.io-adapter) +--- -## Notes to Contributors +## Dart Client Package -### Fork socket.io-dart +Use [`socket_io_client`](https://pub.dev/packages/socket_io_client) to connect a Dart client to this server. -If you'd like to contribute back to the core, you can [fork this repository](https://help.github.com/articles/fork-a-repo) and send us a pull request, when it is ready. +--- -If you are new to Git or GitHub, please read [this guide](https://help.github.com/) first. +## Contributing -## Who Uses +Contributions are welcome! Please open an issue or submit a pull request. -* [Quire](https://quire.io) - a simple, collaborative, multi-level task management tool. -* [KEIKAI](https://keikai.io/) - a web spreadsheet for Big Data. +If you are new to Git or GitHub, read [this guide](https://help.github.com/) first. -## Socket.io Dart Client +--- -* [socket.io-client-dart](https://github.com/rikulo/socket.io-client-dart) +## License -## Contributors -* Thanks [@felangel](https://github.com/felangel) for https://github.com/rikulo/socket.io-dart/issues/7 -* Thanks [@ThinkDigitalSoftware](https://github.com/ThinkDigitalSoftware) for https://github.com/rikulo/socket.io-dart/pull/15 -* Thanks [@guilhermecaldas](https://github.com/guilhermecaldas) for https://github.com/rikulo/socket.io-dart/pull/16 -* Thanks [@jodinathan](https://github.com/jodinathan) for https://github.com/rikulo/socket.io-dart/pull/17 -* Thanks [@jodinathan](https://github.com/jodinathan) for https://github.com/rikulo/socket.io-dart/pull/18 -* Thanks [@nicobritos](https://github.com/nicobritos) for https://github.com/rikulo/socket.io-dart/pull/46 -* Thanks [@nicobritos](https://github.com/nicobritos) for https://github.com/rikulo/socket.io-dart/pull/47 \ No newline at end of file +This project is licensed under the [MIT License](LICENSE). \ No newline at end of file From acbed89b5a9fe9e55d1b5bfb2f112abedbf6ede9 Mon Sep 17 00:00:00 2001 From: kechankrisna Date: Tue, 24 Feb 2026 17:36:32 +0700 Subject: [PATCH 4/5] fixe: on connect --- lib/src/socket.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/socket.dart b/lib/src/socket.dart index d77d06a..304eac7 100644 --- a/lib/src/socket.dart +++ b/lib/src/socket.dart @@ -266,7 +266,10 @@ class Socket extends EventEmitter { // debug('socket connected - writing packet'); nsp.connected[id] = this; join(id); - packet({'type': CONNECT}); + // Socket.IO v3+ protocol requires CONNECT response to include {sid} in + // data so the client can confirm the namespace is joined. Without it, + // socket_io_client v3.x emits a connect_error and never fires onConnect. + packet({'type': CONNECT, 'data': {'sid': id}}); } /// Called with each packet. Called by `Client`. From efb37d80b0553ee80b05e9e5ec18cf2ea451e445 Mon Sep 17 00:00:00 2001 From: kechankrisna Date: Tue, 24 Feb 2026 17:37:52 +0700 Subject: [PATCH 5/5] fixe: on connect --- CHANGELOG.md | 5 +++++ pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc19781..cd91ae2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ +## 2.0.0+1 +* fixed on connect + ## 2.0.0 +* support dart 3.0.0 + **Breaking Changes — Dart 3 upgrade:** * Raised SDK constraint to `>=3.0.0 <4.0.0` diff --git a/pubspec.yaml b/pubspec.yaml index c6d4fa3..58e42fd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: socket_io_plus description: > Port of JS/Node library Socket.io. It enables real-time, bidirectional and event-based communication cross-platform. Dart 3 compatible fork. -version: 2.0.0 +version: 2.0.0+1 homepage: https://pub.dev/packages/socket_io_plus environment: