sendViaServer method
Future<SendResult>
sendViaServer(
- PeerId serverId,
- PeerId recipient,
- Uint8List payload,
- MessagePriority priority,
- Duration? expiry, {
- String? folderPath,
- bool persistent = false,
- String? messageId,
- SFMessageFlags flags = SFMessageFlags.none,
Send message via specific S&F server
Implementation
Future<SendResult> sendViaServer(
PeerId serverId,
PeerId recipient,
Uint8List payload,
MessagePriority priority,
Duration? expiry, {
String? folderPath,
bool persistent = false,
String? messageId,
SFMessageFlags flags = SFMessageFlags.none,
}) async {
_logger.info('Sending via server: ${serverId.toString().substring(0, 12)}...');
P2PStream? stream;
try {
// Open stream to S&F server using MSA (Mail Submission Agent) protocol
final context = Context();
stream = await host.newStream(
serverId,
[SubmissionHandler.protocolId],
context,
).timeout(config.connectionTimeout);
// Submit message to server via MSA
final ack = await SubmissionHandler.submitMessage(
stream,
recipient,
payload,
priority: priority,
expiry: expiry,
folderPath: folderPath,
persistent: persistent,
messageId: messageId,
flags: flags,
).timeout(config.messageTimeout);
if (ack.success) {
_logger.info('Message stored successfully: ${ack.messageId}');
// Protect the S&F server connection so it won't be closed by cleanup
host.connManager.protect(serverId, 'ricochet-sf-server');
_logger.fine('Protected connection to S&F server ${serverId.toBase58().substring(0, 12)}...');
return SendResult.success(
deliveredDirectly: false,
storedAtServer: serverId,
messageId: ack.messageId,
estimatedDeliveryTime: ack.estimatedDeliveryTime != null
? Duration(milliseconds: ack.estimatedDeliveryTime!)
: null,
);
} else {
return SendResult.failure(ack.errorMessage ?? 'Store failed');
}
} on TimeoutException {
throw Exception('Operation timed out');
} catch (e) {
throw Exception('Failed to send via server: $e');
} finally {
// The stream is closed on every path: a stream left open holds a slot
// on the connection for as long as the session lives, and a sender that
// never closes one runs the connection out of slots.
if (stream != null && !stream.isClosed) {
try {
await stream.close();
} catch (e) {
_logger.fine('Error closing stream: $e');
}
}
}
}