removing dev branch, many changes

This commit is contained in:
John Smith
2023-05-29 19:24:57 +00:00
parent 1430f3f656
commit 0a890c8707
250 changed files with 18084 additions and 8040 deletions

View File

@@ -1,15 +0,0 @@
import 'dart:convert';
import 'dart:typed_data';
String base64UrlNoPadEncode(List<int> bytes) {
var x = base64Url.encode(bytes);
while (x.endsWith('=')) {
x = x.substring(0, x.length - 1);
}
return x;
}
Uint8List base64UrlNoPadDecode(String source) {
source = base64.normalize(source);
return base64.decode(source);
}

View File

@@ -1,8 +1,53 @@
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
import 'package:system_info2/system_info2.dart' as sysinfo;
import 'veilid.dart';
const int megaByte = 1024 * 1024;
int getLocalSubkeyCacheSize() {
if (kIsWeb) {
return 128;
}
return 1024;
}
int getLocalMaxSubkeyCacheMemoryMb() {
if (kIsWeb) {
return 256;
}
return sysinfo.SysInfo.getTotalPhysicalMemory() ~/ 32 ~/ megaByte;
}
int getRemoteSubkeyCacheSize() {
if (kIsWeb) {
return 64;
}
return 128;
}
int getRemoteMaxRecords() {
if (kIsWeb) {
return 64;
}
return 128;
}
int getRemoteMaxSubkeyCacheMemoryMb() {
if (kIsWeb) {
return 256;
}
return sysinfo.SysInfo.getTotalPhysicalMemory() ~/ 32 ~/ megaByte;
}
int getRemoteMaxStorageSpaceMb() {
if (kIsWeb) {
return 128;
}
return 256;
}
Future<VeilidConfig> getDefaultVeilidConfig(String programName) async {
return VeilidConfig(
programName: programName,
@@ -19,8 +64,10 @@ Future<VeilidConfig> getDefaultVeilidConfig(String programName) async {
protectedStore: VeilidConfigProtectedStore(
allowInsecureFallback: false,
alwaysUseInsecureStorage: false,
insecureFallbackDirectory: "",
directory: "",
delete: false,
deviceEncryptionKey: "",
newDeviceEncryptionKey: null,
),
tableStore: VeilidConfigTableStore(
directory: kIsWeb
@@ -63,25 +110,30 @@ Future<VeilidConfig> getDefaultVeilidConfig(String programName) async {
queueSize: 1024,
maxTimestampBehindMs: 10000,
maxTimestampAheadMs: 10000,
timeoutMs: 10000,
timeoutMs: 5000,
maxRouteHopCount: 4,
defaultRouteHopCount: 1,
),
dht: VeilidConfigDHT(
resolveNodeTimeoutMs: null,
resolveNodeCount: 20,
resolveNodeFanout: 3,
maxFindNodeCount: 20,
getValueTimeoutMs: null,
getValueCount: 20,
getValueFanout: 3,
setValueTimeoutMs: null,
setValueCount: 20,
setValueFanout: 5,
minPeerCount: 20,
minPeerRefreshTimeMs: 2000,
validateDialInfoReceiptTimeMs: 2000,
),
resolveNodeTimeoutMs: 10000,
resolveNodeCount: 20,
resolveNodeFanout: 3,
maxFindNodeCount: 20,
getValueTimeoutMs: 10000,
getValueCount: 20,
getValueFanout: 3,
setValueTimeoutMs: 10000,
setValueCount: 20,
setValueFanout: 5,
minPeerCount: 20,
minPeerRefreshTimeMs: 2000,
validateDialInfoReceiptTimeMs: 2000,
localSubkeyCacheSize: getLocalSubkeyCacheSize(),
localMaxSubkeyCacheMemoryMb: getLocalMaxSubkeyCacheMemoryMb(),
remoteSubkeyCacheSize: getRemoteSubkeyCacheSize(),
remoteMaxRecords: getRemoteMaxRecords(),
remoteMaxSubkeyCacheMemoryMb: getRemoteMaxSubkeyCacheMemoryMb(),
remoteMaxStorageSpaceMb: getRemoteMaxStorageSpaceMb()),
upnp: true,
detectAddressChanges: true,
restrictedNatRetries: 0,

View File

@@ -0,0 +1,272 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:change_case/change_case.dart';
import 'veilid_encoding.dart';
import 'veilid.dart';
//////////////////////////////////////
//////////////////////////////////////
/// DHT Schema
abstract class DHTSchema {
factory DHTSchema.fromJson(dynamic json) {
switch (json["kind"]) {
case "DFLT":
{
return DHTSchemaDFLT(oCnt: json["o_cnt"]);
}
case "SMPL":
{
return DHTSchemaSMPL(
oCnt: json["o_cnt"],
members: List<DHTSchemaMember>.from(
json['members'].map((j) => DHTSchemaMember.fromJson(j))));
}
default:
{
throw VeilidAPIExceptionInternal(
"Invalid VeilidAPIException type: ${json['kind']}");
}
}
}
Map<String, dynamic> toJson();
}
class DHTSchemaDFLT implements DHTSchema {
final int oCnt;
//
DHTSchemaDFLT({
required this.oCnt,
}) {
if (oCnt < 0 || oCnt > 65535) {
throw VeilidAPIExceptionInvalidArgument(
"value out of range", "oCnt", oCnt.toString());
}
}
@override
Map<String, dynamic> toJson() {
return {
'kind': "DFLT",
'o_cnt': oCnt,
};
}
}
class DHTSchemaMember {
PublicKey mKey;
int mCnt;
DHTSchemaMember({
required this.mKey,
required this.mCnt,
}) {
if (mCnt < 0 || mCnt > 65535) {
throw VeilidAPIExceptionInvalidArgument(
"value out of range", "mCnt", mCnt.toString());
}
}
Map<String, dynamic> toJson() {
return {
'm_key': mKey,
'm_cnt': mCnt,
};
}
DHTSchemaMember.fromJson(dynamic json)
: mKey = json['m_key'],
mCnt = json['m_cnt'];
}
class DHTSchemaSMPL implements DHTSchema {
final int oCnt;
final List<DHTSchemaMember> members;
//
DHTSchemaSMPL({
required this.oCnt,
required this.members,
}) {
if (oCnt < 0 || oCnt > 65535) {
throw VeilidAPIExceptionInvalidArgument(
"value out of range", "oCnt", oCnt.toString());
}
}
@override
Map<String, dynamic> toJson() {
return {
'kind': "SMPL",
'o_cnt': oCnt,
'members': members.map((p) => p.toJson()).toList(),
};
}
}
//////////////////////////////////////
/// DHTRecordDescriptor
class DHTRecordDescriptor {
TypedKey key;
PublicKey owner;
PublicKey? ownerSecret;
DHTSchema schema;
DHTRecordDescriptor({
required this.key,
required this.owner,
this.ownerSecret,
required this.schema,
});
Map<String, dynamic> toJson() {
return {
'key': key.toString(),
'owner': owner,
'owner_secret': ownerSecret,
'schema': schema.toJson(),
};
}
DHTRecordDescriptor.fromJson(dynamic json)
: key = TypedKey.fromString(json['key']),
owner = json['owner'],
ownerSecret = json['owner_secret'],
schema = DHTSchema.fromJson(json['schema']);
}
//////////////////////////////////////
/// ValueSubkeyRange
class ValueSubkeyRange {
final int low;
final int high;
ValueSubkeyRange({
required this.low,
required this.high,
}) {
if (low < 0 || low > high) {
throw VeilidAPIExceptionInvalidArgument(
"invalid range", "low", low.toString());
}
if (high < 0) {
throw VeilidAPIExceptionInvalidArgument(
"invalid range", "high", high.toString());
}
}
ValueSubkeyRange.fromJson(dynamic json)
: low = json[0],
high = json[1] {
if ((json as List<int>).length != 2) {
throw VeilidAPIExceptionInvalidArgument(
"not a pair of integers", "json", json.toString());
}
}
List<dynamic> toJson() {
return [low, high];
}
}
//////////////////////////////////////
/// ValueData
class ValueData {
final int seq;
final Uint8List data;
final PublicKey writer;
ValueData({
required this.seq,
required this.data,
required this.writer,
});
ValueData.fromJson(dynamic json)
: seq = json['seq'],
data = base64UrlNoPadDecode(json['data']),
writer = json['writer'];
Map<String, dynamic> toJson() {
return {'seq': seq, 'data': base64UrlNoPadEncode(data), 'writer': writer};
}
}
/// Stability
enum Stability {
lowLatency,
reliable;
String toJson() {
return name.toPascalCase();
}
factory Stability.fromJson(String j) {
return Stability.values.byName(j.toCamelCase());
}
}
//////////////////////////////////////
/// Sequencing
enum Sequencing {
noPreference,
preferOrdered,
ensureOrdered;
String toJson() {
return name.toPascalCase();
}
factory Sequencing.fromJson(String j) {
return Sequencing.values.byName(j.toCamelCase());
}
}
//////////////////////////////////////
/// RouteBlob
class RouteBlob {
final String routeId;
final Uint8List blob;
RouteBlob(this.routeId, this.blob);
RouteBlob.fromJson(dynamic json)
: routeId = json['route_id'],
blob = base64UrlNoPadDecode(json['blob']);
Map<String, dynamic> toJson() {
return {'route_id': routeId, 'blob': base64UrlNoPadEncode(blob)};
}
}
//////////////////////////////////////
/// VeilidRoutingContext
abstract class VeilidRoutingContext {
// Modifiers
VeilidRoutingContext withPrivacy();
VeilidRoutingContext withCustomPrivacy(Stability stability);
VeilidRoutingContext withSequencing(Sequencing sequencing);
// App call/message
Future<Uint8List> appCall(String target, Uint8List request);
Future<void> appMessage(String target, Uint8List message);
// DHT Operations
Future<DHTRecordDescriptor> createDHTRecord(
CryptoKind kind, DHTSchema schema);
Future<DHTRecordDescriptor> openDHTRecord(TypedKey key, KeyPair? writer);
Future<void> closeDHTRecord(TypedKey key);
Future<void> deleteDHTRecord(TypedKey key);
Future<ValueData?> getDHTValue(TypedKey key, int subkey, bool forceRefresh);
Future<ValueData?> setDHTValue(TypedKey key, int subkey, Uint8List data);
Future<Timestamp> watchDHTValues(
TypedKey key, ValueSubkeyRange subkeys, Timestamp expiration, int count);
Future<bool> cancelDHTWatch(TypedKey key, ValueSubkeyRange subkeys);
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,947 @@
import 'package:change_case/change_case.dart';
import 'veilid.dart';
//////////////////////////////////////////////////////////
// FFI Platform-specific config
class VeilidFFIConfigLoggingTerminal {
bool enabled;
VeilidConfigLogLevel level;
VeilidFFIConfigLoggingTerminal({
required this.enabled,
required this.level,
});
Map<String, dynamic> toJson() {
return {
'enabled': enabled,
'level': level.toJson(),
};
}
VeilidFFIConfigLoggingTerminal.fromJson(dynamic json)
: enabled = json['enabled'],
level = VeilidConfigLogLevel.fromJson(json['level']);
}
class VeilidFFIConfigLoggingOtlp {
bool enabled;
VeilidConfigLogLevel level;
String grpcEndpoint;
String serviceName;
VeilidFFIConfigLoggingOtlp({
required this.enabled,
required this.level,
required this.grpcEndpoint,
required this.serviceName,
});
Map<String, dynamic> toJson() {
return {
'enabled': enabled,
'level': level.toJson(),
'grpc_endpoint': grpcEndpoint,
'service_name': serviceName,
};
}
VeilidFFIConfigLoggingOtlp.fromJson(dynamic json)
: enabled = json['enabled'],
level = VeilidConfigLogLevel.fromJson(json['level']),
grpcEndpoint = json['grpc_endpoint'],
serviceName = json['service_name'];
}
class VeilidFFIConfigLoggingApi {
bool enabled;
VeilidConfigLogLevel level;
VeilidFFIConfigLoggingApi({
required this.enabled,
required this.level,
});
Map<String, dynamic> toJson() {
return {
'enabled': enabled,
'level': level.toJson(),
};
}
VeilidFFIConfigLoggingApi.fromJson(dynamic json)
: enabled = json['enabled'],
level = VeilidConfigLogLevel.fromJson(json['level']);
}
class VeilidFFIConfigLogging {
VeilidFFIConfigLoggingTerminal terminal;
VeilidFFIConfigLoggingOtlp otlp;
VeilidFFIConfigLoggingApi api;
VeilidFFIConfigLogging(
{required this.terminal, required this.otlp, required this.api});
Map<String, dynamic> toJson() {
return {
'terminal': terminal.toJson(),
'otlp': otlp.toJson(),
'api': api.toJson(),
};
}
VeilidFFIConfigLogging.fromJson(dynamic json)
: terminal = VeilidFFIConfigLoggingTerminal.fromJson(json['terminal']),
otlp = VeilidFFIConfigLoggingOtlp.fromJson(json['otlp']),
api = VeilidFFIConfigLoggingApi.fromJson(json['api']);
}
class VeilidFFIConfig {
VeilidFFIConfigLogging logging;
VeilidFFIConfig({
required this.logging,
});
Map<String, dynamic> toJson() {
return {
'logging': logging.toJson(),
};
}
VeilidFFIConfig.fromJson(Map<String, dynamic> json)
: logging = VeilidFFIConfigLogging.fromJson(json['logging']);
}
//////////////////////////////////////
/// VeilidConfigLogLevel
enum VeilidConfigLogLevel {
off,
error,
warn,
info,
debug,
trace;
String toJson() {
return name.toPascalCase();
}
factory VeilidConfigLogLevel.fromJson(dynamic j) {
return VeilidConfigLogLevel.values.byName((j as String).toCamelCase());
}
}
//////////////////////////////////////////////////////////
// WASM Platform-specific config
class VeilidWASMConfigLoggingPerformance {
bool enabled;
VeilidConfigLogLevel level;
bool logsInTimings;
bool logsInConsole;
VeilidWASMConfigLoggingPerformance({
required this.enabled,
required this.level,
required this.logsInTimings,
required this.logsInConsole,
});
Map<String, dynamic> toJson() {
return {
'enabled': enabled,
'level': level.toJson(),
'logs_in_timings': logsInTimings,
'logs_in_console': logsInConsole,
};
}
VeilidWASMConfigLoggingPerformance.fromJson(dynamic json)
: enabled = json['enabled'],
level = VeilidConfigLogLevel.fromJson(json['level']),
logsInTimings = json['logs_in_timings'],
logsInConsole = json['logs_in_console'];
}
class VeilidWASMConfigLoggingApi {
bool enabled;
VeilidConfigLogLevel level;
VeilidWASMConfigLoggingApi({
required this.enabled,
required this.level,
});
Map<String, dynamic> toJson() {
return {
'enabled': enabled,
'level': level.toJson(),
};
}
VeilidWASMConfigLoggingApi.fromJson(dynamic json)
: enabled = json['enabled'],
level = VeilidConfigLogLevel.fromJson(json['level']);
}
class VeilidWASMConfigLogging {
VeilidWASMConfigLoggingPerformance performance;
VeilidWASMConfigLoggingApi api;
VeilidWASMConfigLogging({required this.performance, required this.api});
Map<String, dynamic> toJson() {
return {
'performance': performance.toJson(),
'api': api.toJson(),
};
}
VeilidWASMConfigLogging.fromJson(dynamic json)
: performance =
VeilidWASMConfigLoggingPerformance.fromJson(json['performance']),
api = VeilidWASMConfigLoggingApi.fromJson(json['api']);
}
class VeilidWASMConfig {
VeilidWASMConfigLogging logging;
VeilidWASMConfig({
required this.logging,
});
Map<String, dynamic> toJson() {
return {
'logging': logging.toJson(),
};
}
VeilidWASMConfig.fromJson(dynamic json)
: logging = VeilidWASMConfigLogging.fromJson(json['logging']);
}
//////////////////////////////////////
/// VeilidConfig
class VeilidConfigHTTPS {
bool enabled;
String listenAddress;
String path;
String? url;
VeilidConfigHTTPS({
required this.enabled,
required this.listenAddress,
required this.path,
this.url,
});
Map<String, dynamic> toJson() {
return {
'enabled': enabled,
'listen_address': listenAddress,
'path': path,
'url': url
};
}
VeilidConfigHTTPS.fromJson(dynamic json)
: enabled = json['enabled'],
listenAddress = json['listen_address'],
path = json['path'],
url = json['url'];
}
////////////
class VeilidConfigHTTP {
bool enabled;
String listenAddress;
String path;
String? url;
VeilidConfigHTTP({
required this.enabled,
required this.listenAddress,
required this.path,
this.url,
});
Map<String, dynamic> toJson() {
return {
'enabled': enabled,
'listen_address': listenAddress,
'path': path,
'url': url
};
}
VeilidConfigHTTP.fromJson(dynamic json)
: enabled = json['enabled'],
listenAddress = json['listen_address'],
path = json['path'],
url = json['url'];
}
////////////
class VeilidConfigApplication {
VeilidConfigHTTPS https;
VeilidConfigHTTP http;
VeilidConfigApplication({
required this.https,
required this.http,
});
Map<String, dynamic> toJson() {
return {
'https': https.toJson(),
'http': http.toJson(),
};
}
VeilidConfigApplication.fromJson(dynamic json)
: https = VeilidConfigHTTPS.fromJson(json['https']),
http = VeilidConfigHTTP.fromJson(json['http']);
}
////////////
class VeilidConfigUDP {
bool enabled;
int socketPoolSize;
String listenAddress;
String? publicAddress;
VeilidConfigUDP(
{required this.enabled,
required this.socketPoolSize,
required this.listenAddress,
this.publicAddress});
Map<String, dynamic> toJson() {
return {
'enabled': enabled,
'socket_pool_size': socketPoolSize,
'listen_address': listenAddress,
'public_address': publicAddress,
};
}
VeilidConfigUDP.fromJson(dynamic json)
: enabled = json['enabled'],
socketPoolSize = json['socket_pool_size'],
listenAddress = json['listen_address'],
publicAddress = json['publicAddress'];
}
////////////
class VeilidConfigTCP {
bool connect;
bool listen;
int maxConnections;
String listenAddress;
String? publicAddress;
VeilidConfigTCP(
{required this.connect,
required this.listen,
required this.maxConnections,
required this.listenAddress,
this.publicAddress});
Map<String, dynamic> toJson() {
return {
'connect': connect,
'listen': listen,
'max_connections': maxConnections,
'listen_address': listenAddress,
'public_address': publicAddress,
};
}
VeilidConfigTCP.fromJson(dynamic json)
: connect = json['connect'],
listen = json['listen'],
maxConnections = json['max_connections'],
listenAddress = json['listen_address'],
publicAddress = json['publicAddress'];
}
////////////
class VeilidConfigWS {
bool connect;
bool listen;
int maxConnections;
String listenAddress;
String path;
String? url;
VeilidConfigWS(
{required this.connect,
required this.listen,
required this.maxConnections,
required this.listenAddress,
required this.path,
this.url});
Map<String, dynamic> toJson() {
return {
'connect': connect,
'listen': listen,
'max_connections': maxConnections,
'listen_address': listenAddress,
'path': path,
'url': url,
};
}
VeilidConfigWS.fromJson(dynamic json)
: connect = json['connect'],
listen = json['listen'],
maxConnections = json['max_connections'],
listenAddress = json['listen_address'],
path = json['path'],
url = json['url'];
}
////////////
class VeilidConfigWSS {
bool connect;
bool listen;
int maxConnections;
String listenAddress;
String path;
String? url;
VeilidConfigWSS(
{required this.connect,
required this.listen,
required this.maxConnections,
required this.listenAddress,
required this.path,
this.url});
Map<String, dynamic> toJson() {
return {
'connect': connect,
'listen': listen,
'max_connections': maxConnections,
'listen_address': listenAddress,
'path': path,
'url': url,
};
}
VeilidConfigWSS.fromJson(dynamic json)
: connect = json['connect'],
listen = json['listen'],
maxConnections = json['max_connections'],
listenAddress = json['listen_address'],
path = json['path'],
url = json['url'];
}
////////////
class VeilidConfigProtocol {
VeilidConfigUDP udp;
VeilidConfigTCP tcp;
VeilidConfigWS ws;
VeilidConfigWSS wss;
VeilidConfigProtocol({
required this.udp,
required this.tcp,
required this.ws,
required this.wss,
});
Map<String, dynamic> toJson() {
return {
'udp': udp.toJson(),
'tcp': tcp.toJson(),
'ws': ws.toJson(),
'wss': wss.toJson(),
};
}
VeilidConfigProtocol.fromJson(dynamic json)
: udp = VeilidConfigUDP.fromJson(json['udp']),
tcp = VeilidConfigTCP.fromJson(json['tcp']),
ws = VeilidConfigWS.fromJson(json['ws']),
wss = VeilidConfigWSS.fromJson(json['wss']);
}
////////////
class VeilidConfigTLS {
String certificatePath;
String privateKeyPath;
int connectionInitialTimeoutMs;
VeilidConfigTLS({
required this.certificatePath,
required this.privateKeyPath,
required this.connectionInitialTimeoutMs,
});
Map<String, dynamic> toJson() {
return {
'certificate_path': certificatePath,
'private_key_path': privateKeyPath,
'connection_initial_timeout_ms': connectionInitialTimeoutMs,
};
}
VeilidConfigTLS.fromJson(dynamic json)
: certificatePath = json['certificate_path'],
privateKeyPath = json['private_key_path'],
connectionInitialTimeoutMs = json['connection_initial_timeout_ms'];
}
////////////
class VeilidConfigDHT {
int resolveNodeTimeoutMs;
int resolveNodeCount;
int resolveNodeFanout;
int maxFindNodeCount;
int getValueTimeoutMs;
int getValueCount;
int getValueFanout;
int setValueTimeoutMs;
int setValueCount;
int setValueFanout;
int minPeerCount;
int minPeerRefreshTimeMs;
int validateDialInfoReceiptTimeMs;
int localSubkeyCacheSize;
int localMaxSubkeyCacheMemoryMb;
int remoteSubkeyCacheSize;
int remoteMaxRecords;
int remoteMaxSubkeyCacheMemoryMb;
int remoteMaxStorageSpaceMb;
VeilidConfigDHT(
{required this.resolveNodeTimeoutMs,
required this.resolveNodeCount,
required this.resolveNodeFanout,
required this.maxFindNodeCount,
required this.getValueTimeoutMs,
required this.getValueCount,
required this.getValueFanout,
required this.setValueTimeoutMs,
required this.setValueCount,
required this.setValueFanout,
required this.minPeerCount,
required this.minPeerRefreshTimeMs,
required this.validateDialInfoReceiptTimeMs,
required this.localSubkeyCacheSize,
required this.localMaxSubkeyCacheMemoryMb,
required this.remoteSubkeyCacheSize,
required this.remoteMaxRecords,
required this.remoteMaxSubkeyCacheMemoryMb,
required this.remoteMaxStorageSpaceMb});
Map<String, dynamic> toJson() {
return {
'max_find_node_count': maxFindNodeCount,
'resolve_node_timeout_ms': resolveNodeTimeoutMs,
'resolve_node_count': resolveNodeCount,
'resolve_node_fanout': resolveNodeFanout,
'get_value_timeout_ms': getValueTimeoutMs,
'get_value_count': getValueCount,
'get_value_fanout': getValueFanout,
'set_value_timeout_ms': setValueTimeoutMs,
'set_value_count': setValueCount,
'set_value_fanout': setValueFanout,
'min_peer_count': minPeerCount,
'min_peer_refresh_time_ms': minPeerRefreshTimeMs,
'validate_dial_info_receipt_time_ms': validateDialInfoReceiptTimeMs,
'local_subkey_cache_size': localSubkeyCacheSize,
'local_max_subkey_cache_memory_mb': localMaxSubkeyCacheMemoryMb,
'remote_subkey_cache_size': remoteSubkeyCacheSize,
'remote_max_records': remoteMaxRecords,
'remote_max_subkey_cache_memory_mb': remoteMaxSubkeyCacheMemoryMb,
'remote_max_storage_space_mb': remoteMaxStorageSpaceMb,
};
}
VeilidConfigDHT.fromJson(dynamic json)
: resolveNodeTimeoutMs = json['resolve_node_timeout_ms'],
resolveNodeCount = json['resolve_node_count'],
resolveNodeFanout = json['resolve_node_fanout'],
maxFindNodeCount = json['max_find_node_count'],
getValueTimeoutMs = json['get_value_timeout_ms'],
getValueCount = json['get_value_count'],
getValueFanout = json['get_value_fanout'],
setValueTimeoutMs = json['set_value_timeout_ms'],
setValueCount = json['set_value_count'],
setValueFanout = json['set_value_fanout'],
minPeerCount = json['min_peer_count'],
minPeerRefreshTimeMs = json['min_peer_refresh_time_ms'],
validateDialInfoReceiptTimeMs =
json['validate_dial_info_receipt_time_ms'],
localSubkeyCacheSize = json['local_subkey_cache_size'],
localMaxSubkeyCacheMemoryMb = json['local_max_subkey_cache_memory_mb'],
remoteSubkeyCacheSize = json['remote_subkey_cache_size'],
remoteMaxRecords = json['remote_max_records'],
remoteMaxSubkeyCacheMemoryMb =
json['remote_max_subkey_cache_memory_mb'],
remoteMaxStorageSpaceMb = json['remote_max_storage_space_mb'];
}
////////////
class VeilidConfigRPC {
int concurrency;
int queueSize;
int? maxTimestampBehindMs;
int? maxTimestampAheadMs;
int timeoutMs;
int maxRouteHopCount;
int defaultRouteHopCount;
VeilidConfigRPC(
{required this.concurrency,
required this.queueSize,
this.maxTimestampBehindMs,
this.maxTimestampAheadMs,
required this.timeoutMs,
required this.maxRouteHopCount,
required this.defaultRouteHopCount});
Map<String, dynamic> toJson() {
return {
'concurrency': concurrency,
'queue_size': queueSize,
'max_timestamp_behind_ms': maxTimestampBehindMs,
'max_timestamp_ahead_ms': maxTimestampAheadMs,
'timeout_ms': timeoutMs,
'max_route_hop_count': maxRouteHopCount,
'default_route_hop_count': defaultRouteHopCount,
};
}
VeilidConfigRPC.fromJson(dynamic json)
: concurrency = json['concurrency'],
queueSize = json['queue_size'],
maxTimestampBehindMs = json['max_timestamp_behind_ms'],
maxTimestampAheadMs = json['max_timestamp_ahead_ms'],
timeoutMs = json['timeout_ms'],
maxRouteHopCount = json['max_route_hop_count'],
defaultRouteHopCount = json['default_route_hop_count'];
}
////////////
class VeilidConfigRoutingTable {
List<PublicKey> nodeId;
List<PublicKey> nodeIdSecret;
List<String> bootstrap;
int limitOverAttached;
int limitFullyAttached;
int limitAttachedStrong;
int limitAttachedGood;
int limitAttachedWeak;
VeilidConfigRoutingTable({
required this.nodeId,
required this.nodeIdSecret,
required this.bootstrap,
required this.limitOverAttached,
required this.limitFullyAttached,
required this.limitAttachedStrong,
required this.limitAttachedGood,
required this.limitAttachedWeak,
});
Map<String, dynamic> toJson() {
return {
'node_id': nodeId.map((p) => p.toJson()).toList(),
'node_id_secret': nodeIdSecret.map((p) => p.toJson()).toList(),
'bootstrap': bootstrap.map((p) => p).toList(),
'limit_over_attached': limitOverAttached,
'limit_fully_attached': limitFullyAttached,
'limit_attached_strong': limitAttachedStrong,
'limit_attached_good': limitAttachedGood,
'limit_attached_weak': limitAttachedWeak,
};
}
VeilidConfigRoutingTable.fromJson(dynamic json)
: nodeId = List<PublicKey>.from(
json['node_id'].map((j) => PublicKey.fromJson(j))),
nodeIdSecret = List<PublicKey>.from(
json['node_id_secret'].map((j) => PublicKey.fromJson(j))),
bootstrap = List<String>.from(json['bootstrap'].map((j) => j)),
limitOverAttached = json['limit_over_attached'],
limitFullyAttached = json['limit_fully_attached'],
limitAttachedStrong = json['limit_attached_strong'],
limitAttachedGood = json['limit_attached_good'],
limitAttachedWeak = json['limit_attached_weak'];
}
////////////
class VeilidConfigNetwork {
int connectionInitialTimeoutMs;
int connectionInactivityTimeoutMs;
int maxConnectionsPerIp4;
int maxConnectionsPerIp6Prefix;
int maxConnectionsPerIp6PrefixSize;
int maxConnectionFrequencyPerMin;
int clientWhitelistTimeoutMs;
int reverseConnectionReceiptTimeMs;
int holePunchReceiptTimeMs;
VeilidConfigRoutingTable routingTable;
VeilidConfigRPC rpc;
VeilidConfigDHT dht;
bool upnp;
bool detectAddressChanges;
int restrictedNatRetries;
VeilidConfigTLS tls;
VeilidConfigApplication application;
VeilidConfigProtocol protocol;
VeilidConfigNetwork({
required this.connectionInitialTimeoutMs,
required this.connectionInactivityTimeoutMs,
required this.maxConnectionsPerIp4,
required this.maxConnectionsPerIp6Prefix,
required this.maxConnectionsPerIp6PrefixSize,
required this.maxConnectionFrequencyPerMin,
required this.clientWhitelistTimeoutMs,
required this.reverseConnectionReceiptTimeMs,
required this.holePunchReceiptTimeMs,
required this.routingTable,
required this.rpc,
required this.dht,
required this.upnp,
required this.detectAddressChanges,
required this.restrictedNatRetries,
required this.tls,
required this.application,
required this.protocol,
});
Map<String, dynamic> toJson() {
return {
'connection_initial_timeout_ms': connectionInitialTimeoutMs,
'connection_inactivity_timeout_ms': connectionInactivityTimeoutMs,
'max_connections_per_ip4': maxConnectionsPerIp4,
'max_connections_per_ip6_prefix': maxConnectionsPerIp6Prefix,
'max_connections_per_ip6_prefix_size': maxConnectionsPerIp6PrefixSize,
'max_connection_frequency_per_min': maxConnectionFrequencyPerMin,
'client_whitelist_timeout_ms': clientWhitelistTimeoutMs,
'reverse_connection_receipt_time_ms': reverseConnectionReceiptTimeMs,
'hole_punch_receipt_time_ms': holePunchReceiptTimeMs,
'routing_table': routingTable.toJson(),
'rpc': rpc.toJson(),
'dht': dht.toJson(),
'upnp': upnp,
'detect_address_changes': detectAddressChanges,
'restricted_nat_retries': restrictedNatRetries,
'tls': tls.toJson(),
'application': application.toJson(),
'protocol': protocol.toJson(),
};
}
VeilidConfigNetwork.fromJson(dynamic json)
: connectionInitialTimeoutMs = json['connection_initial_timeout_ms'],
connectionInactivityTimeoutMs =
json['connection_inactivity_timeout_ms'],
maxConnectionsPerIp4 = json['max_connections_per_ip4'],
maxConnectionsPerIp6Prefix = json['max_connections_per_ip6_prefix'],
maxConnectionsPerIp6PrefixSize =
json['max_connections_per_ip6_prefix_size'],
maxConnectionFrequencyPerMin = json['max_connection_frequency_per_min'],
clientWhitelistTimeoutMs = json['client_whitelist_timeout_ms'],
reverseConnectionReceiptTimeMs =
json['reverse_connection_receipt_time_ms'],
holePunchReceiptTimeMs = json['hole_punch_receipt_time_ms'],
routingTable = VeilidConfigRoutingTable.fromJson(json['routing_table']),
rpc = VeilidConfigRPC.fromJson(json['rpc']),
dht = VeilidConfigDHT.fromJson(json['dht']),
upnp = json['upnp'],
detectAddressChanges = json['detect_address_changes'],
restrictedNatRetries = json['restricted_nat_retries'],
tls = VeilidConfigTLS.fromJson(json['tls']),
application = VeilidConfigApplication.fromJson(json['application']),
protocol = VeilidConfigProtocol.fromJson(json['protocol']);
}
////////////
class VeilidConfigTableStore {
String directory;
bool delete;
VeilidConfigTableStore({
required this.directory,
required this.delete,
});
Map<String, dynamic> toJson() {
return {'directory': directory, 'delete': delete};
}
VeilidConfigTableStore.fromJson(dynamic json)
: directory = json['directory'],
delete = json['delete'];
}
////////////
class VeilidConfigBlockStore {
String directory;
bool delete;
VeilidConfigBlockStore({
required this.directory,
required this.delete,
});
Map<String, dynamic> toJson() {
return {'directory': directory, 'delete': delete};
}
VeilidConfigBlockStore.fromJson(dynamic json)
: directory = json['directory'],
delete = json['delete'];
}
////////////
class VeilidConfigProtectedStore {
bool allowInsecureFallback;
bool alwaysUseInsecureStorage;
String directory;
bool delete;
String deviceEncryptionKey;
String? newDeviceEncryptionKey;
VeilidConfigProtectedStore(
{required this.allowInsecureFallback,
required this.alwaysUseInsecureStorage,
required this.directory,
required this.delete,
required this.deviceEncryptionKey,
String? newDeviceEncryptionKey});
Map<String, dynamic> toJson() {
return {
'allow_insecure_fallback': allowInsecureFallback,
'always_use_insecure_storage': alwaysUseInsecureStorage,
'directory': directory,
'delete': delete,
'device_encryption_key': deviceEncryptionKey,
'new_device_encryption_key': newDeviceEncryptionKey,
};
}
VeilidConfigProtectedStore.fromJson(dynamic json)
: allowInsecureFallback = json['allow_insecure_fallback'],
alwaysUseInsecureStorage = json['always_use_insecure_storage'],
directory = json['directory'],
delete = json['delete'],
deviceEncryptionKey = json['device_encryption_key'],
newDeviceEncryptionKey = json['new_device_encryption_key'];
}
////////////
class VeilidConfigCapabilities {
bool protocolUDP;
bool protocolConnectTCP;
bool protocolAcceptTCP;
bool protocolConnectWS;
bool protocolAcceptWS;
bool protocolConnectWSS;
bool protocolAcceptWSS;
VeilidConfigCapabilities({
required this.protocolUDP,
required this.protocolConnectTCP,
required this.protocolAcceptTCP,
required this.protocolConnectWS,
required this.protocolAcceptWS,
required this.protocolConnectWSS,
required this.protocolAcceptWSS,
});
Map<String, dynamic> toJson() {
return {
'protocol_udp': protocolUDP,
'protocol_connect_tcp': protocolConnectTCP,
'protocol_accept_tcp': protocolAcceptTCP,
'protocol_connect_ws': protocolConnectWS,
'protocol_accept_ws': protocolAcceptWS,
'protocol_connect_wss': protocolConnectWSS,
'protocol_accept_wss': protocolAcceptWSS,
};
}
VeilidConfigCapabilities.fromJson(dynamic json)
: protocolUDP = json['protocol_udp'],
protocolConnectTCP = json['protocol_connect_tcp'],
protocolAcceptTCP = json['protocol_accept_tcp'],
protocolConnectWS = json['protocol_connect_ws'],
protocolAcceptWS = json['protocol_accept_ws'],
protocolConnectWSS = json['protocol_connect_wss'],
protocolAcceptWSS = json['protocol_accept_wss'];
}
////////////
class VeilidConfig {
String programName;
String namespace;
VeilidConfigCapabilities capabilities;
VeilidConfigProtectedStore protectedStore;
VeilidConfigTableStore tableStore;
VeilidConfigBlockStore blockStore;
VeilidConfigNetwork network;
VeilidConfig({
required this.programName,
required this.namespace,
required this.capabilities,
required this.protectedStore,
required this.tableStore,
required this.blockStore,
required this.network,
});
Map<String, dynamic> toJson() {
return {
'program_name': programName,
'namespace': namespace,
'capabilities': capabilities.toJson(),
'protected_store': protectedStore.toJson(),
'table_store': tableStore.toJson(),
'block_store': blockStore.toJson(),
'network': network.toJson()
};
}
VeilidConfig.fromJson(dynamic json)
: programName = json['program_name'],
namespace = json['namespace'],
capabilities = VeilidConfigCapabilities.fromJson(json['capabilities']),
protectedStore =
VeilidConfigProtectedStore.fromJson(json['protected_store']),
tableStore = VeilidConfigTableStore.fromJson(json['table_store']),
blockStore = VeilidConfigBlockStore.fromJson(json['block_store']),
network = VeilidConfigNetwork.fromJson(json['network']);
}

View File

@@ -0,0 +1,167 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:charcode/charcode.dart';
import 'veilid_encoding.dart';
import 'veilid.dart';
//////////////////////////////////////
/// CryptoKind
typedef CryptoKind = int;
const CryptoKind cryptoKindVLD0 =
$V << 0 | $L << 8 | $D << 16 | $0 << 24; // "VLD0"
const CryptoKind cryptoKindNONE =
$N << 0 | $O << 8 | $N << 16 | $E << 24; // "NONE"
String cryptoKindToString(CryptoKind kind) {
return "${String.fromCharCode(kind & 0xFF)}${String.fromCharCode((kind >> 8) & 0xFF)}${String.fromCharCode((kind >> 16) & 0xFF)}${String.fromCharCode((kind >> 24) & 0xFF)}";
}
CryptoKind cryptoKindFromString(String s) {
if (s.codeUnits.length != 4) {
throw const FormatException("malformed string");
}
CryptoKind kind = s.codeUnits[0] |
s.codeUnits[1] << 8 |
s.codeUnits[2] << 16 |
s.codeUnits[3] << 24;
return kind;
}
//////////////////////////////////////
/// Types
class Typed<V extends EncodedString> {
late CryptoKind kind;
late V value;
Typed({required this.kind, required this.value});
@override
String toString() {
return "${cryptoKindToString(kind)}:$value";
}
Typed.fromString(String s) {
var parts = s.split(":");
if (parts.length < 2 || parts[0].codeUnits.length != 4) {
throw const FormatException("malformed string");
}
kind = parts[0].codeUnits[0] |
parts[0].codeUnits[1] << 8 |
parts[0].codeUnits[2] << 16 |
parts[0].codeUnits[3] << 24;
value = EncodedString.fromString<V>(parts.sublist(1).join(":"));
}
String toJson() {
return toString();
}
Typed.fromJson(dynamic json) : this.fromString(json as String);
}
class KeyPair {
late PublicKey key;
late PublicKey secret;
KeyPair({required this.key, required this.secret});
@override
String toString() {
return "${key.toString()}:${secret.toString()}";
}
KeyPair.fromString(String s) {
var parts = s.split(":");
if (parts.length != 2 ||
parts[0].codeUnits.length != 43 ||
parts[1].codeUnits.length != 43) {
throw const FormatException("malformed string");
}
key = PublicKey(parts[0]);
secret = PublicKey(parts[1]);
}
String toJson() {
return toString();
}
KeyPair.fromJson(dynamic json) : this.fromString(json as String);
}
class TypedKeyPair {
late CryptoKind kind;
late PublicKey key;
late PublicKey secret;
TypedKeyPair({required this.kind, required this.key, required this.secret});
@override
String toString() {
return "${cryptoKindToString(kind)}:${key.toString()}:${secret.toString()}";
}
TypedKeyPair.fromString(String s) {
var 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);
}
kind = cryptoKindFromString(parts[0]);
key = PublicKey(parts[1]);
secret = PublicKey(parts[2]);
}
String toJson() {
return toString();
}
TypedKeyPair.fromJson(dynamic json) : this.fromString(json as String);
}
typedef CryptoKey = FixedEncodedString43;
typedef Signature = FixedEncodedString86;
typedef Nonce = FixedEncodedString32;
typedef PublicKey = CryptoKey;
typedef SecretKey = CryptoKey;
typedef HashDigest = CryptoKey;
typedef SharedSecret = CryptoKey;
typedef CryptoKeyDistance = CryptoKey;
typedef TypedKey = Typed<CryptoKey>;
typedef TypedSignature = Typed<Signature>;
//////////////////////////////////////
/// VeilidCryptoSystem
abstract class VeilidCryptoSystem {
CryptoKind kind();
Future<SharedSecret> cachedDH(PublicKey key, SecretKey secret);
Future<SharedSecret> computeDH(PublicKey key, SecretKey secret);
Future<Uint8List> randomBytes(int len);
Future<int> defaultSaltLength();
Future<String> hashPassword(Uint8List password, Uint8List salt);
Future<bool> verifyPassword(Uint8List password, String passwordHash);
Future<SharedSecret> deriveSharedSecret(Uint8List password, Uint8List salt);
Future<Nonce> randomNonce();
Future<SharedSecret> randomSharedSecret();
Future<KeyPair> generateKeyPair();
Future<HashDigest> generateHash(Uint8List data);
//Future<HashDigest> generateHashReader(Stream<List<int>> reader);
Future<bool> validateKeyPair(PublicKey key, SecretKey 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<void> verify(PublicKey key, Uint8List data, Signature signature);
Future<int> aeadOverhead();
Future<Uint8List> decryptAead(Uint8List body, Nonce nonce,
SharedSecret sharedSecret, Uint8List? associatedData);
Future<Uint8List> encryptAead(Uint8List body, Nonce nonce,
SharedSecret sharedSecret, Uint8List? associatedData);
Future<Uint8List> cryptNoAuth(
Uint8List body, Nonce nonce, SharedSecret sharedSecret);
}

View File

@@ -0,0 +1,122 @@
import 'dart:convert';
import 'dart:typed_data';
String base64UrlNoPadEncode(List<int> bytes) {
var x = base64Url.encode(bytes);
while (x.endsWith('=')) {
x = x.substring(0, x.length - 1);
}
return x;
}
Uint8List base64UrlNoPadDecode(String source) {
source = base64.normalize(source);
return base64.decode(source);
}
Uint8List base64UrlNoPadDecodeDynamic(dynamic source) {
source = source as String;
source = base64.normalize(source);
return base64.decode(source);
}
abstract class EncodedString {
late String contents;
EncodedString(String s) {
validate(s);
contents = s;
}
EncodedString.encode(List<int> b) {
var s = base64UrlNoPadEncode(b);
validate(s);
contents = s;
}
int encodedLength();
int decodedLength();
void validate(String s) {
var d = base64UrlNoPadDecode(s);
if (d.length != decodedLength()) {
throw Exception("length ${s.length} should be ${encodedLength()}");
}
}
Uint8List decode() {
return base64UrlNoPadDecode(contents);
}
@override
String toString() {
return contents;
}
static T fromString<T extends EncodedString>(String s) {
switch (T) {
case FixedEncodedString32:
return FixedEncodedString32(s) as T;
case FixedEncodedString43:
return FixedEncodedString43(s) as T;
case FixedEncodedString86:
return FixedEncodedString86(s) as T;
default:
throw UnimplementedError();
}
}
}
class FixedEncodedString32 extends EncodedString {
FixedEncodedString32(String s) : super(s);
@override
int encodedLength() {
return 32;
}
@override
int decodedLength() {
return 24;
}
String toJson() {
return toString();
}
FixedEncodedString32.fromJson(dynamic json) : this(json as String);
}
class FixedEncodedString43 extends EncodedString {
FixedEncodedString43(String s) : super(s);
@override
int encodedLength() {
return 43;
}
@override
int decodedLength() {
return 32;
}
String toJson() {
return toString();
}
FixedEncodedString43.fromJson(dynamic json) : this(json as String);
}
class FixedEncodedString86 extends EncodedString {
FixedEncodedString86(String s) : super(s);
@override
int encodedLength() {
return 86;
}
@override
int decodedLength() {
return 64;
}
String toJson() {
return toString();
}
FixedEncodedString86.fromJson(dynamic json) : this(json as String);
}

View File

@@ -8,7 +8,7 @@ import 'dart:typed_data';
import 'package:ffi/ffi.dart';
import 'veilid.dart';
import 'base64url_no_pad.dart';
import 'veilid_encoding.dart';
//////////////////////////////////////////////////////////
@@ -76,6 +76,46 @@ typedef _RoutingContextAppMessageC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>);
typedef _RoutingContextAppMessageDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>);
// fn routing_context_create_dht_record(port: i64, id: u32, kind: u32, schema: FfiStr)
typedef _RoutingContextCreateDHTRecordC = Void Function(
Int64, Uint32, Uint32, Pointer<Utf8>);
typedef _RoutingContextCreateDHTRecordDart = void Function(
int, int, int, Pointer<Utf8>);
// fn routing_context_open_dht_record(port: i64, id: u32, key: FfiStr, writer: FfiStr)
typedef _RoutingContextOpenDHTRecordC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>);
typedef _RoutingContextOpenDHTRecordDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>);
// fn routing_context_close_dht_record(port: i64, id: u32, key: FfiStr)
typedef _RoutingContextCloseDHTRecordC = Void Function(
Int64, Uint32, Pointer<Utf8>);
typedef _RoutingContextCloseDHTRecordDart = void Function(
int, int, Pointer<Utf8>);
// fn routing_context_delete_dht_record(port: i64, id: u32, key: FfiStr)
typedef _RoutingContextDeleteDHTRecordC = Void Function(
Int64, Uint32, Pointer<Utf8>);
typedef _RoutingContextDeleteDHTRecordDart = void Function(
int, int, Pointer<Utf8>);
// fn routing_context_get_dht_value(port: i64, id: u32, key: FfiStr, subkey: u32, force_refresh: bool)
typedef _RoutingContextGetDHTValueC = Void Function(
Int64, Uint32, Pointer<Utf8>, Uint32, Bool);
typedef _RoutingContextGetDHTValueDart = void Function(
int, int, Pointer<Utf8>, int, bool);
// fn routing_context_set_dht_value(port: i64, id: u32, key: FfiStr, subkey: u32, data: FfiStr)
typedef _RoutingContextSetDHTValueC = Void Function(
Int64, Uint32, Pointer<Utf8>, Uint32, Pointer<Utf8>);
typedef _RoutingContextSetDHTValueDart = void Function(
int, int, Pointer<Utf8>, int, Pointer<Utf8>);
// fn routing_context_watch_dht_values(port: i64, id: u32, key: FfiStr, subkeys: FfiStr, expiration: FfiStr, count: u32)
typedef _RoutingContextWatchDHTValuesC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>, Uint64, Uint32);
typedef _RoutingContextWatchDHTValuesDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>, int, int);
// fn routing_context_cancel_dht_watch(port: i64, id: u32, key: FfiStr, subkeys: FfiStr)
typedef _RoutingContextCancelDHTWatchC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>);
typedef _RoutingContextCancelDHTWatchDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>);
// fn new_private_route(port: i64)
typedef _NewPrivateRouteC = Void Function(Int64);
@@ -108,9 +148,9 @@ typedef _DeleteTableDbDart = void Function(int, Pointer<Utf8>);
// fn table_db_get_column_count(id: u32) -> u32
typedef _TableDbGetColumnCountC = Uint32 Function(Uint32);
typedef _TableDbGetColumnCountDart = int Function(int);
// fn table_db_get_keys(id: u32, col: u32) -> *mut c_char
typedef _TableDbGetKeysC = Pointer<Utf8> Function(Uint32, Uint32);
typedef _TableDbGetKeysDart = Pointer<Utf8> Function(int, int);
// fn table_db_get_keys(port: i64, id: u32, col: u32)
typedef _TableDbGetKeysC = Pointer<Utf8> Function(Uint64, Uint32, Uint32);
typedef _TableDbGetKeysDart = Pointer<Utf8> Function(int, int, int);
// fn table_db_store(port: i64, id: u32, col: u32, key: FfiStr, value: FfiStr)
typedef _TableDbStoreC = Void Function(
Int64, Uint32, Uint32, Pointer<Utf8>, Pointer<Utf8>);
@@ -144,7 +184,116 @@ typedef _TableDbTransactionDeleteC = Void Function(
Int64, Uint32, Uint32, Pointer<Utf8>);
typedef _TableDbTransactionDeleteDart = void Function(
int, int, int, Pointer<Utf8>);
// fn valid_crypto_kinds() -> *mut c_char
typedef _ValidCryptoKindsC = Pointer<Utf8> Function();
typedef _ValidCryptoKindsDart = Pointer<Utf8> Function();
// fn best_crypto_kind() -> u32
typedef _BestCryptoKindC = Uint32 Function();
typedef _BestCryptoKindDart = int Function();
// fn verify_signatures(port: i64, node_ids: FfiStr, data: FfiStr, signatures: FfiStr)
typedef _VerifySignaturesC = Void Function(
Int64, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>);
typedef _VerifySignaturesDart = void Function(
int, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>);
// fn generate_signatures(port: i64, data: FfiStr, key_pairs: FfiStr)
typedef _GenerateSignaturesC = Void Function(
Int64, Pointer<Utf8>, Pointer<Utf8>);
typedef _GenerateSignaturesDart = void Function(
int, Pointer<Utf8>, Pointer<Utf8>);
// fn generate_key_pair(port: i64, kind: u32) {
typedef _GenerateKeyPairC = Void Function(Int64, Uint32);
typedef _GenerateKeyPairDart = void Function(int, int);
// fn crypto_cached_dh(port: i64, kind: u32, key: FfiStr, secret: FfiStr)
typedef _CryptoCachedDHC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>);
typedef _CryptoCachedDHDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>);
// fn crypto_compute_dh(port: i64, kind: u32, key: FfiStr, secret: FfiStr)
typedef _CryptoComputeDHC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>);
typedef _CryptoComputeDHDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>);
// fn crypto_random_bytes(port: i64, kind: u32, len: u32)
typedef _CryptoRandomBytesC = Void Function(Int64, Uint32, Uint32);
typedef _CryptoRandomBytesDart = void Function(int, int, int);
// fn crypto_default_salt_length(port: i64, kind: u32)
typedef _CryptoDefaultSaltLengthC = Void Function(Int64, Uint32);
typedef _CryptoDefaultSaltLengthDart = void Function(int, int);
// fn crypto_hash_password(port: i64, kind: u32, password: FfiStr, salt: FfiStr )
typedef _CryptoHashPasswordC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>);
typedef _CryptoHashPasswordDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>);
// fn crypto_verify_password(port: i64, kind: u32, password: FfiStr, password_hash: FfiStr )
typedef _CryptoVerifyPasswordC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>);
typedef _CryptoVerifyPasswordDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>);
// fn crypto_derive_shared_secret(port: i64, kind: u32, password: FfiStr, salt: FfiStr )
typedef _CryptoDeriveSharedSecretC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>);
typedef _CryptoDeriveSharedSecretDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>);
// fn crypto_random_nonce(port: i64, kind: u32)
typedef _CryptoRandomNonceC = Void Function(Int64, Uint32);
typedef _CryptoRandomNonceDart = void Function(int, int);
// fn crypto_random_shared_secret(port: i64, kind: u32)
typedef _CryptoRandomSharedSecretC = Void Function(Int64, Uint32);
typedef _CryptoRandomSharedSecretDart = void Function(int, int);
// fn crypto_generate_key_pair(port: i64, kind: u32)
typedef _CryptoGenerateKeyPairC = Void Function(Int64, Uint32);
typedef _CryptoGenerateKeyPairDart = void Function(int, int);
// fn crypto_generate_hash(port: i64, kind: u32, data: FfiStr)
typedef _CryptoGenerateHashC = Void Function(Int64, Uint32, Pointer<Utf8>);
typedef _CryptoGenerateHashDart = void Function(int, int, Pointer<Utf8>);
// fn crypto_validate_key_pair(port: i64, kind: u32, key: FfiStr, secret: FfiStr)
typedef _CryptoValidateKeyPairC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>);
typedef _CryptoValidateKeyPairDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>);
// fn crypto_validate_hash(port: i64, kind: u32, data: FfiStr, hash: FfiStr)
typedef _CryptoValidateHashC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>);
typedef _CryptoValidateHashDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>);
// fn crypto_distance(port: i64, kind: u32, key1: FfiStr, key2: FfiStr)
typedef _CryptoDistanceC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>);
typedef _CryptoDistanceDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>);
// fn crypto_sign(port: i64, kind: u32, key: FfiStr, secret: FfiStr, data: FfiStr)
typedef _CryptoSignC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>);
typedef _CryptoSignDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>);
// fn crypto_verify(port: i64, kind: u32, key: FfiStr, data: FfiStr, signature: FfiStr)
typedef _CryptoVerifyC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>);
typedef _CryptoVerifyDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>);
// fn crypto_aead_overhead(port: i64, kind: u32)
typedef _CryptoAeadOverheadC = Void Function(Int64, Uint32);
typedef _CryptoAeadOverheadDart = void Function(int, int);
// fn crypto_decrypt_aead(port: i64, kind: u32, body: FfiStr, nonce: FfiStr, shared_secret: FfiStr, associated_data: FfiStr)
typedef _CryptoDecryptAeadC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>);
typedef _CryptoDecryptAeadDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>);
// fn crypto_encrypt_aead(port: i64, kind: u32, body: FfiStr, nonce: FfiStr, shared_secret: FfiStr, associated_data: FfiStr)
typedef _CryptoEncryptAeadC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>);
typedef _CryptoEncryptAeadDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>);
// fn crypto_crypt_no_auth(port: i64, kind: u32, body: FfiStr, nonce: FfiStr, shared_secret: FfiStr)
typedef _CryptoCryptNoAuthC = Void Function(
Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>);
typedef _CryptoCryptNoAuthDart = void Function(
int, int, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>);
// fn now() -> u64
typedef _NowC = Uint64 Function();
typedef _NowDart = int Function();
// fn debug(port: i64, log_level: FfiStr)
typedef _DebugC = Void Function(Int64, Pointer<Utf8>);
typedef _DebugDart = void Function(int, Pointer<Utf8>);
@@ -156,7 +305,7 @@ typedef _VeilidVersionStringC = Pointer<Utf8> Function();
typedef _VeilidVersionStringDart = Pointer<Utf8> Function();
// fn veilid_version() -> VeilidVersion
class VeilidVersionFFI extends Struct {
final class VeilidVersionFFI extends Struct {
@Uint32()
external int major;
@Uint32()
@@ -253,6 +402,42 @@ Future<T> processFutureJson<T>(
});
}
Future<T?> processFutureOptJson<T>(
T Function(dynamic) jsonConstructor, Future<dynamic> future) {
return future.then((value) {
final list = value as List<dynamic>;
switch (list[0] as int) {
case messageErr:
{
throw VeilidAPIExceptionInternal("Internal API Error: ${list[1]}");
}
case messageOkJson:
{
if (list[1] == null) {
return null;
}
var ret = jsonDecode(list[1] as String);
return jsonConstructor(ret);
}
case messageErrJson:
{
throw VeilidAPIException.fromJson(jsonDecode(list[1]));
}
default:
{
throw VeilidAPIExceptionInternal(
"Unexpected async return message type: ${list[0]}");
}
}
}).catchError((e) {
// Wrap all other errors in VeilidAPIExceptionInternal
throw VeilidAPIExceptionInternal(e.toString());
}, test: (e) {
// Pass errors that are already VeilidAPIException through without wrapping
return e is! VeilidAPIException;
});
}
Future<void> processFutureVoid(Future<dynamic> future) {
return future.then((value) {
final list = value as List<dynamic>;
@@ -397,7 +582,7 @@ class _Ctx {
class VeilidRoutingContextFFI implements VeilidRoutingContext {
final _Ctx _ctx;
static final Finalizer<_Ctx> _finalizer =
Finalizer((ctx) => {ctx.ffi._releaseRoutingContext(ctx.id)});
Finalizer((ctx) => ctx.ffi._releaseRoutingContext(ctx.id));
VeilidRoutingContextFFI._(this._ctx) {
_finalizer.attach(this, _ctx, detach: this);
@@ -412,14 +597,14 @@ class VeilidRoutingContextFFI implements VeilidRoutingContext {
@override
VeilidRoutingContextFFI withCustomPrivacy(Stability stability) {
final newId = _ctx.ffi._routingContextWithCustomPrivacy(
_ctx.id, stability.json.toNativeUtf8());
_ctx.id, jsonEncode(stability).toNativeUtf8());
return VeilidRoutingContextFFI._(_Ctx(newId, _ctx.ffi));
}
@override
VeilidRoutingContextFFI withSequencing(Sequencing sequencing) {
final newId = _ctx.ffi
._routingContextWithSequencing(_ctx.id, sequencing.json.toNativeUtf8());
final newId = _ctx.ffi._routingContextWithSequencing(
_ctx.id, jsonEncode(sequencing).toNativeUtf8());
return VeilidRoutingContextFFI._(_Ctx(newId, _ctx.ffi));
}
@@ -437,7 +622,7 @@ class VeilidRoutingContextFFI implements VeilidRoutingContext {
}
@override
Future<void> appMessage(String target, Uint8List message) async {
Future<void> appMessage(String target, Uint8List message) {
final nativeEncodedTarget = target.toNativeUtf8();
final nativeEncodedMessage = base64UrlNoPadEncode(message).toNativeUtf8();
@@ -447,6 +632,111 @@ class VeilidRoutingContextFFI implements VeilidRoutingContext {
nativeEncodedTarget, nativeEncodedMessage);
return processFutureVoid(recvPort.first);
}
@override
Future<DHTRecordDescriptor> createDHTRecord(
CryptoKind kind, DHTSchema schema) async {
final nativeSchema = jsonEncode(schema).toNativeUtf8();
final recvPort = ReceivePort("routing_context_create_dht_record");
final sendPort = recvPort.sendPort;
_ctx.ffi._routingContextCreateDHTRecord(
sendPort.nativePort, _ctx.id, kind, nativeSchema);
final dhtRecordDescriptor =
await processFutureJson(DHTRecordDescriptor.fromJson, recvPort.first);
return dhtRecordDescriptor;
}
@override
Future<DHTRecordDescriptor> openDHTRecord(
TypedKey key, KeyPair? writer) async {
final nativeKey = jsonEncode(key).toNativeUtf8();
final nativeWriter =
writer != null ? jsonEncode(key).toNativeUtf8() : nullptr;
final recvPort = ReceivePort("routing_context_open_dht_record");
final sendPort = recvPort.sendPort;
_ctx.ffi._routingContextOpenDHTRecord(
sendPort.nativePort, _ctx.id, nativeKey, nativeWriter);
final dhtRecordDescriptor =
await processFutureJson(DHTRecordDescriptor.fromJson, recvPort.first);
return dhtRecordDescriptor;
}
@override
Future<void> closeDHTRecord(TypedKey key) {
final nativeKey = jsonEncode(key).toNativeUtf8();
final recvPort = ReceivePort("routing_context_close_dht_record");
final sendPort = recvPort.sendPort;
_ctx.ffi
._routingContextCloseDHTRecord(sendPort.nativePort, _ctx.id, nativeKey);
return processFutureVoid(recvPort.first);
}
@override
Future<void> deleteDHTRecord(TypedKey key) {
final nativeKey = jsonEncode(key).toNativeUtf8();
final recvPort = ReceivePort("routing_context_delete_dht_record");
final sendPort = recvPort.sendPort;
_ctx.ffi._routingContextDeleteDHTRecord(
sendPort.nativePort, _ctx.id, nativeKey);
return processFutureVoid(recvPort.first);
}
@override
Future<ValueData?> getDHTValue(
TypedKey key, int subkey, bool forceRefresh) async {
final nativeKey = jsonEncode(key).toNativeUtf8();
final recvPort = ReceivePort("routing_context_get_dht_value");
final sendPort = recvPort.sendPort;
_ctx.ffi._routingContextGetDHTValue(
sendPort.nativePort, _ctx.id, nativeKey, subkey, forceRefresh);
final valueData = await processFutureJson(
optFromJson(ValueData.fromJson), recvPort.first);
return valueData;
}
@override
Future<ValueData?> setDHTValue(
TypedKey key, int subkey, Uint8List data) async {
final nativeKey = jsonEncode(key).toNativeUtf8();
final nativeData = base64UrlNoPadEncode(data).toNativeUtf8();
final recvPort = ReceivePort("routing_context_set_dht_value");
final sendPort = recvPort.sendPort;
_ctx.ffi._routingContextSetDHTValue(
sendPort.nativePort, _ctx.id, nativeKey, subkey, nativeData);
final valueData = await processFutureJson(
optFromJson(ValueData.fromJson), recvPort.first);
return valueData;
}
@override
Future<Timestamp> watchDHTValues(TypedKey key, ValueSubkeyRange subkeys,
Timestamp expiration, int count) async {
final nativeKey = jsonEncode(key).toNativeUtf8();
final nativeSubkeys = jsonEncode(subkeys).toNativeUtf8();
final nativeExpiration = expiration.value.toInt();
final recvPort = ReceivePort("routing_context_watch_dht_values");
final sendPort = recvPort.sendPort;
_ctx.ffi._routingContextWatchDHTValues(sendPort.nativePort, _ctx.id,
nativeKey, nativeSubkeys, nativeExpiration, count);
final actualExpiration = Timestamp(
value: BigInt.from(await processFuturePlain<int>(recvPort.first)));
return actualExpiration;
}
@override
Future<bool> cancelDHTWatch(TypedKey key, ValueSubkeyRange subkeys) async {
final nativeKey = jsonEncode(key).toNativeUtf8();
final nativeSubkeys = jsonEncode(subkeys).toNativeUtf8();
final recvPort = ReceivePort("routing_context_cancel_dht_watch");
final sendPort = recvPort.sendPort;
_ctx.ffi._routingContextCancelDHTWatch(
sendPort.nativePort, _ctx.id, nativeKey, nativeSubkeys);
final cancelled = await processFuturePlain<bool>(recvPort.first);
return cancelled;
}
}
class _TDBT {
@@ -461,7 +751,7 @@ class _TDBT {
class VeilidTableDBTransactionFFI extends VeilidTableDBTransaction {
final _TDBT _tdbt;
static final Finalizer<_TDBT> _finalizer =
Finalizer((tdbt) => {tdbt.ffi._releaseTableDbTransaction(tdbt.id)});
Finalizer((tdbt) => tdbt.ffi._releaseTableDbTransaction(tdbt.id));
VeilidTableDBTransactionFFI._(this._tdbt) {
_finalizer.attach(this, _tdbt, detach: this);
@@ -532,7 +822,7 @@ class _TDB {
class VeilidTableDBFFI extends VeilidTableDB {
final _TDB _tdb;
static final Finalizer<_TDB> _finalizer =
Finalizer((tdb) => {tdb.ffi._releaseTableDb(tdb.id)});
Finalizer((tdb) => tdb.ffi._releaseTableDb(tdb.id));
VeilidTableDBFFI._(this._tdb) {
_finalizer.attach(this, _tdb, detach: this);
@@ -544,15 +834,15 @@ class VeilidTableDBFFI extends VeilidTableDB {
}
@override
List<Uint8List> getKeys(int col) {
final s = _tdb.ffi._tableDbGetKeys(_tdb.id, col);
if (s.address == nullptr.address) {
throw VeilidAPIExceptionInternal("No db for id");
}
String ja = s.toDartString();
_tdb.ffi._freeString(s);
List<dynamic> jarr = jsonDecode(ja);
return jarr.map((e) => base64UrlNoPadDecode(e)).toList();
Future<List<Uint8List>> getKeys(int col) {
final recvPort = ReceivePort("veilid_table_db_get_keys");
final sendPort = recvPort.sendPort;
_tdb.ffi._tableDbGetKeys(sendPort.nativePort, _tdb.id, col);
return processFutureJson(
jsonListConstructor<Uint8List>(base64UrlNoPadDecodeDynamic),
recvPort.first);
}
@override
@@ -598,12 +888,12 @@ class VeilidTableDBFFI extends VeilidTableDB {
}
@override
Future<bool> delete(int col, Uint8List key) {
Future<Uint8List?> delete(int col, Uint8List key) {
final nativeEncodedKey = base64UrlNoPadEncode(key).toNativeUtf8();
final recvPort = ReceivePort("veilid_table_db_delete");
final sendPort = recvPort.sendPort;
_tdb.ffi._tableDbLoad(
_tdb.ffi._tableDbDelete(
sendPort.nativePort,
_tdb.id,
col,
@@ -613,6 +903,251 @@ class VeilidTableDBFFI extends VeilidTableDB {
}
}
// FFI implementation of VeilidCryptoSystem
class VeilidCryptoSystemFFI implements VeilidCryptoSystem {
final CryptoKind _kind;
final VeilidFFI _ffi;
VeilidCryptoSystemFFI._(this._ffi, this._kind);
@override
CryptoKind kind() {
return _kind;
}
@override
Future<SharedSecret> cachedDH(PublicKey key, SecretKey secret) {
final nativeKey = jsonEncode(key).toNativeUtf8();
final nativeSecret = jsonEncode(secret).toNativeUtf8();
final recvPort = ReceivePort("crypto_cached_dh");
final sendPort = recvPort.sendPort;
_ffi._cryptoCachedDH(sendPort.nativePort, _kind, nativeKey, nativeSecret);
return processFutureJson(SharedSecret.fromJson, recvPort.first);
}
@override
Future<SharedSecret> computeDH(PublicKey key, SecretKey secret) {
final nativeKey = jsonEncode(key).toNativeUtf8();
final nativeSecret = jsonEncode(secret).toNativeUtf8();
final recvPort = ReceivePort("crypto_compute_dh");
final sendPort = recvPort.sendPort;
_ffi._cryptoComputeDH(sendPort.nativePort, _kind, nativeKey, nativeSecret);
return processFutureJson(SharedSecret.fromJson, recvPort.first);
}
@override
Future<Uint8List> randomBytes(int len) async {
final recvPort = ReceivePort("crypto_random_bytes");
final sendPort = recvPort.sendPort;
_ffi._cryptoRandomBytes(sendPort.nativePort, _kind, len);
final out = await processFuturePlain(recvPort.first);
return base64UrlNoPadDecode(out);
}
@override
Future<int> defaultSaltLength() {
final recvPort = ReceivePort("crypto_default_salt_length");
final sendPort = recvPort.sendPort;
_ffi._cryptoDefaultSaltLength(sendPort.nativePort, _kind);
return processFuturePlain(recvPort.first);
}
@override
Future<String> hashPassword(Uint8List password, Uint8List salt) {
final nativeEncodedPassword = base64UrlNoPadEncode(password).toNativeUtf8();
final nativeEncodedSalt = base64UrlNoPadEncode(salt).toNativeUtf8();
final recvPort = ReceivePort("crypto_hash_password");
final sendPort = recvPort.sendPort;
_ffi._cryptoHashPassword(
sendPort.nativePort, _kind, nativeEncodedPassword, nativeEncodedSalt);
return processFuturePlain(recvPort.first);
}
@override
Future<bool> verifyPassword(Uint8List password, String passwordHash) {
final nativeEncodedPassword = base64UrlNoPadEncode(password).toNativeUtf8();
final nativeEncodedPasswordHash = passwordHash.toNativeUtf8();
final recvPort = ReceivePort("crypto_verify_password");
final sendPort = recvPort.sendPort;
_ffi._cryptoVerifyPassword(sendPort.nativePort, _kind,
nativeEncodedPassword, nativeEncodedPasswordHash);
return processFuturePlain(recvPort.first);
}
@override
Future<SharedSecret> deriveSharedSecret(Uint8List password, Uint8List salt) {
final nativeEncodedPassword = base64UrlNoPadEncode(password).toNativeUtf8();
final nativeEncodedSalt = base64UrlNoPadEncode(salt).toNativeUtf8();
final recvPort = ReceivePort("crypto_derive_shared_secret");
final sendPort = recvPort.sendPort;
_ffi._cryptoDeriveSharedSecret(
sendPort.nativePort, _kind, nativeEncodedPassword, nativeEncodedSalt);
return processFutureJson(SharedSecret.fromJson, recvPort.first);
}
@override
Future<Nonce> randomNonce() {
final recvPort = ReceivePort("crypto_random_nonce");
final sendPort = recvPort.sendPort;
_ffi._cryptoRandomNonce(sendPort.nativePort, _kind);
return processFutureJson(Nonce.fromJson, recvPort.first);
}
@override
Future<SharedSecret> randomSharedSecret() {
final recvPort = ReceivePort("crypto_random_shared_secret");
final sendPort = recvPort.sendPort;
_ffi._cryptoRandomSharedSecret(sendPort.nativePort, _kind);
return processFutureJson(SharedSecret.fromJson, recvPort.first);
}
@override
Future<KeyPair> generateKeyPair() {
final recvPort = ReceivePort("crypto_generate_key_pair");
final sendPort = recvPort.sendPort;
_ffi._cryptoGenerateKeyPair(sendPort.nativePort, _kind);
return processFutureJson(KeyPair.fromJson, recvPort.first);
}
@override
Future<HashDigest> generateHash(Uint8List data) {
final nativeEncodedData = base64UrlNoPadEncode(data).toNativeUtf8();
final recvPort = ReceivePort("crypto_generate_hash");
final sendPort = recvPort.sendPort;
_ffi._cryptoGenerateHash(sendPort.nativePort, _kind, nativeEncodedData);
return processFutureJson(HashDigest.fromJson, recvPort.first);
}
@override
Future<bool> validateKeyPair(PublicKey key, SecretKey secret) {
final nativeKey = jsonEncode(key).toNativeUtf8();
final nativeSecret = jsonEncode(secret).toNativeUtf8();
final recvPort = ReceivePort("crypto_validate_key_pair");
final sendPort = recvPort.sendPort;
_ffi._cryptoValidateKeyPair(
sendPort.nativePort, _kind, nativeKey, nativeSecret);
return processFuturePlain(recvPort.first);
}
@override
Future<bool> validateHash(Uint8List data, HashDigest hash) {
final nativeEncodedData = base64UrlNoPadEncode(data).toNativeUtf8();
final nativeHash = jsonEncode(hash).toNativeUtf8();
final recvPort = ReceivePort("crypto_validate_hash");
final sendPort = recvPort.sendPort;
_ffi._cryptoValidateHash(
sendPort.nativePort, _kind, nativeEncodedData, nativeHash);
return processFuturePlain(recvPort.first);
}
@override
Future<CryptoKeyDistance> distance(CryptoKey key1, CryptoKey key2) {
final nativeKey1 = jsonEncode(key1).toNativeUtf8();
final nativeKey2 = jsonEncode(key2).toNativeUtf8();
final recvPort = ReceivePort("crypto_distance");
final sendPort = recvPort.sendPort;
_ffi._cryptoDistance(sendPort.nativePort, _kind, nativeKey1, nativeKey2);
return processFutureJson(CryptoKeyDistance.fromJson, recvPort.first);
}
@override
Future<Signature> sign(PublicKey key, SecretKey secret, Uint8List data) {
final nativeKey = jsonEncode(key).toNativeUtf8();
final nativeSecret = jsonEncode(secret).toNativeUtf8();
final nativeEncodedData = base64UrlNoPadEncode(data).toNativeUtf8();
final recvPort = ReceivePort("crypto_sign");
final sendPort = recvPort.sendPort;
_ffi._cryptoSign(
sendPort.nativePort, _kind, nativeKey, nativeSecret, nativeEncodedData);
return processFutureJson(Signature.fromJson, recvPort.first);
}
@override
Future<void> verify(PublicKey key, Uint8List data, Signature signature) {
final nativeKey = jsonEncode(key).toNativeUtf8();
final nativeEncodedData = base64UrlNoPadEncode(data).toNativeUtf8();
final nativeSignature = jsonEncode(signature).toNativeUtf8();
final recvPort = ReceivePort("crypto_verify");
final sendPort = recvPort.sendPort;
_ffi._cryptoVerify(sendPort.nativePort, _kind, nativeKey, nativeEncodedData,
nativeSignature);
return processFutureVoid(recvPort.first);
}
@override
Future<int> aeadOverhead() {
final recvPort = ReceivePort("crypto_aead_overhead");
final sendPort = recvPort.sendPort;
_ffi._cryptoAeadOverhead(
sendPort.nativePort,
_kind,
);
return processFuturePlain(recvPort.first);
}
@override
Future<Uint8List> decryptAead(Uint8List body, Nonce nonce,
SharedSecret sharedSecret, Uint8List? associatedData) async {
final nativeEncodedBody = base64UrlNoPadEncode(body).toNativeUtf8();
final nativeNonce = jsonEncode(nonce).toNativeUtf8();
final nativeSharedSecret = jsonEncode(sharedSecret).toNativeUtf8();
final nativeSignature = (associatedData != null)
? jsonEncode(associatedData).toNativeUtf8()
: nullptr;
final recvPort = ReceivePort("crypto_decrypt_aead");
final sendPort = recvPort.sendPort;
_ffi._cryptoDecryptAead(sendPort.nativePort, _kind, nativeEncodedBody,
nativeNonce, nativeSharedSecret, nativeSignature);
final out = await processFuturePlain(recvPort.first);
return base64UrlNoPadDecode(out);
}
@override
Future<Uint8List> encryptAead(Uint8List body, Nonce nonce,
SharedSecret sharedSecret, Uint8List? associatedData) async {
final nativeEncodedBody = base64UrlNoPadEncode(body).toNativeUtf8();
final nativeNonce = jsonEncode(nonce).toNativeUtf8();
final nativeSharedSecret = jsonEncode(sharedSecret).toNativeUtf8();
final nativeSignature = (associatedData != null)
? jsonEncode(associatedData).toNativeUtf8()
: nullptr;
final recvPort = ReceivePort("crypto_encrypt_aead");
final sendPort = recvPort.sendPort;
_ffi._cryptoEncryptAead(sendPort.nativePort, _kind, nativeEncodedBody,
nativeNonce, nativeSharedSecret, nativeSignature);
final out = await processFuturePlain(recvPort.first);
return base64UrlNoPadDecode(out);
}
@override
Future<Uint8List> cryptNoAuth(
Uint8List body, Nonce nonce, SharedSecret sharedSecret) async {
final nativeEncodedBody = base64UrlNoPadEncode(body).toNativeUtf8();
final nativeNonce = jsonEncode(nonce).toNativeUtf8();
final nativeSharedSecret = jsonEncode(sharedSecret).toNativeUtf8();
final recvPort = ReceivePort("crypto_crypt_no_auth");
final sendPort = recvPort.sendPort;
_ffi._cryptoCryptNoAuth(sendPort.nativePort, _kind, nativeEncodedBody,
nativeNonce, nativeSharedSecret);
final out = await processFuturePlain(recvPort.first);
return base64UrlNoPadDecode(out);
}
}
// FFI implementation of high level Veilid API
class VeilidFFI implements Veilid {
// veilid_core shared library
@@ -635,6 +1170,14 @@ class VeilidFFI implements Veilid {
final _RoutingContextWithSequencingDart _routingContextWithSequencing;
final _RoutingContextAppCallDart _routingContextAppCall;
final _RoutingContextAppMessageDart _routingContextAppMessage;
final _RoutingContextCreateDHTRecordDart _routingContextCreateDHTRecord;
final _RoutingContextOpenDHTRecordDart _routingContextOpenDHTRecord;
final _RoutingContextCloseDHTRecordDart _routingContextCloseDHTRecord;
final _RoutingContextDeleteDHTRecordDart _routingContextDeleteDHTRecord;
final _RoutingContextGetDHTValueDart _routingContextGetDHTValue;
final _RoutingContextSetDHTValueDart _routingContextSetDHTValue;
final _RoutingContextWatchDHTValuesDart _routingContextWatchDHTValues;
final _RoutingContextCancelDHTWatchDart _routingContextCancelDHTWatch;
final _NewPrivateRouteDart _newPrivateRoute;
final _NewCustomPrivateRouteDart _newCustomPrivateRoute;
@@ -658,6 +1201,36 @@ class VeilidFFI implements Veilid {
final _TableDbTransactionStoreDart _tableDbTransactionStore;
final _TableDbTransactionDeleteDart _tableDbTransactionDelete;
final _ValidCryptoKindsDart _validCryptoKinds;
final _BestCryptoKindDart _bestCryptoKind;
final _VerifySignaturesDart _verifySignatures;
final _GenerateSignaturesDart _generateSignatures;
final _GenerateKeyPairDart _generateKeyPair;
final _CryptoCachedDHDart _cryptoCachedDH;
final _CryptoComputeDHDart _cryptoComputeDH;
final _CryptoRandomBytesDart _cryptoRandomBytes;
final _CryptoDefaultSaltLengthDart _cryptoDefaultSaltLength;
final _CryptoHashPasswordDart _cryptoHashPassword;
final _CryptoVerifyPasswordDart _cryptoVerifyPassword;
final _CryptoDeriveSharedSecretDart _cryptoDeriveSharedSecret;
final _CryptoRandomNonceDart _cryptoRandomNonce;
final _CryptoRandomSharedSecretDart _cryptoRandomSharedSecret;
final _CryptoGenerateKeyPairDart _cryptoGenerateKeyPair;
final _CryptoGenerateHashDart _cryptoGenerateHash;
final _CryptoValidateKeyPairDart _cryptoValidateKeyPair;
final _CryptoValidateHashDart _cryptoValidateHash;
final _CryptoDistanceDart _cryptoDistance;
final _CryptoSignDart _cryptoSign;
final _CryptoVerifyDart _cryptoVerify;
final _CryptoAeadOverheadDart _cryptoAeadOverhead;
final _CryptoDecryptAeadDart _cryptoDecryptAead;
final _CryptoEncryptAeadDart _cryptoEncryptAead;
final _CryptoCryptNoAuthDart _cryptoCryptNoAuth;
final _NowDart _now;
final _DebugDart _debug;
final _VeilidVersionStringDart _veilidVersionString;
final _VeilidVersionDart _veilidVersion;
@@ -703,6 +1276,36 @@ class VeilidFFI implements Veilid {
_routingContextAppMessage = dylib.lookupFunction<
_RoutingContextAppMessageC,
_RoutingContextAppMessageDart>('routing_context_app_message'),
_routingContextCreateDHTRecord = dylib.lookupFunction<
_RoutingContextCreateDHTRecordC,
_RoutingContextCreateDHTRecordDart>(
'routing_context_create_dht_record'),
_routingContextOpenDHTRecord = dylib.lookupFunction<
_RoutingContextOpenDHTRecordC,
_RoutingContextOpenDHTRecordDart>(
'routing_context_open_dht_record'),
_routingContextCloseDHTRecord = dylib.lookupFunction<
_RoutingContextCloseDHTRecordC,
_RoutingContextCloseDHTRecordDart>(
'routing_context_close_dht_record'),
_routingContextDeleteDHTRecord = dylib.lookupFunction<
_RoutingContextDeleteDHTRecordC,
_RoutingContextDeleteDHTRecordDart>(
'routing_context_delete_dht_record'),
_routingContextGetDHTValue = dylib.lookupFunction<
_RoutingContextGetDHTValueC,
_RoutingContextGetDHTValueDart>('routing_context_get_dht_value'),
_routingContextSetDHTValue = dylib.lookupFunction<
_RoutingContextSetDHTValueC,
_RoutingContextSetDHTValueDart>('routing_context_set_dht_value'),
_routingContextWatchDHTValues = dylib.lookupFunction<
_RoutingContextWatchDHTValuesC,
_RoutingContextWatchDHTValuesDart>(
'routing_context_watch_dht_values'),
_routingContextCancelDHTWatch = dylib.lookupFunction<
_RoutingContextCancelDHTWatchC,
_RoutingContextCancelDHTWatchDart>(
'routing_context_cancel_dht_watch'),
_newPrivateRoute =
dylib.lookupFunction<_NewPrivateRouteC, _NewPrivateRouteDart>(
'new_private_route'),
@@ -753,6 +1356,77 @@ class VeilidFFI implements Veilid {
_tableDbTransactionDelete = dylib.lookupFunction<
_TableDbTransactionDeleteC,
_TableDbTransactionDeleteDart>('table_db_transaction_delete'),
_validCryptoKinds =
dylib.lookupFunction<_ValidCryptoKindsC, _ValidCryptoKindsDart>(
'valid_crypto_kinds'),
_bestCryptoKind =
dylib.lookupFunction<_BestCryptoKindC, _BestCryptoKindDart>(
'best_crypto_kind'),
_verifySignatures =
dylib.lookupFunction<_VerifySignaturesC, _VerifySignaturesDart>(
'verify_signatures'),
_generateSignatures =
dylib.lookupFunction<_GenerateSignaturesC, _GenerateSignaturesDart>(
'generate_signatures'),
_generateKeyPair =
dylib.lookupFunction<_GenerateKeyPairC, _GenerateKeyPairDart>(
'generate_key_pair'),
_cryptoCachedDH =
dylib.lookupFunction<_CryptoCachedDHC, _CryptoCachedDHDart>(
'crypto_cached_dh'),
_cryptoComputeDH =
dylib.lookupFunction<_CryptoComputeDHC, _CryptoComputeDHDart>(
'crypto_compute_dh'),
_cryptoRandomBytes =
dylib.lookupFunction<_CryptoRandomBytesC, _CryptoRandomBytesDart>(
'crypto_random_bytes'),
_cryptoDefaultSaltLength = dylib.lookupFunction<
_CryptoDefaultSaltLengthC,
_CryptoDefaultSaltLengthDart>('crypto_default_salt_length'),
_cryptoHashPassword =
dylib.lookupFunction<_CryptoHashPasswordC, _CryptoHashPasswordDart>(
'crypto_hash_password'),
_cryptoVerifyPassword = dylib.lookupFunction<_CryptoVerifyPasswordC,
_CryptoVerifyPasswordDart>('crypto_verify_password'),
_cryptoDeriveSharedSecret = dylib.lookupFunction<
_CryptoDeriveSharedSecretC,
_CryptoVerifyPasswordDart>('crypto_derive_shared_secret'),
_cryptoRandomNonce =
dylib.lookupFunction<_CryptoRandomNonceC, _CryptoRandomNonceDart>(
'crypto_random_nonce'),
_cryptoRandomSharedSecret = dylib.lookupFunction<
_CryptoRandomSharedSecretC,
_CryptoRandomSharedSecretDart>('crypto_random_shared_secret'),
_cryptoGenerateKeyPair = dylib.lookupFunction<_CryptoGenerateKeyPairC,
_CryptoGenerateKeyPairDart>('crypto_generate_key_pair'),
_cryptoGenerateHash =
dylib.lookupFunction<_CryptoGenerateHashC, _CryptoGenerateHashDart>(
'crypto_generate_hash'),
_cryptoValidateKeyPair = dylib.lookupFunction<_CryptoValidateKeyPairC,
_CryptoValidateKeyPairDart>('crypto_validate_key_pair'),
_cryptoValidateHash =
dylib.lookupFunction<_CryptoValidateHashC, _CryptoValidateHashDart>(
'crypto_validate_hash'),
_cryptoDistance =
dylib.lookupFunction<_CryptoDistanceC, _CryptoDistanceDart>(
'crypto_distance'),
_cryptoSign =
dylib.lookupFunction<_CryptoSignC, _CryptoSignDart>('crypto_sign'),
_cryptoVerify = dylib
.lookupFunction<_CryptoVerifyC, _CryptoVerifyDart>('crypto_verify'),
_cryptoAeadOverhead =
dylib.lookupFunction<_CryptoAeadOverheadC, _CryptoAeadOverheadDart>(
'crypto_aead_overhead'),
_cryptoDecryptAead =
dylib.lookupFunction<_CryptoDecryptAeadC, _CryptoDecryptAeadDart>(
'crypto_decrypt_aead'),
_cryptoEncryptAead =
dylib.lookupFunction<_CryptoEncryptAeadC, _CryptoEncryptAeadDart>(
'crypto_encrypt_aead'),
_cryptoCryptNoAuth =
dylib.lookupFunction<_CryptoCryptNoAuthC, _CryptoCryptNoAuthDart>(
'crypto_crypt_no_auth'),
_now = dylib.lookupFunction<_NowC, _NowDart>('now'),
_debug = dylib.lookupFunction<_DebugC, _DebugDart>('debug'),
_veilidVersionString = dylib.lookupFunction<_VeilidVersionStringC,
_VeilidVersionStringDart>('veilid_version_string'),
@@ -768,9 +1442,7 @@ class VeilidFFI implements Veilid {
@override
void initializeVeilidCore(Map<String, dynamic> platformConfigJson) {
var nativePlatformConfig =
jsonEncode(platformConfigJson, toEncodable: veilidApiToEncodable)
.toNativeUtf8();
var nativePlatformConfig = jsonEncode(platformConfigJson).toNativeUtf8();
_initializeVeilidCore(nativePlatformConfig);
@@ -779,9 +1451,7 @@ class VeilidFFI implements Veilid {
@override
void changeLogLevel(String layer, VeilidConfigLogLevel logLevel) {
var nativeLogLevel =
jsonEncode(logLevel.json, toEncodable: veilidApiToEncodable)
.toNativeUtf8();
var nativeLogLevel = jsonEncode(logLevel).toNativeUtf8();
var nativeLayer = layer.toNativeUtf8();
_changeLogLevel(nativeLayer, nativeLogLevel);
malloc.free(nativeLayer);
@@ -790,9 +1460,7 @@ class VeilidFFI implements Veilid {
@override
Future<Stream<VeilidUpdate>> startupVeilidCore(VeilidConfig config) {
var nativeConfig =
jsonEncode(config.json, toEncodable: veilidApiToEncodable)
.toNativeUtf8();
var nativeConfig = jsonEncode(config).toNativeUtf8();
final recvStreamPort = ReceivePort("veilid_api_stream");
final sendStreamPort = recvStreamPort.sendPort;
final recvPort = ReceivePort("startup_veilid_core");
@@ -856,14 +1524,15 @@ class VeilidFFI implements Veilid {
@override
Future<RouteBlob> newCustomPrivateRoute(
Stability stability, Sequencing sequencing) async {
Stability stability, Sequencing sequencing) {
final recvPort = ReceivePort("new_custom_private_route");
final sendPort = recvPort.sendPort;
_newCustomPrivateRoute(sendPort.nativePort, stability.json.toNativeUtf8(),
sequencing.json.toNativeUtf8());
final routeBlob =
await processFutureJson(RouteBlob.fromJson, recvPort.first);
return routeBlob;
_newCustomPrivateRoute(
sendPort.nativePort,
jsonEncode(stability).toNativeUtf8(),
jsonEncode(sequencing).toNativeUtf8());
return processFutureJson(RouteBlob.fromJson, recvPort.first);
}
@override
@@ -914,6 +1583,70 @@ class VeilidFFI implements Veilid {
return deleted;
}
@override
List<CryptoKind> validCryptoKinds() {
final vckString = _validCryptoKinds();
final vck = jsonDecode(vckString.toDartString());
_freeString(vckString);
return vck;
}
@override
Future<VeilidCryptoSystem> getCryptoSystem(CryptoKind kind) async {
if (!validCryptoKinds().contains(kind)) {
throw VeilidAPIExceptionGeneric("unsupported cryptosystem");
}
return VeilidCryptoSystemFFI._(this, kind);
}
@override
Future<VeilidCryptoSystem> bestCryptoSystem() async {
return VeilidCryptoSystemFFI._(this, _bestCryptoKind());
}
@override
Future<List<TypedKey>> verifySignatures(
List<TypedKey> nodeIds, Uint8List data, List<TypedSignature> signatures) {
final nativeNodeIds = jsonEncode(nodeIds).toNativeUtf8();
final nativeData = base64UrlNoPadEncode(data).toNativeUtf8();
final nativeSignatures = jsonEncode(signatures).toNativeUtf8();
final recvPort = ReceivePort("verify_signatures");
final sendPort = recvPort.sendPort;
_verifySignatures(
sendPort.nativePort, nativeNodeIds, nativeData, nativeSignatures);
return processFutureJson(
jsonListConstructor<TypedKey>(TypedKey.fromJson), recvPort.first);
}
@override
Future<List<TypedSignature>> generateSignatures(
Uint8List data, List<TypedKeyPair> keyPairs) {
final nativeData = base64UrlNoPadEncode(data).toNativeUtf8();
final nativeKeyPairs = jsonEncode(keyPairs).toNativeUtf8();
final recvPort = ReceivePort("generate_signatures");
final sendPort = recvPort.sendPort;
_generateSignatures(sendPort.nativePort, nativeData, nativeKeyPairs);
return processFutureJson(
jsonListConstructor<TypedSignature>(TypedSignature.fromJson),
recvPort.first);
}
@override
Timestamp now() {
final ts = _now();
return Timestamp(value: BigInt.from(ts));
}
@override
Future<TypedKeyPair> generateKeyPair(CryptoKind kind) {
final recvPort = ReceivePort("generate_key_pair");
final sendPort = recvPort.sendPort;
_generateKeyPair(sendPort.nativePort, kind);
return processFutureJson(TypedKeyPair.fromJson, recvPort.first);
}
@override
Future<String> debug(String command) async {
var nativeCommand = command.toNativeUtf8();

View File

@@ -7,7 +7,7 @@ import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'base64url_no_pad.dart';
import 'veilid_encoding.dart';
//////////////////////////////////////////////////////////
@@ -30,9 +30,8 @@ class _Ctx {
// JS implementation of VeilidRoutingContext
class VeilidRoutingContextJS implements VeilidRoutingContext {
final _Ctx _ctx;
static final Finalizer<_Ctx> _finalizer = Finalizer((ctx) => {
js_util.callMethod(wasm, "release_routing_context", [ctx.id])
});
static final Finalizer<_Ctx> _finalizer = Finalizer(
(ctx) => js_util.callMethod(wasm, "release_routing_context", [ctx.id]));
VeilidRoutingContextJS._(this._ctx) {
_finalizer.attach(this, _ctx, detach: this);
@@ -48,15 +47,17 @@ class VeilidRoutingContextJS implements VeilidRoutingContext {
@override
VeilidRoutingContextJS withCustomPrivacy(Stability stability) {
final newId = js_util.callMethod(
wasm, "routing_context_with_custom_privacy", [_ctx.id, stability.json]);
wasm,
"routing_context_with_custom_privacy",
[_ctx.id, jsonEncode(stability)]);
return VeilidRoutingContextJS._(_Ctx(newId, _ctx.js));
}
@override
VeilidRoutingContextJS withSequencing(Sequencing sequencing) {
final newId = js_util.callMethod(
wasm, "routing_context_with_sequencing", [_ctx.id, sequencing.json]);
final newId = js_util.callMethod(wasm, "routing_context_with_sequencing",
[_ctx.id, jsonEncode(sequencing)]);
return VeilidRoutingContextJS._(_Ctx(newId, _ctx.js));
}
@@ -75,6 +76,254 @@ class VeilidRoutingContextJS implements VeilidRoutingContext {
return _wrapApiPromise(js_util.callMethod(wasm,
"routing_context_app_message", [_ctx.id, target, encodedMessage]));
}
@override
Future<DHTRecordDescriptor> createDHTRecord(
CryptoKind kind, DHTSchema schema) async {
return DHTRecordDescriptor.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, "routing_context_create_dht_record",
[_ctx.id, kind, jsonEncode(schema)]))));
}
@override
Future<DHTRecordDescriptor> openDHTRecord(
TypedKey key, KeyPair? writer) async {
return DHTRecordDescriptor.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, "routing_context_open_dht_record", [
_ctx.id,
jsonEncode(key),
writer != null ? jsonEncode(writer) : null
]))));
}
@override
Future<void> closeDHTRecord(TypedKey key) {
return _wrapApiPromise(js_util.callMethod(
wasm, "routing_context_close_dht_record", [_ctx.id, jsonEncode(key)]));
}
@override
Future<void> deleteDHTRecord(TypedKey key) {
return _wrapApiPromise(js_util.callMethod(
wasm, "routing_context_delete_dht_record", [_ctx.id, jsonEncode(key)]));
}
@override
Future<ValueData?> getDHTValue(
TypedKey key, int subkey, bool forceRefresh) async {
final opt = await _wrapApiPromise(js_util.callMethod(
wasm,
"routing_context_get_dht_value",
[_ctx.id, jsonEncode(key), subkey, forceRefresh]));
return opt == null ? null : ValueData.fromJson(jsonDecode(opt));
}
@override
Future<ValueData?> setDHTValue(
TypedKey key, int subkey, Uint8List data) async {
final opt = await _wrapApiPromise(js_util.callMethod(
wasm,
"routing_context_set_dht_value",
[_ctx.id, jsonEncode(key), subkey, base64UrlNoPadEncode(data)]));
return opt == null ? null : ValueData.fromJson(jsonDecode(opt));
}
@override
Future<Timestamp> watchDHTValues(TypedKey key, ValueSubkeyRange subkeys,
Timestamp expiration, int count) async {
final ts = await _wrapApiPromise(js_util.callMethod(
wasm, "routing_context_watch_dht_values", [
_ctx.id,
jsonEncode(key),
jsonEncode(subkeys),
expiration.toString(),
count
]));
return Timestamp.fromString(ts);
}
@override
Future<bool> cancelDHTWatch(TypedKey key, ValueSubkeyRange subkeys) {
return _wrapApiPromise(js_util.callMethod(
wasm,
"routing_context_cancel_dht_watch",
[_ctx.id, jsonEncode(key), jsonEncode(subkeys)]));
}
}
// JS implementation of VeilidCryptoSystem
class VeilidCryptoSystemJS implements VeilidCryptoSystem {
final CryptoKind _kind;
final VeilidJS _js;
VeilidCryptoSystemJS._(this._js, this._kind) {
// Keep the reference
_js;
}
@override
CryptoKind kind() {
return _kind;
}
@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)]))));
}
@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)]))));
}
@override
Future<Uint8List> randomBytes(int len) async {
return base64UrlNoPadDecode(await _wrapApiPromise(
js_util.callMethod(wasm, "crypto_random_bytes", [_kind, len])));
}
@override
Future<int> defaultSaltLength() {
return _wrapApiPromise(
js_util.callMethod(wasm, "crypto_default_salt_length", [_kind]));
}
@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]));
}
@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)
]))));
}
@override
Future<Nonce> randomNonce() async {
return 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]))));
}
@override
Future<KeyPair> generateKeyPair() async {
return 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)]))));
}
@override
Future<bool> validateKeyPair(PublicKey key, SecretKey secret) {
return _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)]));
}
@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)]))));
}
@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)
]))));
}
@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),
]));
}
@override
Future<int> aeadOverhead() {
return _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
])));
}
@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
])));
}
@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)
])));
}
}
class _TDBT {
@@ -88,9 +337,8 @@ class _TDBT {
// JS implementation of VeilidTableDBTransaction
class VeilidTableDBTransactionJS extends VeilidTableDBTransaction {
final _TDBT _tdbt;
static final Finalizer<_TDBT> _finalizer = Finalizer((tdbt) => {
js_util.callMethod(wasm, "release_table_db_transaction", [tdbt.id])
});
static final Finalizer<_TDBT> _finalizer = Finalizer((tdbt) =>
js_util.callMethod(wasm, "release_table_db_transaction", [tdbt.id]));
VeilidTableDBTransactionJS._(this._tdbt) {
_finalizer.attach(this, _tdbt, detach: this);
@@ -138,9 +386,8 @@ class _TDB {
// JS implementation of VeilidTableDB
class VeilidTableDBJS extends VeilidTableDB {
final _TDB _tdb;
static final Finalizer<_TDB> _finalizer = Finalizer((tdb) => {
js_util.callMethod(wasm, "release_table_db", [tdb.id])
});
static final Finalizer<_TDB> _finalizer = Finalizer(
(tdb) => js_util.callMethod(wasm, "release_table_db", [tdb.id]));
VeilidTableDBJS._(this._tdb) {
_finalizer.attach(this, _tdb, detach: this);
@@ -152,13 +399,9 @@ class VeilidTableDBJS extends VeilidTableDB {
}
@override
List<Uint8List> getKeys(int col) {
String? s = js_util.callMethod(wasm, "table_db_get_keys", [_tdb.id, col]);
if (s == null) {
throw VeilidAPIExceptionInternal("No db for id");
}
List<dynamic> jarr = jsonDecode(s);
return jarr.map((e) => base64UrlNoPadDecode(e)).toList();
Future<List<Uint8List>> getKeys(int col) async {
return jsonListConstructor(base64UrlNoPadDecodeDynamic)(jsonDecode(
await js_util.callMethod(wasm, "table_db_get_keys", [_tdb.id, col])));
}
@override
@@ -190,7 +433,7 @@ class VeilidTableDBJS extends VeilidTableDB {
}
@override
Future<bool> delete(int col, Uint8List key) {
Future<Uint8List?> delete(int col, Uint8List key) {
final encodedKey = base64UrlNoPadEncode(key);
return _wrapApiPromise(js_util
@@ -203,16 +446,14 @@ class VeilidTableDBJS extends VeilidTableDB {
class VeilidJS implements Veilid {
@override
void initializeVeilidCore(Map<String, dynamic> platformConfigJson) {
var platformConfigJsonString =
jsonEncode(platformConfigJson, toEncodable: veilidApiToEncodable);
var platformConfigJsonString = jsonEncode(platformConfigJson);
js_util
.callMethod(wasm, "initialize_veilid_core", [platformConfigJsonString]);
}
@override
void changeLogLevel(String layer, VeilidConfigLogLevel logLevel) {
var logLevelJsonString =
jsonEncode(logLevel.json, toEncodable: veilidApiToEncodable);
var logLevelJsonString = jsonEncode(logLevel);
js_util.callMethod(wasm, "change_log_level", [layer, logLevelJsonString]);
}
@@ -229,10 +470,8 @@ class VeilidJS implements Veilid {
}
}
await _wrapApiPromise(js_util.callMethod(wasm, "startup_veilid_core", [
js.allowInterop(updateCallback),
jsonEncode(config.json, toEncodable: veilidApiToEncodable)
]));
await _wrapApiPromise(js_util.callMethod(wasm, "startup_veilid_core",
[js.allowInterop(updateCallback), jsonEncode(config)]));
return streamController.stream;
}
@@ -259,6 +498,50 @@ class VeilidJS implements Veilid {
js_util.callMethod(wasm, "shutdown_veilid_core", []));
}
@override
List<CryptoKind> validCryptoKinds() {
return jsonDecode(js_util.callMethod(wasm, "valid_crypto_kinds", []));
}
@override
Future<VeilidCryptoSystem> getCryptoSystem(CryptoKind kind) async {
if (!validCryptoKinds().contains(kind)) {
throw VeilidAPIExceptionGeneric("unsupported cryptosystem");
}
return VeilidCryptoSystemJS._(this, kind);
}
@override
Future<VeilidCryptoSystem> bestCryptoSystem() async {
return 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)
]))));
}
@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)]))));
}
@override
Future<TypedKeyPair> generateKeyPair(CryptoKind kind) async {
return TypedKeyPair.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, "generate_key_pair", [kind]))));
}
@override
Future<VeilidRoutingContext> routingContext() async {
int id =
@@ -268,23 +551,19 @@ class VeilidJS implements Veilid {
@override
Future<RouteBlob> newPrivateRoute() async {
Map<String, dynamic> blobJson = jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, "new_private_route", [])));
return RouteBlob.fromJson(blobJson);
return 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, toEncodable: veilidApiToEncodable);
var sequencingString =
jsonEncode(sequencing, toEncodable: veilidApiToEncodable);
var stabilityString = jsonEncode(stability);
var sequencingString = jsonEncode(sequencing);
Map<String, dynamic> blobJson = jsonDecode(await _wrapApiPromise(js_util
return RouteBlob.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(
wasm, "new_private_route", [stabilityString, sequencingString])));
return RouteBlob.fromJson(blobJson);
wasm, "new_private_route", [stabilityString, sequencingString]))));
}
@override
@@ -319,6 +598,11 @@ class VeilidJS implements Veilid {
return _wrapApiPromise(js_util.callMethod(wasm, "delete_table_db", [name]));
}
@override
Timestamp now() {
return Timestamp.fromString(js_util.callMethod(wasm, "now", []));
}
@override
Future<String> debug(String command) async {
return await _wrapApiPromise(js_util.callMethod(wasm, "debug", [command]));

View File

@@ -0,0 +1,547 @@
import 'dart:typed_data';
import 'package:change_case/change_case.dart';
import 'veilid_encoding.dart';
import 'veilid.dart';
//////////////////////////////////////
/// AttachmentState
enum AttachmentState {
detached,
attaching,
attachedWeak,
attachedGood,
attachedStrong,
fullyAttached,
overAttached,
detaching;
String toJson() {
return name.toPascalCase();
}
factory AttachmentState.fromJson(String j) {
return AttachmentState.values.byName(j.toCamelCase());
}
}
//////////////////////////////////////
/// VeilidLogLevel
enum VeilidLogLevel {
error,
warn,
info,
debug,
trace;
String toJson() {
return name.toPascalCase();
}
factory VeilidLogLevel.fromJson(String j) {
return VeilidLogLevel.values.byName(j.toCamelCase());
}
}
////////////
class LatencyStats {
TimestampDuration fastest;
TimestampDuration average;
TimestampDuration slowest;
LatencyStats({
required this.fastest,
required this.average,
required this.slowest,
});
Map<String, dynamic> toJson() {
return {
'fastest': fastest.toJson(),
'average': average.toJson(),
'slowest': slowest.toJson(),
};
}
LatencyStats.fromJson(dynamic json)
: fastest = TimestampDuration.fromJson(json['fastest']),
average = TimestampDuration.fromJson(json['average']),
slowest = TimestampDuration.fromJson(json['slowest']);
}
////////////
class TransferStats {
BigInt total;
BigInt maximum;
BigInt average;
BigInt minimum;
TransferStats({
required this.total,
required this.maximum,
required this.average,
required this.minimum,
});
Map<String, dynamic> toJson() {
return {
'total': total.toString(),
'maximum': maximum.toString(),
'average': average.toString(),
'minimum': minimum.toString(),
};
}
TransferStats.fromJson(dynamic json)
: total = BigInt.parse(json['total']),
maximum = BigInt.parse(json['maximum']),
average = BigInt.parse(json['average']),
minimum = BigInt.parse(json['minimum']);
}
////////////
class TransferStatsDownUp {
TransferStats down;
TransferStats up;
TransferStatsDownUp({
required this.down,
required this.up,
});
Map<String, dynamic> toJson() {
return {
'down': down.toJson(),
'up': up.toJson(),
};
}
TransferStatsDownUp.fromJson(dynamic json)
: down = TransferStats.fromJson(json['down']),
up = TransferStats.fromJson(json['up']);
}
////////////
class RPCStats {
int messagesSent;
int messagesRcvd;
int questionsInFlight;
Timestamp? lastQuestion;
Timestamp? lastSeenTs;
Timestamp? firstConsecutiveSeenTs;
int recentLostAnswers;
int failedToSend;
RPCStats({
required this.messagesSent,
required this.messagesRcvd,
required this.questionsInFlight,
required this.lastQuestion,
required this.lastSeenTs,
required this.firstConsecutiveSeenTs,
required this.recentLostAnswers,
required this.failedToSend,
});
Map<String, dynamic> toJson() {
return {
'messages_sent': messagesSent,
'messages_rcvd': messagesRcvd,
'questions_in_flight': questionsInFlight,
'last_question': lastQuestion?.toJson(),
'last_seen_ts': lastSeenTs?.toJson(),
'first_consecutive_seen_ts': firstConsecutiveSeenTs?.toJson(),
'recent_lost_answers': recentLostAnswers,
'failed_to_send': failedToSend,
};
}
RPCStats.fromJson(dynamic json)
: messagesSent = json['messages_sent'],
messagesRcvd = json['messages_rcvd'],
questionsInFlight = json['questions_in_flight'],
lastQuestion = json['last_question'] != null
? Timestamp.fromJson(json['last_question'])
: null,
lastSeenTs = json['last_seen_ts'] != null
? Timestamp.fromJson(json['last_seen_ts'])
: null,
firstConsecutiveSeenTs = json['first_consecutive_seen_ts'] != null
? Timestamp.fromJson(json['first_consecutive_seen_ts'])
: null,
recentLostAnswers = json['recent_lost_answers'],
failedToSend = json['failed_to_send'];
}
////////////
class PeerStats {
Timestamp timeAdded;
RPCStats rpcStats;
LatencyStats? latency;
TransferStatsDownUp transfer;
PeerStats({
required this.timeAdded,
required this.rpcStats,
required this.latency,
required this.transfer,
});
Map<String, dynamic> toJson() {
return {
'time_added': timeAdded.toJson(),
'rpc_stats': rpcStats.toJson(),
'latency': latency?.toJson(),
'transfer': transfer.toJson(),
};
}
PeerStats.fromJson(dynamic json)
: timeAdded = Timestamp.fromJson(json['time_added']),
rpcStats = RPCStats.fromJson(json['rpc_stats']),
latency = json['latency'] != null
? LatencyStats.fromJson(json['latency'])
: null,
transfer = TransferStatsDownUp.fromJson(json['transfer']);
}
////////////
class PeerTableData {
List<TypedKey> nodeIds;
String peerAddress;
PeerStats peerStats;
PeerTableData({
required this.nodeIds,
required this.peerAddress,
required this.peerStats,
});
Map<String, dynamic> toJson() {
return {
'node_ids': nodeIds.map((p) => p.toJson()).toList(),
'peer_address': peerAddress,
'peer_stats': peerStats.toJson(),
};
}
PeerTableData.fromJson(dynamic json)
: nodeIds = List<TypedKey>.from(
json['node_ids'].map((j) => TypedKey.fromJson(j))),
peerAddress = json['peer_address'],
peerStats = PeerStats.fromJson(json['peer_stats']);
}
//////////////////////////////////////
/// VeilidUpdate
abstract class VeilidUpdate {
factory VeilidUpdate.fromJson(dynamic json) {
switch (json["kind"]) {
case "Log":
{
return VeilidLog(
logLevel: VeilidLogLevel.fromJson(json["log_level"]),
message: json["message"],
backtrace: json["backtrace"]);
}
case "AppMessage":
{
return VeilidAppMessage(
sender: json["sender"], message: json["message"]);
}
case "AppCall":
{
return VeilidAppCall(
sender: json["sender"], message: json["message"], id: json["id"]);
}
case "Attachment":
{
return VeilidUpdateAttachment(
state: VeilidStateAttachment.fromJson(json));
}
case "Network":
{
return VeilidUpdateNetwork(state: VeilidStateNetwork.fromJson(json));
}
case "Config":
{
return VeilidUpdateConfig(state: VeilidStateConfig.fromJson(json));
}
case "RouteChange":
{
return VeilidUpdateRouteChange(
deadRoutes: List<String>.from(json['dead_routes'].map((j) => j)),
deadRemoteRoutes:
List<String>.from(json['dead_remote_routes'].map((j) => j)));
}
case "ValueChange":
{
return VeilidUpdateValueChange(
key: TypedKey.fromJson(json['key']),
subkeys: List<ValueSubkeyRange>.from(
json['subkeys'].map((j) => ValueSubkeyRange.fromJson(j))),
count: json['count'],
valueData: ValueData.fromJson(json['value_data']));
}
default:
{
throw VeilidAPIExceptionInternal(
"Invalid VeilidAPIException type: ${json['kind']}");
}
}
}
Map<String, dynamic> toJson();
}
class VeilidLog implements VeilidUpdate {
final VeilidLogLevel logLevel;
final String message;
final String? backtrace;
//
VeilidLog({
required this.logLevel,
required this.message,
required this.backtrace,
});
@override
Map<String, dynamic> toJson() {
return {
'kind': "Log",
'log_level': logLevel.toJson(),
'message': message,
'backtrace': backtrace
};
}
}
class VeilidAppMessage implements VeilidUpdate {
final TypedKey? sender;
final Uint8List message;
//
VeilidAppMessage({
required this.sender,
required this.message,
});
@override
Map<String, dynamic> toJson() {
return {
'kind': "AppMessage",
'sender': sender,
'message': base64UrlNoPadEncode(message)
};
}
}
class VeilidAppCall implements VeilidUpdate {
final String? sender;
final Uint8List message;
final String id;
//
VeilidAppCall({
required this.sender,
required this.message,
required this.id,
});
@override
Map<String, dynamic> toJson() {
return {
'kind': "AppMessage",
'sender': sender,
'message': base64UrlNoPadEncode(message),
'id': id,
};
}
}
class VeilidUpdateAttachment implements VeilidUpdate {
final VeilidStateAttachment state;
//
VeilidUpdateAttachment({required this.state});
@override
Map<String, dynamic> toJson() {
var jsonRep = state.toJson();
jsonRep['kind'] = "Attachment";
return jsonRep;
}
}
class VeilidUpdateNetwork implements VeilidUpdate {
final VeilidStateNetwork state;
//
VeilidUpdateNetwork({required this.state});
@override
Map<String, dynamic> toJson() {
var jsonRep = state.toJson();
jsonRep['kind'] = "Network";
return jsonRep;
}
}
class VeilidUpdateConfig implements VeilidUpdate {
final VeilidStateConfig state;
//
VeilidUpdateConfig({required this.state});
@override
Map<String, dynamic> toJson() {
var jsonRep = state.toJson();
jsonRep['kind'] = "Config";
return jsonRep;
}
}
class VeilidUpdateRouteChange implements VeilidUpdate {
final List<String> deadRoutes;
final List<String> deadRemoteRoutes;
//
VeilidUpdateRouteChange({
required this.deadRoutes,
required this.deadRemoteRoutes,
});
@override
Map<String, dynamic> toJson() {
return {
'dead_routes': deadRoutes.map((p) => p).toList(),
'dead_remote_routes': deadRemoteRoutes.map((p) => p).toList()
};
}
}
class VeilidUpdateValueChange implements VeilidUpdate {
final TypedKey key;
final List<ValueSubkeyRange> subkeys;
final int count;
final ValueData valueData;
//
VeilidUpdateValueChange({
required this.key,
required this.subkeys,
required this.count,
required this.valueData,
});
@override
Map<String, dynamic> toJson() {
return {
'key': key.toJson(),
'subkeys': subkeys.map((p) => p.toJson()).toList(),
'count': count,
'value_data': valueData.toJson(),
};
}
}
//////////////////////////////////////
/// VeilidStateAttachment
class VeilidStateAttachment {
final AttachmentState state;
final bool publicInternetReady;
final bool localNetworkReady;
VeilidStateAttachment(
this.state, this.publicInternetReady, this.localNetworkReady);
VeilidStateAttachment.fromJson(dynamic json)
: state = AttachmentState.fromJson(json['state']),
publicInternetReady = json['public_internet_ready'],
localNetworkReady = json['local_network_ready'];
Map<String, dynamic> toJson() {
return {
'state': state.toJson(),
'public_internet_ready': publicInternetReady,
'local_network_ready': localNetworkReady,
};
}
}
//////////////////////////////////////
/// VeilidStateNetwork
class VeilidStateNetwork {
final bool started;
final BigInt bpsDown;
final BigInt bpsUp;
final List<PeerTableData> peers;
VeilidStateNetwork(
{required this.started,
required this.bpsDown,
required this.bpsUp,
required this.peers});
VeilidStateNetwork.fromJson(dynamic json)
: started = json['started'],
bpsDown = BigInt.parse(json['bps_down']),
bpsUp = BigInt.parse(json['bps_up']),
peers = List<PeerTableData>.from(
json['peers'].map((j) => PeerTableData.fromJson(j)));
Map<String, dynamic> toJson() {
return {
'started': started,
'bps_down': bpsDown.toString(),
'bps_up': bpsUp.toString(),
'peers': peers.map((p) => p.toJson()).toList(),
};
}
}
//////////////////////////////////////
/// VeilidStateConfig
class VeilidStateConfig {
final Map<String, dynamic> config;
VeilidStateConfig({
required this.config,
});
VeilidStateConfig.fromJson(dynamic json) : config = json['config'];
Map<String, dynamic> toJson() {
return {'config': config};
}
}
//////////////////////////////////////
/// VeilidState
class VeilidState {
final VeilidStateAttachment attachment;
final VeilidStateNetwork network;
final VeilidStateConfig config;
VeilidState.fromJson(dynamic json)
: attachment = VeilidStateAttachment.fromJson(json['attachment']),
network = VeilidStateNetwork.fromJson(json['network']),
config = VeilidStateConfig.fromJson(json['config']);
Map<String, dynamic> toJson() {
return {
'attachment': attachment.toJson(),
'network': network.toJson(),
'config': config.toJson()
};
}
}

View File

@@ -0,0 +1,73 @@
import 'dart:async';
import 'dart:typed_data';
import 'dart:convert';
/////////////////////////////////////
/// VeilidTableDB
abstract class VeilidTableDBTransaction {
Future<void> commit();
Future<void> rollback();
Future<void> store(int col, Uint8List key, Uint8List value);
Future<bool> 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)));
}
Future<void> storeStringJson(int col, String key, Object? object,
{Object? Function(Object? nonEncodable)? toEncodable}) {
return storeJson(col, utf8.encoder.convert(key), object,
toEncodable: toEncodable);
}
}
abstract class VeilidTableDB {
int getColumnCount();
Future<List<Uint8List>> getKeys(int col);
VeilidTableDBTransaction transact();
Future<void> store(int col, Uint8List key, Uint8List value);
Future<Uint8List?> load(int col, Uint8List key);
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)));
}
Future<void> storeStringJson(int col, String key, Object? object,
{Object? Function(Object? nonEncodable)? toEncodable}) {
return 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);
if (s == null) {
return null;
}
return jsonDecode(utf8.decode(s, allowMalformed: false), reviver: reviver);
}
Future<Object?> loadStringJson(int col, String key,
{Object? Function(Object? key, Object? value)? reviver}) {
return 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);
if (s == null) {
return null;
}
return jsonDecode(utf8.decode(s, allowMalformed: false), reviver: reviver);
}
Future<Object?> deleteStringJson(int col, String key,
{Object? Function(Object? key, Object? value)? reviver}) {
return deleteJson(col, utf8.encoder.convert(key), reviver: reviver);
}
}