Merge branch 'veilidchat-work' into 'main'

0.1.7 release

See merge request veilid/veilid!103
This commit is contained in:
Christien Rioux 2023-07-30 21:23:27 +00:00
commit da76bc9fee
21 changed files with 1341 additions and 1573 deletions

View File

@ -1,3 +1,10 @@
**Changes in Veilid 0.1.7**
- Fix for connection table crash
- Fix for incorrect set_dht_value return value
- Python test updates
- Various VeilidChat-prompted veilid-flutter updates
**Changes in Veilid 0.1.6**
- Fix for 'find_node' too many nodes returned issue

View File

@ -177,10 +177,10 @@ impl ConnectionTable {
// then drop the least recently used connection
let mut out_conn = None;
if inner.conn_by_id[protocol_index].len() > inner.max_connections[protocol_index] {
if let Some((lruk, lru_conn)) = inner.conn_by_id[protocol_index].remove_lru() {
if let Some((lruk, lru_conn)) = inner.conn_by_id[protocol_index].peek_lru() {
let lruk = *lruk;
log_net!(debug "connection lru out: {:?}", lru_conn);
out_conn = Some(lru_conn);
Self::remove_connection_records(&mut *inner, lruk);
out_conn = Some(Self::remove_connection_records(&mut *inner, lruk));
}
}

View File

@ -347,8 +347,9 @@ impl StorageManager {
if last_signed_value_data.value_data().data() == &data
&& last_signed_value_data.value_data().writer() == &writer.key
{
// Data and writer is the name, nothing is changing, just return the same ValueData
return Ok(Some(last_signed_value_data.into_value_data()));
// Data and writer is the same, nothing is changing,
// just return that we set it, but no network activity needs to happen
return Ok(None);
}
let seq = last_signed_value_data.value_data().seq();
ValueData::new_with_seq(seq + 1, data, writer.key)

View File

@ -0,0 +1 @@
Ray says "Go SubSix!"

View File

@ -1,5 +1,11 @@
include: package:flutter_lints/flutter.yaml
include: package:lint_hard/all.yaml
analyzer:
errors:
invalid_annotation_target: ignore
exclude:
- '**/*.g.dart'
- '**/*.freezed.dart'
linter:
rules:
avoid_positional_boolean_parameters: false

View File

@ -3,3 +3,7 @@ include: package:flutter_lints/flutter.yaml
analyzer:
errors:
invalid_annotation_target: ignore
linter:
rules:
- unawaited_futures

View File

@ -1,10 +1,11 @@
import 'dart:io';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:system_info2/system_info2.dart' as sysinfo;
import 'package:system_info_plus/system_info_plus.dart';
import 'veilid.dart';
const int megaByte = 1024 * 1024;
@ -57,136 +58,129 @@ int getRemoteMaxStorageSpaceMb() {
return 256;
}
Future<VeilidConfig> getDefaultVeilidConfig(String programName) async {
return VeilidConfig(
programName: programName,
namespace: "",
capabilities: const VeilidConfigCapabilities(disable: []),
protectedStore: const VeilidConfigProtectedStore(
allowInsecureFallback: false,
alwaysUseInsecureStorage: false,
directory: "",
delete: false,
deviceEncryptionKeyPassword: "",
newDeviceEncryptionKeyPassword: null,
),
tableStore: VeilidConfigTableStore(
directory: kIsWeb
? ""
: p.join((await getApplicationSupportDirectory()).absolute.path,
"table_store"),
delete: false,
),
blockStore: VeilidConfigBlockStore(
directory: kIsWeb
? ""
: p.join((await getApplicationSupportDirectory()).absolute.path,
"block_store"),
delete: false,
),
network: VeilidConfigNetwork(
connectionInitialTimeoutMs: 2000,
connectionInactivityTimeoutMs: 60000,
maxConnectionsPerIp4: 32,
maxConnectionsPerIp6Prefix: 32,
maxConnectionsPerIp6PrefixSize: 56,
maxConnectionFrequencyPerMin: 128,
clientWhitelistTimeoutMs: 300000,
reverseConnectionReceiptTimeMs: 5000,
holePunchReceiptTimeMs: 5000,
routingTable: const VeilidConfigRoutingTable(
nodeId: [],
nodeIdSecret: [],
bootstrap: kIsWeb
? ["ws://bootstrap.veilid.net:5150/ws"]
: ["bootstrap.veilid.net"],
limitOverAttached: 64,
limitFullyAttached: 32,
limitAttachedStrong: 16,
limitAttachedGood: 8,
limitAttachedWeak: 4,
Future<VeilidConfig> getDefaultVeilidConfig(String programName) async =>
VeilidConfig(
programName: programName,
namespace: '',
capabilities: const VeilidConfigCapabilities(disable: []),
protectedStore: const VeilidConfigProtectedStore(
allowInsecureFallback: false,
alwaysUseInsecureStorage: false,
directory: '',
delete: false,
deviceEncryptionKeyPassword: '',
),
rpc: const VeilidConfigRPC(
concurrency: 0,
queueSize: 1024,
maxTimestampBehindMs: 10000,
maxTimestampAheadMs: 10000,
timeoutMs: 5000,
maxRouteHopCount: 4,
defaultRouteHopCount: 1,
tableStore: VeilidConfigTableStore(
directory: kIsWeb
? ''
: p.join((await getApplicationSupportDirectory()).absolute.path,
'table_store'),
delete: false,
),
dht: VeilidConfigDHT(
resolveNodeTimeoutMs: 10000,
resolveNodeCount: 20,
resolveNodeFanout: 3,
maxFindNodeCount: 20,
getValueTimeoutMs: 10000,
getValueCount: 20,
getValueFanout: 3,
setValueTimeoutMs: 10000,
setValueCount: 20,
setValueFanout: 5,
minPeerCount: 20,
minPeerRefreshTimeMs: 60000,
validateDialInfoReceiptTimeMs: 2000,
localSubkeyCacheSize: getLocalSubkeyCacheSize(),
localMaxSubkeyCacheMemoryMb: await getLocalMaxSubkeyCacheMemoryMb(),
remoteSubkeyCacheSize: getRemoteSubkeyCacheSize(),
remoteMaxRecords: getRemoteMaxRecords(),
remoteMaxSubkeyCacheMemoryMb: await getRemoteMaxSubkeyCacheMemoryMb(),
remoteMaxStorageSpaceMb: getRemoteMaxStorageSpaceMb()),
upnp: true,
detectAddressChanges: true,
restrictedNatRetries: 0,
tls: const VeilidConfigTLS(
certificatePath: "",
privateKeyPath: "",
blockStore: VeilidConfigBlockStore(
directory: kIsWeb
? ''
: p.join((await getApplicationSupportDirectory()).absolute.path,
'block_store'),
delete: false,
),
network: VeilidConfigNetwork(
connectionInitialTimeoutMs: 2000,
),
application: const VeilidConfigApplication(
https: VeilidConfigHTTPS(
enabled: false,
listenAddress: "",
path: "",
url: null,
connectionInactivityTimeoutMs: 60000,
maxConnectionsPerIp4: 32,
maxConnectionsPerIp6Prefix: 32,
maxConnectionsPerIp6PrefixSize: 56,
maxConnectionFrequencyPerMin: 128,
clientWhitelistTimeoutMs: 300000,
reverseConnectionReceiptTimeMs: 5000,
holePunchReceiptTimeMs: 5000,
routingTable: const VeilidConfigRoutingTable(
nodeId: [],
nodeIdSecret: [],
bootstrap: kIsWeb
? ['ws://bootstrap.veilid.net:5150/ws']
: ['bootstrap.veilid.net'],
limitOverAttached: 64,
limitFullyAttached: 32,
limitAttachedStrong: 16,
limitAttachedGood: 8,
limitAttachedWeak: 4,
),
rpc: const VeilidConfigRPC(
concurrency: 0,
queueSize: 1024,
maxTimestampBehindMs: 10000,
maxTimestampAheadMs: 10000,
timeoutMs: 5000,
maxRouteHopCount: 4,
defaultRouteHopCount: 1,
),
dht: VeilidConfigDHT(
resolveNodeTimeoutMs: 10000,
resolveNodeCount: 20,
resolveNodeFanout: 3,
maxFindNodeCount: 20,
getValueTimeoutMs: 10000,
getValueCount: 20,
getValueFanout: 3,
setValueTimeoutMs: 10000,
setValueCount: 20,
setValueFanout: 5,
minPeerCount: 20,
minPeerRefreshTimeMs: 60000,
validateDialInfoReceiptTimeMs: 2000,
localSubkeyCacheSize: getLocalSubkeyCacheSize(),
localMaxSubkeyCacheMemoryMb: await getLocalMaxSubkeyCacheMemoryMb(),
remoteSubkeyCacheSize: getRemoteSubkeyCacheSize(),
remoteMaxRecords: getRemoteMaxRecords(),
remoteMaxSubkeyCacheMemoryMb:
await getRemoteMaxSubkeyCacheMemoryMb(),
remoteMaxStorageSpaceMb: getRemoteMaxStorageSpaceMb()),
upnp: true,
detectAddressChanges: true,
restrictedNatRetries: 0,
tls: const VeilidConfigTLS(
certificatePath: '',
privateKeyPath: '',
connectionInitialTimeoutMs: 2000,
),
application: const VeilidConfigApplication(
https: VeilidConfigHTTPS(
enabled: false,
listenAddress: '',
path: '',
),
http: VeilidConfigHTTP(
enabled: false,
listenAddress: '',
path: '',
)),
protocol: const VeilidConfigProtocol(
udp: VeilidConfigUDP(
enabled: !kIsWeb,
socketPoolSize: 0,
listenAddress: '',
),
tcp: VeilidConfigTCP(
connect: !kIsWeb,
listen: !kIsWeb,
maxConnections: 32,
listenAddress: '',
),
ws: VeilidConfigWS(
connect: true,
listen: !kIsWeb,
maxConnections: 16,
listenAddress: '',
path: 'ws',
),
wss: VeilidConfigWSS(
connect: true,
listen: false,
maxConnections: 16,
listenAddress: '',
path: 'ws',
),
http: VeilidConfigHTTP(
enabled: false,
listenAddress: "",
path: "",
url: null,
)),
protocol: const VeilidConfigProtocol(
udp: VeilidConfigUDP(
enabled: !kIsWeb,
socketPoolSize: 0,
listenAddress: "",
publicAddress: null,
),
tcp: VeilidConfigTCP(
connect: !kIsWeb,
listen: !kIsWeb,
maxConnections: 32,
listenAddress: "",
publicAddress: null,
),
ws: VeilidConfigWS(
connect: true,
listen: !kIsWeb,
maxConnections: 16,
listenAddress: "",
path: "ws",
url: null,
),
wss: VeilidConfigWSS(
connect: true,
listen: false,
maxConnections: 16,
listenAddress: "",
path: "ws",
url: null,
),
),
),
);
}
);

View File

@ -26,7 +26,7 @@ extension ValidateDFLT on DHTSchemaDFLT {
extension ValidateSMPL on DHTSchemaSMPL {
bool validate() {
final totalsv = members.fold(0, (acc, v) => (acc + v.mCnt)) + oCnt;
final totalsv = members.fold(0, (acc, v) => acc + v.mCnt) + oCnt;
if (totalsv > 65535) {
return false;
}
@ -76,8 +76,8 @@ class DHTRecordDescriptor with _$DHTRecordDescriptor {
const factory DHTRecordDescriptor({
required TypedKey key,
required PublicKey owner,
PublicKey? ownerSecret,
required DHTSchema schema,
PublicKey? ownerSecret,
}) = _DHTRecordDescriptor;
factory DHTRecordDescriptor.fromJson(dynamic json) =>
_$DHTRecordDescriptorFromJson(json as Map<String, dynamic>);
@ -138,9 +138,9 @@ enum Stability {
lowLatency,
reliable;
String toJson() => name.toPascalCase();
factory Stability.fromJson(dynamic j) =>
Stability.values.byName((j as String).toCamelCase());
String toJson() => name.toPascalCase();
}
//////////////////////////////////////
@ -151,76 +151,70 @@ enum Sequencing {
preferOrdered,
ensureOrdered;
String toJson() => name.toPascalCase();
factory Sequencing.fromJson(dynamic j) =>
Sequencing.values.byName((j as String).toCamelCase());
String toJson() => name.toPascalCase();
}
//////////////////////////////////////
/// SafetySelection
@immutable
abstract class SafetySelection extends Equatable {
abstract class SafetySelection {
factory SafetySelection.fromJson(dynamic jsond) {
final json = jsond as Map<String, dynamic>;
if (json.containsKey("Unsafe")) {
if (json.containsKey('Unsafe')) {
return SafetySelectionUnsafe(
sequencing: Sequencing.fromJson(json["Unsafe"]));
} else if (json.containsKey("Safe")) {
return SafetySelectionSafe(safetySpec: SafetySpec.fromJson(json["Safe"]));
sequencing: Sequencing.fromJson(json['Unsafe']));
} else if (json.containsKey('Safe')) {
return SafetySelectionSafe(safetySpec: SafetySpec.fromJson(json['Safe']));
} else {
throw const VeilidAPIExceptionInternal("Invalid SafetySelection");
throw const VeilidAPIExceptionInternal('Invalid SafetySelection');
}
}
Map<String, dynamic> toJson();
}
@immutable
class SafetySelectionUnsafe implements SafetySelection {
class SafetySelectionUnsafe extends Equatable implements SafetySelection {
//
const SafetySelectionUnsafe({
required this.sequencing,
});
final Sequencing sequencing;
@override
List<Object> get props => [sequencing];
@override
bool? get stringify => null;
//
const SafetySelectionUnsafe({
required this.sequencing,
});
@override
Map<String, dynamic> toJson() {
return {'Unsafe': sequencing.toJson()};
}
Map<String, dynamic> toJson() => {'Unsafe': sequencing.toJson()};
}
@immutable
class SafetySelectionSafe implements SafetySelection {
class SafetySelectionSafe extends Equatable implements SafetySelection {
//
const SafetySelectionSafe({
required this.safetySpec,
});
final SafetySpec safetySpec;
@override
List<Object> get props => [safetySpec];
@override
bool? get stringify => null;
//
const SafetySelectionSafe({
required this.safetySpec,
});
@override
Map<String, dynamic> toJson() {
return {'Safe': safetySpec.toJson()};
}
Map<String, dynamic> toJson() => {'Safe': safetySpec.toJson()};
}
/// Options for safety routes (sender privacy)
@freezed
class SafetySpec with _$SafetySpec {
const factory SafetySpec({
String? preferredRoute,
required int hopCount,
required Stability stability,
required Sequencing sequencing,
String? preferredRoute,
}) = _SafetySpec;
factory SafetySpec.fromJson(dynamic json) =>

View File

@ -4,28 +4,26 @@ import 'dart:typed_data';
import 'package:equatable/equatable.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'veilid_stub.dart'
if (dart.library.io) 'veilid_ffi.dart'
if (dart.library.js) 'veilid_js.dart';
//////////////////////////////////////////////////////////
import 'routing_context.dart';
import 'veilid_config.dart';
import 'veilid_crypto.dart';
import 'veilid_table_db.dart';
import 'veilid_state.dart';
import 'veilid_stub.dart'
if (dart.library.io) 'veilid_ffi.dart'
if (dart.library.js) 'veilid_js.dart';
import 'veilid_table_db.dart';
export 'default_config.dart';
export 'routing_context.dart';
export 'veilid_encoding.dart';
export 'veilid.dart';
export 'veilid_api_exception.dart';
export 'veilid_config.dart';
export 'veilid_crypto.dart';
export 'veilid_table_db.dart';
export 'veilid_api_exception.dart';
export 'veilid_encoding.dart';
export 'veilid_state.dart';
export 'veilid.dart';
export 'veilid_table_db.dart';
//////////////////////////////////////
/// JSON Encode Helper
@ -41,57 +39,39 @@ Object? veilidApiToEncodable(Object? value) {
throw UnsupportedError('Cannot convert to JSON: $value');
}
T? Function(dynamic) optFromJson<T>(
T Function(Map<String, dynamic>) jsonConstructor) {
return (dynamic j) {
if (j == null) {
return null;
} else {
return jsonConstructor(j);
}
};
}
List<T> Function(dynamic) jsonListConstructor<T>(
T Function(Map<String, dynamic>) jsonConstructor) {
return (dynamic j) {
return (j as List<Map<String, dynamic>>)
.map((e) => jsonConstructor(e))
.toList();
};
}
T Function(dynamic) jsonConstructor) =>
(dynamic j) => (j as List<dynamic>).map((e) => jsonConstructor(e)).toList();
//////////////////////////////////////
/// VeilidVersion
@immutable
class VeilidVersion extends Equatable {
const VeilidVersion(this.major, this.minor, this.patch);
final int major;
final int minor;
final int patch;
@override
List<Object> get props => [major, minor, patch];
const VeilidVersion(this.major, this.minor, this.patch);
}
//////////////////////////////////////
/// Timestamp
@immutable
class Timestamp extends Equatable {
const Timestamp({required this.value});
factory Timestamp.fromString(String s) => Timestamp(value: BigInt.parse(s));
factory Timestamp.fromJson(dynamic json) =>
Timestamp.fromString(json as String);
final BigInt value;
@override
List<Object> get props => [value];
const Timestamp({required this.value});
@override
String toString() => value.toString();
factory Timestamp.fromString(String s) => Timestamp(value: BigInt.parse(s));
String toJson() => toString();
factory Timestamp.fromJson(dynamic json) =>
Timestamp.fromString(json as String);
TimestampDuration diff(Timestamp other) =>
TimestampDuration(value: value - other.value);
@ -102,20 +82,19 @@ class Timestamp extends Equatable {
@immutable
class TimestampDuration extends Equatable {
const TimestampDuration({required this.value});
factory TimestampDuration.fromString(String s) =>
TimestampDuration(value: BigInt.parse(s));
factory TimestampDuration.fromJson(dynamic json) =>
TimestampDuration.fromString(json as String);
final BigInt value;
@override
List<Object> get props => [value];
const TimestampDuration({required this.value});
@override
String toString() => value.toString();
factory TimestampDuration.fromString(String s) =>
TimestampDuration(value: BigInt.parse(s));
String toJson() => toString();
factory TimestampDuration.fromJson(dynamic json) =>
TimestampDuration.fromString(json as String);
int toMillis() => (value ~/ BigInt.from(1000)).toInt();
BigInt toMicros() => value;

View File

@ -5,70 +5,73 @@ import 'package:freezed_annotation/freezed_annotation.dart';
@immutable
abstract class VeilidAPIException implements Exception {
factory VeilidAPIException.fromJson(dynamic json) {
switch (json["kind"]) {
case "NotInitialized":
factory VeilidAPIException.fromJson(dynamic j) {
final json = j as Map<String, dynamic>;
switch (json['kind']! as String) {
case 'NotInitialized':
{
return VeilidAPIExceptionNotInitialized();
}
case "AlreadyInitialized":
case 'AlreadyInitialized':
{
return VeilidAPIExceptionAlreadyInitialized();
}
case "Timeout":
case 'Timeout':
{
return VeilidAPIExceptionTimeout();
}
case "TryAgain":
case 'TryAgain':
{
return VeilidAPIExceptionTryAgain();
}
case "Shutdown":
case 'Shutdown':
{
return VeilidAPIExceptionShutdown();
}
case "InvalidTarget":
case 'InvalidTarget':
{
return VeilidAPIExceptionInvalidTarget();
}
case "NoConnection":
case 'NoConnection':
{
return VeilidAPIExceptionNoConnection(json["message"]);
return VeilidAPIExceptionNoConnection(json['message']! as String);
}
case "KeyNotFound":
case 'KeyNotFound':
{
return VeilidAPIExceptionKeyNotFound(json["key"]);
return VeilidAPIExceptionKeyNotFound(json['key']! as String);
}
case "Internal":
case 'Internal':
{
return VeilidAPIExceptionInternal(json["message"]);
return VeilidAPIExceptionInternal(json['message']! as String);
}
case "Unimplemented":
case 'Unimplemented':
{
return VeilidAPIExceptionUnimplemented(json["unimplemented"]);
return VeilidAPIExceptionUnimplemented(
json['unimplemented']! as String);
}
case "ParseError":
case 'ParseError':
{
return VeilidAPIExceptionParseError(json["message"], json["value"]);
return VeilidAPIExceptionParseError(
json['message']! as String, json['value']! as String);
}
case "InvalidArgument":
case 'InvalidArgument':
{
return VeilidAPIExceptionInvalidArgument(
json["context"], json["argument"], json["value"]);
return VeilidAPIExceptionInvalidArgument(json['context']! as String,
json['argument']! as String, json['value']! as String);
}
case "MissingArgument":
case 'MissingArgument':
{
return VeilidAPIExceptionMissingArgument(
json["context"], json["argument"]);
json['context']! as String, json['argument']! as String);
}
case "Generic":
case 'Generic':
{
return VeilidAPIExceptionGeneric(json["message"]);
return VeilidAPIExceptionGeneric(json['message']! as String);
}
default:
{
throw VeilidAPIExceptionInternal(
"Invalid VeilidAPIException type: ${json['kind']}");
"Invalid VeilidAPIException type: ${json['kind']! as String}");
}
}
}
@ -79,224 +82,163 @@ abstract class VeilidAPIException implements Exception {
@immutable
class VeilidAPIExceptionNotInitialized implements VeilidAPIException {
@override
String toString() {
return "VeilidAPIException: NotInitialized";
}
String toString() => 'VeilidAPIException: NotInitialized';
@override
String toDisplayError() {
return "Not initialized";
}
String toDisplayError() => 'Not initialized';
}
@immutable
class VeilidAPIExceptionAlreadyInitialized implements VeilidAPIException {
@override
String toString() {
return "VeilidAPIException: AlreadyInitialized";
}
String toString() => 'VeilidAPIException: AlreadyInitialized';
@override
String toDisplayError() {
return "Already initialized";
}
String toDisplayError() => 'Already initialized';
}
@immutable
class VeilidAPIExceptionTimeout implements VeilidAPIException {
@override
String toString() {
return "VeilidAPIException: Timeout";
}
String toString() => 'VeilidAPIException: Timeout';
@override
String toDisplayError() {
return "Timeout";
}
String toDisplayError() => 'Timeout';
}
@immutable
class VeilidAPIExceptionTryAgain implements VeilidAPIException {
@override
String toString() {
return "VeilidAPIException: TryAgain";
}
String toString() => 'VeilidAPIException: TryAgain';
@override
String toDisplayError() {
return "Try again";
}
String toDisplayError() => 'Try again';
}
@immutable
class VeilidAPIExceptionShutdown implements VeilidAPIException {
@override
String toString() {
return "VeilidAPIException: Shutdown";
}
String toString() => 'VeilidAPIException: Shutdown';
@override
String toDisplayError() {
return "Currently shut down";
}
String toDisplayError() => 'Currently shut down';
}
@immutable
class VeilidAPIExceptionInvalidTarget implements VeilidAPIException {
@override
String toString() {
return "VeilidAPIException: InvalidTarget";
}
String toString() => 'VeilidAPIException: InvalidTarget';
@override
String toDisplayError() {
return "Invalid target";
}
String toDisplayError() => 'Invalid target';
}
@immutable
class VeilidAPIExceptionNoConnection implements VeilidAPIException {
final String message;
@override
String toString() {
return "VeilidAPIException: NoConnection (message: $message)";
}
@override
String toDisplayError() {
return "No connection: $message";
}
//
const VeilidAPIExceptionNoConnection(this.message);
final String message;
@override
String toString() => 'VeilidAPIException: NoConnection (message: $message)';
@override
String toDisplayError() => 'No connection: $message';
}
@immutable
class VeilidAPIExceptionKeyNotFound implements VeilidAPIException {
final String key;
@override
String toString() {
return "VeilidAPIException: KeyNotFound (key: $key)";
}
@override
String toDisplayError() {
return "Key not found: $key";
}
//
const VeilidAPIExceptionKeyNotFound(this.key);
final String key;
@override
String toString() => 'VeilidAPIException: KeyNotFound (key: $key)';
@override
String toDisplayError() => 'Key not found: $key';
}
@immutable
class VeilidAPIExceptionInternal implements VeilidAPIException {
//
const VeilidAPIExceptionInternal(this.message);
final String message;
@override
String toString() {
return "VeilidAPIException: Internal ($message)";
}
String toString() => 'VeilidAPIException: Internal ($message)';
@override
String toDisplayError() {
return "Internal error: $message";
}
//
const VeilidAPIExceptionInternal(this.message);
String toDisplayError() => 'Internal error: $message';
}
@immutable
class VeilidAPIExceptionUnimplemented implements VeilidAPIException {
//
const VeilidAPIExceptionUnimplemented(this.message);
final String message;
@override
String toString() {
return "VeilidAPIException: Unimplemented ($message)";
}
String toString() => 'VeilidAPIException: Unimplemented ($message)';
@override
String toDisplayError() {
return "Unimplemented: $message";
}
//
const VeilidAPIExceptionUnimplemented(this.message);
String toDisplayError() => 'Unimplemented: $message';
}
@immutable
class VeilidAPIExceptionParseError implements VeilidAPIException {
//
const VeilidAPIExceptionParseError(this.message, this.value);
final String message;
final String value;
@override
String toString() {
return "VeilidAPIException: ParseError ($message)\n value: $value";
}
String toString() =>
'VeilidAPIException: ParseError ($message)\n value: $value';
@override
String toDisplayError() {
return "Parse error: $message";
}
//
const VeilidAPIExceptionParseError(this.message, this.value);
String toDisplayError() => 'Parse error: $message';
}
@immutable
class VeilidAPIExceptionInvalidArgument implements VeilidAPIException {
//
const VeilidAPIExceptionInvalidArgument(
this.context, this.argument, this.value);
final String context;
final String argument;
final String value;
@override
String toString() {
return "VeilidAPIException: InvalidArgument ($context:$argument)\n value: $value";
}
String toString() => 'VeilidAPIException: InvalidArgument'
' ($context:$argument)\n value: $value';
@override
String toDisplayError() {
return "Invalid argument for $context: $argument";
}
//
const VeilidAPIExceptionInvalidArgument(
this.context, this.argument, this.value);
String toDisplayError() => 'Invalid argument for $context: $argument';
}
@immutable
class VeilidAPIExceptionMissingArgument implements VeilidAPIException {
//
const VeilidAPIExceptionMissingArgument(this.context, this.argument);
final String context;
final String argument;
@override
String toString() {
return "VeilidAPIException: MissingArgument ($context:$argument)";
}
String toString() =>
'VeilidAPIException: MissingArgument ($context:$argument)';
@override
String toDisplayError() {
return "Missing argument for $context: $argument";
}
//
const VeilidAPIExceptionMissingArgument(this.context, this.argument);
String toDisplayError() => 'Missing argument for $context: $argument';
}
@immutable
class VeilidAPIExceptionGeneric implements VeilidAPIException {
//
const VeilidAPIExceptionGeneric(this.message);
final String message;
@override
String toString() {
return "VeilidAPIException: Generic (message: $message)";
}
String toString() => 'VeilidAPIException: Generic (message: $message)';
@override
String toDisplayError() {
return message;
}
//
const VeilidAPIExceptionGeneric(this.message);
String toDisplayError() => message;
}

View File

@ -1,9 +1,8 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter/foundation.dart';
import 'package:change_case/change_case.dart';
import 'package:flutter/foundation.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'veilid.dart';
import 'veilid_encoding.dart';
import 'veilid_crypto.dart';
part 'veilid_config.freezed.dart';
part 'veilid_config.g.dart';
@ -126,13 +125,9 @@ enum VeilidConfigLogLevel {
debug,
trace;
String toJson() {
return name.toPascalCase();
}
factory VeilidConfigLogLevel.fromJson(dynamic j) {
return VeilidConfigLogLevel.values.byName((j as String).toCamelCase());
}
factory VeilidConfigLogLevel.fromJson(dynamic j) =>
VeilidConfigLogLevel.values.byName((j as String).toCamelCase());
String toJson() => name.toPascalCase();
}
//////////////////////////////////////
@ -300,11 +295,11 @@ class VeilidConfigRPC with _$VeilidConfigRPC {
const factory VeilidConfigRPC(
{required int concurrency,
required int queueSize,
int? maxTimestampBehindMs,
int? maxTimestampAheadMs,
required int timeoutMs,
required int maxRouteHopCount,
required int defaultRouteHopCount}) = _VeilidConfigRPC;
required int defaultRouteHopCount,
int? maxTimestampBehindMs,
int? maxTimestampAheadMs}) = _VeilidConfigRPC;
factory VeilidConfigRPC.fromJson(dynamic json) =>
_$VeilidConfigRPCFromJson(json as Map<String, dynamic>);
@ -343,7 +338,6 @@ class VeilidConfigNetwork with _$VeilidConfigNetwork {
required int clientWhitelistTimeoutMs,
required int reverseConnectionReceiptTimeMs,
required int holePunchReceiptTimeMs,
String? networkKeyPassword,
required VeilidConfigRoutingTable routingTable,
required VeilidConfigRPC rpc,
required VeilidConfigDHT dht,
@ -353,6 +347,7 @@ class VeilidConfigNetwork with _$VeilidConfigNetwork {
required VeilidConfigTLS tls,
required VeilidConfigApplication application,
required VeilidConfigProtocol protocol,
String? networkKeyPassword,
}) = _VeilidConfigNetwork;
factory VeilidConfigNetwork.fromJson(dynamic json) =>

View File

@ -5,7 +5,6 @@ import 'package:charcode/charcode.dart';
import 'package:equatable/equatable.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'veilid_encoding.dart';
import 'veilid.dart';
//////////////////////////////////////
@ -17,24 +16,23 @@ const CryptoKind cryptoKindVLD0 =
const CryptoKind cryptoKindNONE =
$N << 0 | $O << 8 | $N << 16 | $E << 24; // "NONE"
String cryptoKindToString(CryptoKind kind) {
return cryptoKindToBytes(kind).map((c) => String.fromCharCode(c)).join();
}
String cryptoKindToString(CryptoKind kind) =>
cryptoKindToBytes(kind).map(String.fromCharCode).join();
const CryptoKind bestCryptoKind = cryptoKindVLD0;
Uint8List cryptoKindToBytes(CryptoKind kind) {
var b = Uint8List(4);
ByteData.sublistView(b).setUint32(0, kind, Endian.big);
final b = Uint8List(4);
ByteData.sublistView(b).setUint32(0, kind);
return b;
}
CryptoKind cryptoKindFromString(String s) {
if (s.codeUnits.length != 4) {
throw const FormatException("malformed string");
throw const FormatException('malformed string');
}
CryptoKind kind = ByteData.sublistView(Uint8List.fromList(s.codeUnits))
.getUint32(0, Endian.big);
final kind =
ByteData.sublistView(Uint8List.fromList(s.codeUnits)).getUint32(0);
return kind;
}
@ -43,103 +41,95 @@ CryptoKind cryptoKindFromString(String s) {
@immutable
class Typed<V extends EncodedString> extends Equatable {
const Typed({required this.kind, required this.value});
factory Typed.fromString(String s) {
final parts = s.split(':');
if (parts.length < 2 || parts[0].codeUnits.length != 4) {
throw const FormatException('malformed string');
}
final kind = cryptoKindFromString(parts[0]);
final value = EncodedString.fromString<V>(parts.sublist(1).join(':'));
return Typed(kind: kind, value: value);
}
factory Typed.fromJson(dynamic json) => Typed.fromString(json as String);
final CryptoKind kind;
final V value;
@override
List<Object> get props => [kind, value];
const Typed({required this.kind, required this.value});
@override
String toString() {
return "${cryptoKindToString(kind)}:$value";
}
factory Typed.fromString(String s) {
final parts = s.split(":");
if (parts.length < 2 || parts[0].codeUnits.length != 4) {
throw const FormatException("malformed string");
}
final kind = cryptoKindFromString(parts[0]);
final value = EncodedString.fromString<V>(parts.sublist(1).join(":"));
return Typed(kind: kind, value: value);
}
String toString() => '${cryptoKindToString(kind)}:$value';
Uint8List decode() {
var b = BytesBuilder();
b.add(cryptoKindToBytes(kind));
b.add(value.decode());
final b = BytesBuilder()
..add(cryptoKindToBytes(kind))
..add(value.decode());
return b.toBytes();
}
String toJson() => toString();
factory Typed.fromJson(dynamic json) => Typed.fromString(json as String);
}
@immutable
class KeyPair extends Equatable {
final PublicKey key;
final PublicKey secret;
@override
List<Object> get props => [key, secret];
const KeyPair({required this.key, required this.secret});
@override
String toString() {
return "${key.toString()}:${secret.toString()}";
}
factory KeyPair.fromString(String s) {
final parts = s.split(":");
final parts = s.split(':');
if (parts.length != 2 ||
parts[0].codeUnits.length != 43 ||
parts[1].codeUnits.length != 43) {
throw const FormatException("malformed string");
throw const FormatException('malformed string');
}
final key = PublicKey.fromString(parts[0]);
final secret = PublicKey.fromString(parts[1]);
return KeyPair(key: key, secret: secret);
}
factory KeyPair.fromJson(dynamic json) => KeyPair.fromString(json as String);
final PublicKey key;
final PublicKey secret;
@override
List<Object> get props => [key, secret];
@override
String toString() => '$key:$secret';
String toJson() => toString();
factory KeyPair.fromJson(dynamic json) => KeyPair.fromString(json as String);
}
@immutable
class TypedKeyPair extends Equatable {
final CryptoKind kind;
final PublicKey key;
final PublicKey secret;
@override
List<Object> get props => [kind, key, secret];
const TypedKeyPair(
{required this.kind, required this.key, required this.secret});
@override
String toString() =>
"${cryptoKindToString(kind)}:${key.toString()}:${secret.toString()}";
factory TypedKeyPair.fromString(String s) {
final parts = s.split(":");
final parts = s.split(':');
if (parts.length != 3 ||
parts[0].codeUnits.length != 4 ||
parts[1].codeUnits.length != 43 ||
parts[2].codeUnits.length != 43) {
throw VeilidAPIExceptionInvalidArgument("malformed string", "s", s);
throw VeilidAPIExceptionInvalidArgument('malformed string', 's', s);
}
final kind = cryptoKindFromString(parts[0]);
final key = PublicKey.fromString(parts[1]);
final secret = PublicKey.fromString(parts[2]);
return TypedKeyPair(kind: kind, key: key, secret: secret);
}
String toJson() => toString();
factory TypedKeyPair.fromJson(dynamic json) =>
TypedKeyPair.fromString(json as String);
factory TypedKeyPair.fromKeyPair(CryptoKind kind, KeyPair keyPair) =>
TypedKeyPair(kind: kind, key: keyPair.key, secret: keyPair.secret);
final CryptoKind kind;
final PublicKey key;
final PublicKey secret;
@override
List<Object> get props => [kind, key, secret];
@override
String toString() => '${cryptoKindToString(kind)}:$key:$secret';
String toJson() => toString();
}
typedef CryptoKey = FixedEncodedString43;
@ -176,17 +166,15 @@ abstract class VeilidCryptoSystem {
Future<HashDigest> generateHash(Uint8List data);
//Future<HashDigest> generateHashReader(Stream<List<int>> reader);
Future<bool> validateKeyPair(PublicKey key, SecretKey secret);
Future<bool> validateKeyPairWithKeyPair(KeyPair keyPair) {
return validateKeyPair(keyPair.key, keyPair.secret);
}
Future<bool> validateKeyPairWithKeyPair(KeyPair keyPair) =>
validateKeyPair(keyPair.key, keyPair.secret);
Future<bool> validateHash(Uint8List data, HashDigest hash);
//Future<bool> validateHashReader(Stream<List<int>> reader, HashDigest hash);
Future<CryptoKeyDistance> distance(CryptoKey key1, CryptoKey key2);
Future<Signature> sign(PublicKey key, SecretKey secret, Uint8List data);
Future<Signature> signWithKeyPair(KeyPair keyPair, Uint8List data) {
return sign(keyPair.key, keyPair.secret, data);
}
Future<Signature> signWithKeyPair(KeyPair keyPair, Uint8List data) =>
sign(keyPair.key, keyPair.secret, data);
Future<void> verify(PublicKey key, Uint8List data, Signature signature);
Future<int> aeadOverhead();

View File

@ -34,15 +34,13 @@ class Uint8ListJsonConverter implements JsonConverter<Uint8List, String> {
@immutable
abstract class EncodedString extends Equatable {
const EncodedString(String s) : contents = s;
final String contents;
@override
List<Object> get props => [contents];
const EncodedString(String s) : contents = s;
Uint8List decode() {
return base64UrlNoPadDecode(contents);
}
Uint8List decode() => base64UrlNoPadDecode(contents);
@override
String toString() => contents;
@ -76,96 +74,82 @@ abstract class EncodedString extends Equatable {
@immutable
class FixedEncodedString32 extends EncodedString {
const FixedEncodedString32._(String s) : super(s);
static int encodedLength() {
return 32;
}
static int decodedLength() {
return 24;
}
factory FixedEncodedString32.fromBytes(Uint8List bytes) {
if (bytes.length != decodedLength()) {
throw Exception("length ${bytes.length} should be ${decodedLength()}");
throw Exception('length ${bytes.length} should be ${decodedLength()}');
}
return FixedEncodedString32._(base64UrlNoPadEncode(bytes));
}
factory FixedEncodedString32.fromString(String s) {
var d = base64UrlNoPadDecode(s);
final d = base64UrlNoPadDecode(s);
if (d.length != decodedLength()) {
throw Exception("length ${s.length} should be ${encodedLength()}");
throw Exception('length ${s.length} should be ${encodedLength()}');
}
return FixedEncodedString32._(s);
}
String toJson() => toString();
factory FixedEncodedString32.fromJson(dynamic json) =>
FixedEncodedString32.fromString(json as String);
const FixedEncodedString32._(super.s);
static int encodedLength() => 32;
static int decodedLength() => 24;
String toJson() => toString();
}
@immutable
class FixedEncodedString43 extends EncodedString {
const FixedEncodedString43._(String s) : super(s);
static int encodedLength() {
return 43;
}
static int decodedLength() {
return 32;
}
factory FixedEncodedString43.fromBytes(Uint8List bytes) {
if (bytes.length != decodedLength()) {
throw Exception("length ${bytes.length} should be ${decodedLength()}");
throw Exception('length ${bytes.length} should be ${decodedLength()}');
}
return FixedEncodedString43._(base64UrlNoPadEncode(bytes));
}
factory FixedEncodedString43.fromString(String s) {
var d = base64UrlNoPadDecode(s);
final d = base64UrlNoPadDecode(s);
if (d.length != decodedLength()) {
throw Exception("length ${s.length} should be ${encodedLength()}");
throw Exception('length ${s.length} should be ${encodedLength()}');
}
return FixedEncodedString43._(s);
}
String toJson() => toString();
factory FixedEncodedString43.fromJson(dynamic json) =>
FixedEncodedString43.fromString(json as String);
const FixedEncodedString43._(super.s);
static int encodedLength() => 43;
static int decodedLength() => 32;
String toJson() => toString();
}
@immutable
class FixedEncodedString86 extends EncodedString {
const FixedEncodedString86._(String s) : super(s);
static int encodedLength() {
return 86;
}
static int decodedLength() {
return 64;
}
String toJson() {
return toString();
}
factory FixedEncodedString86.fromBytes(Uint8List bytes) {
if (bytes.length != decodedLength()) {
throw Exception("length ${bytes.length} should be ${decodedLength()}");
throw Exception('length ${bytes.length} should be ${decodedLength()}');
}
return FixedEncodedString86._(base64UrlNoPadEncode(bytes));
}
factory FixedEncodedString86.fromString(String s) {
var d = base64UrlNoPadDecode(s);
final d = base64UrlNoPadDecode(s);
if (d.length != decodedLength()) {
throw Exception("length ${s.length} should be ${encodedLength()}");
throw Exception('length ${s.length} should be ${encodedLength()}');
}
return FixedEncodedString86._(s);
}
factory FixedEncodedString86.fromJson(dynamic json) =>
FixedEncodedString86.fromString(json as String);
const FixedEncodedString86._(super.s);
static int encodedLength() => 86;
static int decodedLength() => 64;
String toJson() => toString();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,52 +1,53 @@
import 'veilid.dart';
import 'dart:async';
import 'dart:convert';
import 'dart:html' as html;
import 'dart:js' as js;
import 'dart:js_util' as js_util;
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'veilid_encoding.dart';
import 'veilid.dart';
//////////////////////////////////////////////////////////
Veilid getVeilid() => VeilidJS();
Object wasm = js_util.getProperty(html.window, "veilid_wasm");
Object wasm = js_util.getProperty(html.window, 'veilid_wasm');
Future<T> _wrapApiPromise<T>(Object p) {
return js_util.promiseToFuture(p).then((value) => value as T).catchError(
(error) => Future<T>.error(
VeilidAPIException.fromJson(jsonDecode(error as String))));
}
Future<T> _wrapApiPromise<T>(Object p) => js_util
.promiseToFuture<T>(p)
.then((value) => value)
// ignore: inference_failure_on_untyped_parameter
.catchError((e) {
// Wrap all other errors in VeilidAPIExceptionInternal
throw VeilidAPIExceptionInternal(e.toString());
}, test: (e) => e is! VeilidAPIException);
class _Ctx {
int? id;
_Ctx(int id, this.js) : _id = id;
int? _id;
final VeilidJS js;
_Ctx(int this.id, this.js);
void ensureValid() {
if (id == null) {
int requireId() {
if (_id == null) {
throw VeilidAPIExceptionNotInitialized();
}
return _id!;
}
void close() {
if (id != null) {
js_util.callMethod(wasm, "release_routing_context", [id!]);
id = null;
if (_id != null) {
js_util.callMethod<void>(wasm, 'release_routing_context', [_id]);
_id = null;
}
}
}
// JS implementation of VeilidRoutingContext
class VeilidRoutingContextJS extends VeilidRoutingContext {
final _Ctx _ctx;
static final Finalizer<_Ctx> _finalizer = Finalizer((ctx) => ctx.close());
VeilidRoutingContextJS._(this._ctx) {
_finalizer.attach(this, _ctx, detach: this);
}
final _Ctx _ctx;
static final Finalizer<_Ctx> _finalizer = Finalizer((ctx) => ctx.close());
@override
void close() {
@ -55,113 +56,113 @@ class VeilidRoutingContextJS extends VeilidRoutingContext {
@override
VeilidRoutingContextJS withPrivacy() {
_ctx.ensureValid();
int newId =
js_util.callMethod(wasm, "routing_context_with_privacy", [_ctx.id!]);
final id = _ctx.requireId();
final int newId =
js_util.callMethod(wasm, 'routing_context_with_privacy', [id]);
return VeilidRoutingContextJS._(_Ctx(newId, _ctx.js));
}
@override
VeilidRoutingContextJS withCustomPrivacy(SafetySelection safetySelection) {
_ctx.ensureValid();
final newId = js_util.callMethod(
final id = _ctx.requireId();
final newId = js_util.callMethod<int>(
wasm,
"routing_context_with_custom_privacy",
[_ctx.id!, jsonEncode(safetySelection)]);
'routing_context_with_custom_privacy',
[id, jsonEncode(safetySelection)]);
return VeilidRoutingContextJS._(_Ctx(newId, _ctx.js));
}
@override
VeilidRoutingContextJS withSequencing(Sequencing sequencing) {
_ctx.ensureValid();
final newId = js_util.callMethod(wasm, "routing_context_with_sequencing",
[_ctx.id!, jsonEncode(sequencing)]);
final id = _ctx.requireId();
final newId = js_util.callMethod<int>(
wasm, 'routing_context_with_sequencing', [id, jsonEncode(sequencing)]);
return VeilidRoutingContextJS._(_Ctx(newId, _ctx.js));
}
@override
Future<Uint8List> appCall(String target, Uint8List request) async {
_ctx.ensureValid();
var encodedRequest = base64UrlNoPadEncode(request);
final id = _ctx.requireId();
final encodedRequest = base64UrlNoPadEncode(request);
return base64UrlNoPadDecode(await _wrapApiPromise(js_util.callMethod(
wasm, "routing_context_app_call", [_ctx.id!, target, encodedRequest])));
wasm, 'routing_context_app_call', [id, target, encodedRequest])));
}
@override
Future<void> appMessage(String target, Uint8List message) {
_ctx.ensureValid();
var encodedMessage = base64UrlNoPadEncode(message);
final id = _ctx.requireId();
final encodedMessage = base64UrlNoPadEncode(message);
return _wrapApiPromise(js_util.callMethod(wasm,
"routing_context_app_message", [_ctx.id!, target, encodedMessage]));
return _wrapApiPromise(js_util.callMethod(
wasm, 'routing_context_app_message', [id, target, encodedMessage]));
}
@override
Future<DHTRecordDescriptor> createDHTRecord(DHTSchema schema,
{CryptoKind kind = 0}) async {
_ctx.ensureValid();
final id = _ctx.requireId();
return DHTRecordDescriptor.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, "routing_context_create_dht_record",
[_ctx.id!, jsonEncode(schema), kind]))));
.callMethod(wasm, 'routing_context_create_dht_record',
[id, jsonEncode(schema), kind]))));
}
@override
Future<DHTRecordDescriptor> openDHTRecord(
TypedKey key, KeyPair? writer) async {
_ctx.ensureValid();
final id = _ctx.requireId();
return DHTRecordDescriptor.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, "routing_context_open_dht_record", [
_ctx.id!,
.callMethod(wasm, 'routing_context_open_dht_record', [
id,
jsonEncode(key),
writer != null ? jsonEncode(writer) : null
if (writer != null) jsonEncode(writer) else null
]))));
}
@override
Future<void> closeDHTRecord(TypedKey key) {
_ctx.ensureValid();
final id = _ctx.requireId();
return _wrapApiPromise(js_util.callMethod(
wasm, "routing_context_close_dht_record", [_ctx.id!, jsonEncode(key)]));
wasm, 'routing_context_close_dht_record', [id, jsonEncode(key)]));
}
@override
Future<void> deleteDHTRecord(TypedKey key) {
_ctx.ensureValid();
return _wrapApiPromise(js_util.callMethod(wasm,
"routing_context_delete_dht_record", [_ctx.id!, jsonEncode(key)]));
final id = _ctx.requireId();
return _wrapApiPromise(js_util.callMethod(
wasm, 'routing_context_delete_dht_record', [id, jsonEncode(key)]));
}
@override
Future<ValueData?> getDHTValue(
TypedKey key, int subkey, bool forceRefresh) async {
_ctx.ensureValid();
final opt = await _wrapApiPromise(js_util.callMethod(
final id = _ctx.requireId();
final opt = await _wrapApiPromise<String?>(js_util.callMethod(
wasm,
"routing_context_get_dht_value",
[_ctx.id!, jsonEncode(key), subkey, forceRefresh]));
'routing_context_get_dht_value',
[id, jsonEncode(key), subkey, forceRefresh]));
return opt == null ? null : ValueData.fromJson(jsonDecode(opt));
}
@override
Future<ValueData?> setDHTValue(
TypedKey key, int subkey, Uint8List data) async {
_ctx.ensureValid();
final opt = await _wrapApiPromise(js_util.callMethod(
final id = _ctx.requireId();
final opt = await _wrapApiPromise<String?>(js_util.callMethod(
wasm,
"routing_context_set_dht_value",
[_ctx.id!, jsonEncode(key), subkey, base64UrlNoPadEncode(data)]));
'routing_context_set_dht_value',
[id, jsonEncode(key), subkey, base64UrlNoPadEncode(data)]));
return opt == null ? null : ValueData.fromJson(jsonDecode(opt));
}
@override
Future<Timestamp> watchDHTValues(TypedKey key, List<ValueSubkeyRange> subkeys,
Timestamp expiration, int count) async {
_ctx.ensureValid();
final ts = await _wrapApiPromise(js_util.callMethod(
wasm, "routing_context_watch_dht_values", [
_ctx.id!,
final id = _ctx.requireId();
final ts = await _wrapApiPromise<String>(js_util.callMethod(
wasm, 'routing_context_watch_dht_values', [
id,
jsonEncode(key),
jsonEncode(subkeys),
expiration.toString(),
@ -172,195 +173,176 @@ class VeilidRoutingContextJS extends VeilidRoutingContext {
@override
Future<bool> cancelDHTWatch(TypedKey key, List<ValueSubkeyRange> subkeys) {
_ctx.ensureValid();
final id = _ctx.requireId();
return _wrapApiPromise(js_util.callMethod(
wasm,
"routing_context_cancel_dht_watch",
[_ctx.id!, jsonEncode(key), jsonEncode(subkeys)]));
'routing_context_cancel_dht_watch',
[id, jsonEncode(key), jsonEncode(subkeys)]));
}
}
// JS implementation of VeilidCryptoSystem
class VeilidCryptoSystemJS extends VeilidCryptoSystem {
VeilidCryptoSystemJS._(this._js, this._kind);
final CryptoKind _kind;
// Keep the reference
// ignore: unused_field
final VeilidJS _js;
VeilidCryptoSystemJS._(this._js, this._kind) {
// Keep the reference
_js;
}
@override
CryptoKind kind() => _kind;
@override
CryptoKind kind() {
return _kind;
}
Future<SharedSecret> cachedDH(PublicKey key, SecretKey secret) async =>
SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
wasm,
'crypto_cached_dh',
[_kind, jsonEncode(key), jsonEncode(secret)]))));
@override
Future<SharedSecret> cachedDH(PublicKey key, SecretKey secret) async {
return SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, "crypto_cached_dh",
[_kind, jsonEncode(key), jsonEncode(secret)]))));
}
Future<SharedSecret> computeDH(PublicKey key, SecretKey secret) async =>
SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
wasm,
'crypto_compute_dh',
[_kind, jsonEncode(key), jsonEncode(secret)]))));
@override
Future<SharedSecret> computeDH(PublicKey key, SecretKey secret) async {
return SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, "crypto_compute_dh",
[_kind, jsonEncode(key), jsonEncode(secret)]))));
}
Future<Uint8List> randomBytes(int len) async =>
base64UrlNoPadDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'crypto_random_bytes', [_kind, len])));
@override
Future<Uint8List> randomBytes(int len) async {
return base64UrlNoPadDecode(await _wrapApiPromise(
js_util.callMethod(wasm, "crypto_random_bytes", [_kind, len])));
}
Future<int> defaultSaltLength() => _wrapApiPromise(
js_util.callMethod(wasm, 'crypto_default_salt_length', [_kind]));
@override
Future<int> defaultSaltLength() {
return _wrapApiPromise(
js_util.callMethod(wasm, "crypto_default_salt_length", [_kind]));
}
Future<String> hashPassword(Uint8List password, Uint8List salt) =>
_wrapApiPromise(js_util.callMethod(wasm, 'crypto_hash_password',
[_kind, base64UrlNoPadEncode(password), base64UrlNoPadEncode(salt)]));
@override
Future<String> hashPassword(Uint8List password, Uint8List salt) {
return _wrapApiPromise(js_util.callMethod(wasm, "crypto_hash_password",
[_kind, base64UrlNoPadEncode(password), base64UrlNoPadEncode(salt)]));
}
@override
Future<bool> verifyPassword(Uint8List password, String passwordHash) {
return _wrapApiPromise(js_util.callMethod(wasm, "crypto_verify_password",
[_kind, base64UrlNoPadEncode(password), passwordHash]));
}
Future<bool> verifyPassword(Uint8List password, String passwordHash) =>
_wrapApiPromise(js_util.callMethod(wasm, 'crypto_verify_password',
[_kind, base64UrlNoPadEncode(password), passwordHash]));
@override
Future<SharedSecret> deriveSharedSecret(
Uint8List password, Uint8List salt) async {
return SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, "crypto_derive_shared_secret", [
_kind,
base64UrlNoPadEncode(password),
base64UrlNoPadEncode(salt)
]))));
}
Uint8List password, Uint8List salt) async =>
SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
wasm, 'crypto_derive_shared_secret', [
_kind,
base64UrlNoPadEncode(password),
base64UrlNoPadEncode(salt)
]))));
@override
Future<Nonce> randomNonce() async {
return Nonce.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, "crypto_random_nonce", [_kind]))));
}
Future<Nonce> randomNonce() async =>
Nonce.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'crypto_random_nonce', [_kind]))));
@override
Future<SharedSecret> randomSharedSecret() async {
return SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, "crypto_random_shared_secret", [_kind]))));
}
Future<SharedSecret> randomSharedSecret() async =>
SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'crypto_random_shared_secret', [_kind]))));
@override
Future<KeyPair> generateKeyPair() async {
return KeyPair.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, "crypto_generate_key_pair", [_kind]))));
}
Future<KeyPair> generateKeyPair() async =>
KeyPair.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'crypto_generate_key_pair', [_kind]))));
@override
Future<HashDigest> generateHash(Uint8List data) async {
return HashDigest.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, "crypto_generate_hash",
[_kind, base64UrlNoPadEncode(data)]))));
}
Future<HashDigest> generateHash(Uint8List data) async =>
HashDigest.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
wasm, 'crypto_generate_hash', [_kind, base64UrlNoPadEncode(data)]))));
@override
Future<bool> validateKeyPair(PublicKey key, SecretKey secret) {
return _wrapApiPromise(js_util.callMethod(wasm, "crypto_validate_key_pair",
[_kind, jsonEncode(key), jsonEncode(secret)]));
}
Future<bool> validateKeyPair(PublicKey key, SecretKey secret) =>
_wrapApiPromise(js_util.callMethod(wasm, 'crypto_validate_key_pair',
[_kind, jsonEncode(key), jsonEncode(secret)]));
@override
Future<bool> validateHash(Uint8List data, HashDigest hash) {
return _wrapApiPromise(js_util.callMethod(wasm, "crypto_validate_hash",
[_kind, base64UrlNoPadEncode(data), jsonEncode(hash)]));
}
Future<bool> validateHash(Uint8List data, HashDigest hash) =>
_wrapApiPromise(js_util.callMethod(wasm, 'crypto_validate_hash',
[_kind, base64UrlNoPadEncode(data), jsonEncode(hash)]));
@override
Future<CryptoKeyDistance> distance(CryptoKey key1, CryptoKey key2) async {
return CryptoKeyDistance.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, "crypto_distance",
[_kind, jsonEncode(key1), jsonEncode(key2)]))));
}
Future<CryptoKeyDistance> distance(CryptoKey key1, CryptoKey key2) async =>
CryptoKeyDistance.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, 'crypto_distance',
[_kind, jsonEncode(key1), jsonEncode(key2)]))));
@override
Future<Signature> sign(
PublicKey key, SecretKey secret, Uint8List data) async {
return Signature.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, "crypto_sign", [
_kind,
jsonEncode(key),
jsonEncode(secret),
base64UrlNoPadEncode(data)
]))));
}
PublicKey key, SecretKey secret, Uint8List data) async =>
Signature.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
wasm, 'crypto_sign', [
_kind,
jsonEncode(key),
jsonEncode(secret),
base64UrlNoPadEncode(data)
]))));
@override
Future<void> verify(PublicKey key, Uint8List data, Signature signature) {
return _wrapApiPromise(js_util.callMethod(wasm, "crypto_verify", [
_kind,
jsonEncode(key),
base64UrlNoPadEncode(data),
jsonEncode(signature),
]));
}
Future<void> verify(PublicKey key, Uint8List data, Signature signature) =>
_wrapApiPromise(js_util.callMethod(wasm, 'crypto_verify', [
_kind,
jsonEncode(key),
base64UrlNoPadEncode(data),
jsonEncode(signature),
]));
@override
Future<int> aeadOverhead() {
return _wrapApiPromise(
js_util.callMethod(wasm, "crypto_aead_overhead", [_kind]));
}
Future<int> aeadOverhead() => _wrapApiPromise(
js_util.callMethod(wasm, 'crypto_aead_overhead', [_kind]));
@override
Future<Uint8List> decryptAead(Uint8List body, Nonce nonce,
SharedSecret sharedSecret, Uint8List? associatedData) async {
return base64UrlNoPadDecode(
await _wrapApiPromise(js_util.callMethod(wasm, "crypto_decrypt_aead", [
_kind,
base64UrlNoPadEncode(body),
jsonEncode(nonce),
jsonEncode(sharedSecret),
associatedData != null ? base64UrlNoPadEncode(associatedData) : null
])));
}
SharedSecret sharedSecret, Uint8List? associatedData) async =>
base64UrlNoPadDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'crypto_decrypt_aead', [
_kind,
base64UrlNoPadEncode(body),
jsonEncode(nonce),
jsonEncode(sharedSecret),
if (associatedData != null)
base64UrlNoPadEncode(associatedData)
else
null
])));
@override
Future<Uint8List> encryptAead(Uint8List body, Nonce nonce,
SharedSecret sharedSecret, Uint8List? associatedData) async {
return base64UrlNoPadDecode(
await _wrapApiPromise(js_util.callMethod(wasm, "crypto_encrypt_aead", [
_kind,
base64UrlNoPadEncode(body),
jsonEncode(nonce),
jsonEncode(sharedSecret),
associatedData != null ? base64UrlNoPadEncode(associatedData) : null
])));
}
SharedSecret sharedSecret, Uint8List? associatedData) async =>
base64UrlNoPadDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'crypto_encrypt_aead', [
_kind,
base64UrlNoPadEncode(body),
jsonEncode(nonce),
jsonEncode(sharedSecret),
if (associatedData != null)
base64UrlNoPadEncode(associatedData)
else
null
])));
@override
Future<Uint8List> cryptNoAuth(
Uint8List body, Nonce nonce, SharedSecret sharedSecret) async {
return base64UrlNoPadDecode(await _wrapApiPromise(js_util.callMethod(
wasm, "crypto_crypt_no_auth", [
_kind,
base64UrlNoPadEncode(body),
jsonEncode(nonce),
jsonEncode(sharedSecret)
])));
}
Uint8List body, Nonce nonce, SharedSecret sharedSecret) async =>
base64UrlNoPadDecode(await _wrapApiPromise(js_util.callMethod(
wasm, 'crypto_crypt_no_auth', [
_kind,
base64UrlNoPadEncode(body),
jsonEncode(nonce),
jsonEncode(sharedSecret)
])));
}
class _TDBT {
_TDBT(this.id, this.tdbjs, this.js);
int? id;
final VeilidTableDBJS tdbjs;
final VeilidJS js;
_TDBT(this.id, this.tdbjs, this.js);
void ensureValid() {
if (id == null) {
throw VeilidAPIExceptionNotInitialized();
@ -369,7 +351,7 @@ class _TDBT {
void close() {
if (id != null) {
js_util.callMethod(wasm, "release_table_db_transaction", [id!]);
js_util.callMethod<void>(wasm, 'release_table_db_transaction', [id]);
id = null;
}
}
@ -377,81 +359,83 @@ class _TDBT {
// JS implementation of VeilidTableDBTransaction
class VeilidTableDBTransactionJS extends VeilidTableDBTransaction {
final _TDBT _tdbt;
static final Finalizer<_TDBT> _finalizer = Finalizer((tdbt) => tdbt.close());
VeilidTableDBTransactionJS._(this._tdbt) {
_finalizer.attach(this, _tdbt, detach: this);
}
final _TDBT _tdbt;
static final Finalizer<_TDBT> _finalizer = Finalizer((tdbt) => tdbt.close());
@override
bool isDone() {
return _tdbt.id == null;
}
bool isDone() => _tdbt.id == null;
@override
Future<void> commit() async {
_tdbt.ensureValid();
await _wrapApiPromise(
js_util.callMethod(wasm, "table_db_transaction_commit", [_tdbt.id!]));
final id = _tdbt.id!;
await _wrapApiPromise<void>(
js_util.callMethod(wasm, 'table_db_transaction_commit', [id]));
_tdbt.close();
}
@override
Future<void> rollback() async {
_tdbt.ensureValid();
await _wrapApiPromise(
js_util.callMethod(wasm, "table_db_transaction_rollback", [_tdbt.id!]));
final id = _tdbt.id!;
await _wrapApiPromise<void>(
js_util.callMethod(wasm, 'table_db_transaction_rollback', [id]));
_tdbt.close();
}
@override
Future<void> store(int col, Uint8List key, Uint8List value) async {
_tdbt.ensureValid();
final id = _tdbt.id!;
final encodedKey = base64UrlNoPadEncode(key);
final encodedValue = base64UrlNoPadEncode(value);
await _wrapApiPromise(js_util.callMethod(wasm, "table_db_transaction_store",
[_tdbt.id!, col, encodedKey, encodedValue]));
await _wrapApiPromise<void>(js_util.callMethod(wasm,
'table_db_transaction_store', [id, col, encodedKey, encodedValue]));
}
@override
Future<void> delete(int col, Uint8List key) async {
_tdbt.ensureValid();
final id = _tdbt.id!;
final encodedKey = base64UrlNoPadEncode(key);
await _wrapApiPromise(js_util.callMethod(
wasm, "table_db_transaction_delete", [_tdbt.id!, col, encodedKey]));
await _wrapApiPromise<void>(js_util.callMethod(
wasm, 'table_db_transaction_delete', [id, col, encodedKey]));
}
}
class _TDB {
int? id;
final VeilidJS js;
_TDB(int id, this.js) : _id = id;
_TDB(int this.id, this.js);
void ensureValid() {
if (id == null) {
int? _id;
final VeilidJS js;
int requireId() {
if (_id == null) {
throw VeilidAPIExceptionNotInitialized();
}
return _id!;
}
void close() {
if (id != null) {
js_util.callMethod(wasm, "release_table_db", [id!]);
id = null;
if (_id != null) {
js_util.callMethod<void>(wasm, 'release_table_db', [_id]);
_id = null;
}
}
}
// JS implementation of VeilidTableDB
class VeilidTableDBJS extends VeilidTableDB {
final _TDB _tdb;
static final Finalizer<_TDB> _finalizer = Finalizer((tdb) => tdb.close());
VeilidTableDBJS._(this._tdb) {
_finalizer.attach(this, _tdb, detach: this);
}
final _TDB _tdb;
static final Finalizer<_TDB> _finalizer = Finalizer((tdb) => tdb.close());
@override
void close() {
@ -460,42 +444,42 @@ class VeilidTableDBJS extends VeilidTableDB {
@override
int getColumnCount() {
_tdb.ensureValid();
return js_util.callMethod(wasm, "table_db_get_column_count", [_tdb.id!]);
final id = _tdb.requireId();
return js_util.callMethod(wasm, 'table_db_get_column_count', [id]);
}
@override
Future<List<Uint8List>> getKeys(int col) async {
_tdb.ensureValid();
final id = _tdb.requireId();
return jsonListConstructor(base64UrlNoPadDecodeDynamic)(jsonDecode(
await js_util.callMethod(wasm, "table_db_get_keys", [_tdb.id!, col])));
await js_util.callMethod(wasm, 'table_db_get_keys', [id, col])));
}
@override
VeilidTableDBTransaction transact() {
_tdb.ensureValid();
final id = js_util.callMethod(wasm, "table_db_transact", [_tdb.id!]);
final id = _tdb.requireId();
final xid = js_util.callMethod<int>(wasm, 'table_db_transact', [id]);
return VeilidTableDBTransactionJS._(_TDBT(id, this, _tdb.js));
return VeilidTableDBTransactionJS._(_TDBT(xid, this, _tdb.js));
}
@override
Future<void> store(int col, Uint8List key, Uint8List value) {
_tdb.ensureValid();
final id = _tdb.requireId();
final encodedKey = base64UrlNoPadEncode(key);
final encodedValue = base64UrlNoPadEncode(value);
return _wrapApiPromise(js_util.callMethod(
wasm, "table_db_store", [_tdb.id!, col, encodedKey, encodedValue]));
wasm, 'table_db_store', [id, col, encodedKey, encodedValue]));
}
@override
Future<Uint8List?> load(int col, Uint8List key) async {
_tdb.ensureValid();
final id = _tdb.requireId();
final encodedKey = base64UrlNoPadEncode(key);
String? out = await _wrapApiPromise(
js_util.callMethod(wasm, "table_db_load", [_tdb.id!, col, encodedKey]));
final out = await _wrapApiPromise<String?>(
js_util.callMethod(wasm, 'table_db_load', [id, col, encodedKey]));
if (out == null) {
return null;
}
@ -503,12 +487,16 @@ class VeilidTableDBJS extends VeilidTableDB {
}
@override
Future<Uint8List?> delete(int col, Uint8List key) {
_tdb.ensureValid();
Future<Uint8List?> delete(int col, Uint8List key) async {
final id = _tdb.requireId();
final encodedKey = base64UrlNoPadEncode(key);
return _wrapApiPromise(js_util
.callMethod(wasm, "table_db_delete", [_tdb.id!, col, encodedKey]));
final out = await _wrapApiPromise<String?>(
js_util.callMethod(wasm, 'table_db_delete', [id, col, encodedKey]));
if (out == null) {
return null;
}
return base64UrlNoPadDecode(out);
}
}
@ -517,61 +505,57 @@ class VeilidTableDBJS extends VeilidTableDB {
class VeilidJS extends Veilid {
@override
void initializeVeilidCore(Map<String, dynamic> platformConfigJson) {
var platformConfigJsonString = jsonEncode(platformConfigJson);
js_util
.callMethod(wasm, "initialize_veilid_core", [platformConfigJsonString]);
final platformConfigJsonString = jsonEncode(platformConfigJson);
js_util.callMethod<void>(
wasm, 'initialize_veilid_core', [platformConfigJsonString]);
}
@override
void changeLogLevel(String layer, VeilidConfigLogLevel logLevel) {
var logLevelJsonString = jsonEncode(logLevel);
js_util.callMethod(wasm, "change_log_level", [layer, logLevelJsonString]);
final logLevelJsonString = jsonEncode(logLevel);
js_util.callMethod<void>(
wasm, 'change_log_level', [layer, logLevelJsonString]);
}
@override
Future<Stream<VeilidUpdate>> startupVeilidCore(VeilidConfig config) async {
var streamController = StreamController<VeilidUpdate>();
updateCallback(String update) {
var updateJson = jsonDecode(update);
if (updateJson["kind"] == "Shutdown") {
streamController.close();
final streamController = StreamController<VeilidUpdate>();
void updateCallback(String update) {
final updateJson = jsonDecode(update) as Map<String, dynamic>;
if (updateJson['kind'] == 'Shutdown') {
unawaited(streamController.close());
} else {
var update = VeilidUpdate.fromJson(updateJson);
final update = VeilidUpdate.fromJson(updateJson);
streamController.add(update);
}
}
await _wrapApiPromise(js_util.callMethod(wasm, "startup_veilid_core",
await _wrapApiPromise<void>(js_util.callMethod(wasm, 'startup_veilid_core',
[js.allowInterop(updateCallback), jsonEncode(config)]));
return streamController.stream;
}
@override
Future<VeilidState> getVeilidState() async {
return VeilidState.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, "get_veilid_state", []))));
}
Future<VeilidState> getVeilidState() async =>
VeilidState.fromJson(jsonDecode(await _wrapApiPromise<String>(
js_util.callMethod(wasm, 'get_veilid_state', []))));
@override
Future<void> attach() {
return _wrapApiPromise(js_util.callMethod(wasm, "attach", []));
}
Future<void> attach() =>
_wrapApiPromise(js_util.callMethod(wasm, 'attach', []));
@override
Future<void> detach() {
return _wrapApiPromise(js_util.callMethod(wasm, "detach", []));
}
Future<void> detach() =>
_wrapApiPromise(js_util.callMethod(wasm, 'detach', []));
@override
Future<void> shutdownVeilidCore() {
return _wrapApiPromise(
js_util.callMethod(wasm, "shutdown_veilid_core", []));
}
Future<void> shutdownVeilidCore() =>
_wrapApiPromise(js_util.callMethod(wasm, 'shutdown_veilid_core', []));
@override
List<CryptoKind> validCryptoKinds() {
final vck = jsonDecode(js_util.callMethod(wasm, "valid_crypto_kinds", []))
final vck = jsonDecode(js_util.callMethod(wasm, 'valid_crypto_kinds', []))
as List<dynamic>;
return vck.map((v) => v as CryptoKind).toList();
}
@ -579,118 +563,106 @@ class VeilidJS extends Veilid {
@override
Future<VeilidCryptoSystem> getCryptoSystem(CryptoKind kind) async {
if (!validCryptoKinds().contains(kind)) {
throw const VeilidAPIExceptionGeneric("unsupported cryptosystem");
throw const VeilidAPIExceptionGeneric('unsupported cryptosystem');
}
return VeilidCryptoSystemJS._(this, kind);
}
@override
Future<VeilidCryptoSystem> bestCryptoSystem() async {
return VeilidCryptoSystemJS._(
this, js_util.callMethod(wasm, "best_crypto_kind", []));
}
Future<VeilidCryptoSystem> bestCryptoSystem() async => VeilidCryptoSystemJS._(
this, js_util.callMethod(wasm, 'best_crypto_kind', []));
@override
Future<List<TypedKey>> verifySignatures(List<TypedKey> nodeIds,
Uint8List data, List<TypedSignature> signatures) async {
return jsonListConstructor(TypedKey.fromJson)(jsonDecode(
await _wrapApiPromise(js_util.callMethod(wasm, "verify_signatures", [
jsonEncode(nodeIds),
base64UrlNoPadEncode(data),
jsonEncode(signatures)
]))));
}
Uint8List data, List<TypedSignature> signatures) async =>
jsonListConstructor(TypedKey.fromJson)(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'verify_signatures', [
jsonEncode(nodeIds),
base64UrlNoPadEncode(data),
jsonEncode(signatures)
]))));
@override
Future<List<TypedSignature>> generateSignatures(
Uint8List data, List<TypedKeyPair> keyPairs) async {
return jsonListConstructor(TypedSignature.fromJson)(jsonDecode(
await _wrapApiPromise(js_util.callMethod(wasm, "generate_signatures",
[base64UrlNoPadEncode(data), jsonEncode(keyPairs)]))));
}
Uint8List data, List<TypedKeyPair> keyPairs) async =>
jsonListConstructor(TypedSignature.fromJson)(jsonDecode(
await _wrapApiPromise(js_util.callMethod(wasm, 'generate_signatures',
[base64UrlNoPadEncode(data), jsonEncode(keyPairs)]))));
@override
Future<TypedKeyPair> generateKeyPair(CryptoKind kind) async {
return TypedKeyPair.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, "generate_key_pair", [kind]))));
}
Future<TypedKeyPair> generateKeyPair(CryptoKind kind) async =>
TypedKeyPair.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'generate_key_pair', [kind]))));
@override
Future<VeilidRoutingContext> routingContext() async {
int id =
await _wrapApiPromise(js_util.callMethod(wasm, "routing_context", []));
return VeilidRoutingContextJS._(_Ctx(id, this));
final rcid = await _wrapApiPromise<int>(
js_util.callMethod(wasm, 'routing_context', []));
return VeilidRoutingContextJS._(_Ctx(rcid, this));
}
@override
Future<RouteBlob> newPrivateRoute() async {
return RouteBlob.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, "new_private_route", []))));
}
Future<RouteBlob> newPrivateRoute() async =>
RouteBlob.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'new_private_route', []))));
@override
Future<RouteBlob> newCustomPrivateRoute(
Stability stability, Sequencing sequencing) async {
var stabilityString = jsonEncode(stability);
var sequencingString = jsonEncode(sequencing);
final stabilityString = jsonEncode(stability);
final sequencingString = jsonEncode(sequencing);
return RouteBlob.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(
wasm, "new_private_route", [stabilityString, sequencingString]))));
wasm, 'new_private_route', [stabilityString, sequencingString]))));
}
@override
Future<String> importRemotePrivateRoute(Uint8List blob) {
var encodedBlob = base64UrlNoPadEncode(blob);
final encodedBlob = base64UrlNoPadEncode(blob);
return _wrapApiPromise(
js_util.callMethod(wasm, "import_remote_private_route", [encodedBlob]));
js_util.callMethod(wasm, 'import_remote_private_route', [encodedBlob]));
}
@override
Future<void> releasePrivateRoute(String key) {
return _wrapApiPromise(
js_util.callMethod(wasm, "release_private_route", [key]));
}
Future<void> releasePrivateRoute(String key) =>
_wrapApiPromise(js_util.callMethod(wasm, 'release_private_route', [key]));
@override
Future<void> appCallReply(String callId, Uint8List message) {
var encodedMessage = base64UrlNoPadEncode(message);
final encodedMessage = base64UrlNoPadEncode(message);
return _wrapApiPromise(
js_util.callMethod(wasm, "app_call_reply", [callId, encodedMessage]));
js_util.callMethod(wasm, 'app_call_reply', [callId, encodedMessage]));
}
@override
Future<VeilidTableDB> openTableDB(String name, int columnCount) async {
int id = await _wrapApiPromise(
js_util.callMethod(wasm, "open_table_db", [name, columnCount]));
return VeilidTableDBJS._(_TDB(id, this));
final dbid = await _wrapApiPromise<int>(
js_util.callMethod(wasm, 'open_table_db', [name, columnCount]));
return VeilidTableDBJS._(_TDB(dbid, this));
}
@override
Future<bool> deleteTableDB(String name) {
return _wrapApiPromise(js_util.callMethod(wasm, "delete_table_db", [name]));
}
Future<bool> deleteTableDB(String name) =>
_wrapApiPromise(js_util.callMethod(wasm, 'delete_table_db', [name]));
@override
Timestamp now() {
return Timestamp.fromString(js_util.callMethod(wasm, "now", []));
}
Timestamp now() => Timestamp.fromString(js_util.callMethod(wasm, 'now', []));
@override
Future<String> debug(String command) async {
return await _wrapApiPromise(js_util.callMethod(wasm, "debug", [command]));
}
Future<String> debug(String command) async =>
_wrapApiPromise(js_util.callMethod(wasm, 'debug', [command]));
@override
String veilidVersionString() {
return js_util.callMethod(wasm, "veilid_version_string", []);
}
String veilidVersionString() =>
js_util.callMethod(wasm, 'veilid_version_string', []);
@override
VeilidVersion veilidVersion() {
Map<String, dynamic> jsonVersion =
jsonDecode(js_util.callMethod(wasm, "veilid_version", []));
return VeilidVersion(
jsonVersion["major"], jsonVersion["minor"], jsonVersion["patch"]);
final jsonVersion =
jsonDecode(js_util.callMethod(wasm, 'veilid_version', []))
as Map<String, dynamic>;
return VeilidVersion(jsonVersion['major'] as int,
jsonVersion['minor'] as int, jsonVersion['patch'] as int);
}
}

