browseDirectory method
Browse the user directory on a server
cursor Opaque cursor from a previous page (for pagination)
limit Maximum entries per page (default 20, max 100)
search Optional search string (matches display name, bio)
fromServer Optional: specify which server to browse
Implementation
Future<DirectoryBrowseResult?> browseDirectory({
String? cursor,
int limit = 20,
String? search,
PeerId? fromServer,
}) async {
final serverId = fromServer ??
await _serverSelector.selectServer(config.preferredServers);
if (serverId == null) {
_logger.warning('No S&F server available for directory browse');
return null;
}
try {
final context = Context();
final stream = await host.newStream(
serverId,
[DocumentHandler.protocolId],
context,
).timeout(config.connectionTimeout);
final response = await DocumentHandler.browseDirectory(
stream,
ownerPeerId: host.id,
cursor: cursor,
limit: limit,
search: search,
).timeout(config.messageTimeout);
await stream.close();
if (response.status != 200) {
_logger.warning('DIRECTORY browse failed: ${response.status}');
return null;
}
final rawBody = utf8.decode(response.body!);
_logger.info('DIRECTORY browse raw response: $rawBody');
final body = jsonDecode(rawBody) as Map<String, dynamic>;
final entries = ((body['entries'] as List?) ?? []).map((e) {
final entry = e as Map<String, dynamic>;
// Go server uses 'ownerPeerId', Dart server uses 'peerId'
final peerId = (entry['peerId'] ?? entry['ownerPeerId'] ?? '') as String;
// Go server sends timestamps as RFC3339 strings, Dart server as int ms
final listedAt = entry['listedAt'] is int
? entry['listedAt'] as int
: DateTime.parse(entry['listedAt'] as String).millisecondsSinceEpoch;
final updatedAt = entry['updatedAt'] is int
? entry['updatedAt'] as int
: DateTime.parse(entry['updatedAt'] as String).millisecondsSinceEpoch;
return DirectoryEntryInfo(
peerId: peerId,
displayName: entry['displayName'] as String,
bio: entry['bio'] as String?,
avatarHash: entry['avatarHash'] as String?,
listedAt: listedAt,
updatedAt: updatedAt,
);
}).toList();
// Go server has no 'totalCount' field, uses 'hasMore' instead
final totalCount = body['totalCount'] as int? ?? entries.length;
return DirectoryBrowseResult(
entries: entries,
nextCursor: body['nextCursor'] as String?,
totalCount: totalCount,
);
} on TimeoutException {
_logger.warning('DIRECTORY browse timed out');
return null;
} catch (e) {
_logger.warning('Failed to browse directory: $e');
return null;
}
}