network (2.0.0)
Installation
dart pub add network:2.0.0 --hosted-url=About this package
Dart.Package.Network
Transport-agnostic message networking, ported from the current
CSharp.Package.Network:
id-based message registration and dispatch over any
Dart.Package.Transports
transport, connection wrapping, reconnect-with-backoff, clock sync, and
pluggable authentication.
Rewrite note
This package's first version (1.0.0) was a port of a different, older C#
protocol ("the old platform" — see its own CHANGELOG) that CSharp.Package.Network
no longer implements: that protocol had its own event/request/response
framing (Command, BaseProtocol, EventProtocol, ...). Version 2.0.0 is a
full rewrite against the C# package as it exists today, with no compatibility
with 1.x's wire format or API.
Out of scope: CSharp.Package.Network's NetworkObject/RpcModule/Synced<T>
layer is a Unity/VRC game-object sync system (ownership, prefab spawning,
synced fields) with no Dart consumer — this package only covers the
transport-agnostic messaging core underneath it.
Quick start
import 'package:network/network.dart';
import 'package:serializers/serializers.dart';
import 'package:transports/transports.dart';
import 'package:transports_websocket/transports_websocket.dart';
class Ping implements NetworkMessage {
String text;
Ping([this.text = '']);
@override
void serialize(ByteWriter writer) => writer.writeString(text);
@override
void deserialize(ByteReader reader) => text = reader.readString() ?? '';
}
class ChatManager extends NetworkManager {}
final server = ChatManager()..register<Ping>(() => Ping());
final serverTransport = WebSocketTransport();
server.transport = serverTransport;
server.wireTransportEvents(serverTransport);
await serverTransport.listen(TransportEndPoint('0.0.0.0', 9000));
server.subscribeSimple<Ping>((msg) => print('got: ${msg.text}'));
Both ends must call register<T>() for the same message types in the same
order — the wire id is that registration position, not a type name (Dart has
no Activator.CreateInstance-style reflection, so register takes an
explicit factory closure instead).
API shape
NetworkManager— abstract base. Holds aMessageRegistry, aMessageDispatcher, and the liveNetworkConnections keyed by transport connection id. Subclasses (seeDart.Package.Network.Dedicated,.P2P,.Relay) settransport, callwireTransportEvents, and can overridehandleMessageto gate messages (e.g. during an auth handshake) before normal dispatch runs.NetworkConnection— one peer's connection;sendMessage<T>()andsend(id, serializer).MessageRegistry/MessageDispatcher— id assignment and per-id handler dispatch. A handler that throws is logged and skipped, not fatal to the receive loop.ReconnectHandler— exponential backoff with jitter; watchesNetworkManager.onDisconnectedand retriesTransportConnector.connect.NetworkClock— periodic round-trip time and clock-offset estimation over a reserved message id.Authenticator/JwtAuthenticator/SharedSecretAuthenticator/UsernamePasswordAuthenticator— challenge/response schemes consumed byDart.Package.Network.Dedicated's and.P2P's handshake.
Differences from the C# original
- No cross-package
protected: members the C# base marksprotectedfor its subclasses are public here instead (documented onNetworkManager). - C# events become broadcast
Streams;IDisposablesubscriptions becomeMessageSubscription.cancel(). - No locks anywhere: the C# original guards shared collections for multi-threaded access; Dart's single-threaded event loop makes that unnecessary.
register<T>()takes a factory closure (no reflection-basedActivator.CreateInstance).
Versioning and publishing
Version.txt is the exact version that gets published — a push to main
publishes it only when that version isn't on the feed yet. Pushes to any
other branch only resolve and test.