View File

@ -11,7 +11,7 @@ class VeilidPluginStubWeb {
Future<dynamic> handleMethodCall(MethodCall call) async {
throw PlatformException(
code: 'Unimplemented',
details: 'Veilid for Web doesn\'t implement \'${call.method}\'',
details: "Veilid for Web doesn't implement '${call.method}'",
);
}
}

View File

@ -21,9 +21,10 @@ enum AttachmentState {
overAttached,
detaching;
String toJson() => name.toPascalCase();
factory AttachmentState.fromJson(dynamic j) =>
AttachmentState.values.byName((j as String).toCamelCase());
String toJson() => name.toPascalCase();
}
//////////////////////////////////////
@ -36,9 +37,10 @@ enum VeilidLogLevel {
debug,
trace;
String toJson() => name.toPascalCase();
factory VeilidLogLevel.fromJson(dynamic j) =>
VeilidLogLevel.values.byName((j as String).toCamelCase());
String toJson() => name.toPascalCase();
}
////////////
@ -109,8 +111,8 @@ class PeerStats with _$PeerStats {
const factory PeerStats({
required Timestamp timeAdded,
required RPCStats rpcStats,
LatencyStats? latency,
required TransferStatsDownUp transfer,
LatencyStats? latency,
}) = _PeerStats;
factory PeerStats.fromJson(dynamic json) =>
@ -142,13 +144,13 @@ sealed class VeilidUpdate with _$VeilidUpdate {
String? backtrace,
}) = VeilidLog;
const factory VeilidUpdate.appMessage({
TypedKey? sender,
@Uint8ListJsonConverter() required Uint8List message,
TypedKey? sender,
}) = VeilidAppMessage;
const factory VeilidUpdate.appCall({
TypedKey? sender,
@Uint8ListJsonConverter() required Uint8List message,
required String callId,
TypedKey? sender,
}) = VeilidAppCall;
const factory VeilidUpdate.attachment(
{required AttachmentState state,

View File

@ -1,6 +1,6 @@
import 'dart:async';
import 'dart:typed_data';
import 'dart:convert';
import 'dart:typed_data';
/////////////////////////////////////
/// VeilidTableDB
@ -12,16 +12,14 @@ abstract class VeilidTableDBTransaction {
Future<void> delete(int col, Uint8List key);
Future<void> storeJson(int col, Uint8List key, Object? object,
{Object? Function(Object? nonEncodable)? toEncodable}) async {
return store(col, key,
utf8.encoder.convert(jsonEncode(object, toEncodable: toEncodable)));
}
{Object? Function(Object? nonEncodable)? toEncodable}) async =>
store(col, key,
utf8.encoder.convert(jsonEncode(object, toEncodable: toEncodable)));
Future<void> storeStringJson(int col, String key, Object? object,
{Object? Function(Object? nonEncodable)? toEncodable}) {
return storeJson(col, utf8.encoder.convert(key), object,
toEncodable: toEncodable);
}
{Object? Function(Object? nonEncodable)? toEncodable}) =>
storeJson(col, utf8.encoder.convert(key), object,
toEncodable: toEncodable);
}
abstract class VeilidTableDB {
@ -34,20 +32,18 @@ abstract class VeilidTableDB {
Future<Uint8List?> delete(int col, Uint8List key);
Future<void> storeJson(int col, Uint8List key, Object? object,
{Object? Function(Object? nonEncodable)? toEncodable}) {
return store(col, key,
utf8.encoder.convert(jsonEncode(object, toEncodable: toEncodable)));
}
{Object? Function(Object? nonEncodable)? toEncodable}) =>
store(col, key,
utf8.encoder.convert(jsonEncode(object, toEncodable: toEncodable)));
Future<void> storeStringJson(int col, String key, Object? object,
{Object? Function(Object? nonEncodable)? toEncodable}) {
return storeJson(col, utf8.encoder.convert(key), object,
toEncodable: toEncodable);
}
{Object? Function(Object? nonEncodable)? toEncodable}) =>
storeJson(col, utf8.encoder.convert(key), object,
toEncodable: toEncodable);
Future<Object?> loadJson(int col, Uint8List key,
{Object? Function(Object? key, Object? value)? reviver}) async {
var s = await load(col, key);
final s = await load(col, key);
if (s == null) {
return null;
}
@ -55,13 +51,12 @@ abstract class VeilidTableDB {
}
Future<Object?> loadStringJson(int col, String key,
{Object? Function(Object? key, Object? value)? reviver}) {
return loadJson(col, utf8.encoder.convert(key), reviver: reviver);
}
{Object? Function(Object? key, Object? value)? reviver}) =>
loadJson(col, utf8.encoder.convert(key), reviver: reviver);
Future<Object?> deleteJson(int col, Uint8List key,
{Object? Function(Object? key, Object? value)? reviver}) async {
var s = await delete(col, key);
final s = await delete(col, key);
if (s == null) {
return null;
}
@ -69,7 +64,6 @@ abstract class VeilidTableDB {
}
Future<Object?> deleteStringJson(int col, String key,
{Object? Function(Object? key, Object? value)? reviver}) {
return deleteJson(col, utf8.encoder.convert(key), reviver: reviver);
}
{Object? Function(Object? key, Object? value)? reviver}) =>
deleteJson(col, utf8.encoder.convert(key), reviver: reviver);
}

