Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,33 @@
## 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`
* 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:**
Expand Down
218 changes: 156 additions & 62 deletions README.md
Original file line number Diff line number Diff line change
@@ -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/socket_io.dart';
import 'package:socket_io_plus/socket_io.dart';

void main() async {
final io = Server();

// Default namespace
io.on('connection', (Socket client) {
print('Client connected: ${client.id}');

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");
});
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);
});
});
```

---

## Namespaces

Create separate communication channels that share the same underlying connection:

```dart
final admin = io.of('/admin');
admin.on('connection', (Socket client) {
client.emit('welcome', 'You are in the admin namespace');
});
socket.on('event', (data) => print(data));
socket.on('disconnect', (_) => print('disconnect'));
socket.on('fromServer', (_) => print(_));
```

## Multiplexing support
---

## Transports

Powered by Engine.IO, two transports are supported:

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.
| Transport | Description |
|-------------|------------------------------------------------|
| `polling` | XHR / JSONP long-polling (HTTP fallback) |
| `websocket` | Full-duplex WebSocket connection |

## Room support
Clients start with polling and upgrade to WebSocket automatically when available.

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

## Transports support
Refers to [engine.io](https://github.com/socketio/engine.io)
## Migration from `socket_io`

- `polling`: XHR / JSONP polling transport.
- `websocket`: WebSocket transport.
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
This project is licensed under the [MIT License](LICENSE).
2 changes: 1 addition & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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/**
Expand Down
2 changes: 1 addition & 1 deletion example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion lib/socket_io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
23 changes: 10 additions & 13 deletions lib/src/adapter/adapter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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_common/src/parser/parser.dart';
import 'package:socket_io/src/util/event_emitter.dart';
import 'package:socket_io_plus/src/namespace.dart';
import 'package:socket_io_common/socket_io_common.dart';
import 'package:socket_io_plus/src/util/event_emitter.dart';

abstract class Adapter {
Map nsps = {};
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down
13 changes: 5 additions & 8 deletions lib/src/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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_common/src/parser/parser.dart';
import 'package:socket_io/src/server.dart';
import 'package:socket_io_plus/src/engine/socket.dart';
import 'package:socket_io_common/socket_io_common.dart';
import 'package:socket_io_plus/src/server.dart';

class Client {
Server server;
Expand Down Expand Up @@ -55,7 +55,7 @@ class Client {
_logger.fine('connecting to namespace $name');
if (!server.nsps.containsKey(name)) {
packet(<dynamic, dynamic>{
'type': ERROR,
'type': CONNECT_ERROR,
'nsp': name,
'data': 'Invalid namespace'
});
Expand Down Expand Up @@ -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);
Expand Down
Loading