diff --git a/.gitignore b/.gitignore index 6ca71fb..4adb571 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ index.node **/node_modules **/.DS_Store npm-debug.log* +connection-log.txt diff --git a/Cargo.lock b/Cargo.lock index 9619bf4..aade720 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1626,6 +1626,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.6.4" @@ -1893,8 +1902,10 @@ dependencies = [ "flume", "neon", "once_cell", + "serde_json", "thiserror", "tokio", + "tracing-subscriber", "veilid-core", ] @@ -2405,8 +2416,17 @@ checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.3.9", + "regex-syntax 0.7.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -2417,9 +2437,15 @@ checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.7.5", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.7.5" @@ -3206,10 +3232,14 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ + "matchers", "nu-ansi-term", + "once_cell", + "regex", "sharded-slab", "smallvec", "thread_local", + "tracing", "tracing-core", "tracing-log", ] diff --git a/Cargo.toml b/Cargo.toml index 69e167a..ce5ce55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,11 +13,13 @@ crate-type = ["cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tokio = { version = "1.30.0", features = ["macros", "rt-multi-thread"] } +tokio = { version = "1.32.0", features = ["full"] } veilid-core = { git = "https://gitlab.com/veilid/veilid", tag="v0.2.3", features = [ "rt-tokio" ] } once_cell = "1" thiserror = "1.0.49" flume = "0.11.0" +tracing-subscriber = { version = "0.3.17", features = [ "env-filter" ] } +serde_json = "1.0" [dependencies.neon] version = "0.10" diff --git a/package.json b/package.json index 3397800..f8e7286 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "author": "Sven Slootweg ", "license": "WTFPL OR CC0-1.0", "devDependencies": { - "cargo-cp-artifact": "^0.1" + "cargo-cp-artifact": "^0.1", + "tmp-promise": "^3.0.3" }, "keywords": [ "veilid" diff --git a/src/lib.rs b/src/lib.rs index f4eb805..381d250 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,7 @@ -use std::{path::PathBuf, sync::{Arc, mpsc}, io}; - -use neon::{prelude::*, result::Throw}; +use std::{path::PathBuf, sync::Arc}; +use neon::prelude::*; use once_cell::sync::OnceCell; -use thiserror::Error; +use tracing_subscriber::EnvFilter; use veilid_core::{CryptoKind, CryptoTyped, KeyPair, CRYPTO_KIND_VLD0, VeilidAPI, api_startup_json, VeilidAPIError}; // #[derive(Error, Debug)] @@ -13,12 +12,15 @@ use veilid_core::{CryptoKind, CryptoTyped, KeyPair, CRYPTO_KIND_VLD0, VeilidAPI, // Throw (#[from] Throw) // } -fn make_runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static tokio::runtime::Runtime> { +fn make_runtime_js<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static tokio::runtime::Runtime> { + make_runtime().or_else(|error| cx.throw_error(error.to_string())) +} + +fn make_runtime() -> Result<&'static tokio::runtime::Runtime, std::io::Error> { static RUNTIME: OnceCell = OnceCell::new(); RUNTIME.get_or_try_init(|| tokio::runtime::Runtime::new() - .or_else(|error| cx.throw_error(error.to_string())) ) } @@ -95,6 +97,22 @@ fn crypto_generate_keypair(mut cx: FunctionContext) -> JsResult { Ok(cx.boxed(NoFinalize(keypair))) } +fn crypto_format_keypair(mut cx: FunctionContext) -> JsResult { + let keypair = cx.argument + ::(0)? + .unbox(); + + let object = cx.empty_object(); + + let formatted_key = cx.string(format!("{}", keypair.value.key)); + object.set(&mut cx, "key", formatted_key)?; + + let formatted_secret = cx.string(format!("{}", keypair.value.secret)); + object.set(&mut cx, "secret", formatted_secret)?; + + Ok(object) +} + #[derive(Debug)] struct LibraryCore { api: VeilidAPI @@ -102,7 +120,11 @@ struct LibraryCore { impl Finalize for LibraryCore { fn finalize<'a, C: Context<'a>>(self, _: &mut C) { - // FIXME + println!("Calling finalize!"); + let runtime = make_runtime().unwrap(); // FIXME: Find better alternative to unwrapping here + + let _guard = runtime.enter(); + let _ignored_future = self.api.shutdown(); // FIXME: Probably shouldn't ignore this...? } } @@ -115,11 +137,13 @@ impl LibraryCore { ::(0)? .root(&mut cx); // To allow sending to a different thread + let update_callback_arc = Arc::new(update_callback); + let json_config = cx.argument ::(1)? .value(&mut cx); - let runtime = make_runtime(&mut cx)?; + let runtime = make_runtime_js(&mut cx)?; let (deferred, promise) = cx.promise(); let startup_channel = cx.channel(); let (update_sender, update_receiver) = flume::unbounded(); @@ -138,6 +162,7 @@ impl LibraryCore { let core_result = async { let api = api_startup_json(update_handler, json_config).await?; + api.attach().await?; let core = LibraryCore { api: api }; Ok(core) }.await; @@ -164,18 +189,22 @@ impl LibraryCore { let _calling_task = runtime.spawn(async move { loop { - let update = update_receiver.recv_async().await; - let update_callback = update_callback.clone(&mut cx); + let update = update_receiver.recv_async().await.unwrap(); // FIXME: Not just unwrap + let update_callback_arc = update_callback_arc.clone(); + + let serialized_update = serde_json::to_string_pretty(&update).unwrap(); + + // The caller should ensure Root::into_inner or Root::drop is called to properly dispose of the Root. If the value is dropped without calling one of these methods: update_channel.send(move |mut cx| { - update_callback - .into_inner(&mut cx) // Unpack original callback + update_callback_arc + .to_inner(&mut cx) // Unpack original callback .call_with(&mut cx) - .arg(cx.string(format!("{:?}", update))) - .apply::(&mut cx); + .arg(cx.string(serialized_update)) + .apply::(&mut cx)?; Ok(()) - }).join(); // FIXME: This will probably block? + }).join().unwrap(); // FIXME: This will probably block? Also probably shouldn't unwrap here } }); @@ -203,7 +232,18 @@ impl LibraryCore { #[neon::main] fn main(mut cx: ModuleContext) -> NeonResult<()> { + // TODO: Make logging optional + let default_env_filter = EnvFilter::try_from_default_env(); + let fallback_filter = EnvFilter::new("veilid_core=warn,info,debug"); + let env_filter = default_env_filter.unwrap_or(fallback_filter); + + tracing_subscriber::fmt() + .with_writer(std::io::stderr) + .with_env_filter(env_filter) + .init(); + cx.export_function("makePath", make_path)?; + cx.export_function("crypto_formatKeypair", crypto_format_keypair)?; cx.export_function("crypto_generateKeypair", crypto_generate_keypair)?; cx.export_function("libraryCore_fromJSON", LibraryCore::from_json)?; diff --git a/test.js b/test.js index 2f09981..d81ccd5 100644 --- a/test.js +++ b/test.js @@ -1,12 +1,169 @@ "use strict"; const veilid = require("./"); +const tmp = require("tmp-promise"); + +// let configJSON = JSON.stringify({ +// program_name: "node-veilid-test", +// namespace: "", +// capabilities: { +// disable: [] +// }, +// core: { +// protected_store: { +// directory: "/tmp/node-veilid-test" +// } +// } +// }); + +let keypair = veilid.crypto_generateKeypair(veilid.CRYPTO_KIND_VLD0); +let formatted = veilid.crypto_formatKeypair(keypair); +console.log({formatted}); (async()=>{ + let basePath = (await tmp.dir({ unsafeCleanup: true })).path; // let path = veilid.makePath("/tmp/test"); // let keypair = veilid.crypto_generateKeypair(veilid.CRYPTO_KIND_VLD0); - let core = veilid.libraryCore_fromJSON(); - console.log("core", core); - console.log("test", core.test()); - console.log("test2", core.test2()); + var configJSON = JSON.stringify({ + "program_name": "node-veilid-test", + "namespace": "", + "capabilities": { + "disable": [] + }, + "protected_store": { + "allow_insecure_fallback": true, + "always_use_insecure_storage": true, + "directory": `${basePath}/protected_store`, + "delete": false, + "device_encryption_key_password": "", + "new_device_encryption_key_password": null + }, + "table_store": { + "directory": `${basePath}/table_store`, + "delete": false + }, + "block_store": { + "directory": `${basePath}/block_store`, + "delete": false + }, + "network": { + "connection_initial_timeout_ms": 2000, + "connection_inactivity_timeout_ms": 60000, + "max_connections_per_ip4": 32, + "max_connections_per_ip6_prefix": 32, + "max_connections_per_ip6_prefix_size": 56, + "max_connection_frequency_per_min": 128, + "client_whitelist_timeout_ms": 300000, + "reverse_connection_receipt_time_ms": 5000, + "hole_punch_receipt_time_ms": 5000, + "network_key_password": null, + "routing_table": { + "node_id": [ formatted.key ], + "node_id_secret": [ formatted.secret ], + "bootstrap": [ + "bootstrap.veilid.net" + ], + "limit_over_attached": 64, + "limit_fully_attached": 32, + "limit_attached_strong": 16, + "limit_attached_good": 8, + "limit_attached_weak": 4 + }, + "rpc": { + "concurrency": 0, + "queue_size": 1024, + "max_timestamp_behind_ms": 10000, + "max_timestamp_ahead_ms": 10000, + "timeout_ms": 5000, + "max_route_hop_count": 4, + "default_route_hop_count": 1 + }, + "dht": { + "max_find_node_count": 20, + "resolve_node_timeout_ms": 10000, + "resolve_node_count": 1, + "resolve_node_fanout": 4, + "get_value_timeout_ms": 10000, + "get_value_count": 3, + "get_value_fanout": 4, + "set_value_timeout_ms": 10000, + "set_value_count": 5, + "set_value_fanout": 4, + "min_peer_count": 20, + "min_peer_refresh_time_ms": 60000, + "validate_dial_info_receipt_time_ms": 2000, + "local_subkey_cache_size": 128, + "local_max_subkey_cache_memory_mb": 256, + "remote_subkey_cache_size": 1024, + "remote_max_records": 65536, + "remote_max_subkey_cache_memory_mb": 478, + "remote_max_storage_space_mb": 1000 + }, + "upnp": true, + "detect_address_changes": true, + "restricted_nat_retries": 0, + "tls": { + "certificate_path": `${basePath}/ssl/certs/server.crt`, + "private_key_path": `${basePath}/ssl/keys/server.key`, + "connection_initial_timeout_ms": 2000 + }, + "application": { + "https": { + "enabled": false, + "listen_address": ":443", + "path": "app", + "url": null + }, + "http": { + "enabled": false, + "listen_address": ":80", + "path": "app", + "url": null + } + }, + "protocol": { + "udp": { + "enabled": true, + "socket_pool_size": 0, + "listen_address": "", + "public_address": null + }, + "tcp": { + "connect": true, + "listen": true, + "max_connections": 32, + "listen_address": "", + "public_address": null + }, + "ws": { + "connect": true, + "listen": true, + "max_connections": 32, + "listen_address": "", + "path": "ws", + "url": null + }, + "wss": { + "connect": true, + "listen": false, + "max_connections": 32, + "listen_address": "", + "path": "ws", + "url": null + } + } + } + }, null, 2); + + console.log({configJSON}); + + let core = await veilid.libraryCore_fromJSON((update) => { + console.log("update::", update); + }, configJSON); + + setInterval(() => { + console.log("keepalive", core); + }, 10000); + + console.log({core}); })(); diff --git a/yarn.lock b/yarn.lock index b00b073..9c5a256 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,7 +2,100 @@ # yarn lockfile v1 +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + cargo-cp-artifact@^0.1: version "0.1.8" resolved "https://registry.yarnpkg.com/cargo-cp-artifact/-/cargo-cp-artifact-0.1.8.tgz#353814f49f6aa76601a4bcb3ea5f3071180b90de" integrity sha512-3j4DaoTrsCD1MRkTF2Soacii0Nx7UHCce0EwUf4fHnggwiE4fbmF2AbnfzayR36DF8KGadfh7M/Yfy625kgPlA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +rimraf@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +tmp-promise@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/tmp-promise/-/tmp-promise-3.0.3.tgz#60a1a1cc98c988674fcbfd23b6e3367bdeac4ce7" + integrity sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ== + dependencies: + tmp "^0.2.0" + +tmp@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==