dart-lang / native

Dart packages related to FFI and native assets bundling.
BSD 3-Clause "New" or "Revised" License
114 stars 40 forks source link

[native_assets_cli] AssetDownloader #996

Open dcharkes opened 6 months ago

dcharkes commented 6 months ago

I'm punting this from package:native_assets_cli.

This should likely live in a separate helper package.

// Copyright (c) 2024, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:io';

import 'package:logging/logging.dart';

import '../../native_assets_cli.dart';

abstract class Builder {
  Future<void> run({
    required BuildConfig config,
    required BuildOutput output,
    required Logger? logger,
  });
}

// TODO(dacoharkes): Should we really add this? It seems too specific.
// E.g. what about varying file names, zipped downloads etc. etc. ?
class AssetDownloader implements Builder {
  final Uri Function(OS, Architecture) downloadUri;

  /// Asset identifier.
  ///
  /// If omitted, no asset will be added to the build output.
  final String assetName;

  AssetDownloader({
    required this.downloadUri,
    required this.assetName,
  });

  @override
  Future<void> run({
    required BuildConfig config,
    required BuildOutput output,
    required Logger? logger,
  }) async {
    Uri? targetUri;
    if (!config.dryRun) {
      final downloadUri2 = downloadUri(
        config.targetOS,
        config.targetArchitecture!,
      );
      final fileName =
          downloadUri2.pathSegments.lastWhere((element) => element.isNotEmpty);
      targetUri = config.outputDirectory.resolve(fileName);
      final request = await HttpClient().getUrl(downloadUri2);
      final response = await request.close();
      await response.pipe(File.fromUri(targetUri).openWrite());
    }

    output.addAsset(
      CCodeAsset(
        package: config.packageName,
        name: assetName,
        file: targetUri,
        linkMode: LinkMode.dynamic,
        dynamicLoading: BundledDylib(),
        os: config.targetOS,
        architecture: config.targetArchitecture,
      ),
    );
  }
}

It might implement the shared interface Builder:

dcharkes commented 6 months ago

Also an interesting feature: Take an optional SHA256 hash to check against. Doesn't need to be implemented in this PR though.

knopp commented 3 months ago

In cargokit (project I'm hoping to retire the moment native assets are no longer experimental) I use private / public key to check the downloaded binaries. The public key is part of dart package, and when downloading binaries a ed25519_edwards signature is downloaded alongside to verify that the binary was built by the github workflow (the repository has access to private key as a github secret).