Skip to content

Dart client

This page shows how to talk to a go-ricochet server from Dart or Flutter with the ricochet package (ricochet-dart-client). It describes version 0.2.4. The package’s own documentation is at cryptopeer.net/ricochet/dart-client.

The package does no networking of its own. You build a started dart_libp2p host that can reach the server, put the server’s address in its peerstore (connecting does that), and pass it to SFClient. A PubSub instance is optional; it enables presence tracking and notifications for shared and public mailboxes.

Because the server listens on UDX only, the host needs dart_libp2p’s UDXTransport with Noise and Yamux. UDX: Go, Dart, JS has a host that works against go-ricochet.

pubspec.yaml
dependencies:
ricochet: ^0.2.4
dart_libp2p: ^4.1.0

ricochet 0.2.4 accepts dart_libp2p from 1.0.0 up to 5.0.0, dart_libp2p_pubsub up to 5.0.0 and needs Dart SDK 3.5.1 or later. Use dart_libp2p 3.0.0 or later: earlier releases bundle dart_udx 2.x, whose UDX wire version cannot talk to the server.

client.dart
// Sketch: host is a started dart_libp2p host connected to the server.
import 'package:ricochet/ricochet.dart';
final config = SFClientConfig.withServers([
SFServerPreference(serverId: serverPeerId, priority: 10),
]);
final client = SFClient(
host: host, // required, yours to create and close
config: config,
pubsub: pubsub, // optional
);
await client.start();
// Lets the client refresh the server's address in the peerstore before a redial.
client.registerServerAddress(serverPeerId, serverAddr);

Lower priority values are tried first, as with MX records. client.stop() stops the client; the host stays open.

final result = await client.sendMessage(
recipient: recipientPeerId,
payload: Uint8List.fromList(utf8.encode('Hello!')),
folderPath: 'inbox', // default
priority: MessagePriority.normal,
persistent: false, // removed once acknowledged
);
if (result.success) {
print('Stored at ${result.storedAtServer}');
}
final messages = await client.retrieveMessages(throwOnFailure: true);
await client.markMessagesDelivered(messages.map((m) => m.messageId).toList());

Retrieval never removes a message; markMessagesDelivered removes non-persistent messages and marks persistent ones seen, as on the Go client. Without throwOnFailure: true, a retrieval that fails returns an empty list, indistinguishable from an empty mailbox.

Build the client with a PayloadEncryptor and pass encrypt: true to sendMessage. The format is the Go client’s: NaCl box from the two Ed25519 identity keys, bound to the recipient, folder and message ID. Both repositories carry the same test vectors, so a message sealed by either client opens in the other. See Encryption & compression.

final client = SFClient(
host: host,
config: config,
encryptor: PayloadEncryptor.fromEd25519Seed(identitySeed), // 32 bytes
);
await client.sendMessage(recipient: recipientPeerId, payload: payload, encrypt: true);
Feature Go pkg/client Dart SFClient 0.2.4
Send one message SendMessage sendMessage
Batch submission (/sf-network/submit/batch/1.0.0) SendMessages No
Forward on another sender’s behalf ForwardMessage No
Retrieve, paging, another peer’s public mailbox RetrieveMessages, RetrievePage, WithTargetPeer retrieveMessages (targetPeerId, fromSequence, maxMessages)
Acknowledge, flags, expunge, delete Yes markMessagesDelivered, updateMessageFlags, expungeMessages, deleteMessages
Payload encryption (NaCl box) WithEncryption encrypt: true with a PayloadEncryptor
LZ4 compression WithCompression No
Mailboxes and ACLs Yes client.mailboxes: create, delete, grant, revoke, list ACL, list, update config, info
Server capacity QueryCapacity queryServerCapacity
Documents: get, put, patch, head, delete, list Yes Yes
Document batch put (BATCH_PUT) PutDocuments No
Document visibility Set, grant and revoke readers setDocumentVisibility; no reader grants
Directory Join, leave, browse, get entry Join, leave, browse
Feeds Create, append, get, range, multi-feed, list, delete, visibility and readers Create, append, get, range, batch get, list, delete; no visibility or readers
Collections Create, put, get, delete, list keys, query, visibility and readers Create, put, get, delete, list keys, query, setCollectionVisibility; no reader grants
Private mailbox notifications RegisterNotificationHandler registerPrivateNotificationHandler, then notifications
Shared and public mailbox notifications (GossipSub) No subscribeToMailbox (needs pubsub)
Presence tracking No trackContactPresence, contactPresenceChanges (needs pubsub)
Errors Typed errors with the server’s status Most calls return null or false on failure

The package’s interop harness, bin/store_interop_test.dart, runs document, collection, feed and mailbox checks against a live server:

Terminal window
dart run bin/store_interop_test.dart /ip4/127.0.0.1/udp/55223/udx/p2p/12D3KooW... primary

A second process with role secondary waits for the primary and reads what it wrote, as a different peer. The two coordinate through files in /client_shared/, a volume shared between containers in go-ricochet’s Docker integration test, so create that directory before running the harness outside Docker.