#![allow(unused)]
use std::{
env::current_dir,
path::{Path, PathBuf},
str::FromStr,
};
use anyhow::{Context, Error};
use enumset::EnumSet;
use parking_lot::Mutex;
use swc_common::{
collections::AHashMap,
sync::{Lazy, OnceCell},
};
#[cfg(not(target_arch = "wasm32"))]
use wasmer::{BaseTunables, CpuFeature, Engine, Target, Triple};
use wasmer::{Module, Store};
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
use wasmer_cache::{Cache as WasmerCache, FileSystemCache, Hash};
use crate::plugin_module_bytes::{
CompiledPluginModuleBytes, PluginModuleBytes, RawPluginModuleBytes,
};
const MODULE_SERIALIZATION_VERSION: &str = "v6";
#[derive(Default)]
pub struct PluginModuleCacheInner {
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
fs_cache_root: Option<String>,
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
fs_cache_store: Option<FileSystemCache>,
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
fs_cache_hash_store: AHashMap<String, Hash>,
memory_cache_store: AHashMap<String, Vec<u8>>,
compiled_module_bytes: AHashMap<String, (wasmer::Store, wasmer::Module)>,
}
impl PluginModuleCacheInner {
pub fn get_fs_cache_root(&self) -> Option<String> {
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
return self.fs_cache_root.clone();
None
}
pub fn contains(&self, key: &str) -> bool {
let is_in_cache = self.memory_cache_store.contains_key(key)
|| self.compiled_module_bytes.contains_key(key);
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
{
return is_in_cache || self.fs_cache_hash_store.contains_key(key);
}
is_in_cache
}
pub fn insert_raw_bytes(&mut self, key: String, value: Vec<u8>) {
self.memory_cache_store.insert(key, value);
}
pub fn insert_compiled_module_bytes(
&mut self,
key: String,
value: (wasmer::Store, wasmer::Module),
) {
self.compiled_module_bytes.insert(key, value);
}
pub fn store_bytes_from_path(&mut self, binary_path: &Path, key: &str) -> Result<(), Error> {
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
{
let raw_module_bytes =
std::fs::read(binary_path).context("Cannot read plugin from specified path")?;
if let Some(fs_cache_store) = &mut self.fs_cache_store {
let module_bytes_hash = Hash::generate(&raw_module_bytes);
let store = crate::plugin_module_bytes::new_store();
let module = Module::new(&store, raw_module_bytes.clone())
.context("Cannot compile plugin binary")?;
fs_cache_store.store(module_bytes_hash, &module)?;
self.fs_cache_hash_store
.insert(key.to_string(), module_bytes_hash);
self.insert_compiled_module_bytes(key.to_string(), (store, module));
}
self.insert_raw_bytes(key.to_string(), raw_module_bytes);
return Ok(());
}
anyhow::bail!("Filesystem cache is not enabled, cannot read plugin from phsyical path");
}
pub fn get(&self, key: &str) -> Option<Box<dyn PluginModuleBytes>> {
if let Some(compiled_module) = self.compiled_module_bytes.get(key) {
return Some(Box::new(CompiledPluginModuleBytes::new(
key.to_string(),
compiled_module.1.clone(),
Store::new(compiled_module.0.engine().clone()),
)));
}
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
if let Some(fs_cache_store) = &self.fs_cache_store {
let hash = self.fs_cache_hash_store.get(key)?;
let store = crate::plugin_module_bytes::new_store();
let module = unsafe { fs_cache_store.load(&store, *hash) };
if let Ok(module) = module {
return Some(Box::new(CompiledPluginModuleBytes::new(
key.to_string(),
module,
store,
)));
}
}
if let Some(memory_cache_bytes) = self.memory_cache_store.get(key) {
return Some(Box::new(RawPluginModuleBytes::new(
key.to_string(),
memory_cache_bytes.clone(),
)));
}
None
}
}
#[derive(Default)]
pub struct PluginModuleCache {
pub inner: OnceCell<Mutex<PluginModuleCacheInner>>,
instantiation_lock: Mutex<()>,
}
impl PluginModuleCache {
pub fn create_inner(
enable_fs_cache_store: bool,
fs_cache_store_root: &Option<String>,
) -> PluginModuleCacheInner {
PluginModuleCacheInner {
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
fs_cache_root: fs_cache_store_root.clone(),
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
fs_cache_store: if enable_fs_cache_store {
create_filesystem_cache(fs_cache_store_root)
} else {
None
},
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
fs_cache_hash_store: Default::default(),
memory_cache_store: Default::default(),
compiled_module_bytes: Default::default(),
}
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
#[tracing::instrument(level = "info", skip_all)]
fn create_filesystem_cache(filesystem_cache_root: &Option<String>) -> Option<FileSystemCache> {
let mut root_path = if let Some(root) = filesystem_cache_root {
Some(PathBuf::from(root))
} else if let Ok(cwd) = current_dir() {
Some(cwd.join(".swc"))
} else {
None
};
if let Some(root_path) = &mut root_path {
root_path.push("plugins");
root_path.push(format!(
"{}_{}_{}_{}",
MODULE_SERIALIZATION_VERSION,
std::env::consts::OS,
std::env::consts::ARCH,
option_env!("CARGO_PKG_VERSION").unwrap_or("plugin_runner_unknown")
));
return FileSystemCache::new(&root_path).ok();
}
None
}