View File

@ -8,28 +8,28 @@ environment:
sdk: '>=3.0.0 <4.0.0'
dependencies:
change_case: ^1.0.1
charcode: ^1.3.1
equatable: ^2.0.5
ffi: ^2.0.0
flutter:
sdk: flutter
flutter_web_plugins:
sdk: flutter
ffi: ^2.0.0
change_case: ^1.0.1
path_provider: ^2.0.9
path: ^1.8.0
system_info2: ^3.0.2
system_info_plus: ^0.0.5
charcode: ^1.3.1
freezed_annotation: ^2.2.0
json_annotation: ^4.8.1
equatable: ^2.0.5
path: ^1.8.0
path_provider: ^2.0.9
system_info2: ^3.0.2
system_info_plus: ^0.0.5
dev_dependencies:
build_runner: ^2.4.6
flutter_test:
sdk: flutter
flutter_lints: ^2.0.1
build_runner: ^2.4.6
freezed: ^2.3.5
json_serializable: ^6.7.1
lint_hard: ^4.0.0
# The following section is specific to Flutter.
flutter:

View File

@ -2,7 +2,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:veilid/veilid.dart';
void main() {
Veilid api = Veilid.instance;
final api = Veilid.instance;
TestWidgetsFlutterBinding.ensureInitialized();

View File

@ -7,7 +7,9 @@ import json
from . import *
##################################################################
BOGUS_KEY = veilid.TypedKey.from_value(veilid.CryptoKind.CRYPTO_KIND_VLD0, veilid.PublicKey.from_bytes(b' '))
BOGUS_KEY = veilid.TypedKey.from_value(
veilid.CryptoKind.CRYPTO_KIND_VLD0, veilid.PublicKey.from_bytes(b' '))
@pytest.mark.asyncio
async def test_get_dht_value_unopened(api_connection: veilid.VeilidAPI):
@ -24,6 +26,7 @@ async def test_open_dht_record_nonexistent_no_writer(api_connection: veilid.Veil
with pytest.raises(veilid.VeilidAPIError):
out = await rc.open_dht_record(BOGUS_KEY, None)
@pytest.mark.asyncio
async def test_close_dht_record_nonexistent(api_connection: veilid.VeilidAPI):
rc = await api_connection.new_routing_context()
@ -31,13 +34,15 @@ async def test_close_dht_record_nonexistent(api_connection: veilid.VeilidAPI):
with pytest.raises(veilid.VeilidAPIError):
await rc.close_dht_record(BOGUS_KEY)
@pytest.mark.asyncio
async def test_delete_dht_record_nonexistent(api_connection: veilid.VeilidAPI):
rc = await api_connection.new_routing_context()
async with rc:
with pytest.raises(veilid.VeilidAPIError):
await rc.delete_dht_record(BOGUS_KEY)
@pytest.mark.asyncio
async def test_create_delete_dht_record_simple(api_connection: veilid.VeilidAPI):
rc = await api_connection.new_routing_context()
@ -46,6 +51,7 @@ async def test_create_delete_dht_record_simple(api_connection: veilid.VeilidAPI)
await rc.close_dht_record(rec.key)
await rc.delete_dht_record(rec.key)
@pytest.mark.asyncio
async def test_get_dht_value_nonexistent(api_connection: veilid.VeilidAPI):
rc = await api_connection.new_routing_context()
@ -55,34 +61,34 @@ async def test_get_dht_value_nonexistent(api_connection: veilid.VeilidAPI):
await rc.close_dht_record(rec.key)
await rc.delete_dht_record(rec.key)
@pytest.mark.asyncio
async def test_set_get_dht_value(api_connection: veilid.VeilidAPI):
rc = await api_connection.new_routing_context()
async with rc:
rec = await rc.create_dht_record(veilid.DHTSchema.dflt(2))
vd = await rc.set_dht_value(rec.key, 0, b"BLAH BLAH BLAH")
assert vd != None
assert vd == None
vd2 = await rc.get_dht_value(rec.key, 0, False)
assert vd2 != None
vd3 = await rc.get_dht_value(rec.key, 0, True)
assert vd3 != None
vd4 = await rc.get_dht_value(rec.key, 1, False)
assert vd4 == None
print("vd: {}", vd.__dict__)
print("vd2: {}", vd2.__dict__)
print("vd3: {}", vd3.__dict__)
assert vd == vd2
assert vd2 == vd3
await rc.close_dht_record(rec.key)
await rc.delete_dht_record(rec.key)
@pytest.mark.asyncio
async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
rc = await api_connection.new_routing_context()
@ -104,10 +110,7 @@ async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
# Test subkey writes
vdtemp = await rc.set_dht_value(key, 1, va)
assert vdtemp != None
assert vdtemp.data == va
assert vdtemp.seq == 0
assert vdtemp.writer == owner
assert vdtemp == None
vdtemp = await rc.get_dht_value(key, 1, False)
assert vdtemp.data == va
@ -118,8 +121,7 @@ async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
assert vdtemp == None
vdtemp = await rc.set_dht_value(key, 0, vb)
assert vdtemp.data == vb
assert vdtemp.seq == 0
assert vdtemp == None
vdtemp = await rc.get_dht_value(key, 0, True)
assert vdtemp.data == vb
@ -129,17 +131,11 @@ async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
# Equal value should not trigger sequence number update
vdtemp = await rc.set_dht_value(key, 1, va)
assert vdtemp != None
assert vdtemp.data == va
assert vdtemp.seq == 0
assert vdtemp.writer == owner
assert vdtemp == None
# Different value should trigger sequence number update
vdtemp = await rc.set_dht_value(key, 1, vb)
assert vdtemp != None
assert vdtemp.data == vb
assert vdtemp.seq == 1
assert vdtemp.writer == owner
assert vdtemp == None
# Now that we initialized some subkeys
# and verified they stored correctly
@ -166,11 +162,8 @@ async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
# Verify subkey 1 can be set a second time and it updates because seq is newer
vdtemp = await rc.set_dht_value(key, 1, vc)
assert vdtemp != None
assert vdtemp.data == vc
assert vdtemp.seq == 2
assert vdtemp.writer == owner
assert vdtemp == None
# Verify the network got the subkey update with a refresh check
vdtemp = await rc.get_dht_value(key, 1, True)
assert vdtemp != None
@ -183,7 +176,7 @@ async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
await rc.close_dht_record(key)
await rc.delete_dht_record(key)
rec = await rc.open_dht_record(key, other_keypair)
assert rec != None
assert rec.key == key
@ -195,12 +188,11 @@ async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
# Verify subkey 1 can NOT be set because we have the wrong writer
with pytest.raises(veilid.VeilidAPIError):
vdtemp = await rc.set_dht_value(key, 1, va)
# Verify subkey 0 can NOT be set because we have the wrong writer
with pytest.raises(veilid.VeilidAPIError):
vdtemp = await rc.set_dht_value(key, 0, va)
# Clean up
await rc.close_dht_record(key)
await rc.delete_dht_record(key)