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.
Bring your own host
Section titled “Bring your own host”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.
Install
Section titled “Install”dependencies: ricochet: ^0.2.4 dart_libp2p: ^4.1.0ricochet 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.
Create the client
Section titled “Create the client”// 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.
Send and retrieve
Section titled “Send and retrieve”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.
Encryption
Section titled “Encryption”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);Coverage compared with the Go client
Section titled “Coverage compared with the Go client”| 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 |
Testing against your server
Section titled “Testing against your server”The package’s interop harness, bin/store_interop_test.dart, runs document, collection, feed and mailbox checks against a live server:
dart run bin/store_interop_test.dart /ip4/127.0.0.1/udp/55223/udx/p2p/12D3KooW... primaryA 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.