fix(useragent): unsafe, but working implementation of ml-dsa
This commit is contained in:
@@ -72,6 +72,10 @@ backend = "cargo:diesel_cli"
|
|||||||
default-features = "false"
|
default-features = "false"
|
||||||
features = "sqlite,sqlite-bundled"
|
features = "sqlite,sqlite-bundled"
|
||||||
|
|
||||||
|
[[tools."cargo:flutter_rust_bridge_codegen"]]
|
||||||
|
version = "2.12.0"
|
||||||
|
backend = "cargo:flutter_rust_bridge_codegen"
|
||||||
|
|
||||||
[[tools.flutter]]
|
[[tools.flutter]]
|
||||||
version = "3.38.9-stable"
|
version = "3.38.9-stable"
|
||||||
backend = "asdf:flutter"
|
backend = "asdf:flutter"
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ python = "3.14.3"
|
|||||||
ast-grep = "0.42.0"
|
ast-grep = "0.42.0"
|
||||||
"cargo:cargo-edit" = "0.13.9"
|
"cargo:cargo-edit" = "0.13.9"
|
||||||
"cargo:cargo-mutants" = "27.0.0"
|
"cargo:cargo-mutants" = "27.0.0"
|
||||||
|
"cargo:flutter_rust_bridge_codegen" = "2.12.0"
|
||||||
|
|
||||||
[tasks.codegen]
|
[tasks.codegen]
|
||||||
sources = ['protobufs/*.proto', 'protobufs/**/*.proto']
|
sources = ['protobufs/*.proto', 'protobufs/**/*.proto']
|
||||||
|
|||||||
3
useragent/flutter_rust_bridge.yaml
Normal file
3
useragent/flutter_rust_bridge.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
rust_input: crate::api
|
||||||
|
rust_root: rust/
|
||||||
|
dart_output: lib/src/rust
|
||||||
@@ -18,7 +18,6 @@ sealed class CalloutEvent with _$CalloutEvent {
|
|||||||
required CalloutData data,
|
required CalloutData data,
|
||||||
}) = CalloutEventAdded;
|
}) = CalloutEventAdded;
|
||||||
|
|
||||||
const factory CalloutEvent.cancelled({
|
const factory CalloutEvent.cancelled({required String id}) =
|
||||||
required String id,
|
CalloutEventCancelled;
|
||||||
}) = CalloutEventCancelled;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,8 @@ Future<void> showCallout(BuildContext context, WidgetRef ref, String id) async {
|
|||||||
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
|
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
|
||||||
barrierColor: Colors.transparent,
|
barrierColor: Colors.transparent,
|
||||||
transitionDuration: const Duration(milliseconds: 320),
|
transitionDuration: const Duration(milliseconds: 320),
|
||||||
pageBuilder: (_, animation, _) => _CalloutOverlay(
|
pageBuilder: (_, animation, _) =>
|
||||||
id: id,
|
_CalloutOverlay(id: id, data: data, animation: animation),
|
||||||
data: data,
|
|
||||||
animation: animation,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,21 +32,24 @@ class _CalloutOverlay extends ConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
ref.listen(
|
ref.listen(calloutManagerProvider.select((map) => map.containsKey(id)), (
|
||||||
calloutManagerProvider.select((map) => map.containsKey(id)),
|
wasPresent,
|
||||||
(wasPresent, isPresent) {
|
isPresent,
|
||||||
|
) {
|
||||||
if (wasPresent == true && !isPresent && context.mounted) {
|
if (wasPresent == true && !isPresent && context.mounted) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
final content = switch (data) {
|
final content = switch (data) {
|
||||||
ConnectApprovalData(:final pubkey, :final clientInfo) => SdkConnectCallout(
|
ConnectApprovalData(:final pubkey, :final clientInfo) =>
|
||||||
|
SdkConnectCallout(
|
||||||
pubkey: pubkey,
|
pubkey: pubkey,
|
||||||
clientInfo: clientInfo,
|
clientInfo: clientInfo,
|
||||||
onAccept: () => ref.read(calloutManagerProvider.notifier).sendDecision(id, true),
|
onAccept: () =>
|
||||||
onDecline: () => ref.read(calloutManagerProvider.notifier).sendDecision(id, false),
|
ref.read(calloutManagerProvider.notifier).sendDecision(id, true),
|
||||||
|
onDecline: () =>
|
||||||
|
ref.read(calloutManagerProvider.notifier).sendDecision(id, false),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ Future<void> showCalloutList(BuildContext context, WidgetRef ref) async {
|
|||||||
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
|
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
|
||||||
barrierColor: Colors.transparent,
|
barrierColor: Colors.transparent,
|
||||||
transitionDuration: const Duration(milliseconds: 280),
|
transitionDuration: const Duration(milliseconds: 280),
|
||||||
pageBuilder: (_, animation, __) => _CalloutListOverlay(animation: animation),
|
pageBuilder: (_, animation, __) =>
|
||||||
|
_CalloutListOverlay(animation: animation),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (selectedId != null && context.mounted) {
|
if (selectedId != null && context.mounted) {
|
||||||
@@ -51,7 +52,9 @@ class _CalloutListOverlay extends ConsumerWidget {
|
|||||||
child: AnimatedBuilder(
|
child: AnimatedBuilder(
|
||||||
animation: barrierAnim,
|
animation: barrierAnim,
|
||||||
builder: (_, __) => ColoredBox(
|
builder: (_, __) => ColoredBox(
|
||||||
color: Colors.black.withValues(alpha: 0.35 * barrierAnim.value),
|
color: Colors.black.withValues(
|
||||||
|
alpha: 0.35 * barrierAnim.value,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -50,7 +50,9 @@ class ArbiterUrl {
|
|||||||
try {
|
try {
|
||||||
return base64Url.decode(base64Url.normalize(cert));
|
return base64Url.decode(base64Url.normalize(cert));
|
||||||
} on FormatException catch (error) {
|
} on FormatException catch (error) {
|
||||||
throw FormatException("Invalid base64 in 'cert' query parameter: ${error.message}");
|
throw FormatException(
|
||||||
|
"Invalid base64 in 'cert' query parameter: ${error.message}",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,9 @@ Future<Connection> connectAndAuthorize(
|
|||||||
final solutionResponse = await connection.ask(
|
final solutionResponse = await connection.ask(
|
||||||
UserAgentRequest(
|
UserAgentRequest(
|
||||||
auth: ua_auth.Request(
|
auth: ua_auth.Request(
|
||||||
challengeSolution: ua_auth.AuthChallengeSolution(signature: signature),
|
challengeSolution: ua_auth.AuthChallengeSolution(
|
||||||
|
signature: signature,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -85,7 +85,9 @@ class Connection {
|
|||||||
if (response.hasId()) {
|
if (response.hasId()) {
|
||||||
final completer = _pendingRequests.remove(response.id);
|
final completer = _pendingRequests.remove(response.id);
|
||||||
if (completer == null) {
|
if (completer == null) {
|
||||||
talker.warning('Received response for unknown request id ${response.id}');
|
talker.warning(
|
||||||
|
'Received response for unknown request id ${response.id}',
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
completer.complete(response);
|
completer.complete(response);
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ Future<List<WalletEntry>> listEvmWallets(Connection connection) async {
|
|||||||
UserAgentRequest(evm: ua_evm.Request(walletList: Empty())),
|
UserAgentRequest(evm: ua_evm.Request(walletList: Empty())),
|
||||||
);
|
);
|
||||||
if (!response.hasEvm()) {
|
if (!response.hasEvm()) {
|
||||||
throw Exception(
|
throw Exception('Expected EVM response, got ${response.whichPayload()}');
|
||||||
'Expected EVM response, got ${response.whichPayload()}',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final evmResponse = response.evm;
|
final evmResponse = response.evm;
|
||||||
@@ -37,9 +35,7 @@ Future<void> createEvmWallet(Connection connection) async {
|
|||||||
UserAgentRequest(evm: ua_evm.Request(walletCreate: Empty())),
|
UserAgentRequest(evm: ua_evm.Request(walletCreate: Empty())),
|
||||||
);
|
);
|
||||||
if (!response.hasEvm()) {
|
if (!response.hasEvm()) {
|
||||||
throw Exception(
|
throw Exception('Expected EVM response, got ${response.whichPayload()}');
|
||||||
'Expected EVM response, got ${response.whichPayload()}',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final evmResponse = response.evm;
|
final evmResponse = response.evm;
|
||||||
|
|||||||
@@ -10,9 +10,7 @@ Future<List<GrantEntry>> listEvmGrants(Connection connection) async {
|
|||||||
UserAgentRequest(evm: ua_evm.Request(grantList: request)),
|
UserAgentRequest(evm: ua_evm.Request(grantList: request)),
|
||||||
);
|
);
|
||||||
if (!response.hasEvm()) {
|
if (!response.hasEvm()) {
|
||||||
throw Exception(
|
throw Exception('Expected EVM response, got ${response.whichPayload()}');
|
||||||
'Expected EVM response, got ${response.whichPayload()}',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final evmResponse = response.evm;
|
final evmResponse = response.evm;
|
||||||
@@ -50,9 +48,7 @@ Future<int> createEvmGrant(
|
|||||||
final resp = await connection.ask(request);
|
final resp = await connection.ask(request);
|
||||||
|
|
||||||
if (!resp.hasEvm()) {
|
if (!resp.hasEvm()) {
|
||||||
throw Exception(
|
throw Exception('Expected EVM response, got ${resp.whichPayload()}');
|
||||||
'Expected EVM response, got ${resp.whichPayload()}',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final evmResponse = resp.evm;
|
final evmResponse = resp.evm;
|
||||||
@@ -70,15 +66,11 @@ Future<int> createEvmGrant(
|
|||||||
Future<void> deleteEvmGrant(Connection connection, int grantId) async {
|
Future<void> deleteEvmGrant(Connection connection, int grantId) async {
|
||||||
final response = await connection.ask(
|
final response = await connection.ask(
|
||||||
UserAgentRequest(
|
UserAgentRequest(
|
||||||
evm: ua_evm.Request(
|
evm: ua_evm.Request(grantDelete: EvmGrantDeleteRequest(grantId: grantId)),
|
||||||
grantDelete: EvmGrantDeleteRequest(grantId: grantId),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (!response.hasEvm()) {
|
if (!response.hasEvm()) {
|
||||||
throw Exception(
|
throw Exception('Expected EVM response, got ${response.whichPayload()}');
|
||||||
'Expected EVM response, got ${response.whichPayload()}',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final evmResponse = response.evm;
|
final evmResponse = response.evm;
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ Future<Set<int>> readClientWalletAccess(
|
|||||||
required int clientId,
|
required int clientId,
|
||||||
}) async {
|
}) async {
|
||||||
final response = await connection.ask(
|
final response = await connection.ask(
|
||||||
UserAgentRequest(
|
UserAgentRequest(sdkClient: ua_sdk.Request(listWalletAccess: Empty())),
|
||||||
sdkClient: ua_sdk.Request(listWalletAccess: Empty()),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
if (!response.hasSdkClient()) {
|
if (!response.hasSdkClient()) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
@@ -33,9 +31,7 @@ Future<List<ua_sdk.WalletAccessEntry>> listAllWalletAccesses(
|
|||||||
Connection connection,
|
Connection connection,
|
||||||
) async {
|
) async {
|
||||||
final response = await connection.ask(
|
final response = await connection.ask(
|
||||||
UserAgentRequest(
|
UserAgentRequest(sdkClient: ua_sdk.Request(listWalletAccess: Empty())),
|
||||||
sdkClient: ua_sdk.Request(listWalletAccess: Empty()),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
if (!response.hasSdkClient()) {
|
if (!response.hasSdkClient()) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
@@ -81,9 +77,7 @@ Future<void> writeClientWalletAccess(
|
|||||||
UserAgentRequest(
|
UserAgentRequest(
|
||||||
sdkClient: ua_sdk.Request(
|
sdkClient: ua_sdk.Request(
|
||||||
revokeWalletAccess: ua_sdk.RevokeWalletAccess(
|
revokeWalletAccess: ua_sdk.RevokeWalletAccess(
|
||||||
accesses: [
|
accesses: [for (final walletId in toRevoke) walletId],
|
||||||
for (final walletId in toRevoke) walletId,
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ class StoredServerInfo {
|
|||||||
final int port;
|
final int port;
|
||||||
final String caCertFingerprint;
|
final String caCertFingerprint;
|
||||||
|
|
||||||
factory StoredServerInfo.fromJson(Map<String, dynamic> json) => _$StoredServerInfoFromJson(json);
|
factory StoredServerInfo.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$StoredServerInfoFromJson(json);
|
||||||
Map<String, dynamic> toJson() => _$StoredServerInfoToJson(this);
|
Map<String, dynamic> toJson() => _$StoredServerInfoToJson(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class ServerInfoStorage {
|
abstract class ServerInfoStorage {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:arbiter/features/connection/connection.dart';
|
import 'package:arbiter/features/connection/connection.dart';
|
||||||
import 'package:arbiter/proto/user_agent/vault/bootstrap.pb.dart' as ua_bootstrap;
|
import 'package:arbiter/proto/user_agent/vault/bootstrap.pb.dart'
|
||||||
|
as ua_bootstrap;
|
||||||
import 'package:arbiter/proto/user_agent/vault/unseal.pb.dart' as ua_unseal;
|
import 'package:arbiter/proto/user_agent/vault/unseal.pb.dart' as ua_unseal;
|
||||||
import 'package:arbiter/proto/user_agent/vault/vault.pb.dart' as ua_vault;
|
import 'package:arbiter/proto/user_agent/vault/vault.pb.dart' as ua_vault;
|
||||||
import 'package:arbiter/proto/user_agent.pb.dart';
|
import 'package:arbiter/proto/user_agent.pb.dart';
|
||||||
@@ -27,9 +28,7 @@ Future<ua_bootstrap.BootstrapResult> bootstrapVault(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (!response.hasVault()) {
|
if (!response.hasVault()) {
|
||||||
throw Exception(
|
throw Exception('Expected vault response, got ${response.whichPayload()}');
|
||||||
'Expected vault response, got ${response.whichPayload()}',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final vaultResponse = response.vault;
|
final vaultResponse = response.vault;
|
||||||
|
|||||||
71
useragent/lib/features/identity/hazmat_mldsa.dart
Normal file
71
useragent/lib/features/identity/hazmat_mldsa.dart
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:arbiter/src/rust/api.dart';
|
||||||
|
import 'package:cryptography/cryptography.dart';
|
||||||
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
import 'package:arbiter/features/identity/pk_manager.dart';
|
||||||
|
|
||||||
|
final storage = FlutterSecureStorage(
|
||||||
|
aOptions: AndroidOptions.biometric(
|
||||||
|
enforceBiometrics: true,
|
||||||
|
biometricPromptTitle: 'Authentication Required',
|
||||||
|
),
|
||||||
|
mOptions: MacOsOptions(
|
||||||
|
accessibility: KeychainAccessibility.unlocked_this_device,
|
||||||
|
label: "Arbiter",
|
||||||
|
description: "Confirm your identity to access vault",
|
||||||
|
synchronizable: false,
|
||||||
|
accessControlFlags: [AccessControlFlag.userPresence],
|
||||||
|
usesDataProtectionKeychain: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
class HazmatMldsa extends KeyHandle {
|
||||||
|
final MldsaKey _key;
|
||||||
|
|
||||||
|
HazmatMldsa({required MldsaKey key}) : _key = key;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<int>> getPublicKey() async {
|
||||||
|
final publicKey = await _key.getPublicKey();
|
||||||
|
return publicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<int>> sign(List<int> data) async {
|
||||||
|
final signature = await _key.sign(message: data);
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HazmatMLDSAManager extends KeyManager {
|
||||||
|
static const _storageKey = "ed25519_identity";
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<KeyHandle> create() async {
|
||||||
|
final storedKey = await get();
|
||||||
|
if (storedKey != null) {
|
||||||
|
return storedKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
final newKeypair = await MldsaKey.generate();
|
||||||
|
final keyBytes = await newKeypair.toBytes();
|
||||||
|
|
||||||
|
await storage.write(key: _storageKey, value: base64Encode(keyBytes));
|
||||||
|
|
||||||
|
return HazmatMldsa(key: newKeypair);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<KeyHandle?> get() async {
|
||||||
|
final storedKeyPair = await storage.read(key: _storageKey);
|
||||||
|
if (storedKeyPair == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final keyBytes = base64Decode(storedKeyPair);
|
||||||
|
final key = await MldsaKey.fromBytes(bytes: keyBytes);
|
||||||
|
|
||||||
|
return HazmatMldsa(key: key);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,6 @@
|
|||||||
enum KeyAlgorithm {
|
|
||||||
rsa, ecdsa, ed25519
|
|
||||||
}
|
|
||||||
|
|
||||||
// The API to handle without storing the private key in memory.
|
// The API to handle without storing the private key in memory.
|
||||||
//The implementation will use platform-specific secure storage and signing capabilities.
|
//The implementation will use platform-specific secure storage and signing capabilities.
|
||||||
abstract class KeyHandle {
|
abstract class KeyHandle {
|
||||||
KeyAlgorithm get alg;
|
|
||||||
Future<List<int>> sign(List<int> data);
|
Future<List<int>> sign(List<int> data);
|
||||||
Future<List<int>> getPublicKey();
|
Future<List<int>> getPublicKey();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:cryptography/cryptography.dart';
|
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
||||||
import 'package:arbiter/features/identity/pk_manager.dart';
|
|
||||||
|
|
||||||
final storage = FlutterSecureStorage(
|
|
||||||
aOptions: AndroidOptions.biometric(
|
|
||||||
enforceBiometrics: true,
|
|
||||||
biometricPromptTitle: 'Authentication Required',
|
|
||||||
),
|
|
||||||
mOptions: MacOsOptions(
|
|
||||||
accessibility: KeychainAccessibility.unlocked_this_device,
|
|
||||||
label: "Arbiter",
|
|
||||||
description: "Confirm your identity to access vault",
|
|
||||||
synchronizable: false,
|
|
||||||
accessControlFlags: [
|
|
||||||
AccessControlFlag.userPresence,
|
|
||||||
],
|
|
||||||
usesDataProtectionKeychain: true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
final processor = Ed25519();
|
|
||||||
|
|
||||||
class SimpleEd25519 extends KeyHandle {
|
|
||||||
final SimpleKeyPair _keyPair;
|
|
||||||
|
|
||||||
SimpleEd25519({required SimpleKeyPair keyPair}) : _keyPair = keyPair;
|
|
||||||
|
|
||||||
@override
|
|
||||||
KeyAlgorithm get alg => KeyAlgorithm.ed25519;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<int>> getPublicKey() async {
|
|
||||||
final publicKey = await _keyPair.extractPublicKey();
|
|
||||||
return publicKey.bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<int>> sign(List<int> data) async {
|
|
||||||
final signature = await processor.sign(data, keyPair: _keyPair);
|
|
||||||
return signature.bytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SimpleEd25519Manager extends KeyManager {
|
|
||||||
static const _storageKey = "ed25519_identity";
|
|
||||||
static const _storagePublicKey = "ed25519_public_key";
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<KeyHandle> create() async {
|
|
||||||
final storedKey = await get();
|
|
||||||
if (storedKey != null) {
|
|
||||||
return storedKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
final newKey = await processor.newKeyPair();
|
|
||||||
final rawKey = await newKey.extract();
|
|
||||||
|
|
||||||
final keyData = base64Encode(rawKey.bytes);
|
|
||||||
await storage.write(key: _storageKey, value: keyData);
|
|
||||||
|
|
||||||
final publicKeyData = base64Encode(rawKey.publicKey.bytes);
|
|
||||||
await storage.write(key: _storagePublicKey, value: publicKeyData);
|
|
||||||
|
|
||||||
return SimpleEd25519(keyPair: newKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<KeyHandle?> get() async {
|
|
||||||
final storedKeyPair = await storage.read(key: _storageKey);
|
|
||||||
if (storedKeyPair == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final publicKeyData = await storage.read(key: _storagePublicKey);
|
|
||||||
final publicKeyRaw = base64Decode(publicKeyData!);
|
|
||||||
final publicKey = SimplePublicKey(
|
|
||||||
publicKeyRaw,
|
|
||||||
type: processor.keyPairType,
|
|
||||||
);
|
|
||||||
|
|
||||||
final keyBytes = base64Decode(storedKeyPair);
|
|
||||||
final keypair = SimpleKeyPairData(
|
|
||||||
keyBytes,
|
|
||||||
publicKey: publicKey,
|
|
||||||
type: processor.keyPairType,
|
|
||||||
);
|
|
||||||
|
|
||||||
return SimpleEd25519(keyPair: keypair);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
import 'package:arbiter/router.dart';
|
import 'package:arbiter/router.dart';
|
||||||
|
import 'package:arbiter/src/rust/frb_generated.dart';
|
||||||
import 'package:flutter/material.dart' hide Router;
|
import 'package:flutter/material.dart' hide Router;
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:sizer/sizer.dart';
|
import 'package:sizer/sizer.dart';
|
||||||
|
|
||||||
void main() {
|
Future<void> main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
await RustLib.init();
|
||||||
runApp(const ProviderScope(child: App()));
|
runApp(const ProviderScope(child: App()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,3 +35,5 @@ class _AppState extends State<App> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'bootstrap_token.g.dart';
|
part 'bootstrap_token.g.dart';
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import 'package:arbiter/features/connection/evm.dart' as evm;
|
|||||||
import 'package:arbiter/proto/evm.pb.dart';
|
import 'package:arbiter/proto/evm.pb.dart';
|
||||||
import 'package:arbiter/providers/connection/connection_manager.dart';
|
import 'package:arbiter/providers/connection/connection_manager.dart';
|
||||||
import 'package:hooks_riverpod/experimental/mutation.dart';
|
import 'package:hooks_riverpod/experimental/mutation.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'evm.g.dart';
|
part 'evm.g.dart';
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import 'package:mtcore/markettakers.dart';
|
import 'package:mtcore/markettakers.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:arbiter/features/identity/pk_manager.dart';
|
import 'package:arbiter/features/identity/pk_manager.dart';
|
||||||
import 'package:arbiter/features/identity/simple_ed25519.dart';
|
import 'package:arbiter/features/identity/hazmat_mldsa.dart';
|
||||||
|
|
||||||
part 'key.g.dart';
|
part 'key.g.dart';
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
KeyManager keyManager(Ref ref) {
|
KeyManager keyManager(Ref ref) {
|
||||||
return SimpleEd25519Manager();
|
return HazmatMLDSAManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
|
|||||||
@@ -18,9 +18,7 @@ Future<List<ua_sdk.Entry>?> sdkClients(Ref ref) async {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!resp.hasSdkClient()) {
|
if (!resp.hasSdkClient()) {
|
||||||
throw Exception(
|
throw Exception('Expected SDK client response, got ${resp.whichPayload()}');
|
||||||
'Expected SDK client response, got ${resp.whichPayload()}',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
final sdkClientResponse = resp.sdkClient;
|
final sdkClientResponse = resp.sdkClient;
|
||||||
if (!sdkClientResponse.hasList()) {
|
if (!sdkClientResponse.hasList()) {
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ class ServerInfo extends _$ServerInfo {
|
|||||||
|
|
||||||
Future<String> _fingerprint(List<int> caCert) async {
|
Future<String> _fingerprint(List<int> caCert) async {
|
||||||
final digest = await Sha256().hash(caCert);
|
final digest = await Sha256().hash(caCert);
|
||||||
return digest.bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join();
|
return digest.bytes
|
||||||
|
.map((byte) => byte.toRadixString(16).padLeft(2, '0'))
|
||||||
|
.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,7 @@ class SdkConnectCallout extends StatelessWidget {
|
|||||||
|
|
||||||
final hasDescription =
|
final hasDescription =
|
||||||
clientInfo.hasDescription() && clientInfo.description.isNotEmpty;
|
clientInfo.hasDescription() && clientInfo.description.isNotEmpty;
|
||||||
final hasVersion =
|
final hasVersion = clientInfo.hasVersion() && clientInfo.version.isNotEmpty;
|
||||||
clientInfo.hasVersion() && clientInfo.version.isNotEmpty;
|
|
||||||
final showInfoCard = hasDescription || hasVersion;
|
final showInfoCard = hasDescription || hasVersion;
|
||||||
|
|
||||||
return CreamFrame(
|
return CreamFrame(
|
||||||
@@ -74,10 +73,7 @@ class SdkConnectCallout extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(14),
|
borderRadius: BorderRadius.circular(14),
|
||||||
border: Border.all(color: Palette.line),
|
border: Border.all(color: Palette.line),
|
||||||
),
|
),
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(horizontal: 1.6.w, vertical: 1.2.h),
|
||||||
horizontal: 1.6.w,
|
|
||||||
vertical: 1.2.h,
|
|
||||||
),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
spacing: 0.6.h,
|
spacing: 0.6.h,
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class DashboardRouter extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _CalloutBell extends ConsumerWidget {
|
class _CalloutBell extends ConsumerWidget {
|
||||||
const _CalloutBell({super.key});
|
const _CalloutBell();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import 'package:arbiter/proto/user_agent/sdk_client.pb.dart' as ua_sdk;
|
import 'package:arbiter/proto/user_agent/sdk_client.pb.dart' as ua_sdk;
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -13,5 +12,4 @@ class ClientDetails extends ConsumerWidget {
|
|||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,7 @@ class ClientSummaryCard extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(client.info.name, style: Theme.of(context).textTheme.titleLarge),
|
||||||
client.info.name,
|
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(client.info.description),
|
Text(client.info.description),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
@@ -27,10 +24,7 @@ class ClientSummaryCard extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
_Fact(label: 'Client ID', value: '${client.id}'),
|
_Fact(label: 'Client ID', value: '${client.id}'),
|
||||||
_Fact(label: 'Version', value: client.info.version),
|
_Fact(label: 'Version', value: client.info.version),
|
||||||
_Fact(
|
_Fact(label: 'Registered', value: _formatDate(client.createdAt)),
|
||||||
label: 'Registered',
|
|
||||||
value: _formatDate(client.createdAt),
|
|
||||||
),
|
|
||||||
_Fact(label: 'Pubkey', value: _shortPubkey(client.pubkey)),
|
_Fact(label: 'Pubkey', value: _shortPubkey(client.pubkey)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -32,10 +32,7 @@ class WalletAccessSection extends ConsumerWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text('Wallet access', style: Theme.of(context).textTheme.titleLarge),
|
||||||
'Wallet access',
|
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text('Choose which managed wallets this client can see.'),
|
Text('Choose which managed wallets this client can see.'),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ class ClientPickerField extends ConsumerWidget {
|
|||||||
? null
|
? null
|
||||||
: (value) {
|
: (value) {
|
||||||
ref.read(grantCreationProvider.notifier).setClientId(value);
|
ref.read(grantCreationProvider.notifier).setClientId(value);
|
||||||
FormBuilder.of(context)?.fields['walletAccessId']?.didChange(null);
|
FormBuilder.of(
|
||||||
|
context,
|
||||||
|
)?.fields['walletAccessId']?.didChange(null);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,13 +35,15 @@ class FormBuilderDateTimeField extends FormBuilderField<DateTime?> {
|
|||||||
initialTime: TimeOfDay.fromDateTime(value ?? now),
|
initialTime: TimeOfDay.fromDateTime(value ?? now),
|
||||||
);
|
);
|
||||||
if (time == null) return;
|
if (time == null) return;
|
||||||
field.didChange(DateTime(
|
field.didChange(
|
||||||
|
DateTime(
|
||||||
date.year,
|
date.year,
|
||||||
date.month,
|
date.month,
|
||||||
date.day,
|
date.day,
|
||||||
time.hour,
|
time.hour,
|
||||||
time.minute,
|
time.minute,
|
||||||
));
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
onLongPress: value == null ? null : () => field.didChange(null),
|
onLongPress: value == null ? null : () => field.didChange(null),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
|||||||
@@ -93,9 +93,9 @@ class _EtherTransferForm extends ConsumerWidget {
|
|||||||
SizedBox(height: 1.6.h),
|
SizedBox(height: 1.6.h),
|
||||||
Text(
|
Text(
|
||||||
'Ether volume limit',
|
'Ether volume limit',
|
||||||
style: Theme.of(context).textTheme.labelLarge?.copyWith(
|
style: Theme.of(
|
||||||
fontWeight: FontWeight.w800,
|
context,
|
||||||
),
|
).textTheme.labelLarge?.copyWith(fontWeight: FontWeight.w800),
|
||||||
),
|
),
|
||||||
SizedBox(height: 0.8.h),
|
SizedBox(height: 0.8.h),
|
||||||
Row(
|
Row(
|
||||||
@@ -157,9 +157,9 @@ class _EtherTargetsField extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Ether targets',
|
'Ether targets',
|
||||||
style: Theme.of(context).textTheme.labelLarge?.copyWith(
|
style: Theme.of(
|
||||||
fontWeight: FontWeight.w800,
|
context,
|
||||||
),
|
).textTheme.labelLarge?.copyWith(fontWeight: FontWeight.w800),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
|
|||||||
@@ -13,7 +13,11 @@ import 'package:sizer/sizer.dart';
|
|||||||
part 'token_transfer_grant.g.dart';
|
part 'token_transfer_grant.g.dart';
|
||||||
|
|
||||||
class VolumeLimitEntry {
|
class VolumeLimitEntry {
|
||||||
VolumeLimitEntry({required this.id, this.amount = '', this.windowSeconds = ''});
|
VolumeLimitEntry({
|
||||||
|
required this.id,
|
||||||
|
this.amount = '',
|
||||||
|
this.windowSeconds = '',
|
||||||
|
});
|
||||||
|
|
||||||
final int id;
|
final int id;
|
||||||
final String amount;
|
final String amount;
|
||||||
@@ -27,7 +31,6 @@ class VolumeLimitEntry {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
class TokenGrantLimits extends _$TokenGrantLimits {
|
class TokenGrantLimits extends _$TokenGrantLimits {
|
||||||
int _nextId = 0;
|
int _nextId = 0;
|
||||||
@@ -47,7 +50,6 @@ class TokenGrantLimits extends _$TokenGrantLimits {
|
|||||||
void remove(int index) => state = [...state]..removeAt(index);
|
void remove(int index) => state = [...state]..removeAt(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class TokenTransferGrantHandler implements GrantFormHandler {
|
class TokenTransferGrantHandler implements GrantFormHandler {
|
||||||
const TokenTransferGrantHandler();
|
const TokenTransferGrantHandler();
|
||||||
|
|
||||||
@@ -65,11 +67,16 @@ class TokenTransferGrantHandler implements GrantFormHandler {
|
|||||||
|
|
||||||
return SpecificGrant(
|
return SpecificGrant(
|
||||||
tokenTransfer: TokenTransferSettings(
|
tokenTransfer: TokenTransferSettings(
|
||||||
tokenContract:
|
tokenContract: parseHexAddress(
|
||||||
parseHexAddress(formValues['tokenContract'] as String? ?? ''),
|
formValues['tokenContract'] as String? ?? '',
|
||||||
|
),
|
||||||
target: targetText.trim().isEmpty ? null : parseHexAddress(targetText),
|
target: targetText.trim().isEmpty ? null : parseHexAddress(targetText),
|
||||||
volumeLimits: limits
|
volumeLimits: limits
|
||||||
.where((e) => e.amount.trim().isNotEmpty && e.windowSeconds.trim().isNotEmpty)
|
.where(
|
||||||
|
(e) =>
|
||||||
|
e.amount.trim().isNotEmpty &&
|
||||||
|
e.windowSeconds.trim().isNotEmpty,
|
||||||
|
)
|
||||||
.map(
|
.map(
|
||||||
(e) => VolumeRateLimit(
|
(e) => VolumeRateLimit(
|
||||||
maxVolume: parseBigIntBytes(e.amount),
|
maxVolume: parseBigIntBytes(e.amount),
|
||||||
@@ -153,9 +160,9 @@ class _TokenVolumeLimitsField extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Token volume limits',
|
'Token volume limits',
|
||||||
style: Theme.of(context).textTheme.labelLarge?.copyWith(
|
style: Theme.of(
|
||||||
fontWeight: FontWeight.w800,
|
context,
|
||||||
),
|
).textTheme.labelLarge?.copyWith(fontWeight: FontWeight.w800),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
@@ -196,7 +203,9 @@ class _TokenVolumeLimitRow extends HookWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final amountController = useTextEditingController(text: value.amount);
|
final amountController = useTextEditingController(text: value.amount);
|
||||||
final windowController = useTextEditingController(text: value.windowSeconds);
|
final windowController = useTextEditingController(
|
||||||
|
text: value.windowSeconds,
|
||||||
|
);
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
@@ -214,8 +223,7 @@ class _TokenVolumeLimitRow extends HookWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: windowController,
|
controller: windowController,
|
||||||
onChanged: (next) =>
|
onChanged: (next) => onChanged(value.copyWith(windowSeconds: next)),
|
||||||
onChanged(value.copyWith(windowSeconds: next)),
|
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'Window (seconds)',
|
labelText: 'Window (seconds)',
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ GrantFormHandler _handlerFor(SpecificGrant_Grant type) => switch (type) {
|
|||||||
SpecificGrant_Grant.etherTransfer => _etherHandler,
|
SpecificGrant_Grant.etherTransfer => _etherHandler,
|
||||||
SpecificGrant_Grant.tokenTransfer => _tokenHandler,
|
SpecificGrant_Grant.tokenTransfer => _tokenHandler,
|
||||||
_ => throw ArgumentError('Unsupported grant type: $type'),
|
_ => throw ArgumentError('Unsupported grant type: $type'),
|
||||||
};
|
};
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
class CreateEvmGrantScreen extends HookConsumerWidget {
|
class CreateEvmGrantScreen extends HookConsumerWidget {
|
||||||
@@ -62,12 +62,14 @@ class CreateEvmGrantScreen extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
final validFrom = formValues['validFrom'] as DateTime?;
|
final validFrom = formValues['validFrom'] as DateTime?;
|
||||||
final validUntil = formValues['validUntil'] as DateTime?;
|
final validUntil = formValues['validUntil'] as DateTime?;
|
||||||
if (validFrom != null) sharedSettings.validFrom = toTimestamp(validFrom);
|
if (validFrom != null)
|
||||||
|
sharedSettings.validFrom = toTimestamp(validFrom);
|
||||||
if (validUntil != null) {
|
if (validUntil != null) {
|
||||||
sharedSettings.validUntil = toTimestamp(validUntil);
|
sharedSettings.validUntil = toTimestamp(validUntil);
|
||||||
}
|
}
|
||||||
final gasBytes =
|
final gasBytes = optionalBigIntBytes(
|
||||||
optionalBigIntBytes(formValues['maxGasFeePerGas'] as String? ?? '');
|
formValues['maxGasFeePerGas'] as String? ?? '',
|
||||||
|
);
|
||||||
if (gasBytes != null) sharedSettings.maxGasFeePerGas = gasBytes;
|
if (gasBytes != null) sharedSettings.maxGasFeePerGas = gasBytes;
|
||||||
final priorityBytes = optionalBigIntBytes(
|
final priorityBytes = optionalBigIntBytes(
|
||||||
formValues['maxPriorityFeePerGas'] as String? ?? '',
|
formValues['maxPriorityFeePerGas'] as String? ?? '',
|
||||||
@@ -106,7 +108,8 @@ class CreateEvmGrantScreen extends HookConsumerWidget {
|
|||||||
SizedBox(height: 1.8.h),
|
SizedBox(height: 1.8.h),
|
||||||
const _Section(
|
const _Section(
|
||||||
title: 'Authorization',
|
title: 'Authorization',
|
||||||
tooltip: 'Select which SDK client receives this grant and '
|
tooltip:
|
||||||
|
'Select which SDK client receives this grant and '
|
||||||
'which of its wallet accesses it applies to.',
|
'which of its wallet accesses it applies to.',
|
||||||
child: AuthorizationFields(),
|
child: AuthorizationFields(),
|
||||||
),
|
),
|
||||||
@@ -118,7 +121,8 @@ class CreateEvmGrantScreen extends HookConsumerWidget {
|
|||||||
const Expanded(
|
const Expanded(
|
||||||
child: _Section(
|
child: _Section(
|
||||||
title: 'Chain',
|
title: 'Chain',
|
||||||
tooltip: 'Restrict this grant to a specific EVM chain ID. '
|
tooltip:
|
||||||
|
'Restrict this grant to a specific EVM chain ID. '
|
||||||
'Leave empty to allow any chain.',
|
'Leave empty to allow any chain.',
|
||||||
optional: true,
|
optional: true,
|
||||||
child: ChainIdField(),
|
child: ChainIdField(),
|
||||||
@@ -128,7 +132,8 @@ class CreateEvmGrantScreen extends HookConsumerWidget {
|
|||||||
const Expanded(
|
const Expanded(
|
||||||
child: _Section(
|
child: _Section(
|
||||||
title: 'Timing',
|
title: 'Timing',
|
||||||
tooltip: 'Set an optional validity window. '
|
tooltip:
|
||||||
|
'Set an optional validity window. '
|
||||||
'Signing requests outside this period will be rejected.',
|
'Signing requests outside this period will be rejected.',
|
||||||
optional: true,
|
optional: true,
|
||||||
child: ValidityWindowField(),
|
child: ValidityWindowField(),
|
||||||
@@ -145,7 +150,8 @@ class CreateEvmGrantScreen extends HookConsumerWidget {
|
|||||||
const Expanded(
|
const Expanded(
|
||||||
child: _Section(
|
child: _Section(
|
||||||
title: 'Gas limits',
|
title: 'Gas limits',
|
||||||
tooltip: 'Cap the gas fees this grant may authorize. '
|
tooltip:
|
||||||
|
'Cap the gas fees this grant may authorize. '
|
||||||
'Transactions exceeding these values will be rejected.',
|
'Transactions exceeding these values will be rejected.',
|
||||||
optional: true,
|
optional: true,
|
||||||
child: GasFeeOptionsField(),
|
child: GasFeeOptionsField(),
|
||||||
@@ -155,7 +161,8 @@ class CreateEvmGrantScreen extends HookConsumerWidget {
|
|||||||
const Expanded(
|
const Expanded(
|
||||||
child: _Section(
|
child: _Section(
|
||||||
title: 'Transaction limits',
|
title: 'Transaction limits',
|
||||||
tooltip: 'Limit how many transactions can be signed '
|
tooltip:
|
||||||
|
'Limit how many transactions can be signed '
|
||||||
'within a rolling time window.',
|
'within a rolling time window.',
|
||||||
optional: true,
|
optional: true,
|
||||||
child: TransactionRateLimitField(),
|
child: TransactionRateLimitField(),
|
||||||
@@ -172,7 +179,8 @@ class CreateEvmGrantScreen extends HookConsumerWidget {
|
|||||||
SizedBox(height: 1.8.h),
|
SizedBox(height: 1.8.h),
|
||||||
_Section(
|
_Section(
|
||||||
title: 'Grant-specific options',
|
title: 'Grant-specific options',
|
||||||
tooltip: 'Rules specific to the selected transfer type. '
|
tooltip:
|
||||||
|
'Rules specific to the selected transfer type. '
|
||||||
'Switch between Ether and token above to change these fields.',
|
'Switch between Ether and token above to change these fields.',
|
||||||
child: handler.buildForm(context, ref),
|
child: handler.buildForm(context, ref),
|
||||||
),
|
),
|
||||||
@@ -180,8 +188,7 @@ class CreateEvmGrantScreen extends HookConsumerWidget {
|
|||||||
Align(
|
Align(
|
||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
child: FilledButton.icon(
|
child: FilledButton.icon(
|
||||||
onPressed:
|
onPressed: createMutation is MutationPending ? null : submit,
|
||||||
createMutation is MutationPending ? null : submit,
|
|
||||||
icon: createMutation is MutationPending
|
icon: createMutation is MutationPending
|
||||||
? SizedBox(
|
? SizedBox(
|
||||||
width: 1.8.h,
|
width: 1.8.h,
|
||||||
@@ -266,9 +273,9 @@ class _Section extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
style: Theme.of(
|
||||||
fontWeight: FontWeight.w800,
|
context,
|
||||||
),
|
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w800),
|
||||||
),
|
),
|
||||||
SizedBox(width: 0.4.w),
|
SizedBox(width: 0.4.w),
|
||||||
Tooltip(
|
Tooltip(
|
||||||
@@ -283,9 +290,9 @@ class _Section extends StatelessWidget {
|
|||||||
SizedBox(width: 0.6.w),
|
SizedBox(width: 0.6.w),
|
||||||
Text(
|
Text(
|
||||||
'(optional)',
|
'(optional)',
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: Theme.of(
|
||||||
color: subtleColor,
|
context,
|
||||||
),
|
).textTheme.bodySmall?.copyWith(color: subtleColor),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -19,4 +19,3 @@ class AuthorizationFields extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,9 +46,7 @@ class GrantCard extends ConsumerWidget {
|
|||||||
final accessById = <int, ua_sdk.WalletAccessEntry>{
|
final accessById = <int, ua_sdk.WalletAccessEntry>{
|
||||||
for (final a in walletAccesses) a.id: a,
|
for (final a in walletAccesses) a.id: a,
|
||||||
};
|
};
|
||||||
final walletById = <int, WalletEntry>{
|
final walletById = <int, WalletEntry>{for (final w in wallets) w.id: w};
|
||||||
for (final w in wallets) w.id: w,
|
|
||||||
};
|
|
||||||
final clientNameById = <int, String>{
|
final clientNameById = <int, String>{
|
||||||
for (final c in clients) c.id: c.info.name,
|
for (final c in clients) c.id: c.info.name,
|
||||||
};
|
};
|
||||||
@@ -192,8 +190,9 @@ class GrantCard extends ConsumerWidget {
|
|||||||
padding: EdgeInsets.symmetric(horizontal: 0.8.w),
|
padding: EdgeInsets.symmetric(horizontal: 0.8.w),
|
||||||
child: Text(
|
child: Text(
|
||||||
'·',
|
'·',
|
||||||
style: theme.textTheme.bodySmall
|
style: theme.textTheme.bodySmall?.copyWith(
|
||||||
?.copyWith(color: muted),
|
color: muted,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -201,8 +200,9 @@ class GrantCard extends ConsumerWidget {
|
|||||||
clientLabel,
|
clientLabel,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: theme.textTheme.bodySmall
|
style: theme.textTheme.bodySmall?.copyWith(
|
||||||
?.copyWith(color: muted),
|
color: muted,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import 'package:hooks_riverpod/experimental/mutation.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:sizer/sizer.dart';
|
import 'package:sizer/sizer.dart';
|
||||||
|
|
||||||
|
|
||||||
class CreateWalletButton extends ConsumerWidget {
|
class CreateWalletButton extends ConsumerWidget {
|
||||||
const CreateWalletButton({super.key});
|
const CreateWalletButton({super.key});
|
||||||
|
|
||||||
@@ -88,7 +87,6 @@ class RefreshWalletButton extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String _formatError(Object error) {
|
String _formatError(Object error) {
|
||||||
final message = error.toString();
|
final message = error.toString();
|
||||||
if (message.startsWith('Exception: ')) {
|
if (message.startsWith('Exception: ')) {
|
||||||
|
|||||||
@@ -71,10 +71,7 @@ class WalletTable extends StatelessWidget {
|
|||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
bottom: i == wallets.length - 1 ? 0 : 1.h,
|
bottom: i == wallets.length - 1 ? 0 : 1.h,
|
||||||
),
|
),
|
||||||
child: _WalletTableRow(
|
child: _WalletTableRow(wallet: wallets[i], index: i),
|
||||||
wallet: wallets[i],
|
|
||||||
index: i,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
22
useragent/lib/src/rust/api.dart
Normal file
22
useragent/lib/src/rust/api.dart
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// This file is automatically generated, so please do not edit it.
|
||||||
|
// @generated by `flutter_rust_bridge`@ 2.12.0.
|
||||||
|
|
||||||
|
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
|
||||||
|
|
||||||
|
import 'frb_generated.dart';
|
||||||
|
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
|
||||||
|
|
||||||
|
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<MldsaKey>>
|
||||||
|
abstract class MldsaKey implements RustOpaqueInterface {
|
||||||
|
static Future<MldsaKey> fromBytes({required List<int> bytes}) =>
|
||||||
|
RustLib.instance.api.crateApiMldsaKeyFromBytes(bytes: bytes);
|
||||||
|
|
||||||
|
static Future<MldsaKey> generate() =>
|
||||||
|
RustLib.instance.api.crateApiMldsaKeyGenerate();
|
||||||
|
|
||||||
|
Future<Uint8List> getPublicKey();
|
||||||
|
|
||||||
|
Future<Uint8List> sign({required List<int> message});
|
||||||
|
|
||||||
|
Future<Uint8List> toBytes();
|
||||||
|
}
|
||||||
573
useragent/lib/src/rust/frb_generated.dart
Normal file
573
useragent/lib/src/rust/frb_generated.dart
Normal file
@@ -0,0 +1,573 @@
|
|||||||
|
// This file is automatically generated, so please do not edit it.
|
||||||
|
// @generated by `flutter_rust_bridge`@ 2.12.0.
|
||||||
|
|
||||||
|
// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field
|
||||||
|
|
||||||
|
import 'api.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'frb_generated.dart';
|
||||||
|
import 'frb_generated.io.dart'
|
||||||
|
if (dart.library.js_interop) 'frb_generated.web.dart';
|
||||||
|
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
|
||||||
|
|
||||||
|
/// Main entrypoint of the Rust API
|
||||||
|
class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
|
||||||
|
@internal
|
||||||
|
static final instance = RustLib._();
|
||||||
|
|
||||||
|
RustLib._();
|
||||||
|
|
||||||
|
/// Initialize flutter_rust_bridge
|
||||||
|
static Future<void> init({
|
||||||
|
RustLibApi? api,
|
||||||
|
BaseHandler? handler,
|
||||||
|
ExternalLibrary? externalLibrary,
|
||||||
|
bool forceSameCodegenVersion = true,
|
||||||
|
}) async {
|
||||||
|
await instance.initImpl(
|
||||||
|
api: api,
|
||||||
|
handler: handler,
|
||||||
|
externalLibrary: externalLibrary,
|
||||||
|
forceSameCodegenVersion: forceSameCodegenVersion,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize flutter_rust_bridge in mock mode.
|
||||||
|
/// No libraries for FFI are loaded.
|
||||||
|
static void initMock({required RustLibApi api}) {
|
||||||
|
instance.initMockImpl(api: api);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dispose flutter_rust_bridge
|
||||||
|
///
|
||||||
|
/// The call to this function is optional, since flutter_rust_bridge (and everything else)
|
||||||
|
/// is automatically disposed when the app stops.
|
||||||
|
static void dispose() => instance.disposeImpl();
|
||||||
|
|
||||||
|
@override
|
||||||
|
ApiImplConstructor<RustLibApiImpl, RustLibWire> get apiImplConstructor =>
|
||||||
|
RustLibApiImpl.new;
|
||||||
|
|
||||||
|
@override
|
||||||
|
WireConstructor<RustLibWire> get wireConstructor =>
|
||||||
|
RustLibWire.fromExternalLibrary;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> executeRustInitializers() async {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ExternalLibraryLoaderConfig get defaultExternalLibraryLoaderConfig =>
|
||||||
|
kDefaultExternalLibraryLoaderConfig;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get codegenVersion => '2.12.0';
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get rustContentHash => -437661335;
|
||||||
|
|
||||||
|
static const kDefaultExternalLibraryLoaderConfig =
|
||||||
|
ExternalLibraryLoaderConfig(
|
||||||
|
stem: 'rust_lib_arbiter',
|
||||||
|
ioDirectory: 'rust/target/release/',
|
||||||
|
webPrefix: 'pkg/',
|
||||||
|
wasmBindgenName: 'wasm_bindgen',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class RustLibApi extends BaseApi {
|
||||||
|
Future<MldsaKey> crateApiMldsaKeyFromBytes({required List<int> bytes});
|
||||||
|
|
||||||
|
Future<MldsaKey> crateApiMldsaKeyGenerate();
|
||||||
|
|
||||||
|
Future<Uint8List> crateApiMldsaKeyGetPublicKey({required MldsaKey that});
|
||||||
|
|
||||||
|
Future<Uint8List> crateApiMldsaKeySign({
|
||||||
|
required MldsaKey that,
|
||||||
|
required List<int> message,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Uint8List> crateApiMldsaKeyToBytes({required MldsaKey that});
|
||||||
|
|
||||||
|
RustArcIncrementStrongCountFnType
|
||||||
|
get rust_arc_increment_strong_count_MldsaKey;
|
||||||
|
|
||||||
|
RustArcDecrementStrongCountFnType
|
||||||
|
get rust_arc_decrement_strong_count_MldsaKey;
|
||||||
|
|
||||||
|
CrossPlatformFinalizerArg get rust_arc_decrement_strong_count_MldsaKeyPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
|
RustLibApiImpl({
|
||||||
|
required super.handler,
|
||||||
|
required super.wire,
|
||||||
|
required super.generalizedFrbRustBinding,
|
||||||
|
required super.portManager,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MldsaKey> crateApiMldsaKeyFromBytes({required List<int> bytes}) {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||||
|
sse_encode_list_prim_u_8_loose(bytes, serializer);
|
||||||
|
pdeCallFfi(
|
||||||
|
generalizedFrbRustBinding,
|
||||||
|
serializer,
|
||||||
|
funcId: 1,
|
||||||
|
port: port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: SseCodec(
|
||||||
|
decodeSuccessData:
|
||||||
|
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey,
|
||||||
|
decodeErrorData: sse_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiMldsaKeyFromBytesConstMeta,
|
||||||
|
argValues: [bytes],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiMldsaKeyFromBytesConstMeta => const TaskConstMeta(
|
||||||
|
debugName: "MldsaKey_from_bytes",
|
||||||
|
argNames: ["bytes"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MldsaKey> crateApiMldsaKeyGenerate() {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||||
|
pdeCallFfi(
|
||||||
|
generalizedFrbRustBinding,
|
||||||
|
serializer,
|
||||||
|
funcId: 2,
|
||||||
|
port: port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: SseCodec(
|
||||||
|
decodeSuccessData:
|
||||||
|
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey,
|
||||||
|
decodeErrorData: null,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiMldsaKeyGenerateConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiMldsaKeyGenerateConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "MldsaKey_generate", argNames: []);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> crateApiMldsaKeyGetPublicKey({required MldsaKey that}) {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||||
|
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
that,
|
||||||
|
serializer,
|
||||||
|
);
|
||||||
|
pdeCallFfi(
|
||||||
|
generalizedFrbRustBinding,
|
||||||
|
serializer,
|
||||||
|
funcId: 3,
|
||||||
|
port: port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: SseCodec(
|
||||||
|
decodeSuccessData: sse_decode_list_prim_u_8_strict,
|
||||||
|
decodeErrorData: null,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiMldsaKeyGetPublicKeyConstMeta,
|
||||||
|
argValues: [that],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiMldsaKeyGetPublicKeyConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "MldsaKey_get_public_key",
|
||||||
|
argNames: ["that"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> crateApiMldsaKeySign({
|
||||||
|
required MldsaKey that,
|
||||||
|
required List<int> message,
|
||||||
|
}) {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||||
|
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
that,
|
||||||
|
serializer,
|
||||||
|
);
|
||||||
|
sse_encode_list_prim_u_8_loose(message, serializer);
|
||||||
|
pdeCallFfi(
|
||||||
|
generalizedFrbRustBinding,
|
||||||
|
serializer,
|
||||||
|
funcId: 4,
|
||||||
|
port: port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: SseCodec(
|
||||||
|
decodeSuccessData: sse_decode_list_prim_u_8_strict,
|
||||||
|
decodeErrorData: sse_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiMldsaKeySignConstMeta,
|
||||||
|
argValues: [that, message],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiMldsaKeySignConstMeta => const TaskConstMeta(
|
||||||
|
debugName: "MldsaKey_sign",
|
||||||
|
argNames: ["that", "message"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> crateApiMldsaKeyToBytes({required MldsaKey that}) {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||||
|
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
that,
|
||||||
|
serializer,
|
||||||
|
);
|
||||||
|
pdeCallFfi(
|
||||||
|
generalizedFrbRustBinding,
|
||||||
|
serializer,
|
||||||
|
funcId: 5,
|
||||||
|
port: port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: SseCodec(
|
||||||
|
decodeSuccessData: sse_decode_list_prim_u_8_strict,
|
||||||
|
decodeErrorData: null,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiMldsaKeyToBytesConstMeta,
|
||||||
|
argValues: [that],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiMldsaKeyToBytesConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "MldsaKey_to_bytes", argNames: ["that"]);
|
||||||
|
|
||||||
|
RustArcIncrementStrongCountFnType
|
||||||
|
get rust_arc_increment_strong_count_MldsaKey => wire
|
||||||
|
.rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey;
|
||||||
|
|
||||||
|
RustArcDecrementStrongCountFnType
|
||||||
|
get rust_arc_decrement_strong_count_MldsaKey => wire
|
||||||
|
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey;
|
||||||
|
|
||||||
|
@protected
|
||||||
|
AnyhowException dco_decode_AnyhowException(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return AnyhowException(raw as String);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
dynamic raw,
|
||||||
|
) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return MldsaKeyImpl.frbInternalDcoDecode(raw as List<dynamic>);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
dynamic raw,
|
||||||
|
) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return MldsaKeyImpl.frbInternalDcoDecode(raw as List<dynamic>);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
dynamic raw,
|
||||||
|
) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return MldsaKeyImpl.frbInternalDcoDecode(raw as List<dynamic>);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
String dco_decode_String(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return raw as String;
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<int> dco_decode_list_prim_u_8_loose(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return raw as List<int>;
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return raw as Uint8List;
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int dco_decode_u_8(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return raw as int;
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void dco_decode_unit(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
BigInt dco_decode_usize(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return dcoDecodeU64(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
var inner = sse_decode_String(deserializer);
|
||||||
|
return AnyhowException(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
return MldsaKeyImpl.frbInternalSseDecode(
|
||||||
|
sse_decode_usize(deserializer),
|
||||||
|
sse_decode_i_32(deserializer),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
return MldsaKeyImpl.frbInternalSseDecode(
|
||||||
|
sse_decode_usize(deserializer),
|
||||||
|
sse_decode_i_32(deserializer),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
return MldsaKeyImpl.frbInternalSseDecode(
|
||||||
|
sse_decode_usize(deserializer),
|
||||||
|
sse_decode_i_32(deserializer),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
String sse_decode_String(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
var inner = sse_decode_list_prim_u_8_strict(deserializer);
|
||||||
|
return utf8.decoder.convert(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
var len_ = sse_decode_i_32(deserializer);
|
||||||
|
return deserializer.buffer.getUint8List(len_);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
var len_ = sse_decode_i_32(deserializer);
|
||||||
|
return deserializer.buffer.getUint8List(len_);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int sse_decode_u_8(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
return deserializer.buffer.getUint8();
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_decode_unit(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
BigInt sse_decode_usize(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
return deserializer.buffer.getBigUint64();
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int sse_decode_i_32(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
return deserializer.buffer.getInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
bool sse_decode_bool(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
return deserializer.buffer.getUint8() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_AnyhowException(
|
||||||
|
AnyhowException self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_String(self.message, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void
|
||||||
|
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
MldsaKey self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_usize(
|
||||||
|
(self as MldsaKeyImpl).frbInternalSseEncode(move: true),
|
||||||
|
serializer,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void
|
||||||
|
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
MldsaKey self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_usize(
|
||||||
|
(self as MldsaKeyImpl).frbInternalSseEncode(move: false),
|
||||||
|
serializer,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void
|
||||||
|
sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
MldsaKey self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_usize(
|
||||||
|
(self as MldsaKeyImpl).frbInternalSseEncode(move: null),
|
||||||
|
serializer,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_String(String self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_list_prim_u_8_strict(utf8.encoder.convert(self), serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_prim_u_8_loose(
|
||||||
|
List<int> self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_i_32(self.length, serializer);
|
||||||
|
serializer.buffer.putUint8List(
|
||||||
|
self is Uint8List ? self : Uint8List.fromList(self),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_prim_u_8_strict(
|
||||||
|
Uint8List self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_i_32(self.length, serializer);
|
||||||
|
serializer.buffer.putUint8List(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_u_8(int self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
serializer.buffer.putUint8(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_unit(void self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_usize(BigInt self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
serializer.buffer.putBigUint64(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_i_32(int self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
serializer.buffer.putInt32(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_bool(bool self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
serializer.buffer.putUint8(self ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@sealed
|
||||||
|
class MldsaKeyImpl extends RustOpaque implements MldsaKey {
|
||||||
|
// Not to be used by end users
|
||||||
|
MldsaKeyImpl.frbInternalDcoDecode(List<dynamic> wire)
|
||||||
|
: super.frbInternalDcoDecode(wire, _kStaticData);
|
||||||
|
|
||||||
|
// Not to be used by end users
|
||||||
|
MldsaKeyImpl.frbInternalSseDecode(BigInt ptr, int externalSizeOnNative)
|
||||||
|
: super.frbInternalSseDecode(ptr, externalSizeOnNative, _kStaticData);
|
||||||
|
|
||||||
|
static final _kStaticData = RustArcStaticData(
|
||||||
|
rustArcIncrementStrongCount:
|
||||||
|
RustLib.instance.api.rust_arc_increment_strong_count_MldsaKey,
|
||||||
|
rustArcDecrementStrongCount:
|
||||||
|
RustLib.instance.api.rust_arc_decrement_strong_count_MldsaKey,
|
||||||
|
rustArcDecrementStrongCountPtr:
|
||||||
|
RustLib.instance.api.rust_arc_decrement_strong_count_MldsaKeyPtr,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<Uint8List> getPublicKey() =>
|
||||||
|
RustLib.instance.api.crateApiMldsaKeyGetPublicKey(that: this);
|
||||||
|
|
||||||
|
Future<Uint8List> sign({required List<int> message}) =>
|
||||||
|
RustLib.instance.api.crateApiMldsaKeySign(that: this, message: message);
|
||||||
|
|
||||||
|
Future<Uint8List> toBytes() =>
|
||||||
|
RustLib.instance.api.crateApiMldsaKeyToBytes(that: this);
|
||||||
|
}
|
||||||
211
useragent/lib/src/rust/frb_generated.io.dart
Normal file
211
useragent/lib/src/rust/frb_generated.io.dart
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
// This file is automatically generated, so please do not edit it.
|
||||||
|
// @generated by `flutter_rust_bridge`@ 2.12.0.
|
||||||
|
|
||||||
|
// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field
|
||||||
|
|
||||||
|
import 'api.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:ffi' as ffi;
|
||||||
|
import 'frb_generated.dart';
|
||||||
|
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart';
|
||||||
|
|
||||||
|
abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
|
RustLibApiImplPlatform({
|
||||||
|
required super.handler,
|
||||||
|
required super.wire,
|
||||||
|
required super.generalizedFrbRustBinding,
|
||||||
|
required super.portManager,
|
||||||
|
});
|
||||||
|
|
||||||
|
CrossPlatformFinalizerArg
|
||||||
|
get rust_arc_decrement_strong_count_MldsaKeyPtr => wire
|
||||||
|
._rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKeyPtr;
|
||||||
|
|
||||||
|
@protected
|
||||||
|
AnyhowException dco_decode_AnyhowException(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
dynamic raw,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
dynamic raw,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
dynamic raw,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
String dco_decode_String(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<int> dco_decode_list_prim_u_8_loose(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int dco_decode_u_8(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void dco_decode_unit(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
BigInt dco_decode_usize(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
String sse_decode_String(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int sse_decode_u_8(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_decode_unit(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
BigInt sse_decode_usize(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int sse_decode_i_32(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
bool sse_decode_bool(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_AnyhowException(
|
||||||
|
AnyhowException self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void
|
||||||
|
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
MldsaKey self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void
|
||||||
|
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
MldsaKey self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void
|
||||||
|
sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
MldsaKey self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_String(String self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_prim_u_8_loose(List<int> self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_prim_u_8_strict(
|
||||||
|
Uint8List self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_u_8(int self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_unit(void self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_usize(BigInt self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_i_32(int self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_bool(bool self, SseSerializer serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section: wire_class
|
||||||
|
|
||||||
|
class RustLibWire implements BaseWire {
|
||||||
|
factory RustLibWire.fromExternalLibrary(ExternalLibrary lib) =>
|
||||||
|
RustLibWire(lib.ffiDynamicLibrary);
|
||||||
|
|
||||||
|
/// Holds the symbol lookup function.
|
||||||
|
final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
|
||||||
|
_lookup;
|
||||||
|
|
||||||
|
/// The symbols are looked up in [dynamicLibrary].
|
||||||
|
RustLibWire(ffi.DynamicLibrary dynamicLibrary)
|
||||||
|
: _lookup = dynamicLibrary.lookup;
|
||||||
|
|
||||||
|
void
|
||||||
|
rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
ffi.Pointer<ffi.Void> ptr,
|
||||||
|
) {
|
||||||
|
return _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
ptr,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKeyPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
|
||||||
|
'frbgen_arbiter_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey',
|
||||||
|
);
|
||||||
|
late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey =
|
||||||
|
_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKeyPtr
|
||||||
|
.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
|
||||||
|
|
||||||
|
void
|
||||||
|
rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
ffi.Pointer<ffi.Void> ptr,
|
||||||
|
) {
|
||||||
|
return _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
ptr,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKeyPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
|
||||||
|
'frbgen_arbiter_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey',
|
||||||
|
);
|
||||||
|
late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey =
|
||||||
|
_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKeyPtr
|
||||||
|
.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
|
||||||
|
}
|
||||||
203
useragent/lib/src/rust/frb_generated.web.dart
Normal file
203
useragent/lib/src/rust/frb_generated.web.dart
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
// This file is automatically generated, so please do not edit it.
|
||||||
|
// @generated by `flutter_rust_bridge`@ 2.12.0.
|
||||||
|
|
||||||
|
// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field
|
||||||
|
|
||||||
|
// Static analysis wrongly picks the IO variant, thus ignore this
|
||||||
|
// ignore_for_file: argument_type_not_assignable
|
||||||
|
|
||||||
|
import 'api.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'frb_generated.dart';
|
||||||
|
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart';
|
||||||
|
|
||||||
|
abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||||
|
RustLibApiImplPlatform({
|
||||||
|
required super.handler,
|
||||||
|
required super.wire,
|
||||||
|
required super.generalizedFrbRustBinding,
|
||||||
|
required super.portManager,
|
||||||
|
});
|
||||||
|
|
||||||
|
CrossPlatformFinalizerArg
|
||||||
|
get rust_arc_decrement_strong_count_MldsaKeyPtr => wire
|
||||||
|
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey;
|
||||||
|
|
||||||
|
@protected
|
||||||
|
AnyhowException dco_decode_AnyhowException(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
dynamic raw,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
dynamic raw,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
dynamic raw,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
String dco_decode_String(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<int> dco_decode_list_prim_u_8_loose(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int dco_decode_u_8(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void dco_decode_unit(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
BigInt dco_decode_usize(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
MldsaKey
|
||||||
|
sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
String sse_decode_String(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int sse_decode_u_8(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_decode_unit(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
BigInt sse_decode_usize(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int sse_decode_i_32(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
bool sse_decode_bool(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_AnyhowException(
|
||||||
|
AnyhowException self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void
|
||||||
|
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
MldsaKey self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void
|
||||||
|
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
MldsaKey self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void
|
||||||
|
sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
MldsaKey self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_String(String self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_prim_u_8_loose(List<int> self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_prim_u_8_strict(
|
||||||
|
Uint8List self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_u_8(int self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_unit(void self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_usize(BigInt self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_i_32(int self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_bool(bool self, SseSerializer serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section: wire_class
|
||||||
|
|
||||||
|
class RustLibWire implements BaseWire {
|
||||||
|
RustLibWire.fromExternalLibrary(ExternalLibrary lib);
|
||||||
|
|
||||||
|
void
|
||||||
|
rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
int ptr,
|
||||||
|
) => wasmModule
|
||||||
|
.rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
ptr,
|
||||||
|
);
|
||||||
|
|
||||||
|
void
|
||||||
|
rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
int ptr,
|
||||||
|
) => wasmModule
|
||||||
|
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
ptr,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JS('wasm_bindgen')
|
||||||
|
external RustLibWasmModule get wasmModule;
|
||||||
|
|
||||||
|
@JS()
|
||||||
|
@anonymous
|
||||||
|
extension type RustLibWasmModule._(JSObject _) implements JSObject {
|
||||||
|
external void
|
||||||
|
rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
int ptr,
|
||||||
|
);
|
||||||
|
|
||||||
|
external void
|
||||||
|
rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
int ptr,
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -50,7 +50,9 @@ class _BottomPopupRoute extends StatelessWidget {
|
|||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
onTap: barrierDismissible ? () => Navigator.of(context).pop() : null,
|
onTap: barrierDismissible
|
||||||
|
? () => Navigator.of(context).pop()
|
||||||
|
: null,
|
||||||
child: AnimatedBuilder(
|
child: AnimatedBuilder(
|
||||||
animation: barrierAnimation,
|
animation: barrierAnimation,
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
@@ -71,8 +73,7 @@ class _BottomPopupRoute extends StatelessWidget {
|
|||||||
child: FadeTransition(
|
child: FadeTransition(
|
||||||
opacity: popupAnimation,
|
opacity: popupAnimation,
|
||||||
child: SlideTransition(
|
child: SlideTransition(
|
||||||
position:
|
position: Tween<Offset>(
|
||||||
Tween<Offset>(
|
|
||||||
begin: const Offset(0, 0.08),
|
begin: const Offset(0, 0.08),
|
||||||
end: Offset.zero,
|
end: Offset.zero,
|
||||||
).animate(popupAnimation),
|
).animate(popupAnimation),
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ PODS:
|
|||||||
- FlutterMacOS (1.0.0)
|
- FlutterMacOS (1.0.0)
|
||||||
- rive_native (0.0.1):
|
- rive_native (0.0.1):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- rust_lib_arbiter (0.0.1):
|
||||||
|
- FlutterMacOS
|
||||||
- share_plus (0.0.1):
|
- share_plus (0.0.1):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
|
||||||
@@ -18,6 +20,7 @@ DEPENDENCIES:
|
|||||||
- flutter_secure_storage_darwin (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_darwin/darwin`)
|
- flutter_secure_storage_darwin (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_darwin/darwin`)
|
||||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||||
- rive_native (from `Flutter/ephemeral/.symlinks/plugins/rive_native/macos`)
|
- rive_native (from `Flutter/ephemeral/.symlinks/plugins/rive_native/macos`)
|
||||||
|
- rust_lib_arbiter (from `Flutter/ephemeral/.symlinks/plugins/rust_lib_arbiter/macos`)
|
||||||
- share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`)
|
- share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`)
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
@@ -31,6 +34,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: Flutter/ephemeral
|
:path: Flutter/ephemeral
|
||||||
rive_native:
|
rive_native:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/rive_native/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/rive_native/macos
|
||||||
|
rust_lib_arbiter:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/rust_lib_arbiter/macos
|
||||||
share_plus:
|
share_plus:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos
|
||||||
|
|
||||||
@@ -40,6 +45,7 @@ SPEC CHECKSUMS:
|
|||||||
flutter_secure_storage_darwin: acdb3f316ed05a3e68f856e0353b133eec373a23
|
flutter_secure_storage_darwin: acdb3f316ed05a3e68f856e0353b133eec373a23
|
||||||
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
||||||
rive_native: 1c53d33e44c2b54424810effea4590671dd220c7
|
rive_native: 1c53d33e44c2b54424810effea4590671dd220c7
|
||||||
|
rust_lib_arbiter: 78dcf27cf17e741c6f4f0b12b64a40980746698a
|
||||||
share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc
|
share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc
|
||||||
|
|
||||||
PODFILE CHECKSUM: 224cb1c0d6f5312abfc2477bcb5c7f1fca2574fb
|
PODFILE CHECKSUM: 224cb1c0d6f5312abfc2477bcb5c7f1fca2574fb
|
||||||
|
|||||||
@@ -97,6 +97,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.5"
|
version: "4.0.5"
|
||||||
|
build_cli_annotations:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_cli_annotations
|
||||||
|
sha256: e563c2e01de8974566a1998410d3f6f03521788160a02503b0b1f1a46c7b3d95
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
build_config:
|
build_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -218,7 +226,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.5+2"
|
version: "0.3.5+2"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: crypto
|
name: crypto
|
||||||
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
|
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
|
||||||
@@ -226,7 +234,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.7"
|
version: "3.0.7"
|
||||||
cryptography:
|
cryptography:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: cryptography
|
name: cryptography
|
||||||
sha256: "3eda3029d34ec9095a27a198ac9785630fe525c0eb6a49f3d575272f8e792ef0"
|
sha256: "3eda3029d34ec9095a27a198ac9785630fe525c0eb6a49f3d575272f8e792ef0"
|
||||||
@@ -311,6 +319,11 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.1.1"
|
version: "9.1.1"
|
||||||
|
flutter_driver:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
flutter_form_builder:
|
flutter_form_builder:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -343,6 +356,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "3.1.0"
|
||||||
|
flutter_rust_bridge:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_rust_bridge
|
||||||
|
sha256: e87d6b9ee934dcd24a128ccb2bd91905d2d5fe5c06245d6a8f5477d4907a437a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.12.0"
|
||||||
flutter_secure_storage:
|
flutter_secure_storage:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -433,6 +454,11 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.0"
|
version: "4.0.0"
|
||||||
|
fuchsia_remote_debug_protocol:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
glob:
|
glob:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -537,6 +563,11 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.2"
|
version: "4.1.2"
|
||||||
|
integration_test:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
intl:
|
intl:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -801,6 +832,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.2"
|
version: "1.5.2"
|
||||||
|
process:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: process
|
||||||
|
sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.5"
|
||||||
protobuf:
|
protobuf:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -881,6 +920,13 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.0+1"
|
version: "4.0.0+1"
|
||||||
|
rust_lib_arbiter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: rust_builder
|
||||||
|
relative: true
|
||||||
|
source: path
|
||||||
|
version: "0.0.1"
|
||||||
share_plus:
|
share_plus:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1022,6 +1068,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.1"
|
version: "1.4.1"
|
||||||
|
sync_http:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sync_http
|
||||||
|
sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.1"
|
||||||
talker:
|
talker:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -1182,6 +1236,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.3"
|
version: "3.0.3"
|
||||||
|
webdriver:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webdriver
|
||||||
|
sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.0"
|
||||||
webkit_inspection_protocol:
|
webkit_inspection_protocol:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ dependencies:
|
|||||||
mtcore:
|
mtcore:
|
||||||
hosted: https://git.markettakers.org/api/packages/MarketTakers/pub/
|
hosted: https://git.markettakers.org/api/packages/MarketTakers/pub/
|
||||||
version: ^1.0.6
|
version: ^1.0.6
|
||||||
cryptography: ^2.9.0
|
|
||||||
crypto: ^3.0.6
|
|
||||||
flutter_secure_storage: ^10.0.0
|
flutter_secure_storage: ^10.0.0
|
||||||
cryptography_flutter: ^2.3.4
|
cryptography_flutter: ^2.3.4
|
||||||
riverpod_annotation: ^4.0.0
|
riverpod_annotation: ^4.0.0
|
||||||
@@ -35,6 +33,9 @@ dependencies:
|
|||||||
json_annotation: ^4.9.0
|
json_annotation: ^4.9.0
|
||||||
timeago: ^3.7.1
|
timeago: ^3.7.1
|
||||||
flutter_form_builder: ^10.3.0+2
|
flutter_form_builder: ^10.3.0+2
|
||||||
|
rust_lib_arbiter:
|
||||||
|
path: rust_builder
|
||||||
|
flutter_rust_bridge: 2.12.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@@ -46,6 +47,8 @@ dev_dependencies:
|
|||||||
auto_route_generator: ^10.4.0
|
auto_route_generator: ^10.4.0
|
||||||
freezed: ^3.2.3
|
freezed: ^3.2.3
|
||||||
json_serializable: ^6.11.2
|
json_serializable: ^6.11.2
|
||||||
|
integration_test:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|||||||
1
useragent/rust/.gitignore
vendored
Normal file
1
useragent/rust/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
5086
useragent/rust/Cargo.lock
generated
Normal file
5086
useragent/rust/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
17
useragent/rust/Cargo.toml
Normal file
17
useragent/rust/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "rust_lib_arbiter"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "staticlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
eframe = "0.34.1"
|
||||||
|
egui = "0.34.1"
|
||||||
|
flutter_rust_bridge = "=2.12.0"
|
||||||
|
arbiter-crypto = {path = "../../server/crates/arbiter-crypto"}
|
||||||
|
anyhow = "1.0.102"
|
||||||
|
|
||||||
|
[lints.rust]
|
||||||
|
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(frb_expand)'] }
|
||||||
29
useragent/rust/src/api/mod.rs
Normal file
29
useragent/rust/src/api/mod.rs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
use anyhow::anyhow;
|
||||||
|
use flutter_rust_bridge::frb;
|
||||||
|
use arbiter_crypto::authn::{self, USERAGENT_CONTEXT};
|
||||||
|
|
||||||
|
#[frb(opaque)]
|
||||||
|
pub struct MldsaKey(authn::SigningKey);
|
||||||
|
|
||||||
|
impl MldsaKey {
|
||||||
|
pub fn from_bytes(bytes: &[u8]) -> anyhow::Result<Self> {
|
||||||
|
let bytes: [u8; 32] = bytes.try_into().map_err(|_| anyhow!("Invalid key length"))?;
|
||||||
|
Ok(Self(authn::SigningKey::from_seed(bytes)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
self.0.to_seed().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sign(&self, message: &[u8]) -> anyhow::Result<Vec<u8>> {
|
||||||
|
Ok(self.0.sign_message(message, USERAGENT_CONTEXT)?.to_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate() -> Self {
|
||||||
|
Self(authn::SigningKey::generate())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_public_key(&self) -> Vec<u8> {
|
||||||
|
self.0.public_key().to_bytes().to_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
558
useragent/rust/src/frb_generated.rs
Normal file
558
useragent/rust/src/frb_generated.rs
Normal file
@@ -0,0 +1,558 @@
|
|||||||
|
// This file is automatically generated, so please do not edit it.
|
||||||
|
// @generated by `flutter_rust_bridge`@ 2.12.0.
|
||||||
|
|
||||||
|
#![allow(
|
||||||
|
non_camel_case_types,
|
||||||
|
unused,
|
||||||
|
non_snake_case,
|
||||||
|
clippy::needless_return,
|
||||||
|
clippy::redundant_closure_call,
|
||||||
|
clippy::redundant_closure,
|
||||||
|
clippy::useless_conversion,
|
||||||
|
clippy::unit_arg,
|
||||||
|
clippy::unused_unit,
|
||||||
|
clippy::double_parens,
|
||||||
|
clippy::let_and_return,
|
||||||
|
clippy::too_many_arguments,
|
||||||
|
clippy::match_single_binding,
|
||||||
|
clippy::clone_on_copy,
|
||||||
|
clippy::let_unit_value,
|
||||||
|
clippy::deref_addrof,
|
||||||
|
clippy::explicit_auto_deref,
|
||||||
|
clippy::borrow_deref_ref,
|
||||||
|
clippy::uninlined_format_args,
|
||||||
|
clippy::needless_borrow
|
||||||
|
)]
|
||||||
|
|
||||||
|
// Section: imports
|
||||||
|
|
||||||
|
use crate::api::*;
|
||||||
|
use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};
|
||||||
|
use flutter_rust_bridge::{Handler, IntoIntoDart};
|
||||||
|
|
||||||
|
// Section: boilerplate
|
||||||
|
|
||||||
|
flutter_rust_bridge::frb_generated_boilerplate!(
|
||||||
|
default_stream_sink_codec = SseCodec,
|
||||||
|
default_rust_opaque = RustOpaqueMoi,
|
||||||
|
default_rust_auto_opaque = RustAutoOpaqueMoi,
|
||||||
|
);
|
||||||
|
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.12.0";
|
||||||
|
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -437661335;
|
||||||
|
|
||||||
|
// Section: executor
|
||||||
|
|
||||||
|
flutter_rust_bridge::frb_generated_default_handler!();
|
||||||
|
|
||||||
|
// Section: wire_funcs
|
||||||
|
|
||||||
|
fn wire__crate__api__MldsaKey_from_bytes_impl(
|
||||||
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
|
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
||||||
|
rust_vec_len_: i32,
|
||||||
|
data_len_: i32,
|
||||||
|
) {
|
||||||
|
FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::SseCodec, _, _>(
|
||||||
|
flutter_rust_bridge::for_generated::TaskInfo {
|
||||||
|
debug_name: "MldsaKey_from_bytes",
|
||||||
|
port: Some(port_),
|
||||||
|
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
|
||||||
|
},
|
||||||
|
move || {
|
||||||
|
let message = unsafe {
|
||||||
|
flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
|
||||||
|
ptr_,
|
||||||
|
rust_vec_len_,
|
||||||
|
data_len_,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let mut deserializer =
|
||||||
|
flutter_rust_bridge::for_generated::SseDeserializer::new(message);
|
||||||
|
let api_bytes = <Vec<u8>>::sse_decode(&mut deserializer);
|
||||||
|
deserializer.end();
|
||||||
|
move |context| {
|
||||||
|
transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>(
|
||||||
|
(move || {
|
||||||
|
let output_ok = crate::api::MldsaKey::from_bytes(&api_bytes)?;
|
||||||
|
Ok(output_ok)
|
||||||
|
})(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn wire__crate__api__MldsaKey_generate_impl(
|
||||||
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
|
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
||||||
|
rust_vec_len_: i32,
|
||||||
|
data_len_: i32,
|
||||||
|
) {
|
||||||
|
FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::SseCodec, _, _>(
|
||||||
|
flutter_rust_bridge::for_generated::TaskInfo {
|
||||||
|
debug_name: "MldsaKey_generate",
|
||||||
|
port: Some(port_),
|
||||||
|
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
|
||||||
|
},
|
||||||
|
move || {
|
||||||
|
let message = unsafe {
|
||||||
|
flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
|
||||||
|
ptr_,
|
||||||
|
rust_vec_len_,
|
||||||
|
data_len_,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let mut deserializer =
|
||||||
|
flutter_rust_bridge::for_generated::SseDeserializer::new(message);
|
||||||
|
deserializer.end();
|
||||||
|
move |context| {
|
||||||
|
transform_result_sse::<_, ()>((move || {
|
||||||
|
let output_ok = Result::<_, ()>::Ok(crate::api::MldsaKey::generate())?;
|
||||||
|
Ok(output_ok)
|
||||||
|
})())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn wire__crate__api__MldsaKey_get_public_key_impl(
|
||||||
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
|
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
||||||
|
rust_vec_len_: i32,
|
||||||
|
data_len_: i32,
|
||||||
|
) {
|
||||||
|
FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::SseCodec, _, _>(
|
||||||
|
flutter_rust_bridge::for_generated::TaskInfo {
|
||||||
|
debug_name: "MldsaKey_get_public_key",
|
||||||
|
port: Some(port_),
|
||||||
|
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
|
||||||
|
},
|
||||||
|
move || {
|
||||||
|
let message = unsafe {
|
||||||
|
flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
|
||||||
|
ptr_,
|
||||||
|
rust_vec_len_,
|
||||||
|
data_len_,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let mut deserializer =
|
||||||
|
flutter_rust_bridge::for_generated::SseDeserializer::new(message);
|
||||||
|
let api_that = <RustOpaqueMoi<
|
||||||
|
flutter_rust_bridge::for_generated::RustAutoOpaqueInner<MldsaKey>,
|
||||||
|
>>::sse_decode(&mut deserializer);
|
||||||
|
deserializer.end();
|
||||||
|
move |context| {
|
||||||
|
transform_result_sse::<_, ()>((move || {
|
||||||
|
let mut api_that_guard = None;
|
||||||
|
let decode_indices_ =
|
||||||
|
flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![
|
||||||
|
flutter_rust_bridge::for_generated::LockableOrderInfo::new(
|
||||||
|
&api_that, 0, false,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
for i in decode_indices_ {
|
||||||
|
match i {
|
||||||
|
0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let api_that_guard = api_that_guard.unwrap();
|
||||||
|
let output_ok = Result::<_, ()>::Ok(crate::api::MldsaKey::get_public_key(
|
||||||
|
&*api_that_guard,
|
||||||
|
))?;
|
||||||
|
Ok(output_ok)
|
||||||
|
})())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn wire__crate__api__MldsaKey_sign_impl(
|
||||||
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
|
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
||||||
|
rust_vec_len_: i32,
|
||||||
|
data_len_: i32,
|
||||||
|
) {
|
||||||
|
FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::SseCodec, _, _>(
|
||||||
|
flutter_rust_bridge::for_generated::TaskInfo {
|
||||||
|
debug_name: "MldsaKey_sign",
|
||||||
|
port: Some(port_),
|
||||||
|
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
|
||||||
|
},
|
||||||
|
move || {
|
||||||
|
let message = unsafe {
|
||||||
|
flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
|
||||||
|
ptr_,
|
||||||
|
rust_vec_len_,
|
||||||
|
data_len_,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let mut deserializer =
|
||||||
|
flutter_rust_bridge::for_generated::SseDeserializer::new(message);
|
||||||
|
let api_that = <RustOpaqueMoi<
|
||||||
|
flutter_rust_bridge::for_generated::RustAutoOpaqueInner<MldsaKey>,
|
||||||
|
>>::sse_decode(&mut deserializer);
|
||||||
|
let api_message = <Vec<u8>>::sse_decode(&mut deserializer);
|
||||||
|
deserializer.end();
|
||||||
|
move |context| {
|
||||||
|
transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>(
|
||||||
|
(move || {
|
||||||
|
let mut api_that_guard = None;
|
||||||
|
let decode_indices_ =
|
||||||
|
flutter_rust_bridge::for_generated::lockable_compute_decode_order(
|
||||||
|
vec![flutter_rust_bridge::for_generated::LockableOrderInfo::new(
|
||||||
|
&api_that, 0, false,
|
||||||
|
)],
|
||||||
|
);
|
||||||
|
for i in decode_indices_ {
|
||||||
|
match i {
|
||||||
|
0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let api_that_guard = api_that_guard.unwrap();
|
||||||
|
let output_ok = crate::api::MldsaKey::sign(&*api_that_guard, &api_message)?;
|
||||||
|
Ok(output_ok)
|
||||||
|
})(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn wire__crate__api__MldsaKey_to_bytes_impl(
|
||||||
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
|
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
||||||
|
rust_vec_len_: i32,
|
||||||
|
data_len_: i32,
|
||||||
|
) {
|
||||||
|
FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::SseCodec, _, _>(
|
||||||
|
flutter_rust_bridge::for_generated::TaskInfo {
|
||||||
|
debug_name: "MldsaKey_to_bytes",
|
||||||
|
port: Some(port_),
|
||||||
|
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
|
||||||
|
},
|
||||||
|
move || {
|
||||||
|
let message = unsafe {
|
||||||
|
flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
|
||||||
|
ptr_,
|
||||||
|
rust_vec_len_,
|
||||||
|
data_len_,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let mut deserializer =
|
||||||
|
flutter_rust_bridge::for_generated::SseDeserializer::new(message);
|
||||||
|
let api_that = <RustOpaqueMoi<
|
||||||
|
flutter_rust_bridge::for_generated::RustAutoOpaqueInner<MldsaKey>,
|
||||||
|
>>::sse_decode(&mut deserializer);
|
||||||
|
deserializer.end();
|
||||||
|
move |context| {
|
||||||
|
transform_result_sse::<_, ()>((move || {
|
||||||
|
let mut api_that_guard = None;
|
||||||
|
let decode_indices_ =
|
||||||
|
flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![
|
||||||
|
flutter_rust_bridge::for_generated::LockableOrderInfo::new(
|
||||||
|
&api_that, 0, false,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
for i in decode_indices_ {
|
||||||
|
match i {
|
||||||
|
0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let api_that_guard = api_that_guard.unwrap();
|
||||||
|
let output_ok =
|
||||||
|
Result::<_, ()>::Ok(crate::api::MldsaKey::to_bytes(&*api_that_guard))?;
|
||||||
|
Ok(output_ok)
|
||||||
|
})())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section: related_funcs
|
||||||
|
|
||||||
|
flutter_rust_bridge::frb_generated_moi_arc_impl_value!(
|
||||||
|
flutter_rust_bridge::for_generated::RustAutoOpaqueInner<MldsaKey>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Section: dart2rust
|
||||||
|
|
||||||
|
impl SseDecode for flutter_rust_bridge::for_generated::anyhow::Error {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
|
let mut inner = <String>::sse_decode(deserializer);
|
||||||
|
return flutter_rust_bridge::for_generated::anyhow::anyhow!("{}", inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseDecode for MldsaKey {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
|
let mut inner = <RustOpaqueMoi<
|
||||||
|
flutter_rust_bridge::for_generated::RustAutoOpaqueInner<MldsaKey>,
|
||||||
|
>>::sse_decode(deserializer);
|
||||||
|
return flutter_rust_bridge::for_generated::rust_auto_opaque_decode_owned(inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseDecode
|
||||||
|
for RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<MldsaKey>>
|
||||||
|
{
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
|
let mut inner = <usize>::sse_decode(deserializer);
|
||||||
|
return decode_rust_opaque_moi(inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseDecode for String {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
|
let mut inner = <Vec<u8>>::sse_decode(deserializer);
|
||||||
|
return String::from_utf8(inner).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseDecode for Vec<u8> {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
|
let mut len_ = <i32>::sse_decode(deserializer);
|
||||||
|
let mut ans_ = Vec::with_capacity(len_ as usize);
|
||||||
|
for idx_ in 0..len_ {
|
||||||
|
ans_.push(<u8>::sse_decode(deserializer));
|
||||||
|
}
|
||||||
|
return ans_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseDecode for u8 {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
|
deserializer.cursor.read_u8().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseDecode for () {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseDecode for usize {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
|
deserializer.cursor.read_u64::<NativeEndian>().unwrap() as _
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseDecode for i32 {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
|
deserializer.cursor.read_i32::<NativeEndian>().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseDecode for bool {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
|
deserializer.cursor.read_u8().unwrap() != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pde_ffi_dispatcher_primary_impl(
|
||||||
|
func_id: i32,
|
||||||
|
port: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
|
ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
||||||
|
rust_vec_len: i32,
|
||||||
|
data_len: i32,
|
||||||
|
) {
|
||||||
|
// Codec=Pde (Serialization + dispatch), see doc to use other codecs
|
||||||
|
match func_id {
|
||||||
|
1 => wire__crate__api__MldsaKey_from_bytes_impl(port, ptr, rust_vec_len, data_len),
|
||||||
|
2 => wire__crate__api__MldsaKey_generate_impl(port, ptr, rust_vec_len, data_len),
|
||||||
|
3 => wire__crate__api__MldsaKey_get_public_key_impl(port, ptr, rust_vec_len, data_len),
|
||||||
|
4 => wire__crate__api__MldsaKey_sign_impl(port, ptr, rust_vec_len, data_len),
|
||||||
|
5 => wire__crate__api__MldsaKey_to_bytes_impl(port, ptr, rust_vec_len, data_len),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pde_ffi_dispatcher_sync_impl(
|
||||||
|
func_id: i32,
|
||||||
|
ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
||||||
|
rust_vec_len: i32,
|
||||||
|
data_len: i32,
|
||||||
|
) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse {
|
||||||
|
// Codec=Pde (Serialization + dispatch), see doc to use other codecs
|
||||||
|
match func_id {
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section: rust2dart
|
||||||
|
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
impl flutter_rust_bridge::IntoDart for FrbWrapper<MldsaKey> {
|
||||||
|
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
||||||
|
flutter_rust_bridge::for_generated::rust_auto_opaque_encode::<_, MoiArc<_>>(self.0)
|
||||||
|
.into_dart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for FrbWrapper<MldsaKey> {}
|
||||||
|
|
||||||
|
impl flutter_rust_bridge::IntoIntoDart<FrbWrapper<MldsaKey>> for MldsaKey {
|
||||||
|
fn into_into_dart(self) -> FrbWrapper<MldsaKey> {
|
||||||
|
self.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseEncode for flutter_rust_bridge::for_generated::anyhow::Error {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
|
<String>::sse_encode(format!("{:?}", self), serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseEncode for MldsaKey {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
|
<RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<MldsaKey>>>::sse_encode(flutter_rust_bridge::for_generated::rust_auto_opaque_encode::<_, MoiArc<_>>(self), serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseEncode
|
||||||
|
for RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<MldsaKey>>
|
||||||
|
{
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
|
let (ptr, size) = self.sse_encode_raw();
|
||||||
|
<usize>::sse_encode(ptr, serializer);
|
||||||
|
<i32>::sse_encode(size, serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseEncode for String {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
|
<Vec<u8>>::sse_encode(self.into_bytes(), serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseEncode for Vec<u8> {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
|
<i32>::sse_encode(self.len() as _, serializer);
|
||||||
|
for item in self {
|
||||||
|
<u8>::sse_encode(item, serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseEncode for u8 {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
|
serializer.cursor.write_u8(self).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseEncode for () {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseEncode for usize {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
|
serializer
|
||||||
|
.cursor
|
||||||
|
.write_u64::<NativeEndian>(self as _)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseEncode for i32 {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
|
serializer.cursor.write_i32::<NativeEndian>(self).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseEncode for bool {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
|
serializer.cursor.write_u8(self as _).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
mod io {
|
||||||
|
// This file is automatically generated, so please do not edit it.
|
||||||
|
// @generated by `flutter_rust_bridge`@ 2.12.0.
|
||||||
|
|
||||||
|
// Section: imports
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::api::*;
|
||||||
|
use flutter_rust_bridge::for_generated::byteorder::{
|
||||||
|
NativeEndian, ReadBytesExt, WriteBytesExt,
|
||||||
|
};
|
||||||
|
use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};
|
||||||
|
use flutter_rust_bridge::{Handler, IntoIntoDart};
|
||||||
|
|
||||||
|
// Section: boilerplate
|
||||||
|
|
||||||
|
flutter_rust_bridge::frb_generated_boilerplate_io!();
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn frbgen_arbiter_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
ptr: *const std::ffi::c_void,
|
||||||
|
) {
|
||||||
|
MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<MldsaKey>>::increment_strong_count(ptr as _);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn frbgen_arbiter_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
ptr: *const std::ffi::c_void,
|
||||||
|
) {
|
||||||
|
MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<MldsaKey>>::decrement_strong_count(ptr as _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
pub use io::*;
|
||||||
|
|
||||||
|
/// cbindgen:ignore
|
||||||
|
#[cfg(target_family = "wasm")]
|
||||||
|
mod web {
|
||||||
|
// This file is automatically generated, so please do not edit it.
|
||||||
|
// @generated by `flutter_rust_bridge`@ 2.12.0.
|
||||||
|
|
||||||
|
// Section: imports
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::api::*;
|
||||||
|
use flutter_rust_bridge::for_generated::byteorder::{
|
||||||
|
NativeEndian, ReadBytesExt, WriteBytesExt,
|
||||||
|
};
|
||||||
|
use flutter_rust_bridge::for_generated::wasm_bindgen;
|
||||||
|
use flutter_rust_bridge::for_generated::wasm_bindgen::prelude::*;
|
||||||
|
use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};
|
||||||
|
use flutter_rust_bridge::{Handler, IntoIntoDart};
|
||||||
|
|
||||||
|
// Section: boilerplate
|
||||||
|
|
||||||
|
flutter_rust_bridge::frb_generated_boilerplate_web!();
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
ptr: *const std::ffi::c_void,
|
||||||
|
) {
|
||||||
|
MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<MldsaKey>>::increment_strong_count(ptr as _);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey(
|
||||||
|
ptr: *const std::ffi::c_void,
|
||||||
|
) {
|
||||||
|
MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<MldsaKey>>::decrement_strong_count(ptr as _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(target_family = "wasm")]
|
||||||
|
pub use web::*;
|
||||||
2
useragent/rust/src/lib.rs
Normal file
2
useragent/rust/src/lib.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod api;
|
||||||
|
mod frb_generated;
|
||||||
29
useragent/rust_builder/.gitignore
vendored
Normal file
29
useragent/rust_builder/.gitignore
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
migrate_working_dir/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
|
# is commented out by default.
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||||
|
/pubspec.lock
|
||||||
|
**/doc/api/
|
||||||
|
.dart_tool/
|
||||||
|
build/
|
||||||
1
useragent/rust_builder/README.md
Normal file
1
useragent/rust_builder/README.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Please ignore this folder, which is just glue to build Rust with Flutter.
|
||||||
9
useragent/rust_builder/android/.gitignore
vendored
Normal file
9
useragent/rust_builder/android/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
*.iml
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/libraries
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
||||||
|
.cxx
|
||||||
56
useragent/rust_builder/android/build.gradle
Normal file
56
useragent/rust_builder/android/build.gradle
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// The Android Gradle Plugin builds the native code with the Android NDK.
|
||||||
|
|
||||||
|
group 'com.flutter_rust_bridge.rust_lib_arbiter'
|
||||||
|
version '1.0'
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// The Android Gradle Plugin knows how to build native code with the NDK.
|
||||||
|
classpath 'com.android.tools.build:gradle:7.3.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.android.library'
|
||||||
|
|
||||||
|
android {
|
||||||
|
if (project.android.hasProperty("namespace")) {
|
||||||
|
namespace 'com.flutter_rust_bridge.rust_lib_arbiter'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bumping the plugin compileSdkVersion requires all clients of this plugin
|
||||||
|
// to bump the version in their app.
|
||||||
|
compileSdkVersion 33
|
||||||
|
|
||||||
|
// Use the NDK version
|
||||||
|
// declared in /android/app/build.gradle file of the Flutter project.
|
||||||
|
// Replace it with a version number if this plugin requires a specfic NDK version.
|
||||||
|
// (e.g. ndkVersion "23.1.7779620")
|
||||||
|
ndkVersion android.ndkVersion
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion 19
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "../cargokit/gradle/plugin.gradle"
|
||||||
|
cargokit {
|
||||||
|
manifestDir = "../../rust"
|
||||||
|
libname = "rust_lib_arbiter"
|
||||||
|
}
|
||||||
1
useragent/rust_builder/android/settings.gradle
Normal file
1
useragent/rust_builder/android/settings.gradle
Normal file
@@ -0,0 +1 @@
|
|||||||
|
rootProject.name = 'rust_lib_arbiter'
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.flutter_rust_bridge.rust_lib_arbiter">
|
||||||
|
</manifest>
|
||||||
4
useragent/rust_builder/cargokit/.gitignore
vendored
Normal file
4
useragent/rust_builder/cargokit/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
target
|
||||||
|
.dart_tool
|
||||||
|
*.iml
|
||||||
|
!pubspec.lock
|
||||||
42
useragent/rust_builder/cargokit/LICENSE
Normal file
42
useragent/rust_builder/cargokit/LICENSE
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
Copyright 2022 Matej Knopp
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
MIT LICENSE
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||||
|
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||||
|
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
APACHE LICENSE, VERSION 2.0
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
11
useragent/rust_builder/cargokit/README
Normal file
11
useragent/rust_builder/cargokit/README
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
Experimental repository to provide glue for seamlessly integrating cargo build
|
||||||
|
with flutter plugins and packages.
|
||||||
|
|
||||||
|
See https://matejknopp.com/post/flutter_plugin_in_rust_with_no_prebuilt_binaries/
|
||||||
|
for a tutorial on how to use Cargokit.
|
||||||
|
|
||||||
|
Example plugin available at https://github.com/irondash/hello_rust_ffi_plugin.
|
||||||
|
|
||||||
58
useragent/rust_builder/cargokit/build_pod.sh
Executable file
58
useragent/rust_builder/cargokit/build_pod.sh
Executable file
@@ -0,0 +1,58 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
BASEDIR=$(dirname "$0")
|
||||||
|
|
||||||
|
# Workaround for https://github.com/dart-lang/pub/issues/4010
|
||||||
|
BASEDIR=$(cd "$BASEDIR" ; pwd -P)
|
||||||
|
|
||||||
|
# Remove XCode SDK from path. Otherwise this breaks tool compilation when building iOS project
|
||||||
|
NEW_PATH=`echo $PATH | tr ":" "\n" | grep -v "Contents/Developer/" | tr "\n" ":"`
|
||||||
|
|
||||||
|
export PATH=${NEW_PATH%?} # remove trailing :
|
||||||
|
|
||||||
|
env
|
||||||
|
|
||||||
|
# Platform name (macosx, iphoneos, iphonesimulator)
|
||||||
|
export CARGOKIT_DARWIN_PLATFORM_NAME=$PLATFORM_NAME
|
||||||
|
|
||||||
|
# Arctive architectures (arm64, armv7, x86_64), space separated.
|
||||||
|
export CARGOKIT_DARWIN_ARCHS=$ARCHS
|
||||||
|
|
||||||
|
# Current build configuration (Debug, Release)
|
||||||
|
export CARGOKIT_CONFIGURATION=$CONFIGURATION
|
||||||
|
|
||||||
|
# Path to directory containing Cargo.toml.
|
||||||
|
export CARGOKIT_MANIFEST_DIR=$PODS_TARGET_SRCROOT/$1
|
||||||
|
|
||||||
|
# Temporary directory for build artifacts.
|
||||||
|
export CARGOKIT_TARGET_TEMP_DIR=$TARGET_TEMP_DIR
|
||||||
|
|
||||||
|
# Output directory for final artifacts.
|
||||||
|
export CARGOKIT_OUTPUT_DIR=$PODS_CONFIGURATION_BUILD_DIR/$PRODUCT_NAME
|
||||||
|
|
||||||
|
# Directory to store built tool artifacts.
|
||||||
|
export CARGOKIT_TOOL_TEMP_DIR=$TARGET_TEMP_DIR/build_tool
|
||||||
|
|
||||||
|
# Directory inside root project. Not necessarily the top level directory of root project.
|
||||||
|
export CARGOKIT_ROOT_PROJECT_DIR=$SRCROOT
|
||||||
|
|
||||||
|
FLUTTER_EXPORT_BUILD_ENVIRONMENT=(
|
||||||
|
"$PODS_ROOT/../Flutter/ephemeral/flutter_export_environment.sh" # macOS
|
||||||
|
"$PODS_ROOT/../Flutter/flutter_export_environment.sh" # iOS
|
||||||
|
)
|
||||||
|
|
||||||
|
for path in "${FLUTTER_EXPORT_BUILD_ENVIRONMENT[@]}"
|
||||||
|
do
|
||||||
|
if [[ -f "$path" ]]; then
|
||||||
|
source "$path"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
sh "$BASEDIR/run_build_tool.sh" build-pod "$@"
|
||||||
|
|
||||||
|
# Make a symlink from built framework to phony file, which will be used as input to
|
||||||
|
# build script. This should force rebuild (podspec currently doesn't support alwaysOutOfDate
|
||||||
|
# attribute on custom build phase)
|
||||||
|
ln -fs "$OBJROOT/XCBuildData/build.db" "${BUILT_PRODUCTS_DIR}/cargokit_phony"
|
||||||
|
ln -fs "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}" "${BUILT_PRODUCTS_DIR}/cargokit_phony_out"
|
||||||
5
useragent/rust_builder/cargokit/build_tool/README.md
Normal file
5
useragent/rust_builder/cargokit/build_tool/README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
A sample command-line application with an entrypoint in `bin/`, library code
|
||||||
|
in `lib/`, and example unit test in `test/`.
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
# Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
# This file configures the static analysis results for your project (errors,
|
||||||
|
# warnings, and lints).
|
||||||
|
#
|
||||||
|
# This enables the 'recommended' set of lints from `package:lints`.
|
||||||
|
# This set helps identify many issues that may lead to problems when running
|
||||||
|
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
|
||||||
|
# style and format.
|
||||||
|
#
|
||||||
|
# If you want a smaller set of lints you can change this to specify
|
||||||
|
# 'package:lints/core.yaml'. These are just the most critical lints
|
||||||
|
# (the recommended set includes the core lints).
|
||||||
|
# The core lints are also what is used by pub.dev for scoring packages.
|
||||||
|
|
||||||
|
include: package:lints/recommended.yaml
|
||||||
|
|
||||||
|
# Uncomment the following section to specify additional rules.
|
||||||
|
|
||||||
|
linter:
|
||||||
|
rules:
|
||||||
|
- prefer_relative_imports
|
||||||
|
- directives_ordering
|
||||||
|
|
||||||
|
# analyzer:
|
||||||
|
# exclude:
|
||||||
|
# - path/to/excluded/files/**
|
||||||
|
|
||||||
|
# For more information about the core and recommended set of lints, see
|
||||||
|
# https://dart.dev/go/core-lints
|
||||||
|
|
||||||
|
# For additional information about configuring this file, see
|
||||||
|
# https://dart.dev/guides/language/analysis-options
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'package:build_tool/build_tool.dart' as build_tool;
|
||||||
|
|
||||||
|
void main(List<String> arguments) {
|
||||||
|
build_tool.runMain(arguments);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'src/build_tool.dart' as build_tool;
|
||||||
|
|
||||||
|
Future<void> runMain(List<String> args) async {
|
||||||
|
return build_tool.runMain(args);
|
||||||
|
}
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:isolate';
|
||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
import 'package:version/version.dart';
|
||||||
|
|
||||||
|
import 'target.dart';
|
||||||
|
import 'util.dart';
|
||||||
|
|
||||||
|
class AndroidEnvironment {
|
||||||
|
AndroidEnvironment({
|
||||||
|
required this.sdkPath,
|
||||||
|
required this.ndkVersion,
|
||||||
|
required this.minSdkVersion,
|
||||||
|
required this.targetTempDir,
|
||||||
|
required this.target,
|
||||||
|
});
|
||||||
|
|
||||||
|
static void clangLinkerWrapper(List<String> args) {
|
||||||
|
final clang = Platform.environment['_CARGOKIT_NDK_LINK_CLANG'];
|
||||||
|
if (clang == null) {
|
||||||
|
throw Exception(
|
||||||
|
"cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_CLANG env var");
|
||||||
|
}
|
||||||
|
final target = Platform.environment['_CARGOKIT_NDK_LINK_TARGET'];
|
||||||
|
if (target == null) {
|
||||||
|
throw Exception(
|
||||||
|
"cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_TARGET env var");
|
||||||
|
}
|
||||||
|
|
||||||
|
runCommand(clang, [
|
||||||
|
target,
|
||||||
|
...args,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Full path to Android SDK.
|
||||||
|
final String sdkPath;
|
||||||
|
|
||||||
|
/// Full version of Android NDK.
|
||||||
|
final String ndkVersion;
|
||||||
|
|
||||||
|
/// Minimum supported SDK version.
|
||||||
|
final int minSdkVersion;
|
||||||
|
|
||||||
|
/// Target directory for build artifacts.
|
||||||
|
final String targetTempDir;
|
||||||
|
|
||||||
|
/// Target being built.
|
||||||
|
final Target target;
|
||||||
|
|
||||||
|
bool ndkIsInstalled() {
|
||||||
|
final ndkPath = path.join(sdkPath, 'ndk', ndkVersion);
|
||||||
|
final ndkPackageXml = File(path.join(ndkPath, 'package.xml'));
|
||||||
|
return ndkPackageXml.existsSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
void installNdk({
|
||||||
|
required String javaHome,
|
||||||
|
}) {
|
||||||
|
final sdkManagerExtension = Platform.isWindows ? '.bat' : '';
|
||||||
|
final sdkManager = path.join(
|
||||||
|
sdkPath,
|
||||||
|
'cmdline-tools',
|
||||||
|
'latest',
|
||||||
|
'bin',
|
||||||
|
'sdkmanager$sdkManagerExtension',
|
||||||
|
);
|
||||||
|
|
||||||
|
log.info('Installing NDK $ndkVersion');
|
||||||
|
runCommand(sdkManager, [
|
||||||
|
'--install',
|
||||||
|
'ndk;$ndkVersion',
|
||||||
|
], environment: {
|
||||||
|
'JAVA_HOME': javaHome,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Map<String, String>> buildEnvironment() async {
|
||||||
|
final hostArch = Platform.isMacOS
|
||||||
|
? "darwin-x86_64"
|
||||||
|
: (Platform.isLinux ? "linux-x86_64" : "windows-x86_64");
|
||||||
|
|
||||||
|
final ndkPath = path.join(sdkPath, 'ndk', ndkVersion);
|
||||||
|
final toolchainPath = path.join(
|
||||||
|
ndkPath,
|
||||||
|
'toolchains',
|
||||||
|
'llvm',
|
||||||
|
'prebuilt',
|
||||||
|
hostArch,
|
||||||
|
'bin',
|
||||||
|
);
|
||||||
|
|
||||||
|
final minSdkVersion =
|
||||||
|
math.max(target.androidMinSdkVersion!, this.minSdkVersion);
|
||||||
|
|
||||||
|
final exe = Platform.isWindows ? '.exe' : '';
|
||||||
|
|
||||||
|
final arKey = 'AR_${target.rust}';
|
||||||
|
final arValue = ['${target.rust}-ar', 'llvm-ar', 'llvm-ar.exe']
|
||||||
|
.map((e) => path.join(toolchainPath, e))
|
||||||
|
.firstWhereOrNull((element) => File(element).existsSync());
|
||||||
|
if (arValue == null) {
|
||||||
|
throw Exception('Failed to find ar for $target in $toolchainPath');
|
||||||
|
}
|
||||||
|
|
||||||
|
final targetArg = '--target=${target.rust}$minSdkVersion';
|
||||||
|
|
||||||
|
final ccKey = 'CC_${target.rust}';
|
||||||
|
final ccValue = path.join(toolchainPath, 'clang$exe');
|
||||||
|
final cfFlagsKey = 'CFLAGS_${target.rust}';
|
||||||
|
final cFlagsValue = targetArg;
|
||||||
|
|
||||||
|
final cxxKey = 'CXX_${target.rust}';
|
||||||
|
final cxxValue = path.join(toolchainPath, 'clang++$exe');
|
||||||
|
final cxxFlagsKey = 'CXXFLAGS_${target.rust}';
|
||||||
|
final cxxFlagsValue = targetArg;
|
||||||
|
|
||||||
|
final linkerKey =
|
||||||
|
'cargo_target_${target.rust.replaceAll('-', '_')}_linker'.toUpperCase();
|
||||||
|
|
||||||
|
final ranlibKey = 'RANLIB_${target.rust}';
|
||||||
|
final ranlibValue = path.join(toolchainPath, 'llvm-ranlib$exe');
|
||||||
|
|
||||||
|
final ndkVersionParsed = Version.parse(ndkVersion);
|
||||||
|
final rustFlagsKey = 'CARGO_ENCODED_RUSTFLAGS';
|
||||||
|
final rustFlagsValue = _libGccWorkaround(targetTempDir, ndkVersionParsed);
|
||||||
|
|
||||||
|
final runRustTool =
|
||||||
|
Platform.isWindows ? 'run_build_tool.cmd' : 'run_build_tool.sh';
|
||||||
|
|
||||||
|
final packagePath = (await Isolate.resolvePackageUri(
|
||||||
|
Uri.parse('package:build_tool/buildtool.dart')))!
|
||||||
|
.toFilePath();
|
||||||
|
final selfPath = path.canonicalize(path.join(
|
||||||
|
packagePath,
|
||||||
|
'..',
|
||||||
|
'..',
|
||||||
|
'..',
|
||||||
|
runRustTool,
|
||||||
|
));
|
||||||
|
|
||||||
|
// Make sure that run_build_tool is working properly even initially launched directly
|
||||||
|
// through dart run.
|
||||||
|
final toolTempDir =
|
||||||
|
Platform.environment['CARGOKIT_TOOL_TEMP_DIR'] ?? targetTempDir;
|
||||||
|
|
||||||
|
return {
|
||||||
|
arKey: arValue,
|
||||||
|
ccKey: ccValue,
|
||||||
|
cfFlagsKey: cFlagsValue,
|
||||||
|
cxxKey: cxxValue,
|
||||||
|
cxxFlagsKey: cxxFlagsValue,
|
||||||
|
ranlibKey: ranlibValue,
|
||||||
|
rustFlagsKey: rustFlagsValue,
|
||||||
|
linkerKey: selfPath,
|
||||||
|
// Recognized by main() so we know when we're acting as a wrapper
|
||||||
|
'_CARGOKIT_NDK_LINK_TARGET': targetArg,
|
||||||
|
'_CARGOKIT_NDK_LINK_CLANG': ccValue,
|
||||||
|
'CARGOKIT_TOOL_TEMP_DIR': toolTempDir,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Workaround for libgcc missing in NDK23, inspired by cargo-ndk
|
||||||
|
String _libGccWorkaround(String buildDir, Version ndkVersion) {
|
||||||
|
final workaroundDir = path.join(
|
||||||
|
buildDir,
|
||||||
|
'cargokit',
|
||||||
|
'libgcc_workaround',
|
||||||
|
'${ndkVersion.major}',
|
||||||
|
);
|
||||||
|
Directory(workaroundDir).createSync(recursive: true);
|
||||||
|
if (ndkVersion.major >= 23) {
|
||||||
|
File(path.join(workaroundDir, 'libgcc.a'))
|
||||||
|
.writeAsStringSync('INPUT(-lunwind)');
|
||||||
|
} else {
|
||||||
|
// Other way around, untested, forward libgcc.a from libunwind once Rust
|
||||||
|
// gets updated for NDK23+.
|
||||||
|
File(path.join(workaroundDir, 'libunwind.a'))
|
||||||
|
.writeAsStringSync('INPUT(-lgcc)');
|
||||||
|
}
|
||||||
|
|
||||||
|
var rustFlags = Platform.environment['CARGO_ENCODED_RUSTFLAGS'] ?? '';
|
||||||
|
if (rustFlags.isNotEmpty) {
|
||||||
|
rustFlags = '$rustFlags\x1f';
|
||||||
|
}
|
||||||
|
rustFlags = '$rustFlags-L\x1f$workaroundDir';
|
||||||
|
return rustFlags;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:ed25519_edwards/ed25519_edwards.dart';
|
||||||
|
import 'package:http/http.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
|
import 'builder.dart';
|
||||||
|
import 'crate_hash.dart';
|
||||||
|
import 'options.dart';
|
||||||
|
import 'precompile_binaries.dart';
|
||||||
|
import 'rustup.dart';
|
||||||
|
import 'target.dart';
|
||||||
|
|
||||||
|
class Artifact {
|
||||||
|
/// File system location of the artifact.
|
||||||
|
final String path;
|
||||||
|
|
||||||
|
/// Actual file name that the artifact should have in destination folder.
|
||||||
|
final String finalFileName;
|
||||||
|
|
||||||
|
AritifactType get type {
|
||||||
|
if (finalFileName.endsWith('.dll') ||
|
||||||
|
finalFileName.endsWith('.dll.lib') ||
|
||||||
|
finalFileName.endsWith('.pdb') ||
|
||||||
|
finalFileName.endsWith('.so') ||
|
||||||
|
finalFileName.endsWith('.dylib')) {
|
||||||
|
return AritifactType.dylib;
|
||||||
|
} else if (finalFileName.endsWith('.lib') || finalFileName.endsWith('.a')) {
|
||||||
|
return AritifactType.staticlib;
|
||||||
|
} else {
|
||||||
|
throw Exception('Unknown artifact type for $finalFileName');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Artifact({
|
||||||
|
required this.path,
|
||||||
|
required this.finalFileName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
final _log = Logger('artifacts_provider');
|
||||||
|
|
||||||
|
class ArtifactProvider {
|
||||||
|
ArtifactProvider({
|
||||||
|
required this.environment,
|
||||||
|
required this.userOptions,
|
||||||
|
});
|
||||||
|
|
||||||
|
final BuildEnvironment environment;
|
||||||
|
final CargokitUserOptions userOptions;
|
||||||
|
|
||||||
|
Future<Map<Target, List<Artifact>>> getArtifacts(List<Target> targets) async {
|
||||||
|
final result = await _getPrecompiledArtifacts(targets);
|
||||||
|
|
||||||
|
final pendingTargets = List.of(targets);
|
||||||
|
pendingTargets.removeWhere((element) => result.containsKey(element));
|
||||||
|
|
||||||
|
if (pendingTargets.isEmpty) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
final rustup = Rustup();
|
||||||
|
for (final target in targets) {
|
||||||
|
final builder = RustBuilder(target: target, environment: environment);
|
||||||
|
builder.prepare(rustup);
|
||||||
|
_log.info('Building ${environment.crateInfo.packageName} for $target');
|
||||||
|
final targetDir = await builder.build();
|
||||||
|
// For local build accept both static and dynamic libraries.
|
||||||
|
final artifactNames = <String>{
|
||||||
|
...getArtifactNames(
|
||||||
|
target: target,
|
||||||
|
libraryName: environment.crateInfo.packageName,
|
||||||
|
aritifactType: AritifactType.dylib,
|
||||||
|
remote: false,
|
||||||
|
),
|
||||||
|
...getArtifactNames(
|
||||||
|
target: target,
|
||||||
|
libraryName: environment.crateInfo.packageName,
|
||||||
|
aritifactType: AritifactType.staticlib,
|
||||||
|
remote: false,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
final artifacts = artifactNames
|
||||||
|
.map((artifactName) => Artifact(
|
||||||
|
path: path.join(targetDir, artifactName),
|
||||||
|
finalFileName: artifactName,
|
||||||
|
))
|
||||||
|
.where((element) => File(element.path).existsSync())
|
||||||
|
.toList();
|
||||||
|
result[target] = artifacts;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Map<Target, List<Artifact>>> _getPrecompiledArtifacts(
|
||||||
|
List<Target> targets) async {
|
||||||
|
if (userOptions.usePrecompiledBinaries == false) {
|
||||||
|
_log.info('Precompiled binaries are disabled');
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (environment.crateOptions.precompiledBinaries == null) {
|
||||||
|
_log.fine('Precompiled binaries not enabled for this crate');
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
final start = Stopwatch()..start();
|
||||||
|
final crateHash = CrateHash.compute(environment.manifestDir,
|
||||||
|
tempStorage: environment.targetTempDir);
|
||||||
|
_log.fine(
|
||||||
|
'Computed crate hash $crateHash in ${start.elapsedMilliseconds}ms');
|
||||||
|
|
||||||
|
final downloadedArtifactsDir =
|
||||||
|
path.join(environment.targetTempDir, 'precompiled', crateHash);
|
||||||
|
Directory(downloadedArtifactsDir).createSync(recursive: true);
|
||||||
|
|
||||||
|
final res = <Target, List<Artifact>>{};
|
||||||
|
|
||||||
|
for (final target in targets) {
|
||||||
|
final requiredArtifacts = getArtifactNames(
|
||||||
|
target: target,
|
||||||
|
libraryName: environment.crateInfo.packageName,
|
||||||
|
remote: true,
|
||||||
|
);
|
||||||
|
final artifactsForTarget = <Artifact>[];
|
||||||
|
|
||||||
|
for (final artifact in requiredArtifacts) {
|
||||||
|
final fileName = PrecompileBinaries.fileName(target, artifact);
|
||||||
|
final downloadedPath = path.join(downloadedArtifactsDir, fileName);
|
||||||
|
if (!File(downloadedPath).existsSync()) {
|
||||||
|
final signatureFileName =
|
||||||
|
PrecompileBinaries.signatureFileName(target, artifact);
|
||||||
|
await _tryDownloadArtifacts(
|
||||||
|
crateHash: crateHash,
|
||||||
|
fileName: fileName,
|
||||||
|
signatureFileName: signatureFileName,
|
||||||
|
finalPath: downloadedPath,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (File(downloadedPath).existsSync()) {
|
||||||
|
artifactsForTarget.add(Artifact(
|
||||||
|
path: downloadedPath,
|
||||||
|
finalFileName: artifact,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only provide complete set of artifacts.
|
||||||
|
if (artifactsForTarget.length == requiredArtifacts.length) {
|
||||||
|
_log.fine('Found precompiled artifacts for $target');
|
||||||
|
res[target] = artifactsForTarget;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<Response> _get(Uri url, {Map<String, String>? headers}) async {
|
||||||
|
int attempt = 0;
|
||||||
|
const maxAttempts = 10;
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
return await get(url, headers: headers);
|
||||||
|
} on SocketException catch (e) {
|
||||||
|
// Try to detect reset by peer error and retry.
|
||||||
|
if (attempt++ < maxAttempts &&
|
||||||
|
(e.osError?.errorCode == 54 || e.osError?.errorCode == 10054)) {
|
||||||
|
_log.severe(
|
||||||
|
'Failed to download $url: $e, attempt $attempt of $maxAttempts, will retry...');
|
||||||
|
await Future.delayed(Duration(seconds: 1));
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _tryDownloadArtifacts({
|
||||||
|
required String crateHash,
|
||||||
|
required String fileName,
|
||||||
|
required String signatureFileName,
|
||||||
|
required String finalPath,
|
||||||
|
}) async {
|
||||||
|
final precompiledBinaries = environment.crateOptions.precompiledBinaries!;
|
||||||
|
final prefix = precompiledBinaries.uriPrefix;
|
||||||
|
final url = Uri.parse('$prefix$crateHash/$fileName');
|
||||||
|
final signatureUrl = Uri.parse('$prefix$crateHash/$signatureFileName');
|
||||||
|
_log.fine('Downloading signature from $signatureUrl');
|
||||||
|
final signature = await _get(signatureUrl);
|
||||||
|
if (signature.statusCode == 404) {
|
||||||
|
_log.warning(
|
||||||
|
'Precompiled binaries not available for crate hash $crateHash ($fileName)');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (signature.statusCode != 200) {
|
||||||
|
_log.severe(
|
||||||
|
'Failed to download signature $signatureUrl: status ${signature.statusCode}');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_log.fine('Downloading binary from $url');
|
||||||
|
final res = await _get(url);
|
||||||
|
if (res.statusCode != 200) {
|
||||||
|
_log.severe('Failed to download binary $url: status ${res.statusCode}');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (verify(
|
||||||
|
precompiledBinaries.publicKey, res.bodyBytes, signature.bodyBytes)) {
|
||||||
|
File(finalPath).writeAsBytesSync(res.bodyBytes);
|
||||||
|
} else {
|
||||||
|
_log.shout('Signature verification failed! Ignoring binary.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AritifactType {
|
||||||
|
staticlib,
|
||||||
|
dylib,
|
||||||
|
}
|
||||||
|
|
||||||
|
AritifactType artifactTypeForTarget(Target target) {
|
||||||
|
if (target.darwinPlatform != null) {
|
||||||
|
return AritifactType.staticlib;
|
||||||
|
} else {
|
||||||
|
return AritifactType.dylib;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> getArtifactNames({
|
||||||
|
required Target target,
|
||||||
|
required String libraryName,
|
||||||
|
required bool remote,
|
||||||
|
AritifactType? aritifactType,
|
||||||
|
}) {
|
||||||
|
aritifactType ??= artifactTypeForTarget(target);
|
||||||
|
if (target.darwinArch != null) {
|
||||||
|
if (aritifactType == AritifactType.staticlib) {
|
||||||
|
return ['lib$libraryName.a'];
|
||||||
|
} else {
|
||||||
|
return ['lib$libraryName.dylib'];
|
||||||
|
}
|
||||||
|
} else if (target.rust.contains('-windows-')) {
|
||||||
|
if (aritifactType == AritifactType.staticlib) {
|
||||||
|
return ['$libraryName.lib'];
|
||||||
|
} else {
|
||||||
|
return [
|
||||||
|
'$libraryName.dll',
|
||||||
|
'$libraryName.dll.lib',
|
||||||
|
if (!remote) '$libraryName.pdb'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} else if (target.rust.contains('-linux-')) {
|
||||||
|
if (aritifactType == AritifactType.staticlib) {
|
||||||
|
return ['lib$libraryName.a'];
|
||||||
|
} else {
|
||||||
|
return ['lib$libraryName.so'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception("Unsupported target: ${target.rust}");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
|
import 'artifacts_provider.dart';
|
||||||
|
import 'builder.dart';
|
||||||
|
import 'environment.dart';
|
||||||
|
import 'options.dart';
|
||||||
|
import 'target.dart';
|
||||||
|
|
||||||
|
class BuildCMake {
|
||||||
|
final CargokitUserOptions userOptions;
|
||||||
|
|
||||||
|
BuildCMake({required this.userOptions});
|
||||||
|
|
||||||
|
Future<void> build() async {
|
||||||
|
final targetPlatform = Environment.targetPlatform;
|
||||||
|
final target = Target.forFlutterName(Environment.targetPlatform);
|
||||||
|
if (target == null) {
|
||||||
|
throw Exception("Unknown target platform: $targetPlatform");
|
||||||
|
}
|
||||||
|
|
||||||
|
final environment = BuildEnvironment.fromEnvironment(isAndroid: false);
|
||||||
|
final provider =
|
||||||
|
ArtifactProvider(environment: environment, userOptions: userOptions);
|
||||||
|
final artifacts = await provider.getArtifacts([target]);
|
||||||
|
|
||||||
|
final libs = artifacts[target]!;
|
||||||
|
|
||||||
|
for (final lib in libs) {
|
||||||
|
if (lib.type == AritifactType.dylib) {
|
||||||
|
File(lib.path)
|
||||||
|
.copySync(path.join(Environment.outputDir, lib.finalFileName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
|
import 'artifacts_provider.dart';
|
||||||
|
import 'builder.dart';
|
||||||
|
import 'environment.dart';
|
||||||
|
import 'options.dart';
|
||||||
|
import 'target.dart';
|
||||||
|
|
||||||
|
final log = Logger('build_gradle');
|
||||||
|
|
||||||
|
class BuildGradle {
|
||||||
|
BuildGradle({required this.userOptions});
|
||||||
|
|
||||||
|
final CargokitUserOptions userOptions;
|
||||||
|
|
||||||
|
Future<void> build() async {
|
||||||
|
final targets = Environment.targetPlatforms.map((arch) {
|
||||||
|
final target = Target.forFlutterName(arch);
|
||||||
|
if (target == null) {
|
||||||
|
throw Exception(
|
||||||
|
"Unknown darwin target or platform: $arch, ${Environment.darwinPlatformName}");
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
final environment = BuildEnvironment.fromEnvironment(isAndroid: true);
|
||||||
|
final provider =
|
||||||
|
ArtifactProvider(environment: environment, userOptions: userOptions);
|
||||||
|
final artifacts = await provider.getArtifacts(targets);
|
||||||
|
|
||||||
|
for (final target in targets) {
|
||||||
|
final libs = artifacts[target]!;
|
||||||
|
final outputDir = path.join(Environment.outputDir, target.android!);
|
||||||
|
Directory(outputDir).createSync(recursive: true);
|
||||||
|
|
||||||
|
for (final lib in libs) {
|
||||||
|
if (lib.type == AritifactType.dylib) {
|
||||||
|
File(lib.path).copySync(path.join(outputDir, lib.finalFileName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
|
import 'artifacts_provider.dart';
|
||||||
|
import 'builder.dart';
|
||||||
|
import 'environment.dart';
|
||||||
|
import 'options.dart';
|
||||||
|
import 'target.dart';
|
||||||
|
import 'util.dart';
|
||||||
|
|
||||||
|
class BuildPod {
|
||||||
|
BuildPod({required this.userOptions});
|
||||||
|
|
||||||
|
final CargokitUserOptions userOptions;
|
||||||
|
|
||||||
|
Future<void> build() async {
|
||||||
|
final targets = Environment.darwinArchs.map((arch) {
|
||||||
|
final target = Target.forDarwin(
|
||||||
|
platformName: Environment.darwinPlatformName, darwinAarch: arch);
|
||||||
|
if (target == null) {
|
||||||
|
throw Exception(
|
||||||
|
"Unknown darwin target or platform: $arch, ${Environment.darwinPlatformName}");
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
final environment = BuildEnvironment.fromEnvironment(isAndroid: false);
|
||||||
|
final provider =
|
||||||
|
ArtifactProvider(environment: environment, userOptions: userOptions);
|
||||||
|
final artifacts = await provider.getArtifacts(targets);
|
||||||
|
|
||||||
|
void performLipo(String targetFile, Iterable<String> sourceFiles) {
|
||||||
|
runCommand("lipo", [
|
||||||
|
'-create',
|
||||||
|
...sourceFiles,
|
||||||
|
'-output',
|
||||||
|
targetFile,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
final outputDir = Environment.outputDir;
|
||||||
|
|
||||||
|
Directory(outputDir).createSync(recursive: true);
|
||||||
|
|
||||||
|
final staticLibs = artifacts.values
|
||||||
|
.expand((element) => element)
|
||||||
|
.where((element) => element.type == AritifactType.staticlib)
|
||||||
|
.toList();
|
||||||
|
final dynamicLibs = artifacts.values
|
||||||
|
.expand((element) => element)
|
||||||
|
.where((element) => element.type == AritifactType.dylib)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
final libName = environment.crateInfo.packageName;
|
||||||
|
|
||||||
|
// If there is static lib, use it and link it with pod
|
||||||
|
if (staticLibs.isNotEmpty) {
|
||||||
|
final finalTargetFile = path.join(outputDir, "lib$libName.a");
|
||||||
|
performLipo(finalTargetFile, staticLibs.map((e) => e.path));
|
||||||
|
} else {
|
||||||
|
// Otherwise try to replace bundle dylib with our dylib
|
||||||
|
final bundlePaths = [
|
||||||
|
'$libName.framework/Versions/A/$libName',
|
||||||
|
'$libName.framework/$libName',
|
||||||
|
];
|
||||||
|
|
||||||
|
for (final bundlePath in bundlePaths) {
|
||||||
|
final targetFile = path.join(outputDir, bundlePath);
|
||||||
|
if (File(targetFile).existsSync()) {
|
||||||
|
performLipo(targetFile, dynamicLibs.map((e) => e.path));
|
||||||
|
|
||||||
|
// Replace absolute id with @rpath one so that it works properly
|
||||||
|
// when moved to Frameworks.
|
||||||
|
runCommand("install_name_tool", [
|
||||||
|
'-id',
|
||||||
|
'@rpath/$bundlePath',
|
||||||
|
targetFile,
|
||||||
|
]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw Exception('Unable to find bundle for dynamic library');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,276 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:args/command_runner.dart';
|
||||||
|
import 'package:ed25519_edwards/ed25519_edwards.dart';
|
||||||
|
import 'package:github/github.dart';
|
||||||
|
import 'package:hex/hex.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
|
import 'android_environment.dart';
|
||||||
|
import 'build_cmake.dart';
|
||||||
|
import 'build_gradle.dart';
|
||||||
|
import 'build_pod.dart';
|
||||||
|
import 'logging.dart';
|
||||||
|
import 'options.dart';
|
||||||
|
import 'precompile_binaries.dart';
|
||||||
|
import 'target.dart';
|
||||||
|
import 'util.dart';
|
||||||
|
import 'verify_binaries.dart';
|
||||||
|
|
||||||
|
final log = Logger('build_tool');
|
||||||
|
|
||||||
|
abstract class BuildCommand extends Command {
|
||||||
|
Future<void> runBuildCommand(CargokitUserOptions options);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> run() async {
|
||||||
|
final options = CargokitUserOptions.load();
|
||||||
|
|
||||||
|
if (options.verboseLogging ||
|
||||||
|
Platform.environment['CARGOKIT_VERBOSE'] == '1') {
|
||||||
|
enableVerboseLogging();
|
||||||
|
}
|
||||||
|
|
||||||
|
await runBuildCommand(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BuildPodCommand extends BuildCommand {
|
||||||
|
@override
|
||||||
|
final name = 'build-pod';
|
||||||
|
|
||||||
|
@override
|
||||||
|
final description = 'Build cocoa pod library';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> runBuildCommand(CargokitUserOptions options) async {
|
||||||
|
final build = BuildPod(userOptions: options);
|
||||||
|
await build.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BuildGradleCommand extends BuildCommand {
|
||||||
|
@override
|
||||||
|
final name = 'build-gradle';
|
||||||
|
|
||||||
|
@override
|
||||||
|
final description = 'Build android library';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> runBuildCommand(CargokitUserOptions options) async {
|
||||||
|
final build = BuildGradle(userOptions: options);
|
||||||
|
await build.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BuildCMakeCommand extends BuildCommand {
|
||||||
|
@override
|
||||||
|
final name = 'build-cmake';
|
||||||
|
|
||||||
|
@override
|
||||||
|
final description = 'Build CMake library';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> runBuildCommand(CargokitUserOptions options) async {
|
||||||
|
final build = BuildCMake(userOptions: options);
|
||||||
|
await build.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GenKeyCommand extends Command {
|
||||||
|
@override
|
||||||
|
final name = 'gen-key';
|
||||||
|
|
||||||
|
@override
|
||||||
|
final description = 'Generate key pair for signing precompiled binaries';
|
||||||
|
|
||||||
|
@override
|
||||||
|
void run() {
|
||||||
|
final kp = generateKey();
|
||||||
|
final private = HEX.encode(kp.privateKey.bytes);
|
||||||
|
final public = HEX.encode(kp.publicKey.bytes);
|
||||||
|
print("Private Key: $private");
|
||||||
|
print("Public Key: $public");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrecompileBinariesCommand extends Command {
|
||||||
|
PrecompileBinariesCommand() {
|
||||||
|
argParser
|
||||||
|
..addOption(
|
||||||
|
'repository',
|
||||||
|
mandatory: true,
|
||||||
|
help: 'Github repository slug in format owner/name',
|
||||||
|
)
|
||||||
|
..addOption(
|
||||||
|
'manifest-dir',
|
||||||
|
mandatory: true,
|
||||||
|
help: 'Directory containing Cargo.toml',
|
||||||
|
)
|
||||||
|
..addMultiOption('target',
|
||||||
|
help: 'Rust target triple of artifact to build.\n'
|
||||||
|
'Can be specified multiple times or omitted in which case\n'
|
||||||
|
'all targets for current platform will be built.')
|
||||||
|
..addOption(
|
||||||
|
'android-sdk-location',
|
||||||
|
help: 'Location of Android SDK (if available)',
|
||||||
|
)
|
||||||
|
..addOption(
|
||||||
|
'android-ndk-version',
|
||||||
|
help: 'Android NDK version (if available)',
|
||||||
|
)
|
||||||
|
..addOption(
|
||||||
|
'android-min-sdk-version',
|
||||||
|
help: 'Android minimum rquired version (if available)',
|
||||||
|
)
|
||||||
|
..addOption(
|
||||||
|
'temp-dir',
|
||||||
|
help: 'Directory to store temporary build artifacts',
|
||||||
|
)
|
||||||
|
..addOption(
|
||||||
|
'glibc-version',
|
||||||
|
help: 'GLIBC version to use for linux builds',
|
||||||
|
)
|
||||||
|
..addFlag(
|
||||||
|
"verbose",
|
||||||
|
abbr: "v",
|
||||||
|
defaultsTo: false,
|
||||||
|
help: "Enable verbose logging",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
final name = 'precompile-binaries';
|
||||||
|
|
||||||
|
@override
|
||||||
|
final description = 'Prebuild and upload binaries\n'
|
||||||
|
'Private key must be passed through PRIVATE_KEY environment variable. '
|
||||||
|
'Use gen_key through generate priave key.\n'
|
||||||
|
'Github token must be passed as GITHUB_TOKEN environment variable.\n';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> run() async {
|
||||||
|
final verbose = argResults!['verbose'] as bool;
|
||||||
|
if (verbose) {
|
||||||
|
enableVerboseLogging();
|
||||||
|
}
|
||||||
|
|
||||||
|
final privateKeyString = Platform.environment['PRIVATE_KEY'];
|
||||||
|
if (privateKeyString == null) {
|
||||||
|
throw ArgumentError('Missing PRIVATE_KEY environment variable');
|
||||||
|
}
|
||||||
|
final githubToken = Platform.environment['GITHUB_TOKEN'];
|
||||||
|
if (githubToken == null) {
|
||||||
|
throw ArgumentError('Missing GITHUB_TOKEN environment variable');
|
||||||
|
}
|
||||||
|
final privateKey = HEX.decode(privateKeyString);
|
||||||
|
if (privateKey.length != 64) {
|
||||||
|
throw ArgumentError('Private key must be 64 bytes long');
|
||||||
|
}
|
||||||
|
final manifestDir = argResults!['manifest-dir'] as String;
|
||||||
|
if (!Directory(manifestDir).existsSync()) {
|
||||||
|
throw ArgumentError('Manifest directory does not exist: $manifestDir');
|
||||||
|
}
|
||||||
|
String? androidMinSdkVersionString =
|
||||||
|
argResults!['android-min-sdk-version'] as String?;
|
||||||
|
int? androidMinSdkVersion;
|
||||||
|
if (androidMinSdkVersionString != null) {
|
||||||
|
androidMinSdkVersion = int.tryParse(androidMinSdkVersionString);
|
||||||
|
if (androidMinSdkVersion == null) {
|
||||||
|
throw ArgumentError(
|
||||||
|
'Invalid android-min-sdk-version: $androidMinSdkVersionString');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final targetStrigns = argResults!['target'] as List<String>;
|
||||||
|
final targets = targetStrigns.map((target) {
|
||||||
|
final res = Target.forRustTriple(target);
|
||||||
|
if (res == null) {
|
||||||
|
throw ArgumentError('Invalid target: $target');
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}).toList(growable: false);
|
||||||
|
final precompileBinaries = PrecompileBinaries(
|
||||||
|
privateKey: PrivateKey(privateKey),
|
||||||
|
githubToken: githubToken,
|
||||||
|
manifestDir: manifestDir,
|
||||||
|
repositorySlug: RepositorySlug.full(argResults!['repository'] as String),
|
||||||
|
targets: targets,
|
||||||
|
androidSdkLocation: argResults!['android-sdk-location'] as String?,
|
||||||
|
androidNdkVersion: argResults!['android-ndk-version'] as String?,
|
||||||
|
androidMinSdkVersion: androidMinSdkVersion,
|
||||||
|
tempDir: argResults!['temp-dir'] as String?,
|
||||||
|
glibcVersion: argResults!['glibc-version'] as String?,
|
||||||
|
);
|
||||||
|
|
||||||
|
await precompileBinaries.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VerifyBinariesCommand extends Command {
|
||||||
|
VerifyBinariesCommand() {
|
||||||
|
argParser.addOption(
|
||||||
|
'manifest-dir',
|
||||||
|
mandatory: true,
|
||||||
|
help: 'Directory containing Cargo.toml',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
final name = "verify-binaries";
|
||||||
|
|
||||||
|
@override
|
||||||
|
final description = 'Verifies published binaries\n'
|
||||||
|
'Checks whether there is a binary published for each targets\n'
|
||||||
|
'and checks the signature.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> run() async {
|
||||||
|
final manifestDir = argResults!['manifest-dir'] as String;
|
||||||
|
final verifyBinaries = VerifyBinaries(
|
||||||
|
manifestDir: manifestDir,
|
||||||
|
);
|
||||||
|
await verifyBinaries.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> runMain(List<String> args) async {
|
||||||
|
try {
|
||||||
|
// Init logging before options are loaded
|
||||||
|
initLogging();
|
||||||
|
|
||||||
|
if (Platform.environment['_CARGOKIT_NDK_LINK_TARGET'] != null) {
|
||||||
|
return AndroidEnvironment.clangLinkerWrapper(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
final runner = CommandRunner('build_tool', 'Cargokit built_tool')
|
||||||
|
..addCommand(BuildPodCommand())
|
||||||
|
..addCommand(BuildGradleCommand())
|
||||||
|
..addCommand(BuildCMakeCommand())
|
||||||
|
..addCommand(GenKeyCommand())
|
||||||
|
..addCommand(PrecompileBinariesCommand())
|
||||||
|
..addCommand(VerifyBinariesCommand());
|
||||||
|
|
||||||
|
await runner.run(args);
|
||||||
|
} on ArgumentError catch (e) {
|
||||||
|
stderr.writeln(e.toString());
|
||||||
|
exit(1);
|
||||||
|
} catch (e, s) {
|
||||||
|
log.severe(kDoubleSeparator);
|
||||||
|
log.severe('Cargokit BuildTool failed with error:');
|
||||||
|
log.severe(kSeparator);
|
||||||
|
log.severe(e);
|
||||||
|
// This tells user to install Rust, there's no need to pollute the log with
|
||||||
|
// stack trace.
|
||||||
|
if (e is! RustupNotFoundException) {
|
||||||
|
log.severe(kSeparator);
|
||||||
|
log.severe(s);
|
||||||
|
log.severe(kSeparator);
|
||||||
|
log.severe('BuildTool arguments: $args');
|
||||||
|
}
|
||||||
|
log.severe(kDoubleSeparator);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
209
useragent/rust_builder/cargokit/build_tool/lib/src/builder.dart
Normal file
209
useragent/rust_builder/cargokit/build_tool/lib/src/builder.dart
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
|
import 'android_environment.dart';
|
||||||
|
import 'cargo.dart';
|
||||||
|
import 'environment.dart';
|
||||||
|
import 'options.dart';
|
||||||
|
import 'rustup.dart';
|
||||||
|
import 'target.dart';
|
||||||
|
import 'util.dart';
|
||||||
|
|
||||||
|
final _log = Logger('builder');
|
||||||
|
|
||||||
|
enum BuildConfiguration {
|
||||||
|
debug,
|
||||||
|
release,
|
||||||
|
profile,
|
||||||
|
}
|
||||||
|
|
||||||
|
extension on BuildConfiguration {
|
||||||
|
bool get isDebug => this == BuildConfiguration.debug;
|
||||||
|
String get rustName => switch (this) {
|
||||||
|
BuildConfiguration.debug => 'debug',
|
||||||
|
BuildConfiguration.release => 'release',
|
||||||
|
BuildConfiguration.profile => 'release',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class BuildException implements Exception {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
BuildException(this.message);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'BuildException: $message';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BuildEnvironment {
|
||||||
|
final BuildConfiguration configuration;
|
||||||
|
final CargokitCrateOptions crateOptions;
|
||||||
|
final String targetTempDir;
|
||||||
|
final String manifestDir;
|
||||||
|
final CrateInfo crateInfo;
|
||||||
|
|
||||||
|
final bool isAndroid;
|
||||||
|
final String? androidSdkPath;
|
||||||
|
final String? androidNdkVersion;
|
||||||
|
final int? androidMinSdkVersion;
|
||||||
|
final String? javaHome;
|
||||||
|
|
||||||
|
final String? glibcVersion;
|
||||||
|
|
||||||
|
BuildEnvironment({
|
||||||
|
required this.configuration,
|
||||||
|
required this.crateOptions,
|
||||||
|
required this.targetTempDir,
|
||||||
|
required this.manifestDir,
|
||||||
|
required this.crateInfo,
|
||||||
|
required this.isAndroid,
|
||||||
|
this.androidSdkPath,
|
||||||
|
this.androidNdkVersion,
|
||||||
|
this.androidMinSdkVersion,
|
||||||
|
this.javaHome,
|
||||||
|
this.glibcVersion,
|
||||||
|
});
|
||||||
|
|
||||||
|
static BuildConfiguration parseBuildConfiguration(String value) {
|
||||||
|
// XCode configuration adds the flavor to configuration name.
|
||||||
|
final firstSegment = value.split('-').first;
|
||||||
|
final buildConfiguration = BuildConfiguration.values.firstWhereOrNull(
|
||||||
|
(e) => e.name == firstSegment,
|
||||||
|
);
|
||||||
|
if (buildConfiguration == null) {
|
||||||
|
_log.warning('Unknown build configuraiton $value, will assume release');
|
||||||
|
return BuildConfiguration.release;
|
||||||
|
}
|
||||||
|
return buildConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BuildEnvironment fromEnvironment({
|
||||||
|
required bool isAndroid,
|
||||||
|
}) {
|
||||||
|
final buildConfiguration =
|
||||||
|
parseBuildConfiguration(Environment.configuration);
|
||||||
|
final manifestDir = Environment.manifestDir;
|
||||||
|
final crateOptions = CargokitCrateOptions.load(
|
||||||
|
manifestDir: manifestDir,
|
||||||
|
);
|
||||||
|
final crateInfo = CrateInfo.load(manifestDir);
|
||||||
|
return BuildEnvironment(
|
||||||
|
configuration: buildConfiguration,
|
||||||
|
crateOptions: crateOptions,
|
||||||
|
targetTempDir: Environment.targetTempDir,
|
||||||
|
manifestDir: manifestDir,
|
||||||
|
crateInfo: crateInfo,
|
||||||
|
isAndroid: isAndroid,
|
||||||
|
androidSdkPath: isAndroid ? Environment.sdkPath : null,
|
||||||
|
androidNdkVersion: isAndroid ? Environment.ndkVersion : null,
|
||||||
|
androidMinSdkVersion:
|
||||||
|
isAndroid ? int.parse(Environment.minSdkVersion) : null,
|
||||||
|
javaHome: isAndroid ? Environment.javaHome : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RustBuilder {
|
||||||
|
final Target target;
|
||||||
|
final BuildEnvironment environment;
|
||||||
|
|
||||||
|
RustBuilder({
|
||||||
|
required this.target,
|
||||||
|
required this.environment,
|
||||||
|
});
|
||||||
|
|
||||||
|
void prepare(
|
||||||
|
Rustup rustup,
|
||||||
|
) {
|
||||||
|
final toolchain = _toolchain;
|
||||||
|
if (rustup.installedTargets(toolchain) == null) {
|
||||||
|
rustup.installToolchain(toolchain);
|
||||||
|
}
|
||||||
|
if (toolchain == 'nightly') {
|
||||||
|
rustup.installRustSrcForNightly();
|
||||||
|
}
|
||||||
|
if (!rustup.installedTargets(toolchain)!.contains(target.rust)) {
|
||||||
|
rustup.installTarget(target.rust, toolchain: toolchain);
|
||||||
|
}
|
||||||
|
if (environment.glibcVersion != null) {
|
||||||
|
rustup.installZigBuild(toolchain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CargoBuildOptions? get _buildOptions =>
|
||||||
|
environment.crateOptions.cargo[environment.configuration];
|
||||||
|
|
||||||
|
String get _toolchain => _buildOptions?.toolchain.name ?? 'stable';
|
||||||
|
|
||||||
|
/// Returns the path of directory containing build artifacts.
|
||||||
|
Future<String> build() async {
|
||||||
|
final extraArgs = _buildOptions?.flags ?? [];
|
||||||
|
final manifestPath = path.join(environment.manifestDir, 'Cargo.toml');
|
||||||
|
runCommand(
|
||||||
|
'rustup',
|
||||||
|
[
|
||||||
|
'run',
|
||||||
|
_toolchain,
|
||||||
|
'cargo',
|
||||||
|
(target.android == null && environment.glibcVersion != null)
|
||||||
|
? 'zigbuild'
|
||||||
|
: 'build',
|
||||||
|
...extraArgs,
|
||||||
|
'--manifest-path',
|
||||||
|
manifestPath,
|
||||||
|
'-p',
|
||||||
|
environment.crateInfo.packageName,
|
||||||
|
if (!environment.configuration.isDebug) '--release',
|
||||||
|
'--target',
|
||||||
|
target.rust +
|
||||||
|
((target.android == null && environment.glibcVersion != null)
|
||||||
|
? '.${environment.glibcVersion!}'
|
||||||
|
: ""),
|
||||||
|
'--target-dir',
|
||||||
|
environment.targetTempDir,
|
||||||
|
],
|
||||||
|
environment: await _buildEnvironment(),
|
||||||
|
);
|
||||||
|
return path.join(
|
||||||
|
environment.targetTempDir,
|
||||||
|
target.rust,
|
||||||
|
environment.configuration.rustName,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Map<String, String>> _buildEnvironment() async {
|
||||||
|
if (target.android == null) {
|
||||||
|
return {};
|
||||||
|
} else {
|
||||||
|
final sdkPath = environment.androidSdkPath;
|
||||||
|
final ndkVersion = environment.androidNdkVersion;
|
||||||
|
final minSdkVersion = environment.androidMinSdkVersion;
|
||||||
|
if (sdkPath == null) {
|
||||||
|
throw BuildException('androidSdkPath is not set');
|
||||||
|
}
|
||||||
|
if (ndkVersion == null) {
|
||||||
|
throw BuildException('androidNdkVersion is not set');
|
||||||
|
}
|
||||||
|
if (minSdkVersion == null) {
|
||||||
|
throw BuildException('androidMinSdkVersion is not set');
|
||||||
|
}
|
||||||
|
final env = AndroidEnvironment(
|
||||||
|
sdkPath: sdkPath,
|
||||||
|
ndkVersion: ndkVersion,
|
||||||
|
minSdkVersion: minSdkVersion,
|
||||||
|
targetTempDir: environment.targetTempDir,
|
||||||
|
target: target,
|
||||||
|
);
|
||||||
|
if (!env.ndkIsInstalled() && environment.javaHome != null) {
|
||||||
|
env.installNdk(javaHome: environment.javaHome!);
|
||||||
|
}
|
||||||
|
return env.buildEnvironment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
import 'package:toml/toml.dart';
|
||||||
|
|
||||||
|
class ManifestException {
|
||||||
|
ManifestException(this.message, {required this.fileName});
|
||||||
|
|
||||||
|
final String? fileName;
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
if (fileName != null) {
|
||||||
|
return 'Failed to parse package manifest at $fileName: $message';
|
||||||
|
} else {
|
||||||
|
return 'Failed to parse package manifest: $message';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CrateInfo {
|
||||||
|
CrateInfo({required this.packageName});
|
||||||
|
|
||||||
|
final String packageName;
|
||||||
|
|
||||||
|
static CrateInfo parseManifest(String manifest, {final String? fileName}) {
|
||||||
|
final toml = TomlDocument.parse(manifest);
|
||||||
|
final package = toml.toMap()['package'];
|
||||||
|
if (package == null) {
|
||||||
|
throw ManifestException('Missing package section', fileName: fileName);
|
||||||
|
}
|
||||||
|
final name = package['name'];
|
||||||
|
if (name == null) {
|
||||||
|
throw ManifestException('Missing package name', fileName: fileName);
|
||||||
|
}
|
||||||
|
return CrateInfo(packageName: name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CrateInfo load(String manifestDir) {
|
||||||
|
final manifestFile = File(path.join(manifestDir, 'Cargo.toml'));
|
||||||
|
final manifest = manifestFile.readAsStringSync();
|
||||||
|
return parseManifest(manifest, fileName: manifestFile.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:convert/convert.dart';
|
||||||
|
import 'package:crypto/crypto.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
|
class CrateHash {
|
||||||
|
/// Computes a hash uniquely identifying crate content. This takes into account
|
||||||
|
/// content all all .rs files inside the src directory, as well as Cargo.toml,
|
||||||
|
/// Cargo.lock, build.rs and cargokit.yaml.
|
||||||
|
///
|
||||||
|
/// If [tempStorage] is provided, computed hash is stored in a file in that directory
|
||||||
|
/// and reused on subsequent calls if the crate content hasn't changed.
|
||||||
|
static String compute(String manifestDir, {String? tempStorage}) {
|
||||||
|
return CrateHash._(
|
||||||
|
manifestDir: manifestDir,
|
||||||
|
tempStorage: tempStorage,
|
||||||
|
)._compute();
|
||||||
|
}
|
||||||
|
|
||||||
|
CrateHash._({
|
||||||
|
required this.manifestDir,
|
||||||
|
required this.tempStorage,
|
||||||
|
});
|
||||||
|
|
||||||
|
String _compute() {
|
||||||
|
final files = getFiles();
|
||||||
|
final tempStorage = this.tempStorage;
|
||||||
|
if (tempStorage != null) {
|
||||||
|
final quickHash = _computeQuickHash(files);
|
||||||
|
final quickHashFolder = Directory(path.join(tempStorage, 'crate_hash'));
|
||||||
|
quickHashFolder.createSync(recursive: true);
|
||||||
|
final quickHashFile = File(path.join(quickHashFolder.path, quickHash));
|
||||||
|
if (quickHashFile.existsSync()) {
|
||||||
|
return quickHashFile.readAsStringSync();
|
||||||
|
}
|
||||||
|
final hash = _computeHash(files);
|
||||||
|
quickHashFile.writeAsStringSync(hash);
|
||||||
|
return hash;
|
||||||
|
} else {
|
||||||
|
return _computeHash(files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Computes a quick hash based on files stat (without reading contents). This
|
||||||
|
/// is used to cache the real hash, which is slower to compute since it involves
|
||||||
|
/// reading every single file.
|
||||||
|
String _computeQuickHash(List<File> files) {
|
||||||
|
final output = AccumulatorSink<Digest>();
|
||||||
|
final input = sha256.startChunkedConversion(output);
|
||||||
|
|
||||||
|
final data = ByteData(8);
|
||||||
|
for (final file in files) {
|
||||||
|
input.add(utf8.encode(file.path));
|
||||||
|
final stat = file.statSync();
|
||||||
|
data.setUint64(0, stat.size);
|
||||||
|
input.add(data.buffer.asUint8List());
|
||||||
|
data.setUint64(0, stat.modified.millisecondsSinceEpoch);
|
||||||
|
input.add(data.buffer.asUint8List());
|
||||||
|
}
|
||||||
|
|
||||||
|
input.close();
|
||||||
|
return base64Url.encode(output.events.single.bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _computeHash(List<File> files) {
|
||||||
|
final output = AccumulatorSink<Digest>();
|
||||||
|
final input = sha256.startChunkedConversion(output);
|
||||||
|
|
||||||
|
void addTextFile(File file) {
|
||||||
|
// text Files are hashed by lines in case we're dealing with github checkout
|
||||||
|
// that auto-converts line endings.
|
||||||
|
final splitter = LineSplitter();
|
||||||
|
if (file.existsSync()) {
|
||||||
|
final data = file.readAsStringSync();
|
||||||
|
final lines = splitter.convert(data);
|
||||||
|
for (final line in lines) {
|
||||||
|
input.add(utf8.encode(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final file in files) {
|
||||||
|
addTextFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
input.close();
|
||||||
|
final res = output.events.single;
|
||||||
|
|
||||||
|
// Truncate to 128bits.
|
||||||
|
final hash = res.bytes.sublist(0, 16);
|
||||||
|
return hex.encode(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<File> getFiles() {
|
||||||
|
final src = Directory(path.join(manifestDir, 'src'));
|
||||||
|
final files = src
|
||||||
|
.listSync(recursive: true, followLinks: false)
|
||||||
|
.whereType<File>()
|
||||||
|
.toList();
|
||||||
|
files.sortBy((element) => element.path);
|
||||||
|
void addFile(String relative) {
|
||||||
|
final file = File(path.join(manifestDir, relative));
|
||||||
|
if (file.existsSync()) {
|
||||||
|
files.add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addFile('Cargo.toml');
|
||||||
|
addFile('Cargo.lock');
|
||||||
|
addFile('build.rs');
|
||||||
|
addFile('cargokit.yaml');
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String manifestDir;
|
||||||
|
final String? tempStorage;
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
extension on String {
|
||||||
|
String resolveSymlink() => File(this).resolveSymbolicLinksSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Environment {
|
||||||
|
/// Current build configuration (debug or release).
|
||||||
|
static String get configuration =>
|
||||||
|
_getEnv("CARGOKIT_CONFIGURATION").toLowerCase();
|
||||||
|
|
||||||
|
static bool get isDebug => configuration == 'debug';
|
||||||
|
static bool get isRelease => configuration == 'release';
|
||||||
|
|
||||||
|
/// Temporary directory where Rust build artifacts are placed.
|
||||||
|
static String get targetTempDir => _getEnv("CARGOKIT_TARGET_TEMP_DIR");
|
||||||
|
|
||||||
|
/// Final output directory where the build artifacts are placed.
|
||||||
|
static String get outputDir => _getEnvPath('CARGOKIT_OUTPUT_DIR');
|
||||||
|
|
||||||
|
/// Path to the crate manifest (containing Cargo.toml).
|
||||||
|
static String get manifestDir => _getEnvPath('CARGOKIT_MANIFEST_DIR');
|
||||||
|
|
||||||
|
/// Directory inside root project. Not necessarily root folder. Symlinks are
|
||||||
|
/// not resolved on purpose.
|
||||||
|
static String get rootProjectDir => _getEnv('CARGOKIT_ROOT_PROJECT_DIR');
|
||||||
|
|
||||||
|
// Pod
|
||||||
|
|
||||||
|
/// Platform name (macosx, iphoneos, iphonesimulator).
|
||||||
|
static String get darwinPlatformName =>
|
||||||
|
_getEnv("CARGOKIT_DARWIN_PLATFORM_NAME");
|
||||||
|
|
||||||
|
/// List of architectures to build for (arm64, armv7, x86_64).
|
||||||
|
static List<String> get darwinArchs =>
|
||||||
|
_getEnv("CARGOKIT_DARWIN_ARCHS").split(' ');
|
||||||
|
|
||||||
|
// Gradle
|
||||||
|
static String get minSdkVersion => _getEnv("CARGOKIT_MIN_SDK_VERSION");
|
||||||
|
static String get ndkVersion => _getEnv("CARGOKIT_NDK_VERSION");
|
||||||
|
static String get sdkPath => _getEnvPath("CARGOKIT_SDK_DIR");
|
||||||
|
static String get javaHome => _getEnvPath("CARGOKIT_JAVA_HOME");
|
||||||
|
static List<String> get targetPlatforms =>
|
||||||
|
_getEnv("CARGOKIT_TARGET_PLATFORMS").split(',');
|
||||||
|
|
||||||
|
// CMAKE
|
||||||
|
static String get targetPlatform => _getEnv("CARGOKIT_TARGET_PLATFORM");
|
||||||
|
|
||||||
|
static String _getEnv(String key) {
|
||||||
|
final res = Platform.environment[key];
|
||||||
|
if (res == null) {
|
||||||
|
throw Exception("Missing environment variable $key");
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String _getEnvPath(String key) {
|
||||||
|
final res = _getEnv(key);
|
||||||
|
if (Directory(res).existsSync()) {
|
||||||
|
return res.resolveSymlink();
|
||||||
|
} else {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
|
const String kSeparator = "--";
|
||||||
|
const String kDoubleSeparator = "==";
|
||||||
|
|
||||||
|
bool _lastMessageWasSeparator = false;
|
||||||
|
|
||||||
|
void _log(LogRecord rec) {
|
||||||
|
final prefix = '${rec.level.name}: ';
|
||||||
|
final out = rec.level == Level.SEVERE ? stderr : stdout;
|
||||||
|
if (rec.message == kSeparator) {
|
||||||
|
if (!_lastMessageWasSeparator) {
|
||||||
|
out.write(prefix);
|
||||||
|
out.writeln('-' * 80);
|
||||||
|
_lastMessageWasSeparator = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (rec.message == kDoubleSeparator) {
|
||||||
|
out.write(prefix);
|
||||||
|
out.writeln('=' * 80);
|
||||||
|
_lastMessageWasSeparator = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
out.write(prefix);
|
||||||
|
out.writeln(rec.message);
|
||||||
|
_lastMessageWasSeparator = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initLogging() {
|
||||||
|
Logger.root.level = Level.INFO;
|
||||||
|
Logger.root.onRecord.listen((LogRecord rec) {
|
||||||
|
final lines = rec.message.split('\n');
|
||||||
|
for (final line in lines) {
|
||||||
|
if (line.isNotEmpty || lines.length == 1 || line != lines.last) {
|
||||||
|
_log(LogRecord(
|
||||||
|
rec.level,
|
||||||
|
line,
|
||||||
|
rec.loggerName,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void enableVerboseLogging() {
|
||||||
|
Logger.root.level = Level.ALL;
|
||||||
|
}
|
||||||
309
useragent/rust_builder/cargokit/build_tool/lib/src/options.dart
Normal file
309
useragent/rust_builder/cargokit/build_tool/lib/src/options.dart
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:ed25519_edwards/ed25519_edwards.dart';
|
||||||
|
import 'package:hex/hex.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
import 'package:source_span/source_span.dart';
|
||||||
|
import 'package:yaml/yaml.dart';
|
||||||
|
|
||||||
|
import 'builder.dart';
|
||||||
|
import 'environment.dart';
|
||||||
|
import 'rustup.dart';
|
||||||
|
|
||||||
|
final _log = Logger('options');
|
||||||
|
|
||||||
|
/// A class for exceptions that have source span information attached.
|
||||||
|
class SourceSpanException implements Exception {
|
||||||
|
// This is a getter so that subclasses can override it.
|
||||||
|
/// A message describing the exception.
|
||||||
|
String get message => _message;
|
||||||
|
final String _message;
|
||||||
|
|
||||||
|
// This is a getter so that subclasses can override it.
|
||||||
|
/// The span associated with this exception.
|
||||||
|
///
|
||||||
|
/// This may be `null` if the source location can't be determined.
|
||||||
|
SourceSpan? get span => _span;
|
||||||
|
final SourceSpan? _span;
|
||||||
|
|
||||||
|
SourceSpanException(this._message, this._span);
|
||||||
|
|
||||||
|
/// Returns a string representation of `this`.
|
||||||
|
///
|
||||||
|
/// [color] may either be a [String], a [bool], or `null`. If it's a string,
|
||||||
|
/// it indicates an ANSI terminal color escape that should be used to
|
||||||
|
/// highlight the span's text. If it's `true`, it indicates that the text
|
||||||
|
/// should be highlighted using the default color. If it's `false` or `null`,
|
||||||
|
/// it indicates that the text shouldn't be highlighted.
|
||||||
|
@override
|
||||||
|
String toString({Object? color}) {
|
||||||
|
if (span == null) return message;
|
||||||
|
return 'Error on ${span!.message(message, color: color)}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Toolchain {
|
||||||
|
stable,
|
||||||
|
beta,
|
||||||
|
nightly,
|
||||||
|
}
|
||||||
|
|
||||||
|
class CargoBuildOptions {
|
||||||
|
final Toolchain toolchain;
|
||||||
|
final List<String> flags;
|
||||||
|
|
||||||
|
CargoBuildOptions({
|
||||||
|
required this.toolchain,
|
||||||
|
required this.flags,
|
||||||
|
});
|
||||||
|
|
||||||
|
static Toolchain _toolchainFromNode(YamlNode node) {
|
||||||
|
if (node case YamlScalar(value: String name)) {
|
||||||
|
final toolchain =
|
||||||
|
Toolchain.values.firstWhereOrNull((element) => element.name == name);
|
||||||
|
if (toolchain != null) {
|
||||||
|
return toolchain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw SourceSpanException(
|
||||||
|
'Unknown toolchain. Must be one of ${Toolchain.values.map((e) => e.name)}.',
|
||||||
|
node.span);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CargoBuildOptions parse(YamlNode node) {
|
||||||
|
if (node is! YamlMap) {
|
||||||
|
throw SourceSpanException('Cargo options must be a map', node.span);
|
||||||
|
}
|
||||||
|
Toolchain toolchain = Toolchain.stable;
|
||||||
|
List<String> flags = [];
|
||||||
|
for (final MapEntry(:key, :value) in node.nodes.entries) {
|
||||||
|
if (key case YamlScalar(value: 'toolchain')) {
|
||||||
|
toolchain = _toolchainFromNode(value);
|
||||||
|
} else if (key case YamlScalar(value: 'extra_flags')) {
|
||||||
|
if (value case YamlList(nodes: List<YamlNode> list)) {
|
||||||
|
if (list.every((element) {
|
||||||
|
if (element case YamlScalar(value: String _)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})) {
|
||||||
|
flags = list.map((e) => e.value as String).toList();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw SourceSpanException(
|
||||||
|
'Extra flags must be a list of strings', value.span);
|
||||||
|
} else {
|
||||||
|
throw SourceSpanException(
|
||||||
|
'Unknown cargo option type. Must be "toolchain" or "extra_flags".',
|
||||||
|
key.span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CargoBuildOptions(toolchain: toolchain, flags: flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension on YamlMap {
|
||||||
|
/// Map that extracts keys so that we can do map case check on them.
|
||||||
|
Map<dynamic, YamlNode> get valueMap =>
|
||||||
|
nodes.map((key, value) => MapEntry(key.value, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrecompiledBinaries {
|
||||||
|
final String uriPrefix;
|
||||||
|
final PublicKey publicKey;
|
||||||
|
|
||||||
|
PrecompiledBinaries({
|
||||||
|
required this.uriPrefix,
|
||||||
|
required this.publicKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
static PublicKey _publicKeyFromHex(String key, SourceSpan? span) {
|
||||||
|
final bytes = HEX.decode(key);
|
||||||
|
if (bytes.length != 32) {
|
||||||
|
throw SourceSpanException(
|
||||||
|
'Invalid public key. Must be 32 bytes long.', span);
|
||||||
|
}
|
||||||
|
return PublicKey(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PrecompiledBinaries parse(YamlNode node) {
|
||||||
|
if (node case YamlMap(valueMap: Map<dynamic, YamlNode> map)) {
|
||||||
|
if (map
|
||||||
|
case {
|
||||||
|
'url_prefix': YamlNode urlPrefixNode,
|
||||||
|
'public_key': YamlNode publicKeyNode,
|
||||||
|
}) {
|
||||||
|
final urlPrefix = switch (urlPrefixNode) {
|
||||||
|
YamlScalar(value: String urlPrefix) => urlPrefix,
|
||||||
|
_ => throw SourceSpanException(
|
||||||
|
'Invalid URL prefix value.', urlPrefixNode.span),
|
||||||
|
};
|
||||||
|
final publicKey = switch (publicKeyNode) {
|
||||||
|
YamlScalar(value: String publicKey) =>
|
||||||
|
_publicKeyFromHex(publicKey, publicKeyNode.span),
|
||||||
|
_ => throw SourceSpanException(
|
||||||
|
'Invalid public key value.', publicKeyNode.span),
|
||||||
|
};
|
||||||
|
return PrecompiledBinaries(
|
||||||
|
uriPrefix: urlPrefix,
|
||||||
|
publicKey: publicKey,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw SourceSpanException(
|
||||||
|
'Invalid precompiled binaries value. '
|
||||||
|
'Expected Map with "url_prefix" and "public_key".',
|
||||||
|
node.span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cargokit options specified for Rust crate.
|
||||||
|
class CargokitCrateOptions {
|
||||||
|
CargokitCrateOptions({
|
||||||
|
this.cargo = const {},
|
||||||
|
this.precompiledBinaries,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Map<BuildConfiguration, CargoBuildOptions> cargo;
|
||||||
|
final PrecompiledBinaries? precompiledBinaries;
|
||||||
|
|
||||||
|
static CargokitCrateOptions parse(YamlNode node) {
|
||||||
|
if (node is! YamlMap) {
|
||||||
|
throw SourceSpanException('Cargokit options must be a map', node.span);
|
||||||
|
}
|
||||||
|
final options = <BuildConfiguration, CargoBuildOptions>{};
|
||||||
|
PrecompiledBinaries? precompiledBinaries;
|
||||||
|
|
||||||
|
for (final entry in node.nodes.entries) {
|
||||||
|
if (entry
|
||||||
|
case MapEntry(
|
||||||
|
key: YamlScalar(value: 'cargo'),
|
||||||
|
value: YamlNode node,
|
||||||
|
)) {
|
||||||
|
if (node is! YamlMap) {
|
||||||
|
throw SourceSpanException('Cargo options must be a map', node.span);
|
||||||
|
}
|
||||||
|
for (final MapEntry(:YamlNode key, :value) in node.nodes.entries) {
|
||||||
|
if (key case YamlScalar(value: String name)) {
|
||||||
|
final configuration = BuildConfiguration.values
|
||||||
|
.firstWhereOrNull((element) => element.name == name);
|
||||||
|
if (configuration != null) {
|
||||||
|
options[configuration] = CargoBuildOptions.parse(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw SourceSpanException(
|
||||||
|
'Unknown build configuration. Must be one of ${BuildConfiguration.values.map((e) => e.name)}.',
|
||||||
|
key.span);
|
||||||
|
}
|
||||||
|
} else if (entry.key case YamlScalar(value: 'precompiled_binaries')) {
|
||||||
|
precompiledBinaries = PrecompiledBinaries.parse(entry.value);
|
||||||
|
} else {
|
||||||
|
throw SourceSpanException(
|
||||||
|
'Unknown cargokit option type. Must be "cargo" or "precompiled_binaries".',
|
||||||
|
entry.key.span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CargokitCrateOptions(
|
||||||
|
cargo: options,
|
||||||
|
precompiledBinaries: precompiledBinaries,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CargokitCrateOptions load({
|
||||||
|
required String manifestDir,
|
||||||
|
}) {
|
||||||
|
final uri = Uri.file(path.join(manifestDir, "cargokit.yaml"));
|
||||||
|
final file = File.fromUri(uri);
|
||||||
|
if (file.existsSync()) {
|
||||||
|
final contents = loadYamlNode(file.readAsStringSync(), sourceUrl: uri);
|
||||||
|
return parse(contents);
|
||||||
|
} else {
|
||||||
|
return CargokitCrateOptions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CargokitUserOptions {
|
||||||
|
// When Rustup is installed always build locally unless user opts into
|
||||||
|
// using precompiled binaries.
|
||||||
|
static bool defaultUsePrecompiledBinaries() {
|
||||||
|
return Rustup.executablePath() == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
CargokitUserOptions({
|
||||||
|
required this.usePrecompiledBinaries,
|
||||||
|
required this.verboseLogging,
|
||||||
|
});
|
||||||
|
|
||||||
|
CargokitUserOptions._()
|
||||||
|
: usePrecompiledBinaries = defaultUsePrecompiledBinaries(),
|
||||||
|
verboseLogging = false;
|
||||||
|
|
||||||
|
static CargokitUserOptions parse(YamlNode node) {
|
||||||
|
if (node is! YamlMap) {
|
||||||
|
throw SourceSpanException('Cargokit options must be a map', node.span);
|
||||||
|
}
|
||||||
|
bool usePrecompiledBinaries = defaultUsePrecompiledBinaries();
|
||||||
|
bool verboseLogging = false;
|
||||||
|
|
||||||
|
for (final entry in node.nodes.entries) {
|
||||||
|
if (entry.key case YamlScalar(value: 'use_precompiled_binaries')) {
|
||||||
|
if (entry.value case YamlScalar(value: bool value)) {
|
||||||
|
usePrecompiledBinaries = value;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw SourceSpanException(
|
||||||
|
'Invalid value for "use_precompiled_binaries". Must be a boolean.',
|
||||||
|
entry.value.span);
|
||||||
|
} else if (entry.key case YamlScalar(value: 'verbose_logging')) {
|
||||||
|
if (entry.value case YamlScalar(value: bool value)) {
|
||||||
|
verboseLogging = value;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw SourceSpanException(
|
||||||
|
'Invalid value for "verbose_logging". Must be a boolean.',
|
||||||
|
entry.value.span);
|
||||||
|
} else {
|
||||||
|
throw SourceSpanException(
|
||||||
|
'Unknown cargokit option type. Must be "use_precompiled_binaries" or "verbose_logging".',
|
||||||
|
entry.key.span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CargokitUserOptions(
|
||||||
|
usePrecompiledBinaries: usePrecompiledBinaries,
|
||||||
|
verboseLogging: verboseLogging,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CargokitUserOptions load() {
|
||||||
|
String fileName = "cargokit_options.yaml";
|
||||||
|
var userProjectDir = Directory(Environment.rootProjectDir);
|
||||||
|
|
||||||
|
while (userProjectDir.parent.path != userProjectDir.path) {
|
||||||
|
final configFile = File(path.join(userProjectDir.path, fileName));
|
||||||
|
if (configFile.existsSync()) {
|
||||||
|
final contents = loadYamlNode(
|
||||||
|
configFile.readAsStringSync(),
|
||||||
|
sourceUrl: configFile.uri,
|
||||||
|
);
|
||||||
|
final res = parse(contents);
|
||||||
|
if (res.verboseLogging) {
|
||||||
|
_log.info('Found user options file at ${configFile.path}');
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
userProjectDir = userProjectDir.parent;
|
||||||
|
}
|
||||||
|
return CargokitUserOptions._();
|
||||||
|
}
|
||||||
|
|
||||||
|
final bool usePrecompiledBinaries;
|
||||||
|
final bool verboseLogging;
|
||||||
|
}
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:ed25519_edwards/ed25519_edwards.dart';
|
||||||
|
import 'package:github/github.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
|
import 'artifacts_provider.dart';
|
||||||
|
import 'builder.dart';
|
||||||
|
import 'cargo.dart';
|
||||||
|
import 'crate_hash.dart';
|
||||||
|
import 'options.dart';
|
||||||
|
import 'rustup.dart';
|
||||||
|
import 'target.dart';
|
||||||
|
|
||||||
|
final _log = Logger('precompile_binaries');
|
||||||
|
|
||||||
|
class PrecompileBinaries {
|
||||||
|
PrecompileBinaries({
|
||||||
|
required this.privateKey,
|
||||||
|
required this.githubToken,
|
||||||
|
required this.repositorySlug,
|
||||||
|
required this.manifestDir,
|
||||||
|
required this.targets,
|
||||||
|
this.androidSdkLocation,
|
||||||
|
this.androidNdkVersion,
|
||||||
|
this.androidMinSdkVersion,
|
||||||
|
this.tempDir,
|
||||||
|
this.glibcVersion,
|
||||||
|
});
|
||||||
|
|
||||||
|
final PrivateKey privateKey;
|
||||||
|
final String githubToken;
|
||||||
|
final RepositorySlug repositorySlug;
|
||||||
|
final String manifestDir;
|
||||||
|
final List<Target> targets;
|
||||||
|
final String? androidSdkLocation;
|
||||||
|
final String? androidNdkVersion;
|
||||||
|
final int? androidMinSdkVersion;
|
||||||
|
final String? tempDir;
|
||||||
|
final String? glibcVersion;
|
||||||
|
|
||||||
|
static String fileName(Target target, String name) {
|
||||||
|
return '${target.rust}_$name';
|
||||||
|
}
|
||||||
|
|
||||||
|
static String signatureFileName(Target target, String name) {
|
||||||
|
return '${target.rust}_$name.sig';
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> run() async {
|
||||||
|
final crateInfo = CrateInfo.load(manifestDir);
|
||||||
|
|
||||||
|
final targets = List.of(this.targets);
|
||||||
|
if (targets.isEmpty) {
|
||||||
|
targets.addAll([
|
||||||
|
...Target.buildableTargets(),
|
||||||
|
if (androidSdkLocation != null) ...Target.androidTargets(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_log.info('Precompiling binaries for $targets');
|
||||||
|
|
||||||
|
final hash = CrateHash.compute(manifestDir);
|
||||||
|
_log.info('Computed crate hash: $hash');
|
||||||
|
|
||||||
|
final String tagName = 'precompiled_$hash';
|
||||||
|
|
||||||
|
final github = GitHub(auth: Authentication.withToken(githubToken));
|
||||||
|
final repo = github.repositories;
|
||||||
|
final release = await _getOrCreateRelease(
|
||||||
|
repo: repo,
|
||||||
|
tagName: tagName,
|
||||||
|
packageName: crateInfo.packageName,
|
||||||
|
hash: hash,
|
||||||
|
);
|
||||||
|
|
||||||
|
final tempDir = this.tempDir != null
|
||||||
|
? Directory(this.tempDir!)
|
||||||
|
: Directory.systemTemp.createTempSync('precompiled_');
|
||||||
|
|
||||||
|
tempDir.createSync(recursive: true);
|
||||||
|
|
||||||
|
final crateOptions = CargokitCrateOptions.load(
|
||||||
|
manifestDir: manifestDir,
|
||||||
|
);
|
||||||
|
|
||||||
|
final buildEnvironment = BuildEnvironment(
|
||||||
|
configuration: BuildConfiguration.release,
|
||||||
|
crateOptions: crateOptions,
|
||||||
|
targetTempDir: tempDir.path,
|
||||||
|
manifestDir: manifestDir,
|
||||||
|
crateInfo: crateInfo,
|
||||||
|
isAndroid: androidSdkLocation != null,
|
||||||
|
androidSdkPath: androidSdkLocation,
|
||||||
|
androidNdkVersion: androidNdkVersion,
|
||||||
|
androidMinSdkVersion: androidMinSdkVersion,
|
||||||
|
glibcVersion: glibcVersion,
|
||||||
|
);
|
||||||
|
|
||||||
|
final rustup = Rustup();
|
||||||
|
|
||||||
|
for (final target in targets) {
|
||||||
|
final artifactNames = getArtifactNames(
|
||||||
|
target: target,
|
||||||
|
libraryName: crateInfo.packageName,
|
||||||
|
remote: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (artifactNames.every((name) {
|
||||||
|
final fileName = PrecompileBinaries.fileName(target, name);
|
||||||
|
return (release.assets ?? []).any((e) => e.name == fileName);
|
||||||
|
})) {
|
||||||
|
_log.info("All artifacts for $target already exist - skipping");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_log.info('Building for $target');
|
||||||
|
|
||||||
|
final builder =
|
||||||
|
RustBuilder(target: target, environment: buildEnvironment);
|
||||||
|
builder.prepare(rustup);
|
||||||
|
final res = await builder.build();
|
||||||
|
|
||||||
|
final assets = <CreateReleaseAsset>[];
|
||||||
|
for (final name in artifactNames) {
|
||||||
|
final file = File(path.join(res, name));
|
||||||
|
if (!file.existsSync()) {
|
||||||
|
throw Exception('Missing artifact: ${file.path}');
|
||||||
|
}
|
||||||
|
|
||||||
|
final data = file.readAsBytesSync();
|
||||||
|
final create = CreateReleaseAsset(
|
||||||
|
name: PrecompileBinaries.fileName(target, name),
|
||||||
|
contentType: "application/octet-stream",
|
||||||
|
assetData: data,
|
||||||
|
);
|
||||||
|
final signature = sign(privateKey, data);
|
||||||
|
final signatureCreate = CreateReleaseAsset(
|
||||||
|
name: signatureFileName(target, name),
|
||||||
|
contentType: "application/octet-stream",
|
||||||
|
assetData: signature,
|
||||||
|
);
|
||||||
|
bool verified = verify(public(privateKey), data, signature);
|
||||||
|
if (!verified) {
|
||||||
|
throw Exception('Signature verification failed');
|
||||||
|
}
|
||||||
|
assets.add(create);
|
||||||
|
assets.add(signatureCreate);
|
||||||
|
}
|
||||||
|
_log.info('Uploading assets: ${assets.map((e) => e.name)}');
|
||||||
|
for (final asset in assets) {
|
||||||
|
// This seems to be failing on CI so do it one by one
|
||||||
|
int retryCount = 0;
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
await repo.uploadReleaseAssets(release, [asset]);
|
||||||
|
break;
|
||||||
|
} on Exception catch (e) {
|
||||||
|
if (retryCount == 10) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
++retryCount;
|
||||||
|
_log.shout(
|
||||||
|
'Upload failed (attempt $retryCount, will retry): ${e.toString()}');
|
||||||
|
await Future.delayed(Duration(seconds: 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_log.info('Cleaning up');
|
||||||
|
tempDir.deleteSync(recursive: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Release> _getOrCreateRelease({
|
||||||
|
required RepositoriesService repo,
|
||||||
|
required String tagName,
|
||||||
|
required String packageName,
|
||||||
|
required String hash,
|
||||||
|
}) async {
|
||||||
|
Release release;
|
||||||
|
try {
|
||||||
|
_log.info('Fetching release $tagName');
|
||||||
|
release = await repo.getReleaseByTagName(repositorySlug, tagName);
|
||||||
|
} on ReleaseNotFound {
|
||||||
|
_log.info('Release not found - creating release $tagName');
|
||||||
|
release = await repo.createRelease(
|
||||||
|
repositorySlug,
|
||||||
|
CreateRelease.from(
|
||||||
|
tagName: tagName,
|
||||||
|
name: 'Precompiled binaries ${hash.substring(0, 8)}',
|
||||||
|
targetCommitish: null,
|
||||||
|
isDraft: false,
|
||||||
|
isPrerelease: false,
|
||||||
|
body: 'Precompiled binaries for crate $packageName, '
|
||||||
|
'crate hash $hash.',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return release;
|
||||||
|
}
|
||||||
|
}
|
||||||
149
useragent/rust_builder/cargokit/build_tool/lib/src/rustup.dart
Normal file
149
useragent/rust_builder/cargokit/build_tool/lib/src/rustup.dart
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
|
import 'util.dart';
|
||||||
|
|
||||||
|
class _Toolchain {
|
||||||
|
_Toolchain(
|
||||||
|
this.name,
|
||||||
|
this.targets,
|
||||||
|
);
|
||||||
|
|
||||||
|
final String name;
|
||||||
|
final List<String> targets;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Rustup {
|
||||||
|
List<String>? installedTargets(String toolchain) {
|
||||||
|
final targets = _installedTargets(toolchain);
|
||||||
|
return targets != null ? List.unmodifiable(targets) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void installToolchain(String toolchain) {
|
||||||
|
log.info("Installing Rust toolchain: $toolchain");
|
||||||
|
runCommand("rustup", ['toolchain', 'install', toolchain]);
|
||||||
|
_installedToolchains
|
||||||
|
.add(_Toolchain(toolchain, _getInstalledTargets(toolchain)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void installTarget(
|
||||||
|
String target, {
|
||||||
|
required String toolchain,
|
||||||
|
}) {
|
||||||
|
log.info("Installing Rust target: $target");
|
||||||
|
runCommand("rustup", ['target', 'add', '--toolchain', toolchain, target]);
|
||||||
|
_installedTargets(toolchain)?.add(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _didInstallZigBuild = false;
|
||||||
|
|
||||||
|
void installZigBuild(String toolchain) {
|
||||||
|
if (_didInstallZigBuild) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Installing Zig build");
|
||||||
|
runCommand("rustup", [
|
||||||
|
'run',
|
||||||
|
toolchain,
|
||||||
|
'cargo',
|
||||||
|
'install',
|
||||||
|
'--locked',
|
||||||
|
'cargo-zigbuild',
|
||||||
|
]);
|
||||||
|
_didInstallZigBuild = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<_Toolchain> _installedToolchains;
|
||||||
|
|
||||||
|
Rustup() : _installedToolchains = _getInstalledToolchains();
|
||||||
|
|
||||||
|
List<String>? _installedTargets(String toolchain) => _installedToolchains
|
||||||
|
.firstWhereOrNull(
|
||||||
|
(e) => e.name == toolchain || e.name.startsWith('$toolchain-'))
|
||||||
|
?.targets;
|
||||||
|
|
||||||
|
static List<_Toolchain> _getInstalledToolchains() {
|
||||||
|
String extractToolchainName(String line) {
|
||||||
|
// ignore (default) after toolchain name
|
||||||
|
final parts = line.split(' ');
|
||||||
|
return parts[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
final res = runCommand("rustup", ['toolchain', 'list']);
|
||||||
|
|
||||||
|
// To list all non-custom toolchains, we need to filter out lines that
|
||||||
|
// don't start with "stable", "beta", or "nightly".
|
||||||
|
Pattern nonCustom = RegExp(r"^(stable|beta|nightly)");
|
||||||
|
final lines = res.stdout
|
||||||
|
.toString()
|
||||||
|
.split('\n')
|
||||||
|
.where((e) => e.isNotEmpty && e.startsWith(nonCustom))
|
||||||
|
.map(extractToolchainName)
|
||||||
|
.toList(growable: true);
|
||||||
|
|
||||||
|
return lines
|
||||||
|
.map(
|
||||||
|
(name) => _Toolchain(
|
||||||
|
name,
|
||||||
|
_getInstalledTargets(name),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(growable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<String> _getInstalledTargets(String toolchain) {
|
||||||
|
final res = runCommand("rustup", [
|
||||||
|
'target',
|
||||||
|
'list',
|
||||||
|
'--toolchain',
|
||||||
|
toolchain,
|
||||||
|
'--installed',
|
||||||
|
]);
|
||||||
|
final lines = res.stdout
|
||||||
|
.toString()
|
||||||
|
.split('\n')
|
||||||
|
.where((e) => e.isNotEmpty)
|
||||||
|
.toList(growable: true);
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _didInstallRustSrcForNightly = false;
|
||||||
|
|
||||||
|
void installRustSrcForNightly() {
|
||||||
|
if (_didInstallRustSrcForNightly) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Useful for -Z build-std
|
||||||
|
runCommand(
|
||||||
|
"rustup",
|
||||||
|
['component', 'add', 'rust-src', '--toolchain', 'nightly'],
|
||||||
|
);
|
||||||
|
_didInstallRustSrcForNightly = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String? executablePath() {
|
||||||
|
final envPath = Platform.environment['PATH'];
|
||||||
|
final envPathSeparator = Platform.isWindows ? ';' : ':';
|
||||||
|
final home = Platform.isWindows
|
||||||
|
? Platform.environment['USERPROFILE']
|
||||||
|
: Platform.environment['HOME'];
|
||||||
|
final paths = [
|
||||||
|
if (home != null) path.join(home, '.cargo', 'bin'),
|
||||||
|
if (envPath != null) ...envPath.split(envPathSeparator),
|
||||||
|
];
|
||||||
|
for (final p in paths) {
|
||||||
|
final rustup = Platform.isWindows ? 'rustup.exe' : 'rustup';
|
||||||
|
final rustupPath = path.join(p, rustup);
|
||||||
|
if (File(rustupPath).existsSync()) {
|
||||||
|
return rustupPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
147
useragent/rust_builder/cargokit/build_tool/lib/src/target.dart
Normal file
147
useragent/rust_builder/cargokit/build_tool/lib/src/target.dart
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
|
import 'util.dart';
|
||||||
|
|
||||||
|
class Target {
|
||||||
|
Target({
|
||||||
|
required this.rust,
|
||||||
|
this.flutter,
|
||||||
|
this.android,
|
||||||
|
this.androidMinSdkVersion,
|
||||||
|
this.darwinPlatform,
|
||||||
|
this.darwinArch,
|
||||||
|
});
|
||||||
|
|
||||||
|
static final all = [
|
||||||
|
Target(
|
||||||
|
rust: 'armv7-linux-androideabi',
|
||||||
|
flutter: 'android-arm',
|
||||||
|
android: 'armeabi-v7a',
|
||||||
|
androidMinSdkVersion: 16,
|
||||||
|
),
|
||||||
|
Target(
|
||||||
|
rust: 'aarch64-linux-android',
|
||||||
|
flutter: 'android-arm64',
|
||||||
|
android: 'arm64-v8a',
|
||||||
|
androidMinSdkVersion: 21,
|
||||||
|
),
|
||||||
|
Target(
|
||||||
|
rust: 'i686-linux-android',
|
||||||
|
flutter: 'android-x86',
|
||||||
|
android: 'x86',
|
||||||
|
androidMinSdkVersion: 16,
|
||||||
|
),
|
||||||
|
Target(
|
||||||
|
rust: 'x86_64-linux-android',
|
||||||
|
flutter: 'android-x64',
|
||||||
|
android: 'x86_64',
|
||||||
|
androidMinSdkVersion: 21,
|
||||||
|
),
|
||||||
|
Target(
|
||||||
|
rust: 'x86_64-pc-windows-msvc',
|
||||||
|
flutter: 'windows-x64',
|
||||||
|
),
|
||||||
|
Target(
|
||||||
|
rust: 'aarch64-pc-windows-msvc',
|
||||||
|
flutter: 'windows-arm64',
|
||||||
|
),
|
||||||
|
Target(
|
||||||
|
rust: 'x86_64-unknown-linux-gnu',
|
||||||
|
flutter: 'linux-x64',
|
||||||
|
),
|
||||||
|
Target(
|
||||||
|
rust: 'aarch64-unknown-linux-gnu',
|
||||||
|
flutter: 'linux-arm64',
|
||||||
|
),
|
||||||
|
Target(rust: 'riscv64gc-unknown-linux-gnu', flutter: 'linux-riscv64'),
|
||||||
|
Target(
|
||||||
|
rust: 'x86_64-apple-darwin',
|
||||||
|
darwinPlatform: 'macosx',
|
||||||
|
darwinArch: 'x86_64',
|
||||||
|
),
|
||||||
|
Target(
|
||||||
|
rust: 'aarch64-apple-darwin',
|
||||||
|
darwinPlatform: 'macosx',
|
||||||
|
darwinArch: 'arm64',
|
||||||
|
),
|
||||||
|
Target(
|
||||||
|
rust: 'aarch64-apple-ios',
|
||||||
|
darwinPlatform: 'iphoneos',
|
||||||
|
darwinArch: 'arm64',
|
||||||
|
),
|
||||||
|
Target(
|
||||||
|
rust: 'aarch64-apple-ios-sim',
|
||||||
|
darwinPlatform: 'iphonesimulator',
|
||||||
|
darwinArch: 'arm64',
|
||||||
|
),
|
||||||
|
Target(
|
||||||
|
rust: 'x86_64-apple-ios',
|
||||||
|
darwinPlatform: 'iphonesimulator',
|
||||||
|
darwinArch: 'x86_64',
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
static Target? forFlutterName(String flutterName) {
|
||||||
|
return all.firstWhereOrNull((element) => element.flutter == flutterName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Target? forDarwin({
|
||||||
|
required String platformName,
|
||||||
|
required String darwinAarch,
|
||||||
|
}) {
|
||||||
|
return all.firstWhereOrNull((element) => //
|
||||||
|
element.darwinPlatform == platformName &&
|
||||||
|
element.darwinArch == darwinAarch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Target? forRustTriple(String triple) {
|
||||||
|
return all.firstWhereOrNull((element) => element.rust == triple);
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Target> androidTargets() {
|
||||||
|
return all
|
||||||
|
.where((element) => element.android != null)
|
||||||
|
.toList(growable: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns buildable targets on current host platform ignoring Android targets.
|
||||||
|
static List<Target> buildableTargets() {
|
||||||
|
if (Platform.isLinux) {
|
||||||
|
// Right now we don't support cross-compiling on Linux. So we just return
|
||||||
|
// the host target.
|
||||||
|
final arch = (runCommand('arch', []).stdout as String).trim();
|
||||||
|
if (arch == 'aarch64') {
|
||||||
|
return [Target.forRustTriple('aarch64-unknown-linux-gnu')!];
|
||||||
|
} else if (arch == 'riscv64') {
|
||||||
|
return [Target.forRustTriple('riscv64gc-unknown-linux-gnu')!];
|
||||||
|
} else {
|
||||||
|
return [Target.forRustTriple('x86_64-unknown-linux-gnu')!];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return all.where((target) {
|
||||||
|
if (Platform.isWindows) {
|
||||||
|
return target.rust.contains('-windows-');
|
||||||
|
} else if (Platform.isMacOS) {
|
||||||
|
return target.darwinPlatform != null;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}).toList(growable: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return rust;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String? flutter;
|
||||||
|
final String rust;
|
||||||
|
final String? android;
|
||||||
|
final int? androidMinSdkVersion;
|
||||||
|
final String? darwinPlatform;
|
||||||
|
final String? darwinArch;
|
||||||
|
}
|
||||||
172
useragent/rust_builder/cargokit/build_tool/lib/src/util.dart
Normal file
172
useragent/rust_builder/cargokit/build_tool/lib/src/util.dart
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
|
import 'logging.dart';
|
||||||
|
import 'rustup.dart';
|
||||||
|
|
||||||
|
final log = Logger("process");
|
||||||
|
|
||||||
|
class CommandFailedException implements Exception {
|
||||||
|
final String executable;
|
||||||
|
final List<String> arguments;
|
||||||
|
final ProcessResult result;
|
||||||
|
|
||||||
|
CommandFailedException({
|
||||||
|
required this.executable,
|
||||||
|
required this.arguments,
|
||||||
|
required this.result,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
final stdout = result.stdout.toString().trim();
|
||||||
|
final stderr = result.stderr.toString().trim();
|
||||||
|
return [
|
||||||
|
"External Command: $executable ${arguments.map((e) => '"$e"').join(' ')}",
|
||||||
|
"Returned Exit Code: ${result.exitCode}",
|
||||||
|
kSeparator,
|
||||||
|
"STDOUT:",
|
||||||
|
if (stdout.isNotEmpty) stdout,
|
||||||
|
kSeparator,
|
||||||
|
"STDERR:",
|
||||||
|
if (stderr.isNotEmpty) stderr,
|
||||||
|
].join('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestRunCommandArgs {
|
||||||
|
final String executable;
|
||||||
|
final List<String> arguments;
|
||||||
|
final String? workingDirectory;
|
||||||
|
final Map<String, String>? environment;
|
||||||
|
final bool includeParentEnvironment;
|
||||||
|
final bool runInShell;
|
||||||
|
final Encoding? stdoutEncoding;
|
||||||
|
final Encoding? stderrEncoding;
|
||||||
|
|
||||||
|
TestRunCommandArgs({
|
||||||
|
required this.executable,
|
||||||
|
required this.arguments,
|
||||||
|
this.workingDirectory,
|
||||||
|
this.environment,
|
||||||
|
this.includeParentEnvironment = true,
|
||||||
|
this.runInShell = false,
|
||||||
|
this.stdoutEncoding,
|
||||||
|
this.stderrEncoding,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestRunCommandResult {
|
||||||
|
TestRunCommandResult({
|
||||||
|
this.pid = 1,
|
||||||
|
this.exitCode = 0,
|
||||||
|
this.stdout = '',
|
||||||
|
this.stderr = '',
|
||||||
|
});
|
||||||
|
|
||||||
|
final int pid;
|
||||||
|
final int exitCode;
|
||||||
|
final String stdout;
|
||||||
|
final String stderr;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestRunCommandResult Function(TestRunCommandArgs args)? testRunCommandOverride;
|
||||||
|
|
||||||
|
ProcessResult runCommand(
|
||||||
|
String executable,
|
||||||
|
List<String> arguments, {
|
||||||
|
String? workingDirectory,
|
||||||
|
Map<String, String>? environment,
|
||||||
|
bool includeParentEnvironment = true,
|
||||||
|
bool runInShell = false,
|
||||||
|
Encoding? stdoutEncoding = systemEncoding,
|
||||||
|
Encoding? stderrEncoding = systemEncoding,
|
||||||
|
}) {
|
||||||
|
if (testRunCommandOverride != null) {
|
||||||
|
final result = testRunCommandOverride!(TestRunCommandArgs(
|
||||||
|
executable: executable,
|
||||||
|
arguments: arguments,
|
||||||
|
workingDirectory: workingDirectory,
|
||||||
|
environment: environment,
|
||||||
|
includeParentEnvironment: includeParentEnvironment,
|
||||||
|
runInShell: runInShell,
|
||||||
|
stdoutEncoding: stdoutEncoding,
|
||||||
|
stderrEncoding: stderrEncoding,
|
||||||
|
));
|
||||||
|
return ProcessResult(
|
||||||
|
result.pid,
|
||||||
|
result.exitCode,
|
||||||
|
result.stdout,
|
||||||
|
result.stderr,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
log.finer('Running command $executable ${arguments.join(' ')}');
|
||||||
|
final res = Process.runSync(
|
||||||
|
_resolveExecutable(executable),
|
||||||
|
arguments,
|
||||||
|
workingDirectory: workingDirectory,
|
||||||
|
environment: environment,
|
||||||
|
includeParentEnvironment: includeParentEnvironment,
|
||||||
|
runInShell: runInShell,
|
||||||
|
stderrEncoding: stderrEncoding,
|
||||||
|
stdoutEncoding: stdoutEncoding,
|
||||||
|
);
|
||||||
|
if (res.exitCode != 0) {
|
||||||
|
throw CommandFailedException(
|
||||||
|
executable: executable,
|
||||||
|
arguments: arguments,
|
||||||
|
result: res,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RustupNotFoundException implements Exception {
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return [
|
||||||
|
' ',
|
||||||
|
'rustup not found in PATH.',
|
||||||
|
' ',
|
||||||
|
'Maybe you need to install Rust? It only takes a minute:',
|
||||||
|
' ',
|
||||||
|
if (Platform.isWindows) 'https://www.rust-lang.org/tools/install',
|
||||||
|
if (hasHomebrewRustInPath()) ...[
|
||||||
|
'\$ brew unlink rust # Unlink homebrew Rust from PATH',
|
||||||
|
],
|
||||||
|
if (!Platform.isWindows)
|
||||||
|
"\$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh",
|
||||||
|
' ',
|
||||||
|
].join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hasHomebrewRustInPath() {
|
||||||
|
if (!Platform.isMacOS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final envPath = Platform.environment['PATH'] ?? '';
|
||||||
|
final paths = envPath.split(':');
|
||||||
|
return paths.any((p) {
|
||||||
|
return p.contains('homebrew') && File(path.join(p, 'rustc')).existsSync();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _resolveExecutable(String executable) {
|
||||||
|
if (executable == 'rustup') {
|
||||||
|
final resolved = Rustup.executablePath();
|
||||||
|
if (resolved != null) {
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
throw RustupNotFoundException();
|
||||||
|
} else {
|
||||||
|
return executable;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:ed25519_edwards/ed25519_edwards.dart';
|
||||||
|
import 'package:http/http.dart';
|
||||||
|
|
||||||
|
import 'artifacts_provider.dart';
|
||||||
|
import 'cargo.dart';
|
||||||
|
import 'crate_hash.dart';
|
||||||
|
import 'options.dart';
|
||||||
|
import 'precompile_binaries.dart';
|
||||||
|
import 'target.dart';
|
||||||
|
|
||||||
|
class VerifyBinaries {
|
||||||
|
VerifyBinaries({
|
||||||
|
required this.manifestDir,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String manifestDir;
|
||||||
|
|
||||||
|
Future<void> run() async {
|
||||||
|
final crateInfo = CrateInfo.load(manifestDir);
|
||||||
|
|
||||||
|
final config = CargokitCrateOptions.load(manifestDir: manifestDir);
|
||||||
|
final precompiledBinaries = config.precompiledBinaries;
|
||||||
|
if (precompiledBinaries == null) {
|
||||||
|
stdout.writeln('Crate does not support precompiled binaries.');
|
||||||
|
} else {
|
||||||
|
final crateHash = CrateHash.compute(manifestDir);
|
||||||
|
stdout.writeln('Crate hash: $crateHash');
|
||||||
|
|
||||||
|
for (final target in Target.all) {
|
||||||
|
final message = 'Checking ${target.rust}...';
|
||||||
|
stdout.write(message.padRight(40));
|
||||||
|
stdout.flush();
|
||||||
|
|
||||||
|
final artifacts = getArtifactNames(
|
||||||
|
target: target,
|
||||||
|
libraryName: crateInfo.packageName,
|
||||||
|
remote: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
final prefix = precompiledBinaries.uriPrefix;
|
||||||
|
|
||||||
|
bool ok = true;
|
||||||
|
|
||||||
|
for (final artifact in artifacts) {
|
||||||
|
final fileName = PrecompileBinaries.fileName(target, artifact);
|
||||||
|
final signatureFileName =
|
||||||
|
PrecompileBinaries.signatureFileName(target, artifact);
|
||||||
|
|
||||||
|
final url = Uri.parse('$prefix$crateHash/$fileName');
|
||||||
|
final signatureUrl =
|
||||||
|
Uri.parse('$prefix$crateHash/$signatureFileName');
|
||||||
|
|
||||||
|
final signature = await get(signatureUrl);
|
||||||
|
if (signature.statusCode != 200) {
|
||||||
|
stdout.writeln('MISSING');
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
final asset = await get(url);
|
||||||
|
if (asset.statusCode != 200) {
|
||||||
|
stdout.writeln('MISSING');
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!verify(precompiledBinaries.publicKey, asset.bodyBytes,
|
||||||
|
signature.bodyBytes)) {
|
||||||
|
stdout.writeln('INVALID SIGNATURE');
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
stdout.writeln('OK');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
453
useragent/rust_builder/cargokit/build_tool/pubspec.lock
Normal file
453
useragent/rust_builder/cargokit/build_tool/pubspec.lock
Normal file
@@ -0,0 +1,453 @@
|
|||||||
|
# Generated by pub
|
||||||
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
|
packages:
|
||||||
|
_fe_analyzer_shared:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: _fe_analyzer_shared
|
||||||
|
sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "64.0.0"
|
||||||
|
adaptive_number:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: adaptive_number
|
||||||
|
sha256: "3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
|
analyzer:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: analyzer
|
||||||
|
sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.2.0"
|
||||||
|
args:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: args
|
||||||
|
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.2"
|
||||||
|
async:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: async
|
||||||
|
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.11.0"
|
||||||
|
boolean_selector:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: boolean_selector
|
||||||
|
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
collection:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: collection
|
||||||
|
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.18.0"
|
||||||
|
convert:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: convert
|
||||||
|
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.1"
|
||||||
|
coverage:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: coverage
|
||||||
|
sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.6.3"
|
||||||
|
crypto:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: crypto
|
||||||
|
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.3"
|
||||||
|
ed25519_edwards:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: ed25519_edwards
|
||||||
|
sha256: "6ce0112d131327ec6d42beede1e5dfd526069b18ad45dcf654f15074ad9276cd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.1"
|
||||||
|
file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file
|
||||||
|
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.4"
|
||||||
|
fixnum:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fixnum
|
||||||
|
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
|
frontend_server_client:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: frontend_server_client
|
||||||
|
sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.0"
|
||||||
|
github:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: github
|
||||||
|
sha256: "9966bc13bf612342e916b0a343e95e5f046c88f602a14476440e9b75d2295411"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.17.0"
|
||||||
|
glob:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: glob
|
||||||
|
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
hex:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: hex
|
||||||
|
sha256: "4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.0"
|
||||||
|
http:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: http
|
||||||
|
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
|
http_multi_server:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_multi_server
|
||||||
|
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.1"
|
||||||
|
http_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_parser
|
||||||
|
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.2"
|
||||||
|
io:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: io
|
||||||
|
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
|
js:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: js
|
||||||
|
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.7"
|
||||||
|
json_annotation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: json_annotation
|
||||||
|
sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.8.1"
|
||||||
|
lints:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: lints
|
||||||
|
sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
logging:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: logging
|
||||||
|
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
|
matcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: matcher
|
||||||
|
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.12.16"
|
||||||
|
meta:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: meta
|
||||||
|
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.9.1"
|
||||||
|
mime:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mime
|
||||||
|
sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
|
node_preamble:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: node_preamble
|
||||||
|
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
|
package_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_config
|
||||||
|
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
|
path:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: path
|
||||||
|
sha256: "2ad4cddff7f5cc0e2d13069f2a3f7a73ca18f66abd6f5ecf215219cdb3638edb"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.8.0"
|
||||||
|
petitparser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: petitparser
|
||||||
|
sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.4.0"
|
||||||
|
pool:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pool
|
||||||
|
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.1"
|
||||||
|
pub_semver:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pub_semver
|
||||||
|
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.4"
|
||||||
|
shelf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf
|
||||||
|
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.1"
|
||||||
|
shelf_packages_handler:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_packages_handler
|
||||||
|
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.2"
|
||||||
|
shelf_static:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_static
|
||||||
|
sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.2"
|
||||||
|
shelf_web_socket:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_web_socket
|
||||||
|
sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
|
source_map_stack_trace:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_map_stack_trace
|
||||||
|
sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
source_maps:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_maps
|
||||||
|
sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.10.12"
|
||||||
|
source_span:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: source_span
|
||||||
|
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.10.0"
|
||||||
|
stack_trace:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stack_trace
|
||||||
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.11.1"
|
||||||
|
stream_channel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stream_channel
|
||||||
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
string_scanner:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: string_scanner
|
||||||
|
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
|
term_glyph:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: term_glyph
|
||||||
|
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
|
test:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: test
|
||||||
|
sha256: "9b0dd8e36af4a5b1569029949d50a52cb2a2a2fdaa20cebb96e6603b9ae241f9"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.24.6"
|
||||||
|
test_api:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: test_api
|
||||||
|
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.1"
|
||||||
|
test_core:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: test_core
|
||||||
|
sha256: "4bef837e56375537055fdbbbf6dd458b1859881f4c7e6da936158f77d61ab265"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.5.6"
|
||||||
|
toml:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: toml
|
||||||
|
sha256: "157c5dca5160fced243f3ce984117f729c788bb5e475504f3dbcda881accee44"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.14.0"
|
||||||
|
typed_data:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: typed_data
|
||||||
|
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.2"
|
||||||
|
version:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: version
|
||||||
|
sha256: "2307e23a45b43f96469eeab946208ed63293e8afca9c28cd8b5241ff31c55f55"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
|
vm_service:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vm_service
|
||||||
|
sha256: "0fae432c85c4ea880b33b497d32824b97795b04cdaa74d270219572a1f50268d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "11.9.0"
|
||||||
|
watcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: watcher
|
||||||
|
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
|
web_socket_channel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket_channel
|
||||||
|
sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.0"
|
||||||
|
webkit_inspection_protocol:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webkit_inspection_protocol
|
||||||
|
sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
|
yaml:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: yaml
|
||||||
|
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.2"
|
||||||
|
sdks:
|
||||||
|
dart: ">=3.0.0 <4.0.0"
|
||||||
33
useragent/rust_builder/cargokit/build_tool/pubspec.yaml
Normal file
33
useragent/rust_builder/cargokit/build_tool/pubspec.yaml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
# Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
name: build_tool
|
||||||
|
description: Cargokit build_tool. Facilitates the build of Rust crate during Flutter application build.
|
||||||
|
publish_to: none
|
||||||
|
version: 1.0.0
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: ">=3.0.0 <4.0.0"
|
||||||
|
|
||||||
|
# Add regular dependencies here.
|
||||||
|
dependencies:
|
||||||
|
# these are pinned on purpose because the bundle_tool_runner doesn't have
|
||||||
|
# pubspec.lock. See run_build_tool.sh
|
||||||
|
logging: 1.2.0
|
||||||
|
path: 1.8.0
|
||||||
|
version: 3.0.0
|
||||||
|
collection: 1.18.0
|
||||||
|
ed25519_edwards: 0.3.1
|
||||||
|
hex: 0.2.0
|
||||||
|
yaml: 3.1.2
|
||||||
|
source_span: 1.10.0
|
||||||
|
github: 9.17.0
|
||||||
|
args: 2.4.2
|
||||||
|
crypto: 3.0.3
|
||||||
|
convert: 3.1.1
|
||||||
|
http: 1.1.0
|
||||||
|
toml: 0.14.0
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
lints: ^2.1.0
|
||||||
|
test: ^1.24.0
|
||||||
99
useragent/rust_builder/cargokit/cmake/cargokit.cmake
Normal file
99
useragent/rust_builder/cargokit/cmake/cargokit.cmake
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
SET(cargokit_cmake_root "${CMAKE_CURRENT_LIST_DIR}/..")
|
||||||
|
|
||||||
|
# Workaround for https://github.com/dart-lang/pub/issues/4010
|
||||||
|
get_filename_component(cargokit_cmake_root "${cargokit_cmake_root}" REALPATH)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
# REALPATH does not properly resolve symlinks on windows :-/
|
||||||
|
execute_process(COMMAND powershell -ExecutionPolicy Bypass -File "${CMAKE_CURRENT_LIST_DIR}/resolve_symlinks.ps1" "${cargokit_cmake_root}" OUTPUT_VARIABLE cargokit_cmake_root OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Arguments
|
||||||
|
# - target: CMAKE target to which rust library is linked
|
||||||
|
# - manifest_dir: relative path from current folder to directory containing cargo manifest
|
||||||
|
# - lib_name: cargo package name
|
||||||
|
# - any_symbol_name: name of any exported symbol from the library.
|
||||||
|
# used on windows to force linking with library.
|
||||||
|
function(apply_cargokit target manifest_dir lib_name any_symbol_name)
|
||||||
|
|
||||||
|
set(CARGOKIT_LIB_NAME "${lib_name}")
|
||||||
|
set(CARGOKIT_LIB_FULL_NAME "${CMAKE_SHARED_MODULE_PREFIX}${CARGOKIT_LIB_NAME}${CMAKE_SHARED_MODULE_SUFFIX}")
|
||||||
|
if (CMAKE_CONFIGURATION_TYPES)
|
||||||
|
set(CARGOKIT_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
|
||||||
|
set(OUTPUT_LIB "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/${CARGOKIT_LIB_FULL_NAME}")
|
||||||
|
else()
|
||||||
|
set(CARGOKIT_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
|
set(OUTPUT_LIB "${CMAKE_CURRENT_BINARY_DIR}/${CARGOKIT_LIB_FULL_NAME}")
|
||||||
|
endif()
|
||||||
|
set(CARGOKIT_TEMP_DIR "${CMAKE_CURRENT_BINARY_DIR}/cargokit_build")
|
||||||
|
|
||||||
|
if (FLUTTER_TARGET_PLATFORM)
|
||||||
|
set(CARGOKIT_TARGET_PLATFORM "${FLUTTER_TARGET_PLATFORM}")
|
||||||
|
else()
|
||||||
|
set(CARGOKIT_TARGET_PLATFORM "windows-x64")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CARGOKIT_ENV
|
||||||
|
"CARGOKIT_CMAKE=${CMAKE_COMMAND}"
|
||||||
|
"CARGOKIT_CONFIGURATION=$<CONFIG>"
|
||||||
|
"CARGOKIT_MANIFEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/${manifest_dir}"
|
||||||
|
"CARGOKIT_TARGET_TEMP_DIR=${CARGOKIT_TEMP_DIR}"
|
||||||
|
"CARGOKIT_OUTPUT_DIR=${CARGOKIT_OUTPUT_DIR}"
|
||||||
|
"CARGOKIT_TARGET_PLATFORM=${CARGOKIT_TARGET_PLATFORM}"
|
||||||
|
"CARGOKIT_TOOL_TEMP_DIR=${CARGOKIT_TEMP_DIR}/tool"
|
||||||
|
"CARGOKIT_ROOT_PROJECT_DIR=${CMAKE_SOURCE_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
set(SCRIPT_EXTENSION ".cmd")
|
||||||
|
set(IMPORT_LIB_EXTENSION ".lib")
|
||||||
|
else()
|
||||||
|
set(SCRIPT_EXTENSION ".sh")
|
||||||
|
set(IMPORT_LIB_EXTENSION "")
|
||||||
|
execute_process(COMMAND chmod +x "${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Using generators in custom command is only supported in CMake 3.20+
|
||||||
|
if (CMAKE_CONFIGURATION_TYPES AND ${CMAKE_VERSION} VERSION_LESS "3.20.0")
|
||||||
|
foreach(CONFIG IN LISTS CMAKE_CONFIGURATION_TYPES)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/${CONFIG}/${CARGOKIT_LIB_FULL_NAME}"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/_phony_"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E env ${CARGOKIT_ENV}
|
||||||
|
"${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}" build-cmake
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
else()
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT
|
||||||
|
${OUTPUT_LIB}
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/_phony_"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E env ${CARGOKIT_ENV}
|
||||||
|
"${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}" build-cmake
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/_phony_" PROPERTIES SYMBOLIC TRUE)
|
||||||
|
|
||||||
|
if (TARGET ${target})
|
||||||
|
# If we have actual cmake target provided create target and make existing
|
||||||
|
# target depend on it
|
||||||
|
add_custom_target("${target}_cargokit" DEPENDS ${OUTPUT_LIB})
|
||||||
|
add_dependencies("${target}" "${target}_cargokit")
|
||||||
|
target_link_libraries("${target}" PRIVATE "${OUTPUT_LIB}${IMPORT_LIB_EXTENSION}")
|
||||||
|
if(WIN32)
|
||||||
|
target_link_options(${target} PRIVATE "/INCLUDE:${any_symbol_name}")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
# Otherwise (FFI) just use ALL to force building always
|
||||||
|
add_custom_target("${target}_cargokit" ALL DEPENDS ${OUTPUT_LIB})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Allow adding the output library to plugin bundled libraries
|
||||||
|
set("${target}_cargokit_lib" ${OUTPUT_LIB} PARENT_SCOPE)
|
||||||
|
|
||||||
|
endfunction()
|
||||||
34
useragent/rust_builder/cargokit/cmake/resolve_symlinks.ps1
Normal file
34
useragent/rust_builder/cargokit/cmake/resolve_symlinks.ps1
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
function Resolve-Symlinks {
|
||||||
|
[CmdletBinding()]
|
||||||
|
[OutputType([string])]
|
||||||
|
param(
|
||||||
|
[Parameter(Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
|
||||||
|
[string] $Path
|
||||||
|
)
|
||||||
|
|
||||||
|
[string] $separator = '/'
|
||||||
|
[string[]] $parts = $Path.Split($separator)
|
||||||
|
|
||||||
|
[string] $realPath = ''
|
||||||
|
foreach ($part in $parts) {
|
||||||
|
if ($realPath -and !$realPath.EndsWith($separator)) {
|
||||||
|
$realPath += $separator
|
||||||
|
}
|
||||||
|
|
||||||
|
$realPath += $part.Replace('\', '/')
|
||||||
|
|
||||||
|
# The slash is important when using Get-Item on Drive letters in pwsh.
|
||||||
|
if (-not($realPath.Contains($separator)) -and $realPath.EndsWith(':')) {
|
||||||
|
$realPath += '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = Get-Item $realPath
|
||||||
|
if ($item.LinkTarget) {
|
||||||
|
$realPath = $item.LinkTarget.Replace('\', '/')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$realPath
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = Resolve-Symlinks -Path $args[0]
|
||||||
|
Write-Host $path
|
||||||
184
useragent/rust_builder/cargokit/gradle/plugin.gradle
Normal file
184
useragent/rust_builder/cargokit/gradle/plugin.gradle
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
/// This is copied from Cargokit (which is the official way to use it currently)
|
||||||
|
/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin
|
||||||
|
|
||||||
|
import java.nio.file.Paths
|
||||||
|
import org.apache.tools.ant.taskdefs.condition.Os
|
||||||
|
|
||||||
|
CargoKitPlugin.file = buildscript.sourceFile
|
||||||
|
|
||||||
|
apply plugin: CargoKitPlugin
|
||||||
|
|
||||||
|
class CargoKitExtension {
|
||||||
|
String manifestDir; // Relative path to folder containing Cargo.toml
|
||||||
|
String libname; // Library name within Cargo.toml. Must be a cdylib
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class CargoKitBuildTask extends DefaultTask {
|
||||||
|
|
||||||
|
@Input
|
||||||
|
String buildMode
|
||||||
|
|
||||||
|
@Input
|
||||||
|
String buildDir
|
||||||
|
|
||||||
|
@Input
|
||||||
|
String outputDir
|
||||||
|
|
||||||
|
@Input
|
||||||
|
String ndkVersion
|
||||||
|
|
||||||
|
@Input
|
||||||
|
String sdkDirectory
|
||||||
|
|
||||||
|
@Input
|
||||||
|
int compileSdkVersion;
|
||||||
|
|
||||||
|
@Input
|
||||||
|
int minSdkVersion;
|
||||||
|
|
||||||
|
@Input
|
||||||
|
String pluginFile
|
||||||
|
|
||||||
|
@Input
|
||||||
|
List<String> targetPlatforms
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
def build() {
|
||||||
|
if (project.cargokit.manifestDir == null) {
|
||||||
|
throw new GradleException("Property 'manifestDir' must be set on cargokit extension");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (project.cargokit.libname == null) {
|
||||||
|
throw new GradleException("Property 'libname' must be set on cargokit extension");
|
||||||
|
}
|
||||||
|
|
||||||
|
def executableName = Os.isFamily(Os.FAMILY_WINDOWS) ? "run_build_tool.cmd" : "run_build_tool.sh"
|
||||||
|
def path = Paths.get(new File(pluginFile).parent, "..", executableName);
|
||||||
|
|
||||||
|
def manifestDir = Paths.get(project.buildscript.sourceFile.parent, project.cargokit.manifestDir)
|
||||||
|
|
||||||
|
def rootProjectDir = project.rootProject.projectDir
|
||||||
|
|
||||||
|
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||||
|
project.exec {
|
||||||
|
commandLine 'chmod', '+x', path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
project.exec {
|
||||||
|
executable path
|
||||||
|
args "build-gradle"
|
||||||
|
environment "CARGOKIT_ROOT_PROJECT_DIR", rootProjectDir
|
||||||
|
environment "CARGOKIT_TOOL_TEMP_DIR", "${buildDir}/build_tool"
|
||||||
|
environment "CARGOKIT_MANIFEST_DIR", manifestDir
|
||||||
|
environment "CARGOKIT_CONFIGURATION", buildMode
|
||||||
|
environment "CARGOKIT_TARGET_TEMP_DIR", buildDir
|
||||||
|
environment "CARGOKIT_OUTPUT_DIR", outputDir
|
||||||
|
environment "CARGOKIT_NDK_VERSION", ndkVersion
|
||||||
|
environment "CARGOKIT_SDK_DIR", sdkDirectory
|
||||||
|
environment "CARGOKIT_COMPILE_SDK_VERSION", compileSdkVersion
|
||||||
|
environment "CARGOKIT_MIN_SDK_VERSION", minSdkVersion
|
||||||
|
environment "CARGOKIT_TARGET_PLATFORMS", targetPlatforms.join(",")
|
||||||
|
environment "CARGOKIT_JAVA_HOME", System.properties['java.home']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CargoKitPlugin implements Plugin<Project> {
|
||||||
|
|
||||||
|
static String file;
|
||||||
|
|
||||||
|
private Plugin findFlutterPlugin(Project rootProject) {
|
||||||
|
_findFlutterPlugin(rootProject.childProjects)
|
||||||
|
}
|
||||||
|
|
||||||
|
private Plugin _findFlutterPlugin(Map projects) {
|
||||||
|
for (project in projects) {
|
||||||
|
for (plugin in project.value.getPlugins()) {
|
||||||
|
if (plugin.class.name == "com.flutter.gradle.FlutterPlugin" || plugin.class.name == "FlutterPlugin") {
|
||||||
|
return plugin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def plugin = _findFlutterPlugin(project.value.childProjects);
|
||||||
|
if (plugin != null) {
|
||||||
|
return plugin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void apply(Project project) {
|
||||||
|
def plugin = findFlutterPlugin(project.rootProject);
|
||||||
|
|
||||||
|
project.extensions.create("cargokit", CargoKitExtension)
|
||||||
|
|
||||||
|
if (plugin == null) {
|
||||||
|
print("Flutter plugin not found, CargoKit plugin will not be applied.")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
def cargoBuildDir = "${project.buildDir}/build"
|
||||||
|
|
||||||
|
// Determine if the project is an application or library
|
||||||
|
def isApplication = plugin.project.plugins.hasPlugin('com.android.application')
|
||||||
|
def variants = isApplication ? plugin.project.android.applicationVariants : plugin.project.android.libraryVariants
|
||||||
|
|
||||||
|
variants.all { variant ->
|
||||||
|
|
||||||
|
final buildType = variant.buildType.name
|
||||||
|
|
||||||
|
def cargoOutputDir = "${project.buildDir}/jniLibs/${buildType}";
|
||||||
|
def jniLibs = project.android.sourceSets.maybeCreate(buildType).jniLibs;
|
||||||
|
jniLibs.srcDir(new File(cargoOutputDir))
|
||||||
|
|
||||||
|
def List<String> platforms
|
||||||
|
try {
|
||||||
|
platforms = com.flutter.gradle.FlutterPluginUtils.getTargetPlatforms(project).collect()
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
platforms = plugin.getTargetPlatforms().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same thing addFlutterDependencies does in flutter.gradle
|
||||||
|
if (buildType == "debug") {
|
||||||
|
platforms.add("android-x86")
|
||||||
|
platforms.add("android-x64")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The task name depends on plugin properties, which are not available
|
||||||
|
// at this point
|
||||||
|
project.getGradle().afterProject {
|
||||||
|
def taskName = "cargokitCargoBuild${project.cargokit.libname.capitalize()}${buildType.capitalize()}";
|
||||||
|
|
||||||
|
if (project.tasks.findByName(taskName)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.project.android.ndkVersion == null) {
|
||||||
|
throw new GradleException("Please set 'android.ndkVersion' in 'app/build.gradle'.")
|
||||||
|
}
|
||||||
|
|
||||||
|
def task = project.tasks.create(taskName, CargoKitBuildTask.class) {
|
||||||
|
buildMode = variant.buildType.name
|
||||||
|
buildDir = cargoBuildDir
|
||||||
|
outputDir = cargoOutputDir
|
||||||
|
ndkVersion = plugin.project.android.ndkVersion
|
||||||
|
sdkDirectory = plugin.project.android.sdkDirectory
|
||||||
|
minSdkVersion = plugin.project.android.defaultConfig.minSdkVersion.apiLevel as int
|
||||||
|
compileSdkVersion = plugin.project.android.compileSdkVersion.substring(8) as int
|
||||||
|
targetPlatforms = platforms
|
||||||
|
pluginFile = CargoKitPlugin.file
|
||||||
|
}
|
||||||
|
def onTask = { newTask ->
|
||||||
|
if (newTask.name == "merge${buildType.capitalize()}NativeLibs") {
|
||||||
|
newTask.dependsOn task
|
||||||
|
// Fix gradle 7.4.2 not picking up JNI library changes
|
||||||
|
newTask.outputs.upToDateWhen { false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
project.tasks.each onTask
|
||||||
|
project.tasks.whenTaskAdded onTask
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
91
useragent/rust_builder/cargokit/run_build_tool.cmd
Executable file
91
useragent/rust_builder/cargokit/run_build_tool.cmd
Executable file
@@ -0,0 +1,91 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
setlocal ENABLEDELAYEDEXPANSION
|
||||||
|
|
||||||
|
SET BASEDIR=%~dp0
|
||||||
|
|
||||||
|
if not exist "%CARGOKIT_TOOL_TEMP_DIR%" (
|
||||||
|
mkdir "%CARGOKIT_TOOL_TEMP_DIR%"
|
||||||
|
)
|
||||||
|
cd /D "%CARGOKIT_TOOL_TEMP_DIR%"
|
||||||
|
|
||||||
|
SET BUILD_TOOL_PKG_DIR=%BASEDIR%build_tool
|
||||||
|
SET DART=%FLUTTER_ROOT%\bin\cache\dart-sdk\bin\dart
|
||||||
|
|
||||||
|
set BUILD_TOOL_PKG_DIR_POSIX=%BUILD_TOOL_PKG_DIR:\=/%
|
||||||
|
|
||||||
|
(
|
||||||
|
echo name: build_tool_runner
|
||||||
|
echo version: 1.0.0
|
||||||
|
echo publish_to: none
|
||||||
|
echo.
|
||||||
|
echo environment:
|
||||||
|
echo sdk: '^>=3.0.0 ^<4.0.0'
|
||||||
|
echo.
|
||||||
|
echo dependencies:
|
||||||
|
echo build_tool:
|
||||||
|
echo path: %BUILD_TOOL_PKG_DIR_POSIX%
|
||||||
|
) >pubspec.yaml
|
||||||
|
|
||||||
|
if not exist bin (
|
||||||
|
mkdir bin
|
||||||
|
)
|
||||||
|
|
||||||
|
(
|
||||||
|
echo import 'package:build_tool/build_tool.dart' as build_tool;
|
||||||
|
echo void main^(List^<String^> args^) ^{
|
||||||
|
echo build_tool.runMain^(args^);
|
||||||
|
echo ^}
|
||||||
|
) >bin\build_tool_runner.dart
|
||||||
|
|
||||||
|
SET PRECOMPILED=bin\build_tool_runner.dill
|
||||||
|
|
||||||
|
REM To detect changes in package we compare output of DIR /s (recursive)
|
||||||
|
set PREV_PACKAGE_INFO=.dart_tool\package_info.prev
|
||||||
|
set CUR_PACKAGE_INFO=.dart_tool\package_info.cur
|
||||||
|
|
||||||
|
DIR "%BUILD_TOOL_PKG_DIR%" /s > "%CUR_PACKAGE_INFO%_orig"
|
||||||
|
|
||||||
|
REM Last line in dir output is free space on harddrive. That is bound to
|
||||||
|
REM change between invocation so we need to remove it
|
||||||
|
(
|
||||||
|
Set "Line="
|
||||||
|
For /F "UseBackQ Delims=" %%A In ("%CUR_PACKAGE_INFO%_orig") Do (
|
||||||
|
SetLocal EnableDelayedExpansion
|
||||||
|
If Defined Line Echo !Line!
|
||||||
|
EndLocal
|
||||||
|
Set "Line=%%A")
|
||||||
|
) >"%CUR_PACKAGE_INFO%"
|
||||||
|
DEL "%CUR_PACKAGE_INFO%_orig"
|
||||||
|
|
||||||
|
REM Compare current directory listing with previous
|
||||||
|
FC /B "%CUR_PACKAGE_INFO%" "%PREV_PACKAGE_INFO%" > nul 2>&1
|
||||||
|
|
||||||
|
If %ERRORLEVEL% neq 0 (
|
||||||
|
REM Changed - copy current to previous and remove precompiled kernel
|
||||||
|
if exist "%PREV_PACKAGE_INFO%" (
|
||||||
|
DEL "%PREV_PACKAGE_INFO%"
|
||||||
|
)
|
||||||
|
MOVE /Y "%CUR_PACKAGE_INFO%" "%PREV_PACKAGE_INFO%"
|
||||||
|
if exist "%PRECOMPILED%" (
|
||||||
|
DEL "%PRECOMPILED%"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
REM There is no CUR_PACKAGE_INFO it was renamed in previous step to %PREV_PACKAGE_INFO%
|
||||||
|
REM which means we need to do pub get and precompile
|
||||||
|
if not exist "%PRECOMPILED%" (
|
||||||
|
echo Running pub get in "%cd%"
|
||||||
|
"%DART%" pub get --no-precompile
|
||||||
|
"%DART%" compile kernel bin/build_tool_runner.dart
|
||||||
|
)
|
||||||
|
|
||||||
|
"%DART%" "%PRECOMPILED%" %*
|
||||||
|
|
||||||
|
REM 253 means invalid snapshot version.
|
||||||
|
If %ERRORLEVEL% equ 253 (
|
||||||
|
"%DART%" pub get --no-precompile
|
||||||
|
"%DART%" compile kernel bin/build_tool_runner.dart
|
||||||
|
"%DART%" "%PRECOMPILED%" %*
|
||||||
|
)
|
||||||
99
useragent/rust_builder/cargokit/run_build_tool.sh
Executable file
99
useragent/rust_builder/cargokit/run_build_tool.sh
Executable file
@@ -0,0 +1,99 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
BASEDIR=$(dirname "$0")
|
||||||
|
|
||||||
|
mkdir -p "$CARGOKIT_TOOL_TEMP_DIR"
|
||||||
|
|
||||||
|
cd "$CARGOKIT_TOOL_TEMP_DIR"
|
||||||
|
|
||||||
|
# Write a very simple bin package in temp folder that depends on build_tool package
|
||||||
|
# from Cargokit. This is done to ensure that we don't pollute Cargokit folder
|
||||||
|
# with .dart_tool contents.
|
||||||
|
|
||||||
|
BUILD_TOOL_PKG_DIR="$BASEDIR/build_tool"
|
||||||
|
|
||||||
|
if [[ -z $FLUTTER_ROOT ]]; then # not defined
|
||||||
|
DART=dart
|
||||||
|
else
|
||||||
|
DART="$FLUTTER_ROOT/bin/cache/dart-sdk/bin/dart"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat << EOF > "pubspec.yaml"
|
||||||
|
name: build_tool_runner
|
||||||
|
version: 1.0.0
|
||||||
|
publish_to: none
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: '>=3.0.0 <4.0.0'
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
build_tool:
|
||||||
|
path: "$BUILD_TOOL_PKG_DIR"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
mkdir -p "bin"
|
||||||
|
|
||||||
|
cat << EOF > "bin/build_tool_runner.dart"
|
||||||
|
import 'package:build_tool/build_tool.dart' as build_tool;
|
||||||
|
void main(List<String> args) {
|
||||||
|
build_tool.runMain(args);
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Create alias for `shasum` if it does not exist and `sha1sum` exists
|
||||||
|
if ! [ -x "$(command -v shasum)" ] && [ -x "$(command -v sha1sum)" ]; then
|
||||||
|
shopt -s expand_aliases
|
||||||
|
alias shasum="sha1sum"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Dart run will not cache any package that has a path dependency, which
|
||||||
|
# is the case for our build_tool_runner. So instead we precompile the package
|
||||||
|
# ourselves.
|
||||||
|
# To invalidate the cached kernel we use the hash of ls -LR of the build_tool
|
||||||
|
# package directory. This should be good enough, as the build_tool package
|
||||||
|
# itself is not meant to have any path dependencies.
|
||||||
|
|
||||||
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
|
PACKAGE_HASH=$(ls -lTR "$BUILD_TOOL_PKG_DIR" | shasum)
|
||||||
|
else
|
||||||
|
PACKAGE_HASH=$(ls -lR --full-time "$BUILD_TOOL_PKG_DIR" | shasum)
|
||||||
|
fi
|
||||||
|
|
||||||
|
PACKAGE_HASH_FILE=".package_hash"
|
||||||
|
|
||||||
|
if [ -f "$PACKAGE_HASH_FILE" ]; then
|
||||||
|
EXISTING_HASH=$(cat "$PACKAGE_HASH_FILE")
|
||||||
|
if [ "$PACKAGE_HASH" != "$EXISTING_HASH" ]; then
|
||||||
|
rm "$PACKAGE_HASH_FILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run pub get if needed.
|
||||||
|
if [ ! -f "$PACKAGE_HASH_FILE" ]; then
|
||||||
|
"$DART" pub get --no-precompile
|
||||||
|
"$DART" compile kernel bin/build_tool_runner.dart
|
||||||
|
echo "$PACKAGE_HASH" > "$PACKAGE_HASH_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Rebuild the tool if it was deleted by Android Studio
|
||||||
|
if [ ! -f "bin/build_tool_runner.dill" ]; then
|
||||||
|
"$DART" compile kernel bin/build_tool_runner.dart
|
||||||
|
fi
|
||||||
|
|
||||||
|
set +e
|
||||||
|
|
||||||
|
"$DART" bin/build_tool_runner.dill "$@"
|
||||||
|
|
||||||
|
exit_code=$?
|
||||||
|
|
||||||
|
# 253 means invalid snapshot version.
|
||||||
|
if [ $exit_code == 253 ]; then
|
||||||
|
"$DART" pub get --no-precompile
|
||||||
|
"$DART" compile kernel bin/build_tool_runner.dart
|
||||||
|
"$DART" bin/build_tool_runner.dill "$@"
|
||||||
|
exit_code=$?
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit $exit_code
|
||||||
1
useragent/rust_builder/ios/Classes/dummy_file.c
Normal file
1
useragent/rust_builder/ios/Classes/dummy_file.c
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// This is an empty file to force CocoaPods to create a framework.
|
||||||
45
useragent/rust_builder/ios/rust_lib_arbiter.podspec
Normal file
45
useragent/rust_builder/ios/rust_lib_arbiter.podspec
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#
|
||||||
|
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
|
||||||
|
# Run `pod lib lint rust_lib_arbiter.podspec` to validate before publishing.
|
||||||
|
#
|
||||||
|
Pod::Spec.new do |s|
|
||||||
|
s.name = 'rust_lib_arbiter'
|
||||||
|
s.version = '0.0.1'
|
||||||
|
s.summary = 'A new Flutter FFI plugin project.'
|
||||||
|
s.description = <<-DESC
|
||||||
|
A new Flutter FFI plugin project.
|
||||||
|
DESC
|
||||||
|
s.homepage = 'http://example.com'
|
||||||
|
s.license = { :file => '../LICENSE' }
|
||||||
|
s.author = { 'Your Company' => 'email@example.com' }
|
||||||
|
|
||||||
|
# This will ensure the source files in Classes/ are included in the native
|
||||||
|
# builds of apps using this FFI plugin. Podspec does not support relative
|
||||||
|
# paths, so Classes contains a forwarder C file that relatively imports
|
||||||
|
# `../src/*` so that the C sources can be shared among all target platforms.
|
||||||
|
s.source = { :path => '.' }
|
||||||
|
s.source_files = 'Classes/**/*'
|
||||||
|
s.dependency 'Flutter'
|
||||||
|
s.platform = :ios, '11.0'
|
||||||
|
|
||||||
|
# Flutter.framework does not contain a i386 slice.
|
||||||
|
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
|
||||||
|
s.swift_version = '5.0'
|
||||||
|
|
||||||
|
s.script_phase = {
|
||||||
|
:name => 'Build Rust library',
|
||||||
|
# First argument is relative path to the `rust` folder, second is name of rust library
|
||||||
|
:script => 'sh "$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh" ../../rust rust_lib_arbiter',
|
||||||
|
:execution_position => :before_compile,
|
||||||
|
:input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'],
|
||||||
|
# Let XCode know that the static library referenced in -force_load below is
|
||||||
|
# created by this build step.
|
||||||
|
:output_files => ["${BUILT_PRODUCTS_DIR}/librust_lib_arbiter.a"],
|
||||||
|
}
|
||||||
|
s.pod_target_xcconfig = {
|
||||||
|
'DEFINES_MODULE' => 'YES',
|
||||||
|
# Flutter.framework does not contain a i386 slice.
|
||||||
|
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386',
|
||||||
|
'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib_arbiter.a',
|
||||||
|
}
|
||||||
|
end
|
||||||
19
useragent/rust_builder/linux/CMakeLists.txt
Normal file
19
useragent/rust_builder/linux/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# The Flutter tooling requires that developers have CMake 3.10 or later
|
||||||
|
# installed. You should not increase this version, as doing so will cause
|
||||||
|
# the plugin to fail to compile for some customers of the plugin.
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
# Project-level configuration.
|
||||||
|
set(PROJECT_NAME "rust_lib_arbiter")
|
||||||
|
project(${PROJECT_NAME} LANGUAGES CXX)
|
||||||
|
|
||||||
|
include("../cargokit/cmake/cargokit.cmake")
|
||||||
|
apply_cargokit(${PROJECT_NAME} ../../rust rust_lib_arbiter "")
|
||||||
|
|
||||||
|
# List of absolute paths to libraries that should be bundled with the plugin.
|
||||||
|
# This list could contain prebuilt libraries, or libraries created by an
|
||||||
|
# external build triggered from this build file.
|
||||||
|
set(rust_lib_arbiter_bundled_libraries
|
||||||
|
"${${PROJECT_NAME}_cargokit_lib}"
|
||||||
|
PARENT_SCOPE
|
||||||
|
)
|
||||||
1
useragent/rust_builder/macos/Classes/dummy_file.c
Normal file
1
useragent/rust_builder/macos/Classes/dummy_file.c
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// This is an empty file to force CocoaPods to create a framework.
|
||||||
44
useragent/rust_builder/macos/rust_lib_arbiter.podspec
Normal file
44
useragent/rust_builder/macos/rust_lib_arbiter.podspec
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#
|
||||||
|
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
|
||||||
|
# Run `pod lib lint rust_lib_arbiter.podspec` to validate before publishing.
|
||||||
|
#
|
||||||
|
Pod::Spec.new do |s|
|
||||||
|
s.name = 'rust_lib_arbiter'
|
||||||
|
s.version = '0.0.1'
|
||||||
|
s.summary = 'A new Flutter FFI plugin project.'
|
||||||
|
s.description = <<-DESC
|
||||||
|
A new Flutter FFI plugin project.
|
||||||
|
DESC
|
||||||
|
s.homepage = 'http://example.com'
|
||||||
|
s.license = { :file => '../LICENSE' }
|
||||||
|
s.author = { 'Your Company' => 'email@example.com' }
|
||||||
|
|
||||||
|
# This will ensure the source files in Classes/ are included in the native
|
||||||
|
# builds of apps using this FFI plugin. Podspec does not support relative
|
||||||
|
# paths, so Classes contains a forwarder C file that relatively imports
|
||||||
|
# `../src/*` so that the C sources can be shared among all target platforms.
|
||||||
|
s.source = { :path => '.' }
|
||||||
|
s.source_files = 'Classes/**/*'
|
||||||
|
s.dependency 'FlutterMacOS'
|
||||||
|
|
||||||
|
s.platform = :osx, '10.11'
|
||||||
|
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
|
||||||
|
s.swift_version = '5.0'
|
||||||
|
|
||||||
|
s.script_phase = {
|
||||||
|
:name => 'Build Rust library',
|
||||||
|
# First argument is relative path to the `rust` folder, second is name of rust library
|
||||||
|
:script => 'sh "$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh" ../../rust rust_lib_arbiter',
|
||||||
|
:execution_position => :before_compile,
|
||||||
|
:input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'],
|
||||||
|
# Let XCode know that the static library referenced in -force_load below is
|
||||||
|
# created by this build step.
|
||||||
|
:output_files => ["${BUILT_PRODUCTS_DIR}/librust_lib_arbiter.a"],
|
||||||
|
}
|
||||||
|
s.pod_target_xcconfig = {
|
||||||
|
'DEFINES_MODULE' => 'YES',
|
||||||
|
# Flutter.framework does not contain a i386 slice.
|
||||||
|
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386',
|
||||||
|
'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib_arbiter.a',
|
||||||
|
}
|
||||||
|
end
|
||||||
34
useragent/rust_builder/pubspec.yaml
Normal file
34
useragent/rust_builder/pubspec.yaml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
name: rust_lib_arbiter
|
||||||
|
description: "Utility to build Rust code"
|
||||||
|
version: 0.0.1
|
||||||
|
publish_to: none
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: '>=3.3.0 <4.0.0'
|
||||||
|
flutter: '>=3.3.0'
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
plugin_platform_interface: ^2.0.2
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
ffi: ^2.0.2
|
||||||
|
ffigen: ^11.0.0
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
flutter_lints: ^2.0.0
|
||||||
|
|
||||||
|
flutter:
|
||||||
|
plugin:
|
||||||
|
platforms:
|
||||||
|
android:
|
||||||
|
ffiPlugin: true
|
||||||
|
ios:
|
||||||
|
ffiPlugin: true
|
||||||
|
linux:
|
||||||
|
ffiPlugin: true
|
||||||
|
macos:
|
||||||
|
ffiPlugin: true
|
||||||
|
windows:
|
||||||
|
ffiPlugin: true
|
||||||
17
useragent/rust_builder/windows/.gitignore
vendored
Normal file
17
useragent/rust_builder/windows/.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
flutter/
|
||||||
|
|
||||||
|
# Visual Studio user-specific files.
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# Visual Studio build-related files.
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!*.[Cc]ache/
|
||||||
20
useragent/rust_builder/windows/CMakeLists.txt
Normal file
20
useragent/rust_builder/windows/CMakeLists.txt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# The Flutter tooling requires that developers have a version of Visual Studio
|
||||||
|
# installed that includes CMake 3.14 or later. You should not increase this
|
||||||
|
# version, as doing so will cause the plugin to fail to compile for some
|
||||||
|
# customers of the plugin.
|
||||||
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
|
||||||
|
# Project-level configuration.
|
||||||
|
set(PROJECT_NAME "rust_lib_arbiter")
|
||||||
|
project(${PROJECT_NAME} LANGUAGES CXX)
|
||||||
|
|
||||||
|
include("../cargokit/cmake/cargokit.cmake")
|
||||||
|
apply_cargokit(${PROJECT_NAME} ../../../../../../rust rust_lib_arbiter "")
|
||||||
|
|
||||||
|
# List of absolute paths to libraries that should be bundled with the plugin.
|
||||||
|
# This list could contain prebuilt libraries, or libraries created by an
|
||||||
|
# external build triggered from this build file.
|
||||||
|
set(rust_lib_arbiter_bundled_libraries
|
||||||
|
"${${PROJECT_NAME}_cargokit_lib}"
|
||||||
|
PARENT_SCOPE
|
||||||
|
)
|
||||||
3
useragent/test_driver/integration_test.dart
Normal file
3
useragent/test_driver/integration_test.dart
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import 'package:integration_test/integration_test_driver.dart';
|
||||||
|
|
||||||
|
Future<void> main() => integrationDriver();
|
||||||
@@ -11,6 +11,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
rust_lib_arbiter
|
||||||
)
|
)
|
||||||
|
|
||||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||||
|
|||||||
Reference in New Issue
Block a user