sendMediaMessage method
Sends a media message (image, video, audio, or file).
The file is:
- Validated (size check against kMaxMediaFileSizeBytes).
- Copied to internal Airpass storage.
- SHA-256 hashed for integrity verification.
- Thumbnailed for instant preview (images only in v1).
- Saved as a message with metadata + embedded thumbnail.
The actual binary propagates via FILE payloads on-demand (Phase 3). The metadata + thumbnail propagate through epidemic routing immediately.
filePath — absolute path to the source file on the device.
mediaType — the type of media (image, video, audio, file).
targetId — the target (group ID, node UUID, or '*' for broadcast).
caption — optional text caption alongside the media.
Throws MediaFileTooLargeException if the file exceeds the size limit. Throws FileSystemException if the file doesn't exist.
Returns the generated message ID.
Implementation
Future<String> sendMediaMessage({
required String filePath,
required MediaType mediaType,
required String targetId,
String? caption,
}) async {
final file = File(filePath);
// 1. Validate file exists
if (!await file.exists()) {
throw FileSystemException('File not found', filePath);
}
// 2. Validate file size
final fileSize = await file.length();
if (fileSize > kMaxMediaFileSizeBytes) {
throw MediaFileTooLargeException(
fileSize: fileSize,
maxSize: kMaxMediaFileSizeBytes,
fileName: file.uri.pathSegments.last,
);
}
final messageId = _uuid.v4();
final fileName = file.uri.pathSegments.last;
// 3. Copy to internal storage
final localPath = await _mediaStorage.saveMediaFromPath(
messageId: messageId,
sourcePath: filePath,
fileName: fileName,
);
// 4. Compute SHA-256 hash
final hash = await _mediaStorage.computeHash(localPath);
// 5. Generate thumbnail (images only in v1)
Uint8List? thumbnail;
if (mediaType == MediaType.image) {
final imageBytes = await file.readAsBytes();
thumbnail = await _mediaStorage.generateThumbnail(imageBytes);
}
// 6. Determine MIME type from extension
final mimeType = _inferMimeType(fileName, mediaType);
// 7. Encode caption (or empty string) as the message payload
final payloadBytes = utf8.encode(caption ?? '');
// 8. Save to database
await _db.createMessage(
messageId: messageId,
senderId: _localNodeId,
targetId: targetId,
payload: payloadBytes,
ttl: kMediaDefaultMaxHops,
mediaType: mediaType,
mediaFileName: fileName,
mediaMimeType: mimeType,
mediaFileSize: fileSize,
mediaHash: hash,
mediaLocalPath: localPath,
mediaAvailability: MediaAvailability.available, // We have it locally
mediaThumbnail: thumbnail,
);
_log(
'Saved outgoing media message $messageId '
'(${mediaType.name}, $fileSize bytes) for target "$targetId"',
);
// Wake up the background service to broadcast metadata immediately
triggerImmediateSync();
return messageId;
}