attachAsset method

  1. @override
Future<Asset> attachAsset({
  1. required String releaseId,
  2. required String name,
  3. required Stream<List<int>> data,
  4. int? length,
  5. String contentType = 'application/octet-stream',
  6. String? expectedSha256,
  7. String? platform,
  8. String? kind,
  9. Map<String, String> metadata = const {},
})
override

Attaches an asset named name to releaseId, streaming data into storage.

The SHA-256 and size are computed as the bytes stream past; when expectedSha256 is given they are verified against it and nothing is stored on mismatch. Passing length lets backends that need the size up front stream instead of buffering.

platform (linux-x64) is what lets the update service answer "is there an update for me", so publishers should always set it on platform-specific artifacts.

Implementation

@override
Future<Asset> attachAsset({
  required String releaseId,
  required String name,
  required Stream<List<int>> data,
  int? length,
  String contentType = 'application/octet-stream',
  String? expectedSha256,
  String? platform,
  String? kind,
  Map<String, String> metadata = const {},
}) async {
  final begin = await _call(StoreProtocol.uploadBegin, {
    'releaseId': releaseId,
    'name': name,
    'length': ?length,
    'contentType': contentType,
    'expectedSha256': ?expectedSha256,
    'platform': ?platform,
    'kind': ?kind,
    'metadata': metadata,
  });
  final uploadId = Json.requireString(begin, 'uploadId');

  try {
    // Re-chunked to the protocol's frame size: the source's own boundaries
    // come from wherever the bytes originated (a file read, an HTTP body) and
    // may be far larger than a control frame should carry.
    var buffer = <int>[];
    await for (final chunk in data) {
      buffer.addAll(chunk);
      while (buffer.length >= chunkBytes) {
        await _sendChunk(uploadId, buffer.sublist(0, chunkBytes));
        buffer = buffer.sublist(chunkBytes);
      }
    }
    if (buffer.isNotEmpty) await _sendChunk(uploadId, buffer);

    return Asset.fromJson(
      await _result(StoreProtocol.uploadCommit, {'uploadId': uploadId}),
    );
  } on Object {
    // Tell the node to unwind its partial object rather than leaving it to
    // the session timeout, which would keep the bytes around for minutes.
    await _abortQuietly(uploadId);
    rethrow;
  }
}