This commit is contained in:
John Smith
2023-05-13 20:36:52 -04:00
parent cb899b44ea
commit 5eb2ea656c
17 changed files with 2745 additions and 2261 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

@@ -0,0 +1,277 @@
import 'dart:async';
import 'dart:typed_data';
import 'dart:convert';
import 'package:change_case/change_case.dart';
import 'base64url_no_pad.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> get json;
}
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> get json {
return {
'kind': "DFLT",
'o_cnt': oCnt,
};
}
}
class DHTSchemaMember {
Key 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> get json {
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> get json {
return {
'kind': "SMPL",
'o_cnt': oCnt,
'members': members.map((p) => p.json).toList(),
};
}
}
//////////////////////////////////////
/// DHTRecordDescriptor
class DHTRecordDescriptor {
TypedKey key;
Key owner;
Key? ownerSecret;
DHTSchema schema;
DHTRecordDescriptor({
required this.key,
required this.owner,
this.ownerSecret,
required this.schema,
});
Map<String, dynamic> get json {
return {
'key': key.toString(),
'owner': owner,
'owner_secret': ownerSecret,
'schema': schema.json,
};
}
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> get json {
return [low, high];
}
}
//////////////////////////////////////
/// ValueData
class ValueData {
final int seq;
final Uint8List data;
final Key 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> get json {
return {'seq': seq, 'data': base64UrlNoPadEncode(data), 'writer': writer};
}
}
/// Stability
enum Stability {
lowLatency,
reliable,
}
extension StabilityExt on Stability {
String get json {
return name.toPascalCase();
}
}
Stability stabilityFromJson(String j) {
return Stability.values.byName(j.toCamelCase());
}
//////////////////////////////////////
/// Sequencing
enum Sequencing {
noPreference,
preferOrdered,
ensureOrdered,
}
extension SequencingExt on Sequencing {
String get json {
return name.toPascalCase();
}
}
Sequencing sequencingFromJson(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> get json {
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,744 @@
import 'dart:async';
import 'dart:typed_data';
import 'dart:convert';
import 'package:change_case/change_case.dart';
import 'veilid_encoding.dart';
import 'veilid.dart';
//////////////////////////////////////
/// VeilidConfigLogLevel
enum VeilidConfigLogLevel {
off,
error,
warn,
info,
debug,
trace,
}
extension VeilidConfigLogLevelExt on VeilidConfigLogLevel {
String get json {
return name.toPascalCase();
}
}
VeilidConfigLogLevel veilidConfigLogLevelFromJson(String j) {
return VeilidConfigLogLevel.values.byName(j.toCamelCase());
}
//////////////////////////////////////
/// 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> get json {
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> get json {
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> get json {
return {
'https': https.json,
'http': http.json,
};
}
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> get json {
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> get json {
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> get json {
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> get json {
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> get json {
return {
'udp': udp.json,
'tcp': tcp.json,
'ws': ws.json,
'wss': wss.json,
};
}
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> get json {
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> get json {
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: 128': 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> get json {
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<Key> nodeId;
List<Key> 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> get json {
return {
'node_id': nodeId.map((p) => p.json).toList(),
'node_id_secret': nodeIdSecret.map((p) => p.json).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<Key>.from(json['node_id'].map((j) => Key.fromJson(j))),
nodeIdSecret =
List<Key>.from(json['node_id_secret'].map((j) => Key.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> get json {
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.json,
'rpc': rpc.json,
'dht': dht.json,
'upnp': upnp,
'detect_address_changes': detectAddressChanges,
'restricted_nat_retries': restrictedNatRetries,
'tls': tls.json,
'application': application.json,
'protocol': protocol.json,
};
}
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> get json {
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> get json {
return {'directory': directory, 'delete': delete};
}
VeilidConfigBlockStore.fromJson(dynamic json)
: directory = json['directory'],
delete = json['delete'];
}
////////////
class VeilidConfigProtectedStore {
bool allowInsecureFallback;
bool alwaysUseInsecureStorage;
String insecureFallbackDirectory;
bool delete;
VeilidConfigProtectedStore({
required this.allowInsecureFallback,
required this.alwaysUseInsecureStorage,
required this.insecureFallbackDirectory,
required this.delete,
});
Map<String, dynamic> get json {
return {
'allow_insecure_fallback': allowInsecureFallback,
'always_use_insecure_storage': alwaysUseInsecureStorage,
'insecure_fallback_directory': insecureFallbackDirectory,
'delete': delete,
};
}
VeilidConfigProtectedStore.fromJson(dynamic json)
: allowInsecureFallback = json['allow_insecure_fallback'],
alwaysUseInsecureStorage = json['always_use_insecure_storage'],
insecureFallbackDirectory = json['insecure_fallback_directory'],
delete = json['delete'];
}
////////////
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> get json {
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> get json {
return {
'program_name': programName,
'namespace': namespace,
'capabilities': capabilities.json,
'protected_store': protectedStore.json,
'table_store': tableStore.json,
'block_store': blockStore.json,
'network': network.json
};
}
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,155 @@
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 get json {
return toString();
}
Typed.fromJson(dynamic json) : this.fromString(json as String);
}
class KeyPair {
late Key key;
late Key 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 = Key(parts[0]);
secret = Key(parts[1]);
}
String get json {
return toString();
}
KeyPair.fromJson(dynamic json) : this.fromString(json as String);
}
class TypedKeyPair {
late CryptoKind kind;
late Key key;
late Key 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 = Key(parts[1]);
secret = Key(parts[2]);
}
String get json {
return toString();
}
TypedKeyPair.fromJson(dynamic json) : this.fromString(json as String);
}
typedef Key = FixedEncodedString43;
typedef Signature = FixedEncodedString86;
typedef Nonce = FixedEncodedString32;
typedef TypedKey = Typed<Key>;
typedef TypedSignature = Typed<Signature>;
//////////////////////////////////////
/// VeilidCryptoSystem
abstract class VeilidCryptoSystem {
CryptoKind kind();
Key cachedDH(Key key, Key secret);
Key computeDH(Key key, Key secret);
Nonce randomNonce();
Key randomSharedSecret();
KeyPair generateKeyPair();
Key generateHash(Uint8List data);
Key generateHashReader(Stream<List<int>> reader);
bool validateKeyPair(Key key, Key secret);
bool validateHash(Uint8List data, Key hash);
bool validateHashReader(Stream<List<int>> reader, Key hash);
Key distance(Key key1, Key key2);
Signature sign(Key key, Key secret, Uint8List data);
void verify(Key key, Uint8List data, Signature signature);
BigInt aeadOverhead();
Uint8List decryptAead(
Uint8List body, Nonce nonce, Key sharedSecret, Uint8List? associatedData);
Uint8List encryptAead(
Uint8List body, Nonce nonce, Key sharedSecret, Uint8List? associatedData);
Uint8List cryptNoAuth(Uint8List body, Nonce nonce, Key sharedSecret);
}

View File

@@ -0,0 +1,116 @@
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);
}
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 get json {
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 get json {
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 get json {
return toString();
}
FixedEncodedString86.fromJson(dynamic json) : this(json as String);
}

View File

@@ -10,6 +10,119 @@ import 'package:ffi/ffi.dart';
import 'veilid.dart';
import 'base64url_no_pad.dart';
//////////////////////////////////////////////////////////
// FFI Platform-specific config
class VeilidFFIConfigLoggingTerminal {
bool enabled;
VeilidConfigLogLevel level;
VeilidFFIConfigLoggingTerminal({
required this.enabled,
required this.level,
});
Map<String, dynamic> get json {
return {
'enabled': enabled,
'level': level.json,
};
}
VeilidFFIConfigLoggingTerminal.fromJson(dynamic json)
: enabled = json['enabled'],
level = veilidConfigLogLevelFromJson(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> get json {
return {
'enabled': enabled,
'level': level.json,
'grpc_endpoint': grpcEndpoint,
'service_name': serviceName,
};
}
VeilidFFIConfigLoggingOtlp.fromJson(dynamic json)
: enabled = json['enabled'],
level = veilidConfigLogLevelFromJson(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> get json {
return {
'enabled': enabled,
'level': level.json,
};
}
VeilidFFIConfigLoggingApi.fromJson(dynamic json)
: enabled = json['enabled'],
level = veilidConfigLogLevelFromJson(json['level']);
}
class VeilidFFIConfigLogging {
VeilidFFIConfigLoggingTerminal terminal;
VeilidFFIConfigLoggingOtlp otlp;
VeilidFFIConfigLoggingApi api;
VeilidFFIConfigLogging(
{required this.terminal, required this.otlp, required this.api});
Map<String, dynamic> get json {
return {
'terminal': terminal.json,
'otlp': otlp.json,
'api': api.json,
};
}
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> get json {
return {
'logging': logging.json,
};
}
VeilidFFIConfig.fromJson(Map<String, dynamic> json)
: logging = VeilidFFIConfigLogging.fromJson(json['logging']);
}
//////////////////////////////////////////////////////////
// Load the veilid_flutter library once
@@ -603,7 +716,7 @@ class VeilidTableDBFFI extends VeilidTableDB {
final recvPort = ReceivePort("veilid_table_db_delete");
final sendPort = recvPort.sendPort;
_tdb.ffi._tableDbLoad(
_tdb.ffi._tableDbDelete(
sendPort.nativePort,
_tdb.id,
col,
@@ -635,6 +748,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 +779,32 @@ class VeilidFFI implements Veilid {
final _TableDbTransactionStoreDart _tableDbTransactionStore;
final _TableDbTransactionDeleteDart _tableDbTransactionDelete;
final _ValidCryptoKindsDart _validCryptoKinds;
final _GetCryptoSystemDart _getCryptoSystem;
final _BestCryptoSystemDart _bestCryptoSystem;
final _VerifySignaturesDart _verifySignatures;
final _GenerateSignaturesDart _generateSignatures;
final _GenerateKeyPairDart _generateKeyPair;
final _CryptoCachedDHDart _cryptoCachedDH;
final _CryptoComputeDHDart _cryptoComputeDH;
final _CryptoRandomNonceDart _cryptoRandomNonce;
final _CryptoRandomSharedSecretDart _cryptoRandomSharedSecret;
final _CryptoGenerateKeyPairDart _cryptoGenerateKeyPair;
final _CryptoGenerateHashDart _cryptoGenerateHash;
final _CryptoGenerateHashReaderDart _cryptoGenerateHashReader;
final _CryptoValidateKeyPairDart _cryptoValidateKeyPair;
final _CryptoValidateHashDart _cryptoValidateHash;
final _CryptoValidateHashReaderDart _cryptoValidateHashReader;
final _CryptoDistanceDart _cryptoDistance;
final _CryptoSignDart _cryptoSign;
final _CryptoVerifyDart _cryptoVerify;
final _CryptoAaedOverheadDart _cryptoAeadOverhead;
final _CryptoDecryptAeadDart _cryptoDecryptAead;
final _CryptoEncryptAeadDart _cryptoEncryptAead;
final _CryptoCryptNoAuthDart _cryptoCryptNoAuth;
final _NowDart _now;
final _DebugDart _debug;
final _VeilidVersionStringDart _veilidVersionString;
final _VeilidVersionDart _veilidVersion;

View File

@@ -9,6 +9,95 @@ import 'dart:typed_data';
import 'base64url_no_pad.dart';
//////////////////////////////////////////////////////////
// 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> get json {
return {
'enabled': enabled,
'level': level.json,
'logs_in_timings': logsInTimings,
'logs_in_console': logsInConsole,
};
}
VeilidWASMConfigLoggingPerformance.fromJson(dynamic json)
: enabled = json['enabled'],
level = veilidConfigLogLevelFromJson(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> get json {
return {
'enabled': enabled,
'level': level.json,
};
}
VeilidWASMConfigLoggingApi.fromJson(dynamic json)
: enabled = json['enabled'],
level = veilidConfigLogLevelFromJson(json['level']);
}
class VeilidWASMConfigLogging {
VeilidWASMConfigLoggingPerformance performance;
VeilidWASMConfigLoggingApi api;
VeilidWASMConfigLogging({required this.performance, required this.api});
Map<String, dynamic> get json {
return {
'performance': performance.json,
'api': api.json,
};
}
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> get json {
return {
'logging': logging.json,
};
}
VeilidWASMConfig.fromJson(dynamic json)
: logging = VeilidWASMConfigLogging.fromJson(json['logging']);
}
//////////////////////////////////////////////////////////
Veilid getVeilid() => VeilidJS();

View File

@@ -0,0 +1,594 @@
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,
}
extension AttachmentStateExt on AttachmentState {
String get json {
return name.toPascalCase();
}
}
AttachmentState attachmentStateFromJson(String j) {
return AttachmentState.values.byName(j.toCamelCase());
}
//////////////////////////////////////
/// VeilidLogLevel
enum VeilidLogLevel {
error,
warn,
info,
debug,
trace,
}
extension VeilidLogLevelExt on VeilidLogLevel {
String get json {
return name.toPascalCase();
}
}
VeilidLogLevel veilidLogLevelFromJson(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> get json {
return {
'fastest': fastest.json,
'average': average.json,
'slowest': slowest.json,
};
}
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> get json {
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> get json {
return {
'down': down.json,
'up': up.json,
};
}
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> get json {
return {
'messages_sent': messagesSent,
'messages_rcvd': messagesRcvd,
'questions_in_flight': questionsInFlight,
'last_question': lastQuestion?.json,
'last_seen_ts': lastSeenTs?.json,
'first_consecutive_seen_ts': firstConsecutiveSeenTs?.json,
'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> get json {
return {
'time_added': timeAdded.json,
'rpc_stats': rpcStats.json,
'latency': latency?.json,
'transfer': transfer.json,
};
}
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;
PeerAddress peerAddress;
PeerStats peerStats;
PeerTableData({
required this.nodeIds,
required this.peerAddress,
required this.peerStats,
});
Map<String, dynamic> get json {
return {
'node_ids': nodeIds.map((p) => p.json).toList(),
'peer_address': peerAddress.json,
'peer_stats': peerStats.json,
};
}
PeerTableData.fromJson(dynamic json)
: nodeIds = List<TypedKey>.from(
json['node_ids'].map((j) => TypedKey.fromJson(j))),
peerAddress = PeerAddress.fromJson(json['peer_address']),
peerStats = PeerStats.fromJson(json['peer_stats']);
}
//////////////////////////////////////
/// AttachmentState
enum ProtocolType {
udp,
tcp,
ws,
wss,
}
extension ProtocolTypeExt on ProtocolType {
String get json {
return name.toUpperCase();
}
}
ProtocolType protocolTypeFromJson(String j) {
return ProtocolType.values.byName(j.toLowerCase());
}
////////////
class PeerAddress {
ProtocolType protocolType;
String socketAddress;
PeerAddress({
required this.protocolType,
required this.socketAddress,
});
Map<String, dynamic> get json {
return {
'protocol_type': protocolType.json,
'socket_address': socketAddress,
};
}
PeerAddress.fromJson(dynamic json)
: protocolType = protocolTypeFromJson(json['protocol_type']),
socketAddress = json['socket_address'];
}
//////////////////////////////////////
/// VeilidUpdate
abstract class VeilidUpdate {
factory VeilidUpdate.fromJson(dynamic json) {
switch (json["kind"]) {
case "Log":
{
return VeilidLog(
logLevel: veilidLogLevelFromJson(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> get json;
}
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> get json {
return {
'kind': "Log",
'log_level': logLevel.json,
'message': message,
'backtrace': backtrace
};
}
}
class VeilidAppMessage implements VeilidUpdate {
final String? sender;
final Uint8List message;
//
VeilidAppMessage({
required this.sender,
required this.message,
});
@override
Map<String, dynamic> get json {
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> get json {
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> get json {
var jsonRep = state.json;
jsonRep['kind'] = "Attachment";
return jsonRep;
}
}
class VeilidUpdateNetwork implements VeilidUpdate {
final VeilidStateNetwork state;
//
VeilidUpdateNetwork({required this.state});
@override
Map<String, dynamic> get json {
var jsonRep = state.json;
jsonRep['kind'] = "Network";
return jsonRep;
}
}
class VeilidUpdateConfig implements VeilidUpdate {
final VeilidStateConfig state;
//
VeilidUpdateConfig({required this.state});
@override
Map<String, dynamic> get json {
var jsonRep = state.json;
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> get json {
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> get json {
return {
'key': key.json,
'subkeys': subkeys.map((p) => p.json).toList(),
'count': count,
'value_data': valueData.json,
};
}
}
//////////////////////////////////////
/// VeilidStateAttachment
class VeilidStateAttachment {
final AttachmentState state;
final bool publicInternetReady;
final bool localNetworkReady;
VeilidStateAttachment(
this.state, this.publicInternetReady, this.localNetworkReady);
VeilidStateAttachment.fromJson(dynamic json)
: state = attachmentStateFromJson(json['state']),
publicInternetReady = json['public_internet_ready'],
localNetworkReady = json['local_network_ready'];
Map<String, dynamic> get json {
return {
'state': state.json,
'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> get json {
return {
'started': started,
'bps_down': bpsDown.toString(),
'bps_up': bpsUp.toString(),
'peers': peers.map((p) => p.json).toList(),
};
}
}
//////////////////////////////////////
/// VeilidStateConfig
class VeilidStateConfig {
final Map<String, dynamic> config;
VeilidStateConfig({
required this.config,
});
VeilidStateConfig.fromJson(dynamic json) : config = json['config'];
Map<String, dynamic> get json {
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> get json {
return {
'attachment': attachment.json,
'network': network.json,
'config': config.json
};
}
}

View File

@@ -0,0 +1,59 @@
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();
List<Uint8List> getKeys(int col);
VeilidTableDBTransaction transact();
Future<void> store(int col, Uint8List key, Uint8List value);
Future<Uint8List?> load(int col, Uint8List key);
Future<bool> 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);
}
}