use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
use std::time::Duration;
use deno_core::{located_script_name, serde_json, JsRuntime, ModuleSpecifier, RuntimeOptions};
use deno_web::BlobStore;
use crate::module_loader::ZinniaModuleLoader;
use crate::{colors, Reporter};
use crate::ext::ZinniaPermissions;
use zinnia_libp2p;
pub type AnyError = deno_core::anyhow::Error;
use deno_core::anyhow::Result;
#[derive(Clone)]
pub struct BootstrapOptions {
pub no_color: bool,
pub is_tty: bool,
pub agent_version: String,
pub rng_seed: Option<u64>,
pub module_root: Option<PathBuf>,
pub wallet_address: String,
pub station_id: String,
pub reporter: Rc<dyn Reporter>,
pub lassie_daemon: Arc<lassie::Daemon>,
pub zinnia_version: &'static str,
}
impl BootstrapOptions {
pub fn new(
agent_version: String,
reporter: Rc<dyn Reporter>,
lassie_daemon: Arc<lassie::Daemon>,
module_root: Option<PathBuf>,
) -> Self {
Self {
no_color: !colors::use_color(),
is_tty: colors::is_tty(),
agent_version,
rng_seed: None,
module_root,
wallet_address: String::from("t1abjxfbp274xpdqcpuaykwkfb43omjotacm2p3za"),
station_id: String::from("zinnia-dev"),
reporter,
lassie_daemon,
zinnia_version: env!("CARGO_PKG_VERSION"),
}
}
pub fn as_json(&self) -> String {
let payload = serde_json::json!({
"noColor": self.no_color,
"isTty": self.is_tty,
"walletAddress": self.wallet_address,
"stationId": self.station_id,
"lassieUrl": format!("http://127.0.0.1:{}/", self.lassie_daemon.port()),
"lassieAuth": match self.lassie_daemon.access_token() {
Some(token) => serde_json::Value::String(format!("Bearer {token}")),
None => serde_json::Value::Null,
},
"zinniaVersion": self.zinnia_version,
"v8Version": deno_core::v8_version(),
});
serde_json::to_string_pretty(&payload).unwrap()
}
}
pub async fn run_js_module(
module_specifier: &ModuleSpecifier,
bootstrap_options: &BootstrapOptions,
) -> Result<(), AnyError> {
let blob_store = Arc::new(BlobStore::default());
let reporter = Rc::clone(&bootstrap_options.reporter);
let mut runtime = JsRuntime::new(RuntimeOptions {
extensions: vec![
deno_console::deno_console::init_ops_and_esm(),
deno_webidl::deno_webidl::init_ops_and_esm(),
deno_url::deno_url::init_ops_and_esm(),
deno_web::deno_web::init_ops_and_esm::<ZinniaPermissions>(
blob_store,
Some(module_specifier.clone()),
),
deno_fetch::deno_fetch::init_ops_and_esm::<ZinniaPermissions>(deno_fetch::Options {
user_agent: bootstrap_options.agent_version.clone(),
..Default::default()
}),
deno_crypto::deno_crypto::init_ops_and_esm(bootstrap_options.rng_seed),
zinnia_libp2p::zinnia_libp2p::init_ops_and_esm(zinnia_libp2p::PeerNodeConfig {
agent_version: bootstrap_options.agent_version.clone(),
..Default::default()
}),
crate::ext::zinnia_runtime::init_ops_and_esm(reporter),
],
inspector: false,
module_loader: Some(Rc::new(ZinniaModuleLoader::build(
bootstrap_options.module_root.clone(),
)?)),
..Default::default()
});
let script = format!("bootstrap.mainRuntime({})", bootstrap_options.as_json());
runtime.execute_script(located_script_name!(), script.into())?;
let main_module_id = runtime.load_main_module(module_specifier, None).await?;
let res = runtime.mod_evaluate(main_module_id);
runtime.run_event_loop(false).await?;
res.await??;
zinnia_libp2p::shutdown(runtime.op_state()).await?;
Ok(())
}
use deno_crypto::rand::{self, distributions::Alphanumeric, Rng};
const ONE_DAY: Duration = Duration::from_secs(24 * 3600);
pub fn lassie_config() -> lassie::DaemonConfig {
let access_token = rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(24)
.map(char::from)
.collect();
lassie::DaemonConfig {
port: 0,
access_token: Some(access_token),
provider_timeout: Some(ONE_DAY),
global_timeout: Some(ONE_DAY),
..Default::default()
}
}