queryServerCapacity method
Query server capacity (with caching)
Implementation
Future<ServerCapacity?> queryServerCapacity(PeerId serverId) async {
final cacheKey = serverId.toString();
// Check cache first
final cached = _capacityCache[cacheKey];
if (cached != null) {
_logger.fine('Using cached capacity for ${serverId.toString().substring(0, 12)}...');
return cached;
}
try {
// Open stream and query capacity via MMA (admin) protocol
final context = Context();
final stream = await host.newStream(
serverId,
[adminProtocolId],
context,
);
// Create query capacity request
final request = QueryCapacityRequest();
final requestBytes = AdminFrame.encodeRequest(request);
// Send with length prefix
final lengthBytes = ByteData(4)..setUint32(0, requestBytes.length);
final combined = Uint8List(4 + requestBytes.length);
combined.setRange(0, 4, lengthBytes.buffer.asUint8List());
combined.setRange(4, 4 + requestBytes.length, requestBytes);
await stream.write(combined);
// Read response length
final responseLengthBytes = await stream.read(4);
if (responseLengthBytes.length < 4) {
throw StateError('Failed to read response length');
}
final responseLength = responseLengthBytes.buffer.asByteData().getUint32(0);
// Read response
final responseBytes = await stream.read(responseLength);
if (responseBytes.length < responseLength) {
throw StateError('Failed to read complete response');
}
final response = AdminFrame.decodeResponse(responseBytes);
await stream.close();
if (!response.success || response.data == null) {
_logger.warning('Server capacity query failed: ${response.errorMessage}');
return null;
}
final capacity = ServerCapacity.fromJson(response.data as Map<String, dynamic>);
// Cache the result
_capacityCache[cacheKey] = capacity;
// Schedule cache cleanup
Future.delayed(_capacityCacheDuration, () {
_capacityCache.remove(cacheKey);
});
return capacity;
} catch (e) {
_logger.warning('Failed to query server capacity: $e');
return null;
}
}