resolveNativeModelAsset function
Resolves URI-backed model assets before crossing the native ABI.
Implementation
Future<ModelAsset> resolveNativeModelAsset(ModelAsset asset) async {
if (asset case ModelAssetUri(:final uri, sha256: final expectedSha256)) {
if (uri.scheme == 'file') {
return ModelAsset.path(uri.toFilePath());
}
if (uri.scheme != 'https') {
throw const MpException(
MpStatus.invalidArgument,
'Native model URIs must use HTTPS or the file scheme.',
);
}
final HttpClient client = HttpClient()..connectionTimeout = const Duration(seconds: 30);
try {
final HttpClientRequest request = await client.getUrl(uri);
final HttpClientResponse response = await request.close();
if (response.statusCode < 200 || response.statusCode >= 300) {
throw MpException(
MpStatus.unavailable,
'Downloading the model failed with HTTP ${response.statusCode}.',
);
}
final BytesBuilder bytes = BytesBuilder(copy: false);
var length = 0;
await for (final List<int> chunk in response) {
length += chunk.length;
if (length > _maximumRemoteModelBytes) {
throw const MpException(
MpStatus.resourceExhausted,
'The remote model exceeds the 512 MiB safety limit.',
);
}
bytes.add(chunk);
}
final Uint8List result = bytes.takeBytes();
if (expectedSha256 != null && sha256.convert(result).toString() != expectedSha256) {
throw const MpException(
MpStatus.dataLoss,
'The downloaded model does not match its SHA-256 digest.',
);
}
return ModelAsset.bytes(result, name: uri.pathSegments.lastOrNull);
} finally {
client.close(force: true);
}
}
return asset;
}