veilid/veilid-flutter/lib/veilid_js.dart

755 lines
23 KiB
Dart
Raw Normal View History

2023-07-26 14:20:17 -04:00
import 'dart:async';
import 'dart:convert';
2022-03-17 10:31:10 -04:00
import 'dart:html' as html;
import 'dart:js' as js;
2023-10-14 20:18:37 -04:00
import 'dart:js_interop' as js_interop;
2022-03-17 10:31:10 -04:00
import 'dart:js_util' as js_util;
2022-09-30 22:37:55 -04:00
import 'dart:typed_data';
2022-02-06 21:18:42 -05:00
2023-07-26 14:20:17 -04:00
import 'veilid.dart';
2023-01-04 17:02:45 -05:00
2022-02-06 21:18:42 -05:00
//////////////////////////////////////////////////////////
Veilid getVeilid() => VeilidJS();
2023-07-26 14:20:17 -04:00
Object wasm = js_util.getProperty(html.window, 'veilid_wasm');
2022-03-15 23:02:24 -04:00
2023-10-14 20:18:37 -04:00
Uint8List convertUint8ListFromJson(dynamic json) => Uint8List.fromList(
((json as js_interop.JSArray).dartify()! as List<Object?>)
.map((e) => e! as int)
.toList());
dynamic convertUint8ListToJson(Uint8List data) => data.toList().jsify();
2023-07-26 15:12:28 -04:00
Future<T> _wrapApiPromise<T>(Object p) => js_util
2023-07-26 15:30:00 -04:00
.promiseToFuture<T>(p)
.then((value) => value)
// ignore: inference_failure_on_untyped_parameter
.catchError((e) {
2023-10-14 20:18:37 -04:00
try {
final ex = VeilidAPIException.fromJson(jsonDecode(e as String));
throw ex;
} on Exception catch (_) {
// Wrap all other errors in VeilidAPIExceptionInternal
throw VeilidAPIExceptionInternal(e.toString());
}
});
2022-03-15 23:02:24 -04:00
2022-12-02 22:52:03 -05:00
class _Ctx {
2023-07-30 15:57:06 -04:00
_Ctx(int id, this.js) : _id = id;
int? _id;
2022-12-02 22:52:03 -05:00
final VeilidJS js;
2023-07-30 15:57:06 -04:00
int requireId() {
if (_id == null) {
2023-07-19 10:07:51 -04:00
throw VeilidAPIExceptionNotInitialized();
}
2023-07-30 15:57:06 -04:00
return _id!;
2023-07-19 10:07:51 -04:00
}
void close() {
2023-07-30 15:57:06 -04:00
if (_id != null) {
js_util.callMethod<void>(wasm, 'release_routing_context', [_id]);
_id = null;
2023-07-19 10:07:51 -04:00
}
}
2022-12-02 22:52:03 -05:00
}
2022-11-26 14:16:02 -05:00
// JS implementation of VeilidRoutingContext
2023-07-19 10:07:51 -04:00
class VeilidRoutingContextJS extends VeilidRoutingContext {
2022-12-02 22:52:03 -05:00
VeilidRoutingContextJS._(this._ctx) {
_finalizer.attach(this, _ctx, detach: this);
}
2023-07-26 14:20:17 -04:00
final _Ctx _ctx;
static final Finalizer<_Ctx> _finalizer = Finalizer((ctx) => ctx.close());
2022-11-26 14:16:02 -05:00
2023-07-19 10:07:51 -04:00
@override
void close() {
_ctx.close();
}
2022-11-26 14:16:02 -05:00
@override
2024-03-16 23:57:46 -04:00
VeilidRoutingContextJS withDefaultSafety({bool closeSelf = false}) {
2023-07-30 15:57:06 -04:00
final id = _ctx.requireId();
2023-07-26 14:20:17 -04:00
final int newId =
2023-11-05 18:38:05 -05:00
js_util.callMethod(wasm, 'routing_context_with_default_safety', [id]);
2024-03-16 23:57:46 -04:00
final out = VeilidRoutingContextJS._(_Ctx(newId, _ctx.js));
if (closeSelf) {
close();
}
return out;
2022-11-26 14:16:02 -05:00
}
@override
2024-03-16 23:57:46 -04:00
VeilidRoutingContextJS withSafety(SafetySelection safetySelection,
{bool closeSelf = false}) {
2023-07-30 15:57:06 -04:00
final id = _ctx.requireId();
2023-07-26 15:12:28 -04:00
final newId = js_util.callMethod<int>(
2023-11-05 18:38:05 -05:00
wasm, 'routing_context_with_safety', [id, jsonEncode(safetySelection)]);
2024-03-16 23:57:46 -04:00
final out = VeilidRoutingContextJS._(_Ctx(newId, _ctx.js));
if (closeSelf) {
close();
}
return out;
2022-11-26 14:16:02 -05:00
}
@override
2024-03-16 23:57:46 -04:00
VeilidRoutingContextJS withSequencing(Sequencing sequencing,
{bool closeSelf = false}) {
2023-07-30 15:57:06 -04:00
final id = _ctx.requireId();
2023-07-26 15:12:28 -04:00
final newId = js_util.callMethod<int>(
wasm, 'routing_context_with_sequencing', [id, jsonEncode(sequencing)]);
2024-03-16 23:57:46 -04:00
final out = VeilidRoutingContextJS._(_Ctx(newId, _ctx.js));
if (closeSelf) {
close();
}
return out;
2022-11-26 14:16:02 -05:00
}
2023-11-05 18:38:05 -05:00
@override
Future<SafetySelection> safety() async {
final id = _ctx.requireId();
return SafetySelection.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'routing_context_safety', [
id,
]))));
}
2022-11-26 14:16:02 -05:00
@override
Future<Uint8List> appCall(String target, Uint8List request) async {
2023-07-30 15:57:06 -04:00
final id = _ctx.requireId();
2023-07-26 14:20:17 -04:00
final encodedRequest = base64UrlNoPadEncode(request);
2022-11-26 14:16:02 -05:00
2023-01-04 17:02:45 -05:00
return base64UrlNoPadDecode(await _wrapApiPromise(js_util.callMethod(
2023-07-26 15:12:28 -04:00
wasm, 'routing_context_app_call', [id, target, encodedRequest])));
2022-11-26 14:16:02 -05:00
}
@override
2022-12-28 22:53:58 -05:00
Future<void> appMessage(String target, Uint8List message) {
2023-07-30 15:57:06 -04:00
final id = _ctx.requireId();
2023-07-26 14:20:17 -04:00
final encodedMessage = base64UrlNoPadEncode(message);
2022-11-26 14:16:02 -05:00
2023-07-26 15:12:28 -04:00
return _wrapApiPromise(js_util.callMethod(
wasm, 'routing_context_app_message', [id, target, encodedMessage]));
2022-11-26 14:16:02 -05:00
}
2023-05-29 15:24:57 -04:00
@override
2023-07-08 22:50:44 -04:00
Future<DHTRecordDescriptor> createDHTRecord(DHTSchema schema,
{CryptoKind kind = 0}) async {
2023-07-30 15:57:06 -04:00
final id = _ctx.requireId();
2023-05-29 15:24:57 -04:00
return DHTRecordDescriptor.fromJson(jsonDecode(await _wrapApiPromise(js_util
2023-07-26 14:20:17 -04:00
.callMethod(wasm, 'routing_context_create_dht_record',
2023-07-26 15:12:28 -04:00
[id, jsonEncode(schema), kind]))));
2023-05-29 15:24:57 -04:00
}
@override
Future<DHTRecordDescriptor> openDHTRecord(TypedKey key,
{KeyPair? writer}) async {
2023-07-30 15:57:06 -04:00
final id = _ctx.requireId();
2023-05-29 15:24:57 -04:00
return DHTRecordDescriptor.fromJson(jsonDecode(await _wrapApiPromise(js_util
2023-07-26 14:20:17 -04:00
.callMethod(wasm, 'routing_context_open_dht_record', [
2023-07-26 15:12:28 -04:00
id,
2023-05-29 15:24:57 -04:00
jsonEncode(key),
2023-07-26 14:20:17 -04:00
if (writer != null) jsonEncode(writer) else null
2023-05-29 15:24:57 -04:00
]))));
}
@override
Future<void> closeDHTRecord(TypedKey key) {
2023-07-30 15:57:06 -04:00
final id = _ctx.requireId();
2023-05-29 15:24:57 -04:00
return _wrapApiPromise(js_util.callMethod(
2023-07-26 15:12:28 -04:00
wasm, 'routing_context_close_dht_record', [id, jsonEncode(key)]));
2023-05-29 15:24:57 -04:00
}
@override
Future<void> deleteDHTRecord(TypedKey key) {
2023-07-30 15:57:06 -04:00
final id = _ctx.requireId();
2023-07-26 15:12:28 -04:00
return _wrapApiPromise(js_util.callMethod(
wasm, 'routing_context_delete_dht_record', [id, jsonEncode(key)]));
2023-05-29 15:24:57 -04:00
}
@override
Future<ValueData?> getDHTValue(TypedKey key, int subkey,
{bool forceRefresh = false}) async {
2023-07-30 15:57:06 -04:00
final id = _ctx.requireId();
2023-07-26 15:12:28 -04:00
final opt = await _wrapApiPromise<String?>(js_util.callMethod(
2023-05-29 15:24:57 -04:00
wasm,
2023-07-26 14:20:17 -04:00
'routing_context_get_dht_value',
2023-07-26 15:12:28 -04:00
[id, jsonEncode(key), subkey, forceRefresh]));
2023-10-14 20:18:37 -04:00
if (opt == null) {
return null;
}
final jsonOpt = jsonDecode(opt);
return jsonOpt == null ? null : ValueData.fromJson(jsonOpt);
2023-05-29 15:24:57 -04:00
}
@override
Future<ValueData?> setDHTValue(TypedKey key, int subkey, Uint8List data,
{KeyPair? writer}) async {
2023-07-30 15:57:06 -04:00
final id = _ctx.requireId();
final opt = await _wrapApiPromise<String?>(
js_util.callMethod(wasm, 'routing_context_set_dht_value', [
id,
jsonEncode(key),
subkey,
base64UrlNoPadEncode(data),
if (writer != null) jsonEncode(writer) else null
]));
2023-10-14 20:18:37 -04:00
if (opt == null) {
return null;
}
final jsonOpt = jsonDecode(opt);
return jsonOpt == null ? null : ValueData.fromJson(jsonOpt);
2023-05-29 15:24:57 -04:00
}
@override
2024-01-04 22:29:31 -05:00
Future<Timestamp> watchDHTValues(TypedKey key,
{List<ValueSubkeyRange>? subkeys,
Timestamp? expiration,
int? count}) async {
subkeys ??= [];
expiration ??= Timestamp.zero();
2024-01-04 22:29:31 -05:00
count ??= 0xFFFFFFFF;
2023-07-30 15:57:06 -04:00
final id = _ctx.requireId();
2023-07-26 15:12:28 -04:00
final ts = await _wrapApiPromise<String>(js_util.callMethod(
2023-07-26 14:20:17 -04:00
wasm, 'routing_context_watch_dht_values', [
2023-07-26 15:12:28 -04:00
id,
2023-05-29 15:24:57 -04:00
jsonEncode(key),
jsonEncode(subkeys),
expiration.toString(),
count
]));
return Timestamp.fromString(ts);
}
@override
2024-01-04 22:29:31 -05:00
Future<bool> cancelDHTWatch(TypedKey key, {List<ValueSubkeyRange>? subkeys}) {
subkeys ??= [];
2023-07-30 15:57:06 -04:00
final id = _ctx.requireId();
2023-05-29 15:24:57 -04:00
return _wrapApiPromise(js_util.callMethod(
wasm,
2023-07-26 14:20:17 -04:00
'routing_context_cancel_dht_watch',
2023-07-26 15:12:28 -04:00
[id, jsonEncode(key), jsonEncode(subkeys)]));
2023-05-29 15:24:57 -04:00
}
2024-03-16 23:57:46 -04:00
@override
Future<DHTRecordReport> inspectDHTRecord(TypedKey key,
{List<ValueSubkeyRange>? subkeys,
DHTReportScope scope = DHTReportScope.local}) async {
subkeys ??= [];
final id = _ctx.requireId();
return DHTRecordReport.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, 'routing_context_inspect_dht_record',
[id, jsonEncode(key), jsonEncode(subkeys), jsonEncode(scope)]))));
}
2023-05-29 15:24:57 -04:00
}
// JS implementation of VeilidCryptoSystem
2023-07-19 10:07:51 -04:00
class VeilidCryptoSystemJS extends VeilidCryptoSystem {
2023-07-30 15:57:06 -04:00
VeilidCryptoSystemJS._(this._js, this._kind);
2023-07-26 14:20:17 -04:00
final CryptoKind _kind;
2023-07-30 15:57:06 -04:00
// Keep the reference
// ignore: unused_field
2023-07-26 14:20:17 -04:00
final VeilidJS _js;
2023-05-29 15:24:57 -04:00
@override
2023-07-26 14:20:17 -04:00
CryptoKind kind() => _kind;
2023-05-29 15:24:57 -04:00
@override
2023-07-26 15:12:28 -04:00
Future<SharedSecret> cachedDH(PublicKey key, SecretKey secret) async =>
SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
wasm,
'crypto_cached_dh',
[_kind, jsonEncode(key), jsonEncode(secret)]))));
2023-05-29 15:24:57 -04:00
@override
2023-07-26 15:12:28 -04:00
Future<SharedSecret> computeDH(PublicKey key, SecretKey secret) async =>
SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
wasm,
'crypto_compute_dh',
[_kind, jsonEncode(key), jsonEncode(secret)]))));
@override
Future<SharedSecret> generateSharedSecret(
PublicKey key, SecretKey secret, Uint8List domain) async =>
SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
wasm, 'crypto_generate_shared_secret', [
_kind,
jsonEncode(key),
jsonEncode(secret),
base64UrlNoPadEncode(domain)
]))));
2023-05-29 15:24:57 -04:00
@override
2023-07-26 15:12:28 -04:00
Future<Uint8List> randomBytes(int len) async =>
base64UrlNoPadDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'crypto_random_bytes', [_kind, len])));
2023-05-29 15:24:57 -04:00
@override
2023-07-26 14:20:17 -04:00
Future<int> defaultSaltLength() => _wrapApiPromise(
2023-07-26 15:12:28 -04:00
js_util.callMethod(wasm, 'crypto_default_salt_length', [_kind]));
2023-05-29 15:24:57 -04:00
@override
2023-07-26 15:12:28 -04:00
Future<String> hashPassword(Uint8List password, Uint8List salt) =>
_wrapApiPromise(js_util.callMethod(wasm, 'crypto_hash_password',
[_kind, base64UrlNoPadEncode(password), base64UrlNoPadEncode(salt)]));
2023-05-29 15:24:57 -04:00
@override
2023-07-26 15:12:28 -04:00
Future<bool> verifyPassword(Uint8List password, String passwordHash) =>
_wrapApiPromise(js_util.callMethod(wasm, 'crypto_verify_password',
[_kind, base64UrlNoPadEncode(password), passwordHash]));
2023-05-29 15:24:57 -04:00
@override
Future<SharedSecret> deriveSharedSecret(
2023-07-26 15:12:28 -04:00
Uint8List password, Uint8List salt) async =>
SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
wasm, 'crypto_derive_shared_secret', [
_kind,
base64UrlNoPadEncode(password),
base64UrlNoPadEncode(salt)
]))));
2023-05-29 15:24:57 -04:00
@override
2023-07-26 15:12:28 -04:00
Future<Nonce> randomNonce() async =>
Nonce.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'crypto_random_nonce', [_kind]))));
2023-05-29 15:24:57 -04:00
@override
2023-07-26 15:12:28 -04:00
Future<SharedSecret> randomSharedSecret() async =>
SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'crypto_random_shared_secret', [_kind]))));
2023-05-29 15:24:57 -04:00
@override
2023-07-26 15:12:28 -04:00
Future<KeyPair> generateKeyPair() async =>
KeyPair.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'crypto_generate_key_pair', [_kind]))));
2023-05-29 15:24:57 -04:00
@override
2023-07-26 15:12:28 -04:00
Future<HashDigest> generateHash(Uint8List data) async =>
HashDigest.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
wasm, 'crypto_generate_hash', [_kind, base64UrlNoPadEncode(data)]))));
2023-05-29 15:24:57 -04:00
@override
2023-07-26 15:12:28 -04:00
Future<bool> validateKeyPair(PublicKey key, SecretKey secret) =>
_wrapApiPromise(js_util.callMethod(wasm, 'crypto_validate_key_pair',
[_kind, jsonEncode(key), jsonEncode(secret)]));
2023-05-29 15:24:57 -04:00
@override
2023-07-26 15:12:28 -04:00
Future<bool> validateHash(Uint8List data, HashDigest hash) =>
_wrapApiPromise(js_util.callMethod(wasm, 'crypto_validate_hash',
[_kind, base64UrlNoPadEncode(data), jsonEncode(hash)]));
2023-05-29 15:24:57 -04:00
@override
2023-07-26 15:12:28 -04:00
Future<CryptoKeyDistance> distance(CryptoKey key1, CryptoKey key2) async =>
CryptoKeyDistance.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, 'crypto_distance',
[_kind, jsonEncode(key1), jsonEncode(key2)]))));
2023-05-29 15:24:57 -04:00
@override
Future<Signature> sign(
2023-07-26 15:12:28 -04:00
PublicKey key, SecretKey secret, Uint8List data) async =>
Signature.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
wasm, 'crypto_sign', [
_kind,
jsonEncode(key),
jsonEncode(secret),
base64UrlNoPadEncode(data)
]))));
2023-05-29 15:24:57 -04:00
@override
Future<bool> verify(PublicKey key, Uint8List data, Signature signature) =>
2023-07-26 15:12:28 -04:00
_wrapApiPromise(js_util.callMethod(wasm, 'crypto_verify', [
_kind,
jsonEncode(key),
base64UrlNoPadEncode(data),
jsonEncode(signature),
]));
2023-05-29 15:24:57 -04:00
@override
2023-07-26 14:20:17 -04:00
Future<int> aeadOverhead() => _wrapApiPromise(
2023-07-26 15:12:28 -04:00
js_util.callMethod(wasm, 'crypto_aead_overhead', [_kind]));
2023-05-29 15:24:57 -04:00
@override
Future<Uint8List> decryptAead(Uint8List body, Nonce nonce,
2023-07-26 15:12:28 -04:00
SharedSecret sharedSecret, Uint8List? associatedData) async =>
base64UrlNoPadDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'crypto_decrypt_aead', [
_kind,
base64UrlNoPadEncode(body),
jsonEncode(nonce),
jsonEncode(sharedSecret),
if (associatedData != null)
base64UrlNoPadEncode(associatedData)
else
null
])));
2023-05-29 15:24:57 -04:00
@override
Future<Uint8List> encryptAead(Uint8List body, Nonce nonce,
2023-07-26 15:12:28 -04:00
SharedSecret sharedSecret, Uint8List? associatedData) async =>
base64UrlNoPadDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'crypto_encrypt_aead', [
_kind,
base64UrlNoPadEncode(body),
jsonEncode(nonce),
jsonEncode(sharedSecret),
if (associatedData != null)
base64UrlNoPadEncode(associatedData)
else
null
])));
2023-05-29 15:24:57 -04:00
@override
Future<Uint8List> cryptNoAuth(
2023-07-26 15:12:28 -04:00
Uint8List body, Nonce nonce, SharedSecret sharedSecret) async =>
base64UrlNoPadDecode(await _wrapApiPromise(js_util.callMethod(
wasm, 'crypto_crypt_no_auth', [
_kind,
base64UrlNoPadEncode(body),
jsonEncode(nonce),
jsonEncode(sharedSecret)
])));
2022-11-26 14:16:02 -05:00
}
2022-12-28 22:53:58 -05:00
class _TDBT {
2023-07-26 14:20:17 -04:00
_TDBT(this.id, this.tdbjs, this.js);
2023-07-19 10:07:51 -04:00
int? id;
final VeilidTableDBJS tdbjs;
final VeilidJS js;
void ensureValid() {
if (id == null) {
throw VeilidAPIExceptionNotInitialized();
}
}
void close() {
if (id != null) {
2023-07-26 15:12:28 -04:00
js_util.callMethod<void>(wasm, 'release_table_db_transaction', [id]);
2023-07-19 10:07:51 -04:00
id = null;
}
}
2022-12-28 22:53:58 -05:00
}
// JS implementation of VeilidTableDBTransaction
class VeilidTableDBTransactionJS extends VeilidTableDBTransaction {
VeilidTableDBTransactionJS._(this._tdbt) {
_finalizer.attach(this, _tdbt, detach: this);
}
2023-07-26 14:20:17 -04:00
final _TDBT _tdbt;
static final Finalizer<_TDBT> _finalizer = Finalizer((tdbt) => tdbt.close());
2022-12-28 22:53:58 -05:00
@override
2023-07-26 14:20:17 -04:00
bool isDone() => _tdbt.id == null;
2022-12-28 22:53:58 -05:00
@override
2023-07-19 10:07:51 -04:00
Future<void> commit() async {
_tdbt.ensureValid();
2023-07-26 15:12:28 -04:00
final id = _tdbt.id!;
await _wrapApiPromise<void>(
js_util.callMethod(wasm, 'table_db_transaction_commit', [id]));
2023-07-19 10:07:51 -04:00
_tdbt.close();
2022-12-28 22:53:58 -05:00
}
@override
2023-07-19 10:07:51 -04:00
Future<void> rollback() async {
_tdbt.ensureValid();
2023-07-26 15:12:28 -04:00
final id = _tdbt.id!;
await _wrapApiPromise<void>(
js_util.callMethod(wasm, 'table_db_transaction_rollback', [id]));
2023-07-19 10:07:51 -04:00
_tdbt.close();
}
@override
Future<void> store(int col, Uint8List key, Uint8List value) async {
_tdbt.ensureValid();
2023-07-26 15:12:28 -04:00
final id = _tdbt.id!;
2023-01-04 17:02:45 -05:00
final encodedKey = base64UrlNoPadEncode(key);
final encodedValue = base64UrlNoPadEncode(value);
2022-12-28 22:53:58 -05:00
2023-07-26 15:12:28 -04:00
await _wrapApiPromise<void>(js_util.callMethod(wasm,
'table_db_transaction_store', [id, col, encodedKey, encodedValue]));
2022-12-28 22:53:58 -05:00
}
@override
2023-07-19 10:07:51 -04:00
Future<void> delete(int col, Uint8List key) async {
_tdbt.ensureValid();
2023-07-26 15:12:28 -04:00
final id = _tdbt.id!;
2023-01-04 17:02:45 -05:00
final encodedKey = base64UrlNoPadEncode(key);
2022-12-28 22:53:58 -05:00
2023-07-26 15:12:28 -04:00
await _wrapApiPromise<void>(js_util.callMethod(
wasm, 'table_db_transaction_delete', [id, col, encodedKey]));
2022-12-28 22:53:58 -05:00
}
}
class _TDB {
2023-07-30 15:57:06 -04:00
_TDB(int id, this.js) : _id = id;
int? _id;
2023-07-26 14:20:17 -04:00
final VeilidJS js;
2023-07-30 15:57:06 -04:00
int requireId() {
if (_id == null) {
2023-07-19 10:07:51 -04:00
throw VeilidAPIExceptionNotInitialized();
}
2023-07-30 15:57:06 -04:00
return _id!;
2023-07-19 10:07:51 -04:00
}
void close() {
2023-07-30 15:57:06 -04:00
if (_id != null) {
js_util.callMethod<void>(wasm, 'release_table_db', [_id]);
_id = null;
2023-07-19 10:07:51 -04:00
}
}
2022-12-28 22:53:58 -05:00
}
// JS implementation of VeilidTableDB
class VeilidTableDBJS extends VeilidTableDB {
VeilidTableDBJS._(this._tdb) {
_finalizer.attach(this, _tdb, detach: this);
}
2023-07-26 14:20:17 -04:00
final _TDB _tdb;
static final Finalizer<_TDB> _finalizer = Finalizer((tdb) => tdb.close());
2022-12-28 22:53:58 -05:00
2023-07-19 10:07:51 -04:00
@override
void close() {
_tdb.close();
}
2022-12-28 22:53:58 -05:00
@override
int getColumnCount() {
2023-07-30 15:57:06 -04:00
final id = _tdb.requireId();
return js_util.callMethod(wasm, 'table_db_get_column_count', [id]);
2022-12-28 22:53:58 -05:00
}
@override
2023-05-29 15:24:57 -04:00
Future<List<Uint8List>> getKeys(int col) async {
2023-07-30 15:57:06 -04:00
final id = _tdb.requireId();
2023-05-29 15:24:57 -04:00
return jsonListConstructor(base64UrlNoPadDecodeDynamic)(jsonDecode(
2023-07-26 15:12:28 -04:00
await js_util.callMethod(wasm, 'table_db_get_keys', [id, col])));
2022-12-28 22:53:58 -05:00
}
@override
VeilidTableDBTransaction transact() {
2023-07-30 15:57:06 -04:00
final id = _tdb.requireId();
2023-07-26 15:12:28 -04:00
final xid = js_util.callMethod<int>(wasm, 'table_db_transact', [id]);
2022-12-28 22:53:58 -05:00
2023-07-26 15:12:28 -04:00
return VeilidTableDBTransactionJS._(_TDBT(xid, this, _tdb.js));
2022-12-28 22:53:58 -05:00
}
@override
Future<void> store(int col, Uint8List key, Uint8List value) {
2023-07-30 15:57:06 -04:00
final id = _tdb.requireId();
2023-01-04 17:02:45 -05:00
final encodedKey = base64UrlNoPadEncode(key);
final encodedValue = base64UrlNoPadEncode(value);
2022-12-28 22:53:58 -05:00
return _wrapApiPromise(js_util.callMethod(
2023-07-26 15:12:28 -04:00
wasm, 'table_db_store', [id, col, encodedKey, encodedValue]));
2022-12-28 22:53:58 -05:00
}
@override
Future<Uint8List?> load(int col, Uint8List key) async {
2023-07-30 15:57:06 -04:00
final id = _tdb.requireId();
2023-01-04 17:02:45 -05:00
final encodedKey = base64UrlNoPadEncode(key);
2022-12-28 22:53:58 -05:00
2023-07-26 15:12:28 -04:00
final out = await _wrapApiPromise<String?>(
js_util.callMethod(wasm, 'table_db_load', [id, col, encodedKey]));
2022-12-28 22:53:58 -05:00
if (out == null) {
return null;
}
2023-01-04 17:02:45 -05:00
return base64UrlNoPadDecode(out);
2022-12-28 22:53:58 -05:00
}
@override
2023-07-26 15:12:28 -04:00
Future<Uint8List?> delete(int col, Uint8List key) async {
2023-07-30 15:57:06 -04:00
final id = _tdb.requireId();
2023-01-04 17:02:45 -05:00
final encodedKey = base64UrlNoPadEncode(key);
2022-12-28 22:53:58 -05:00
2023-07-26 15:12:28 -04:00
final out = await _wrapApiPromise<String?>(
js_util.callMethod(wasm, 'table_db_delete', [id, col, encodedKey]));
if (out == null) {
return null;
}
return base64UrlNoPadDecode(out);
2022-12-28 22:53:58 -05:00
}
}
2022-11-26 14:16:02 -05:00
// JS implementation of high level Veilid API
2023-07-19 10:07:51 -04:00
class VeilidJS extends Veilid {
2022-06-15 21:51:38 -04:00
@override
2022-07-01 16:20:43 -04:00
void initializeVeilidCore(Map<String, dynamic> platformConfigJson) {
2023-07-26 14:20:17 -04:00
final platformConfigJsonString = jsonEncode(platformConfigJson);
2023-07-26 15:12:28 -04:00
js_util.callMethod<void>(
wasm, 'initialize_veilid_core', [platformConfigJsonString]);
2022-06-15 21:51:38 -04:00
}
2022-07-01 12:13:52 -04:00
@override
void changeLogLevel(String layer, VeilidConfigLogLevel logLevel) {
2023-07-26 14:20:17 -04:00
final logLevelJsonString = jsonEncode(logLevel);
2023-07-26 15:12:28 -04:00
js_util.callMethod<void>(
wasm, 'change_log_level', [layer, logLevelJsonString]);
2022-07-01 12:13:52 -04:00
}
2024-03-07 12:38:20 -05:00
@override
void changeLogIgnore(String layer, List<String> changes) {
final changesJsonString = jsonEncode(changes.join(','));
js_util.callMethod<void>(
wasm, 'change_log_ignore', [layer, changesJsonString]);
}
2022-03-03 20:45:39 -05:00
@override
2022-09-09 16:27:13 -04:00
Future<Stream<VeilidUpdate>> startupVeilidCore(VeilidConfig config) async {
2023-07-26 14:20:17 -04:00
final streamController = StreamController<VeilidUpdate>();
2023-07-26 15:12:28 -04:00
void updateCallback(String update) {
final updateJson = jsonDecode(update) as Map<String, dynamic>;
2023-07-26 14:20:17 -04:00
if (updateJson['kind'] == 'Shutdown') {
2023-07-26 15:12:28 -04:00
unawaited(streamController.close());
2022-03-17 10:31:10 -04:00
} else {
2023-07-26 14:20:17 -04:00
final update = VeilidUpdate.fromJson(updateJson);
2022-03-17 10:31:10 -04:00
streamController.add(update);
}
}
2023-07-26 15:12:28 -04:00
await _wrapApiPromise<void>(js_util.callMethod(wasm, 'startup_veilid_core',
2023-05-29 15:24:57 -04:00
[js.allowInterop(updateCallback), jsonEncode(config)]));
2022-09-09 16:27:13 -04:00
return streamController.stream;
2022-02-06 21:18:42 -05:00
}
2022-03-03 20:45:39 -05:00
@override
2023-07-26 15:12:28 -04:00
Future<VeilidState> getVeilidState() async =>
VeilidState.fromJson(jsonDecode(await _wrapApiPromise<String>(
js_util.callMethod(wasm, 'get_veilid_state', []))));
2022-02-06 21:18:42 -05:00
2022-09-06 18:59:41 -04:00
@override
2023-07-26 15:12:28 -04:00
Future<void> attach() =>
_wrapApiPromise(js_util.callMethod(wasm, 'attach', []));
2022-09-06 18:59:41 -04:00
@override
2023-07-26 15:12:28 -04:00
Future<void> detach() =>
_wrapApiPromise(js_util.callMethod(wasm, 'detach', []));
2022-09-06 18:59:41 -04:00
2022-03-03 20:45:39 -05:00
@override
2023-07-26 15:12:28 -04:00
Future<void> shutdownVeilidCore() =>
_wrapApiPromise(js_util.callMethod(wasm, 'shutdown_veilid_core', []));
2022-02-06 21:18:42 -05:00
2023-05-29 15:24:57 -04:00
@override
List<CryptoKind> validCryptoKinds() {
2023-07-26 14:20:17 -04:00
final vck = jsonDecode(js_util.callMethod(wasm, 'valid_crypto_kinds', []))
2023-07-25 01:04:22 -04:00
as List<dynamic>;
2024-02-27 22:12:34 -05:00
return vck.cast<CryptoKind>();
2023-05-29 15:24:57 -04:00
}
@override
Future<VeilidCryptoSystem> getCryptoSystem(CryptoKind kind) async {
if (!validCryptoKinds().contains(kind)) {
2023-07-26 14:20:17 -04:00
throw const VeilidAPIExceptionGeneric('unsupported cryptosystem');
2023-05-29 15:24:57 -04:00
}
return VeilidCryptoSystemJS._(this, kind);
}
@override
2023-07-26 14:20:17 -04:00
Future<VeilidCryptoSystem> bestCryptoSystem() async => VeilidCryptoSystemJS._(
2023-07-26 15:12:28 -04:00
this, js_util.callMethod(wasm, 'best_crypto_kind', []));
2023-05-29 15:24:57 -04:00
@override
Future<List<TypedKey>?> verifySignatures(List<TypedKey> nodeIds,
2023-07-26 15:12:28 -04:00
Uint8List data, List<TypedSignature> signatures) async =>
optJsonListConstructor(TypedKey.fromJson)(jsonDecode(
await _wrapApiPromise(js_util.callMethod(wasm, 'verify_signatures', [
2023-07-26 15:12:28 -04:00
jsonEncode(nodeIds),
base64UrlNoPadEncode(data),
jsonEncode(signatures)
]))));
2023-05-29 15:24:57 -04:00
@override
Future<List<TypedSignature>> generateSignatures(
2023-07-26 15:12:28 -04:00
Uint8List data, List<TypedKeyPair> keyPairs) async =>
jsonListConstructor(TypedSignature.fromJson)(jsonDecode(
await _wrapApiPromise(js_util.callMethod(wasm, 'generate_signatures',
[base64UrlNoPadEncode(data), jsonEncode(keyPairs)]))));
2023-05-29 15:24:57 -04:00
@override
2023-07-26 15:12:28 -04:00
Future<TypedKeyPair> generateKeyPair(CryptoKind kind) async =>
TypedKeyPair.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'generate_key_pair', [kind]))));
2023-05-29 15:24:57 -04:00
2022-03-03 20:45:39 -05:00
@override
2022-11-26 14:16:02 -05:00
Future<VeilidRoutingContext> routingContext() async {
2023-07-26 15:12:28 -04:00
final rcid = await _wrapApiPromise<int>(
js_util.callMethod(wasm, 'routing_context', []));
return VeilidRoutingContextJS._(_Ctx(rcid, this));
2022-11-26 14:16:02 -05:00
}
@override
2023-07-26 15:12:28 -04:00
Future<RouteBlob> newPrivateRoute() async =>
RouteBlob.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, 'new_private_route', []))));
2022-11-26 14:16:02 -05:00
@override
2023-03-01 15:50:30 -05:00
Future<RouteBlob> newCustomPrivateRoute(
2022-11-26 14:16:02 -05:00
Stability stability, Sequencing sequencing) async {
2023-07-26 14:20:17 -04:00
final stabilityString = jsonEncode(stability);
final sequencingString = jsonEncode(sequencing);
2022-11-26 14:16:02 -05:00
2023-05-29 15:24:57 -04:00
return RouteBlob.fromJson(jsonDecode(await _wrapApiPromise(js_util
2022-12-02 22:52:03 -05:00
.callMethod(
2023-07-26 14:20:17 -04:00
wasm, 'new_private_route', [stabilityString, sequencingString]))));
2022-11-26 14:16:02 -05:00
}
@override
2022-12-28 22:53:58 -05:00
Future<String> importRemotePrivateRoute(Uint8List blob) {
2023-07-26 14:20:17 -04:00
final encodedBlob = base64UrlNoPadEncode(blob);
2022-11-26 14:16:02 -05:00
return _wrapApiPromise(
2023-07-26 14:20:17 -04:00
js_util.callMethod(wasm, 'import_remote_private_route', [encodedBlob]));
2022-11-26 14:16:02 -05:00
}
@override
2024-03-08 00:17:38 -05:00
Future<void> releasePrivateRoute(String routeId) => _wrapApiPromise(
js_util.callMethod(wasm, 'release_private_route', [routeId]));
2022-03-03 20:45:39 -05:00
2022-09-30 22:37:55 -04:00
@override
2023-06-16 11:57:55 -04:00
Future<void> appCallReply(String callId, Uint8List message) {
2023-07-26 14:20:17 -04:00
final encodedMessage = base64UrlNoPadEncode(message);
2022-09-30 22:37:55 -04:00
return _wrapApiPromise(
2023-07-26 14:20:17 -04:00
js_util.callMethod(wasm, 'app_call_reply', [callId, encodedMessage]));
2022-09-30 22:37:55 -04:00
}
2022-12-02 22:52:03 -05:00
2022-12-28 22:53:58 -05:00
@override
Future<VeilidTableDB> openTableDB(String name, int columnCount) async {
2023-07-26 15:12:28 -04:00
final dbid = await _wrapApiPromise<int>(
2023-07-26 14:20:17 -04:00
js_util.callMethod(wasm, 'open_table_db', [name, columnCount]));
2023-07-26 15:12:28 -04:00
return VeilidTableDBJS._(_TDB(dbid, this));
2022-12-28 22:53:58 -05:00
}
@override
2023-07-26 15:12:28 -04:00
Future<bool> deleteTableDB(String name) =>
_wrapApiPromise(js_util.callMethod(wasm, 'delete_table_db', [name]));
2022-12-28 22:53:58 -05:00
2023-05-29 15:24:57 -04:00
@override
2023-07-26 14:20:17 -04:00
Timestamp now() => Timestamp.fromString(js_util.callMethod(wasm, 'now', []));
2023-05-29 15:24:57 -04:00
2022-11-26 14:16:02 -05:00
@override
2023-07-26 15:12:28 -04:00
Future<String> debug(String command) async =>
_wrapApiPromise(js_util.callMethod(wasm, 'debug', [command]));
2022-09-30 22:37:55 -04:00
2022-03-03 20:45:39 -05:00
@override
2023-07-26 15:12:28 -04:00
String veilidVersionString() =>
js_util.callMethod(wasm, 'veilid_version_string', []);
2022-02-06 21:18:42 -05:00
2022-03-03 20:45:39 -05:00
@override
2022-03-17 10:31:10 -04:00
VeilidVersion veilidVersion() {
2023-07-26 15:12:28 -04:00
final jsonVersion =
jsonDecode(js_util.callMethod(wasm, 'veilid_version', []))
as Map<String, dynamic>;
return VeilidVersion(jsonVersion['major'] as int,
jsonVersion['minor'] as int, jsonVersion['patch'] as int);
2022-02-06 21:18:42 -05:00
}
2024-03-02 11:32:08 -05:00
@override
String defaultVeilidConfig() =>
js_util.callMethod(wasm, 'default_veilid_config', []);
2022-02-06 21:18:42 -05:00
}