listDocuments method

Future<List<DocumentInfo>?> listDocuments({
  1. required PeerId ownerPeerId,
  2. String pathPrefix = '',
  3. PeerId? fromServer,
})

List all documents for a peer

ownerPeerId The peer who owns the documents pathPrefix Optional: filter documents by path prefix (e.g., "settings/" for all settings docs) fromServer Optional: specify which server to query

Returns list of document metadata, or null if error occurred

Implementation

Future<List<DocumentInfo>?> listDocuments({
  required PeerId ownerPeerId,
  String pathPrefix = '',
  PeerId? fromServer,
}) async {
  final serverId = fromServer ?? await _serverSelector.selectServer(config.preferredServers);
  if (serverId == null) {
    _logger.warning('No S&F server available for document LIST');
    return null;
  }

  try {
    final context = Context();
    final stream = await host.newStream(
      serverId,
      ['/ricochet/store/doc/1.0.0'],
      context,
    ).timeout(config.connectionTimeout);

    final response = await DocumentHandler.listDocuments(
      stream,
      ownerPeerId: ownerPeerId,
      pathPrefix: pathPrefix,
    ).timeout(config.messageTimeout);

    await stream.close();

    if (response.status != 200) {
      _logger.warning('LIST documents failed with status ${response.status}: ${response.error}');
      return null;
    }

    // Parse the response body
    // Go server returns a bare JSON array, Dart server wraps in {"documents": [...]}
    final decoded = jsonDecode(utf8.decode(response.body!));
    final List<dynamic> docsList;
    if (decoded is List) {
      docsList = decoded;
    } else {
      docsList = (decoded as Map<String, dynamic>)['documents'] as List<dynamic>;
    }

    return docsList.map((doc) {
      final docMap = doc as Map<String, dynamic>;
      // Go server uses 'contentHash' and 'updatedAt' (RFC3339 string)
      // Dart server uses 'etag' and 'lastModified' (int timestamp)
      final etag = (docMap['etag'] ?? docMap['contentHash'] ?? '') as String;
      final lastModified = docMap['lastModified'] as int? ??
          (docMap['updatedAt'] != null
              ? DateTime.parse(docMap['updatedAt'] as String).millisecondsSinceEpoch
              : 0);
      return DocumentInfo(
        path: docMap['path'] as String,
        contentType: docMap['contentType'] as String,
        size: docMap['size'] as int,
        etag: etag,
        lastModified: lastModified,
      );
    }).toList();
  } on TimeoutException {
    _logger.warning('LIST documents timed out');
    return null;
  } catch (e) {
    _logger.warning('Failed to LIST documents: $e');
    return null;
  }
}