mirror of
https://github.com/zellij-org/zellij.git
synced 2024-11-22 04:33:22 +03:00
dependencies: switch from Wasmer to Wasmtime (#3349)
* Remove ForeignFunctionEnv wrapper around PluginEnv This will enable PluginEnv to be the Store context when migrating to Wasmtime. * Pass PluginEnv by value to load_plugin_instance This will allow removing the Clone impl from PluginEnv when migrating to Wasmtime as required by the missing Clone impl on Wasmtime's WasiCtx. * Avoid passing a Store around when an Engine is enough * Pass PluginEnv to the wasi read/write functions Wasmtime requires storing the read/write end of the pipe outside of the WasiCtx. Passing PluginEnv to these functions allows storing them in the PluginEnv. * Migrate to Wasmtime * Switch from wasi-common to wasmtime-wasi * Reduce verbosity of wasmtime_wasi logs * Increase startup delay To wait for all plugins to be compiled. * Disable some wasmtime features * Update to Wasmtime 21.0.1
This commit is contained in:
parent
fa110515aa
commit
7d7848cddc
@ -92,7 +92,7 @@ Note that the output is truncated at 100KB. This can be adjusted for the purpose
|
|||||||
When running Zellij with the `--debug` flag, Zellij will dump a copy of all bytes received over the pty for each pane in: `/$temp_dir/zellij-<UID>/zellij-log/zellij-<pane_id>.log`. These might be useful when troubleshooting terminal issues.
|
When running Zellij with the `--debug` flag, Zellij will dump a copy of all bytes received over the pty for each pane in: `/$temp_dir/zellij-<UID>/zellij-log/zellij-<pane_id>.log`. These might be useful when troubleshooting terminal issues.
|
||||||
|
|
||||||
## Testing plugins
|
## Testing plugins
|
||||||
Zellij allows the use of the [Singlepass](https://crates.io/crates/wasmer-compiler-singlepass) compiler for wasmer. This can enable great gains in compilation time of plugins in detriment of stability, notably on Arm64 architectures.
|
Zellij allows the use of the singlepass [Winch](https://crates.io/crates/wasmtime-winch) compiler for wasmtime. This can enable great gains in compilation time of plugins at the cost of slower execution and less supported architectures.
|
||||||
|
|
||||||
To enable the singlepass compiler, use the `singlepass` flag. E.g.:
|
To enable the singlepass compiler, use the `singlepass` flag. E.g.:
|
||||||
```sh
|
```sh
|
||||||
@ -113,7 +113,7 @@ If you are new contributor to `Zellij` going through
|
|||||||
[Discord server][discord-invite-link], we would be happy to help finding
|
[Discord server][discord-invite-link], we would be happy to help finding
|
||||||
something interesting to work on and guide through.
|
something interesting to work on and guide through.
|
||||||
|
|
||||||
[discord-invite-link]: https://discord.gg/feHDHahHCz
|
[discord-invite-link]: https://discord.gg/feHDHahHCz
|
||||||
[good-first-issue]: https://github.com/zellij-org/zellij/labels/good%20first%20issue
|
[good-first-issue]: https://github.com/zellij-org/zellij/labels/good%20first%20issue
|
||||||
|
|
||||||
|
|
||||||
|
1843
Cargo.lock
generated
1843
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -84,7 +84,7 @@ fn start_zellij(channel: &mut ssh2::Channel) {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
channel.flush().unwrap();
|
channel.flush().unwrap();
|
||||||
std::thread::sleep(std::time::Duration::from_secs(1)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
std::thread::sleep(std::time::Duration::from_secs(3)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_zellij_mirrored_session(channel: &mut ssh2::Channel) {
|
fn start_zellij_mirrored_session(channel: &mut ssh2::Channel) {
|
||||||
@ -99,7 +99,7 @@ fn start_zellij_mirrored_session(channel: &mut ssh2::Channel) {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
channel.flush().unwrap();
|
channel.flush().unwrap();
|
||||||
std::thread::sleep(std::time::Duration::from_secs(1)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
std::thread::sleep(std::time::Duration::from_secs(3)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_zellij_mirrored_session_with_layout(channel: &mut ssh2::Channel, layout_file_name: &str) {
|
fn start_zellij_mirrored_session_with_layout(channel: &mut ssh2::Channel, layout_file_name: &str) {
|
||||||
@ -118,7 +118,7 @@ fn start_zellij_mirrored_session_with_layout(channel: &mut ssh2::Channel, layout
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
channel.flush().unwrap();
|
channel.flush().unwrap();
|
||||||
std::thread::sleep(std::time::Duration::from_secs(1)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
std::thread::sleep(std::time::Duration::from_secs(3)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_zellij_mirrored_session_with_layout_and_viewport_serialization(
|
fn start_zellij_mirrored_session_with_layout_and_viewport_serialization(
|
||||||
@ -140,7 +140,7 @@ fn start_zellij_mirrored_session_with_layout_and_viewport_serialization(
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
channel.flush().unwrap();
|
channel.flush().unwrap();
|
||||||
std::thread::sleep(std::time::Duration::from_secs(1)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
std::thread::sleep(std::time::Duration::from_secs(3)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_zellij_in_session(channel: &mut ssh2::Channel, session_name: &str, mirrored: bool) {
|
fn start_zellij_in_session(channel: &mut ssh2::Channel, session_name: &str, mirrored: bool) {
|
||||||
@ -159,7 +159,7 @@ fn start_zellij_in_session(channel: &mut ssh2::Channel, session_name: &str, mirr
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
channel.flush().unwrap();
|
channel.flush().unwrap();
|
||||||
std::thread::sleep(std::time::Duration::from_secs(1)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
std::thread::sleep(std::time::Duration::from_secs(3)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
||||||
}
|
}
|
||||||
|
|
||||||
fn attach_to_existing_session(channel: &mut ssh2::Channel, session_name: &str) {
|
fn attach_to_existing_session(channel: &mut ssh2::Channel, session_name: &str) {
|
||||||
@ -173,7 +173,7 @@ fn attach_to_existing_session(channel: &mut ssh2::Channel, session_name: &str) {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
channel.flush().unwrap();
|
channel.flush().unwrap();
|
||||||
std::thread::sleep(std::time::Duration::from_secs(1)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
std::thread::sleep(std::time::Duration::from_secs(3)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_zellij_without_frames(channel: &mut ssh2::Channel) {
|
fn start_zellij_without_frames(channel: &mut ssh2::Channel) {
|
||||||
@ -188,7 +188,7 @@ fn start_zellij_without_frames(channel: &mut ssh2::Channel) {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
channel.flush().unwrap();
|
channel.flush().unwrap();
|
||||||
std::thread::sleep(std::time::Duration::from_secs(1)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
std::thread::sleep(std::time::Duration::from_secs(3)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_zellij_with_config(channel: &mut ssh2::Channel, config_path: &str) {
|
fn start_zellij_with_config(channel: &mut ssh2::Channel, config_path: &str) {
|
||||||
@ -207,7 +207,7 @@ fn start_zellij_with_config(channel: &mut ssh2::Channel, config_path: &str) {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
channel.flush().unwrap();
|
channel.flush().unwrap();
|
||||||
std::thread::sleep(std::time::Duration::from_secs(1)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
std::thread::sleep(std::time::Duration::from_secs(3)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_from_channel(
|
fn read_from_channel(
|
||||||
|
@ -14,12 +14,12 @@ ansi_term = "0.12.1"
|
|||||||
async-trait = "0.1.50"
|
async-trait = "0.1.50"
|
||||||
base64 = "0.13.0"
|
base64 = "0.13.0"
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
|
bytes = "1.6.0"
|
||||||
daemonize = "0.5"
|
daemonize = "0.5"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
unicode-width = "0.1.8"
|
unicode-width = "0.1.8"
|
||||||
url = "2.2.2"
|
url = "2.2.2"
|
||||||
wasmer = "3.1.1"
|
wasmtime-wasi = "21.0.1" # Keep in sync with wasmtime
|
||||||
wasmer-wasi = "3.1.1"
|
|
||||||
cassowary = "0.3.0"
|
cassowary = "0.3.0"
|
||||||
zellij-utils = { path = "../zellij-utils/", version = "0.41.0" }
|
zellij-utils = { path = "../zellij-utils/", version = "0.41.0" }
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
@ -33,10 +33,26 @@ arrayvec = "0.7.2"
|
|||||||
uuid = { version = "1.4.1", features = ["serde", "v4"] }
|
uuid = { version = "1.4.1", features = ["serde", "v4"] }
|
||||||
semver = "0.11.0"
|
semver = "0.11.0"
|
||||||
|
|
||||||
|
[dependencies.wasmtime]
|
||||||
|
version = "21.0.1" # Keep in sync with wasmtime-wasi
|
||||||
|
default-features = false
|
||||||
|
features = [
|
||||||
|
'async',
|
||||||
|
'cache',
|
||||||
|
'parallel-compilation',
|
||||||
|
'cranelift',
|
||||||
|
'demangle',
|
||||||
|
'addr2line',
|
||||||
|
'debug-builtins',
|
||||||
|
'runtime',
|
||||||
|
'component-model',
|
||||||
|
'std',
|
||||||
|
]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
insta = "1.6.0"
|
insta = "1.6.0"
|
||||||
tempfile = "3.2.0"
|
tempfile = "3.2.0"
|
||||||
wasmer = { version = "3.1.1", features = ["singlepass"] }
|
wasmtime = { version = "21.0.1", features = ["winch"] } # Keep in sync with the other wasmtime dep
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
singlepass = ["wasmer/singlepass"]
|
singlepass = ["wasmtime/winch"]
|
||||||
|
@ -28,7 +28,7 @@ use zellij_utils::envs;
|
|||||||
use zellij_utils::nix::sys::stat::{umask, Mode};
|
use zellij_utils::nix::sys::stat::{umask, Mode};
|
||||||
use zellij_utils::pane_size::Size;
|
use zellij_utils::pane_size::Size;
|
||||||
|
|
||||||
use wasmer::Store;
|
use wasmtime::{Config, Engine, Strategy};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
os_input_output::ServerOsApi,
|
os_input_output::ServerOsApi,
|
||||||
@ -1069,7 +1069,7 @@ fn init_session(
|
|||||||
Some(&to_background_jobs),
|
Some(&to_background_jobs),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
let store = get_store();
|
let engine = get_engine();
|
||||||
|
|
||||||
let layout = layout.clone();
|
let layout = layout.clone();
|
||||||
let client_attributes = client_attributes.clone();
|
let client_attributes = client_attributes.clone();
|
||||||
@ -1079,7 +1079,7 @@ fn init_session(
|
|||||||
move || {
|
move || {
|
||||||
plugin_thread_main(
|
plugin_thread_main(
|
||||||
plugin_bus,
|
plugin_bus,
|
||||||
store,
|
engine,
|
||||||
data_dir,
|
data_dir,
|
||||||
layout,
|
layout,
|
||||||
layout_dir,
|
layout_dir,
|
||||||
@ -1162,22 +1162,13 @@ fn init_session(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "singlepass"))]
|
#[cfg(not(feature = "singlepass"))]
|
||||||
fn get_store() -> Store {
|
fn get_engine() -> Engine {
|
||||||
use wasmer::{BaseTunables, Cranelift, Engine, Pages, Target};
|
|
||||||
log::info!("Compiling plugins using Cranelift");
|
log::info!("Compiling plugins using Cranelift");
|
||||||
|
Engine::new(Config::new().strategy(Strategy::Cranelift)).unwrap()
|
||||||
// workaround for https://github.com/bytecodealliance/wasmtime/security/advisories/GHSA-ff4p-7xrq-q5r8
|
|
||||||
let mut tunables = BaseTunables::for_target(&Target::default());
|
|
||||||
tunables.static_memory_bound = Pages(0);
|
|
||||||
let compiler = Cranelift::default();
|
|
||||||
let mut engine: Engine = compiler.into();
|
|
||||||
engine.set_tunables(tunables);
|
|
||||||
|
|
||||||
Store::new(engine)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "singlepass")]
|
#[cfg(feature = "singlepass")]
|
||||||
fn get_store() -> Store {
|
fn get_engine() -> Engine {
|
||||||
log::info!("Compiling plugins using Singlepass");
|
log::info!("Compiling plugins using Singlepass");
|
||||||
Store::new(wasmer::Singlepass::default())
|
Engine::new(Config::new().strategy(Strategy::Winch)).unwrap()
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
use std::{
|
use std::{collections::VecDeque, io::Write};
|
||||||
collections::VecDeque,
|
|
||||||
io::{Read, Seek, Write},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::plugins::PluginId;
|
use crate::plugins::PluginId;
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
use wasmer_wasi::{WasiFile, WasiFsError};
|
|
||||||
use zellij_utils::{errors::prelude::*, serde};
|
use zellij_utils::{errors::prelude::*, serde};
|
||||||
|
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
@ -41,15 +37,6 @@ impl LoggingPipe {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Read for LoggingPipe {
|
|
||||||
fn read(&mut self, _: &mut [u8]) -> std::io::Result<usize> {
|
|
||||||
Err(std::io::Error::new(
|
|
||||||
std::io::ErrorKind::Other,
|
|
||||||
"Can not reed from a LoggingPipe",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Write for LoggingPipe {
|
impl Write for LoggingPipe {
|
||||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
if self.buffer.len() + buf.len() > ZELLIJ_MAX_PIPE_BUFFER_SIZE {
|
if self.buffer.len() + buf.len() > ZELLIJ_MAX_PIPE_BUFFER_SIZE {
|
||||||
@ -106,40 +93,6 @@ impl Write for LoggingPipe {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Seek for LoggingPipe {
|
|
||||||
fn seek(&mut self, _pos: std::io::SeekFrom) -> std::io::Result<u64> {
|
|
||||||
Err(std::io::Error::new(
|
|
||||||
std::io::ErrorKind::Other,
|
|
||||||
"can not seek in a pipe",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WasiFile for LoggingPipe {
|
|
||||||
fn last_accessed(&self) -> u64 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
fn last_modified(&self) -> u64 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
fn created_time(&self) -> u64 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
fn size(&self) -> u64 {
|
|
||||||
self.buffer.len() as u64
|
|
||||||
}
|
|
||||||
fn set_len(&mut self, len: u64) -> Result<(), WasiFsError> {
|
|
||||||
self.buffer.resize(len as usize, 0);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn unlink(&mut self) -> Result<(), WasiFsError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn bytes_available(&self) -> Result<usize, WasiFsError> {
|
|
||||||
Ok(self.buffer.len())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unit tests
|
// Unit tests
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod logging_pipe_test {
|
mod logging_pipe_test {
|
||||||
|
@ -10,10 +10,9 @@ use std::{
|
|||||||
collections::{BTreeMap, HashMap, HashSet},
|
collections::{BTreeMap, HashMap, HashSet},
|
||||||
fs,
|
fs,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{Arc, Mutex},
|
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
use wasmer::Store;
|
use wasmtime::Engine;
|
||||||
|
|
||||||
use crate::panes::PaneId;
|
use crate::panes::PaneId;
|
||||||
use crate::screen::ScreenInstruction;
|
use crate::screen::ScreenInstruction;
|
||||||
@ -189,7 +188,7 @@ impl From<&PluginInstruction> for PluginContext {
|
|||||||
|
|
||||||
pub(crate) fn plugin_thread_main(
|
pub(crate) fn plugin_thread_main(
|
||||||
bus: Bus<PluginInstruction>,
|
bus: Bus<PluginInstruction>,
|
||||||
store: Store,
|
engine: Engine,
|
||||||
data_dir: PathBuf,
|
data_dir: PathBuf,
|
||||||
mut layout: Box<Layout>,
|
mut layout: Box<Layout>,
|
||||||
layout_dir: Option<PathBuf>,
|
layout_dir: Option<PathBuf>,
|
||||||
@ -204,7 +203,6 @@ pub(crate) fn plugin_thread_main(
|
|||||||
let plugin_dir = data_dir.join("plugins/");
|
let plugin_dir = data_dir.join("plugins/");
|
||||||
let plugin_global_data_dir = plugin_dir.join("data");
|
let plugin_global_data_dir = plugin_dir.join("data");
|
||||||
layout.populate_plugin_aliases_in_layout(&plugin_aliases);
|
layout.populate_plugin_aliases_in_layout(&plugin_aliases);
|
||||||
let store = Arc::new(Mutex::new(store));
|
|
||||||
|
|
||||||
// use this channel to ensure that tasks spawned from this thread terminate before exiting
|
// use this channel to ensure that tasks spawned from this thread terminate before exiting
|
||||||
// https://tokio.rs/tokio/topics/shutdown#waiting-for-things-to-finish-shutting-down
|
// https://tokio.rs/tokio/topics/shutdown#waiting-for-things-to-finish-shutting-down
|
||||||
@ -212,7 +210,7 @@ pub(crate) fn plugin_thread_main(
|
|||||||
|
|
||||||
let mut wasm_bridge = WasmBridge::new(
|
let mut wasm_bridge = WasmBridge::new(
|
||||||
bus.senders.clone(),
|
bus.senders.clone(),
|
||||||
store,
|
engine,
|
||||||
plugin_dir,
|
plugin_dir,
|
||||||
path_to_default_shell,
|
path_to_default_shell,
|
||||||
zellij_cwd,
|
zellij_cwd,
|
||||||
|
@ -3,7 +3,6 @@ use crate::plugins::plugin_map::RunningPlugin;
|
|||||||
use crate::plugins::wasm_bridge::PluginRenderAsset;
|
use crate::plugins::wasm_bridge::PluginRenderAsset;
|
||||||
use crate::plugins::zellij_exports::{wasi_read_string, wasi_write_object};
|
use crate::plugins::zellij_exports::{wasi_read_string, wasi_write_object};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use wasmer::Value;
|
|
||||||
use zellij_utils::data::{PipeMessage, PipeSource};
|
use zellij_utils::data::{PipeMessage, PipeSource};
|
||||||
use zellij_utils::plugin_api::pipe_message::ProtobufPipeMessage;
|
use zellij_utils::plugin_api::pipe_message::ProtobufPipeMessage;
|
||||||
|
|
||||||
@ -147,7 +146,6 @@ pub fn apply_pipe_message_to_plugin(
|
|||||||
senders: &ThreadSenders,
|
senders: &ThreadSenders,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let instance = &running_plugin.instance;
|
let instance = &running_plugin.instance;
|
||||||
let plugin_env = &running_plugin.plugin_env;
|
|
||||||
let rows = running_plugin.rows;
|
let rows = running_plugin.rows;
|
||||||
let columns = running_plugin.columns;
|
let columns = running_plugin.columns;
|
||||||
|
|
||||||
@ -156,31 +154,24 @@ pub fn apply_pipe_message_to_plugin(
|
|||||||
.clone()
|
.clone()
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|e| anyhow!("Failed to convert to protobuf: {:?}", e))?;
|
.map_err(|e| anyhow!("Failed to convert to protobuf: {:?}", e))?;
|
||||||
match instance.exports.get_function("pipe") {
|
match instance.get_typed_func::<(), i32>(&mut running_plugin.store, "pipe") {
|
||||||
Ok(pipe) => {
|
Ok(pipe) => {
|
||||||
wasi_write_object(&plugin_env.wasi_env, &protobuf_pipe_message.encode_to_vec())
|
wasi_write_object(
|
||||||
|
running_plugin.store.data(),
|
||||||
|
&protobuf_pipe_message.encode_to_vec(),
|
||||||
|
)
|
||||||
|
.with_context(err_context)?;
|
||||||
|
let should_render = pipe
|
||||||
|
.call(&mut running_plugin.store, ())
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
let pipe_return = pipe
|
let should_render = should_render == 1;
|
||||||
.call(&mut running_plugin.store, &[])
|
|
||||||
.with_context(err_context)?;
|
|
||||||
let should_render = match pipe_return.get(0) {
|
|
||||||
Some(Value::I32(n)) => *n == 1,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
if rows > 0 && columns > 0 && should_render {
|
if rows > 0 && columns > 0 && should_render {
|
||||||
let rendered_bytes = instance
|
let rendered_bytes = instance
|
||||||
.exports
|
.get_typed_func::<(i32, i32), ()>(&mut running_plugin.store, "render")
|
||||||
.get_function("render")
|
|
||||||
.map_err(anyError::new)
|
|
||||||
.and_then(|render| {
|
.and_then(|render| {
|
||||||
render
|
render.call(&mut running_plugin.store, (rows as i32, columns as i32))
|
||||||
.call(
|
|
||||||
&mut running_plugin.store,
|
|
||||||
&[Value::I32(rows as i32), Value::I32(columns as i32)],
|
|
||||||
)
|
|
||||||
.map_err(anyError::new)
|
|
||||||
})
|
})
|
||||||
.and_then(|_| wasi_read_string(&plugin_env.wasi_env))
|
.and_then(|_| wasi_read_string(running_plugin.store.data()))
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
let pipes_to_block_or_unblock =
|
let pipes_to_block_or_unblock =
|
||||||
pipes_to_block_or_unblock(running_plugin, Some(&pipe_message.source));
|
pipes_to_block_or_unblock(running_plugin, Some(&pipe_message.source));
|
||||||
@ -230,14 +221,16 @@ pub fn pipes_to_block_or_unblock(
|
|||||||
) -> HashMap<String, PipeStateChange> {
|
) -> HashMap<String, PipeStateChange> {
|
||||||
let mut pipe_state_changes = HashMap::new();
|
let mut pipe_state_changes = HashMap::new();
|
||||||
let mut input_pipes_to_unblock: HashSet<String> = running_plugin
|
let mut input_pipes_to_unblock: HashSet<String> = running_plugin
|
||||||
.plugin_env
|
.store
|
||||||
|
.data()
|
||||||
.input_pipes_to_unblock
|
.input_pipes_to_unblock
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.drain()
|
.drain()
|
||||||
.collect();
|
.collect();
|
||||||
let mut input_pipes_to_block: HashSet<String> = running_plugin
|
let mut input_pipes_to_block: HashSet<String> = running_plugin
|
||||||
.plugin_env
|
.store
|
||||||
|
.data()
|
||||||
.input_pipes_to_block
|
.input_pipes_to_block
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
use crate::get_store;
|
use crate::plugins::plugin_map::{
|
||||||
use crate::plugins::plugin_map::{PluginEnv, PluginMap, RunningPlugin, Subscriptions};
|
PluginEnv, PluginMap, RunningPlugin, VecDequeInputStream, WriteOutputStream,
|
||||||
|
};
|
||||||
use crate::plugins::plugin_worker::{plugin_worker, RunningWorker};
|
use crate::plugins::plugin_worker::{plugin_worker, RunningWorker};
|
||||||
use crate::plugins::zellij_exports::{wasi_write_object, zellij_exports};
|
use crate::plugins::zellij_exports::{wasi_write_object, zellij_exports};
|
||||||
use crate::plugins::PluginId;
|
use crate::plugins::PluginId;
|
||||||
use highway::{HighwayHash, PortableHash};
|
use highway::{HighwayHash, PortableHash};
|
||||||
use log::info;
|
use log::info;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet, VecDeque},
|
||||||
fs,
|
fs,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use wasmer::{AsStoreRef, Instance, Module, Store};
|
use wasmtime::{Engine, Instance, Linker, Module, Store};
|
||||||
use wasmer_wasi::{Pipe, WasiState};
|
use wasmtime_wasi::{DirPerms, FilePerms, WasiCtxBuilder};
|
||||||
use zellij_utils::consts::ZELLIJ_PLUGIN_ARTIFACT_DIR;
|
use zellij_utils::consts::ZELLIJ_PLUGIN_ARTIFACT_DIR;
|
||||||
use zellij_utils::prost::Message;
|
use zellij_utils::prost::Message;
|
||||||
|
|
||||||
@ -53,7 +54,7 @@ pub struct PluginLoader<'a> {
|
|||||||
senders: ThreadSenders,
|
senders: ThreadSenders,
|
||||||
plugin_id: PluginId,
|
plugin_id: PluginId,
|
||||||
client_id: ClientId,
|
client_id: ClientId,
|
||||||
store: Arc<Mutex<Store>>,
|
engine: Engine,
|
||||||
plugin: PluginConfig,
|
plugin: PluginConfig,
|
||||||
plugin_dir: &'a PathBuf,
|
plugin_dir: &'a PathBuf,
|
||||||
tab_index: Option<usize>,
|
tab_index: Option<usize>,
|
||||||
@ -75,7 +76,7 @@ impl<'a> PluginLoader<'a> {
|
|||||||
plugin_dir: PathBuf,
|
plugin_dir: PathBuf,
|
||||||
plugin_cache: Arc<Mutex<HashMap<PathBuf, Module>>>,
|
plugin_cache: Arc<Mutex<HashMap<PathBuf, Module>>>,
|
||||||
senders: ThreadSenders,
|
senders: ThreadSenders,
|
||||||
store: Arc<Mutex<Store>>,
|
engine: Engine,
|
||||||
plugin_map: Arc<Mutex<PluginMap>>,
|
plugin_map: Arc<Mutex<PluginMap>>,
|
||||||
connected_clients: Arc<Mutex<Vec<ClientId>>>,
|
connected_clients: Arc<Mutex<Vec<ClientId>>>,
|
||||||
loading_indication: &mut LoadingIndication,
|
loading_indication: &mut LoadingIndication,
|
||||||
@ -102,7 +103,7 @@ impl<'a> PluginLoader<'a> {
|
|||||||
&senders,
|
&senders,
|
||||||
plugin_id,
|
plugin_id,
|
||||||
first_client_id,
|
first_client_id,
|
||||||
store,
|
engine,
|
||||||
&plugin_dir,
|
&plugin_dir,
|
||||||
path_to_default_shell,
|
path_to_default_shell,
|
||||||
zellij_cwd,
|
zellij_cwd,
|
||||||
@ -115,14 +116,8 @@ impl<'a> PluginLoader<'a> {
|
|||||||
plugin_loader
|
plugin_loader
|
||||||
.load_module_from_memory()
|
.load_module_from_memory()
|
||||||
.and_then(|module| plugin_loader.create_plugin_environment(module))
|
.and_then(|module| plugin_loader.create_plugin_environment(module))
|
||||||
.and_then(|(store, instance, plugin_env, subscriptions)| {
|
.and_then(|(store, instance)| {
|
||||||
plugin_loader.load_plugin_instance(
|
plugin_loader.load_plugin_instance(store, &instance, &plugin_map)
|
||||||
store,
|
|
||||||
&instance,
|
|
||||||
&plugin_env,
|
|
||||||
&plugin_map,
|
|
||||||
&subscriptions,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.and_then(|_| {
|
.and_then(|_| {
|
||||||
plugin_loader.clone_instance_for_other_clients(&connected_clients, &plugin_map)
|
plugin_loader.clone_instance_for_other_clients(&connected_clients, &plugin_map)
|
||||||
@ -140,7 +135,7 @@ impl<'a> PluginLoader<'a> {
|
|||||||
plugin_dir: PathBuf,
|
plugin_dir: PathBuf,
|
||||||
plugin_cache: Arc<Mutex<HashMap<PathBuf, Module>>>,
|
plugin_cache: Arc<Mutex<HashMap<PathBuf, Module>>>,
|
||||||
senders: ThreadSenders,
|
senders: ThreadSenders,
|
||||||
store: Arc<Mutex<Store>>,
|
engine: Engine,
|
||||||
plugin_map: Arc<Mutex<PluginMap>>,
|
plugin_map: Arc<Mutex<PluginMap>>,
|
||||||
size: Size,
|
size: Size,
|
||||||
connected_clients: Arc<Mutex<Vec<ClientId>>>,
|
connected_clients: Arc<Mutex<Vec<ClientId>>>,
|
||||||
@ -161,7 +156,7 @@ impl<'a> PluginLoader<'a> {
|
|||||||
&senders,
|
&senders,
|
||||||
plugin_id,
|
plugin_id,
|
||||||
client_id,
|
client_id,
|
||||||
store.clone(),
|
engine,
|
||||||
plugin.clone(),
|
plugin.clone(),
|
||||||
&plugin_dir,
|
&plugin_dir,
|
||||||
tab_index,
|
tab_index,
|
||||||
@ -178,14 +173,8 @@ impl<'a> PluginLoader<'a> {
|
|||||||
plugin_loader
|
plugin_loader
|
||||||
.compile_module()
|
.compile_module()
|
||||||
.and_then(|module| plugin_loader.create_plugin_environment(module))
|
.and_then(|module| plugin_loader.create_plugin_environment(module))
|
||||||
.and_then(|(store, instance, plugin_env, subscriptions)| {
|
.and_then(|(store, instance)| {
|
||||||
plugin_loader.load_plugin_instance(
|
plugin_loader.load_plugin_instance(store, &instance, &plugin_map)
|
||||||
store,
|
|
||||||
&instance,
|
|
||||||
&plugin_env,
|
|
||||||
&plugin_map,
|
|
||||||
&subscriptions,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.and_then(|_| {
|
.and_then(|_| {
|
||||||
plugin_loader.clone_instance_for_other_clients(
|
plugin_loader.clone_instance_for_other_clients(
|
||||||
@ -200,14 +189,8 @@ impl<'a> PluginLoader<'a> {
|
|||||||
.or_else(|_e| plugin_loader.load_module_from_hd_cache())
|
.or_else(|_e| plugin_loader.load_module_from_hd_cache())
|
||||||
.or_else(|_e| plugin_loader.compile_module())
|
.or_else(|_e| plugin_loader.compile_module())
|
||||||
.and_then(|module| plugin_loader.create_plugin_environment(module))
|
.and_then(|module| plugin_loader.create_plugin_environment(module))
|
||||||
.and_then(|(store, instance, plugin_env, subscriptions)| {
|
.and_then(|(store, instance)| {
|
||||||
plugin_loader.load_plugin_instance(
|
plugin_loader.load_plugin_instance(store, &instance, &plugin_map)
|
||||||
store,
|
|
||||||
&instance,
|
|
||||||
&plugin_env,
|
|
||||||
&plugin_map,
|
|
||||||
&subscriptions,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.and_then(|_| {
|
.and_then(|_| {
|
||||||
plugin_loader.clone_instance_for_other_clients(
|
plugin_loader.clone_instance_for_other_clients(
|
||||||
@ -226,7 +209,7 @@ impl<'a> PluginLoader<'a> {
|
|||||||
plugin_dir: PathBuf,
|
plugin_dir: PathBuf,
|
||||||
plugin_cache: Arc<Mutex<HashMap<PathBuf, Module>>>,
|
plugin_cache: Arc<Mutex<HashMap<PathBuf, Module>>>,
|
||||||
senders: ThreadSenders,
|
senders: ThreadSenders,
|
||||||
store: Arc<Mutex<Store>>,
|
engine: Engine,
|
||||||
plugin_map: Arc<Mutex<PluginMap>>,
|
plugin_map: Arc<Mutex<PluginMap>>,
|
||||||
connected_clients: Arc<Mutex<Vec<ClientId>>>,
|
connected_clients: Arc<Mutex<Vec<ClientId>>>,
|
||||||
loading_indication: &mut LoadingIndication,
|
loading_indication: &mut LoadingIndication,
|
||||||
@ -250,7 +233,7 @@ impl<'a> PluginLoader<'a> {
|
|||||||
&senders,
|
&senders,
|
||||||
plugin_id,
|
plugin_id,
|
||||||
existing_client_id,
|
existing_client_id,
|
||||||
store.clone(),
|
engine.clone(),
|
||||||
&plugin_dir,
|
&plugin_dir,
|
||||||
path_to_default_shell.clone(),
|
path_to_default_shell.clone(),
|
||||||
zellij_cwd.clone(),
|
zellij_cwd.clone(),
|
||||||
@ -263,14 +246,8 @@ impl<'a> PluginLoader<'a> {
|
|||||||
plugin_loader
|
plugin_loader
|
||||||
.load_module_from_memory()
|
.load_module_from_memory()
|
||||||
.and_then(|module| plugin_loader.create_plugin_environment(module))
|
.and_then(|module| plugin_loader.create_plugin_environment(module))
|
||||||
.and_then(|(store, instance, plugin_env, subscriptions)| {
|
.and_then(|(store, instance)| {
|
||||||
plugin_loader.load_plugin_instance(
|
plugin_loader.load_plugin_instance(store, &instance, &plugin_map)
|
||||||
store,
|
|
||||||
&instance,
|
|
||||||
&plugin_env,
|
|
||||||
&plugin_map,
|
|
||||||
&subscriptions,
|
|
||||||
)
|
|
||||||
})?
|
})?
|
||||||
}
|
}
|
||||||
connected_clients.lock().unwrap().push(client_id);
|
connected_clients.lock().unwrap().push(client_id);
|
||||||
@ -282,7 +259,7 @@ impl<'a> PluginLoader<'a> {
|
|||||||
plugin_dir: PathBuf,
|
plugin_dir: PathBuf,
|
||||||
plugin_cache: Arc<Mutex<HashMap<PathBuf, Module>>>,
|
plugin_cache: Arc<Mutex<HashMap<PathBuf, Module>>>,
|
||||||
senders: ThreadSenders,
|
senders: ThreadSenders,
|
||||||
store: Arc<Mutex<Store>>,
|
engine: Engine,
|
||||||
plugin_map: Arc<Mutex<PluginMap>>,
|
plugin_map: Arc<Mutex<PluginMap>>,
|
||||||
connected_clients: Arc<Mutex<Vec<ClientId>>>,
|
connected_clients: Arc<Mutex<Vec<ClientId>>>,
|
||||||
loading_indication: &mut LoadingIndication,
|
loading_indication: &mut LoadingIndication,
|
||||||
@ -310,7 +287,7 @@ impl<'a> PluginLoader<'a> {
|
|||||||
&senders,
|
&senders,
|
||||||
plugin_id,
|
plugin_id,
|
||||||
first_client_id,
|
first_client_id,
|
||||||
store.clone(),
|
engine,
|
||||||
&plugin_dir,
|
&plugin_dir,
|
||||||
path_to_default_shell,
|
path_to_default_shell,
|
||||||
zellij_cwd,
|
zellij_cwd,
|
||||||
@ -323,14 +300,8 @@ impl<'a> PluginLoader<'a> {
|
|||||||
plugin_loader
|
plugin_loader
|
||||||
.compile_module()
|
.compile_module()
|
||||||
.and_then(|module| plugin_loader.create_plugin_environment(module))
|
.and_then(|module| plugin_loader.create_plugin_environment(module))
|
||||||
.and_then(|(store, instance, plugin_env, subscriptions)| {
|
.and_then(|(store, instance)| {
|
||||||
plugin_loader.load_plugin_instance(
|
plugin_loader.load_plugin_instance(store, &instance, &plugin_map)
|
||||||
store,
|
|
||||||
&instance,
|
|
||||||
&plugin_env,
|
|
||||||
&plugin_map,
|
|
||||||
&subscriptions,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.and_then(|_| {
|
.and_then(|_| {
|
||||||
plugin_loader.clone_instance_for_other_clients(&connected_clients, &plugin_map)
|
plugin_loader.clone_instance_for_other_clients(&connected_clients, &plugin_map)
|
||||||
@ -345,7 +316,7 @@ impl<'a> PluginLoader<'a> {
|
|||||||
senders: &ThreadSenders,
|
senders: &ThreadSenders,
|
||||||
plugin_id: PluginId,
|
plugin_id: PluginId,
|
||||||
client_id: ClientId,
|
client_id: ClientId,
|
||||||
store: Arc<Mutex<Store>>,
|
engine: Engine,
|
||||||
plugin: PluginConfig,
|
plugin: PluginConfig,
|
||||||
plugin_dir: &'a PathBuf,
|
plugin_dir: &'a PathBuf,
|
||||||
tab_index: Option<usize>,
|
tab_index: Option<usize>,
|
||||||
@ -370,7 +341,7 @@ impl<'a> PluginLoader<'a> {
|
|||||||
senders: senders.clone(),
|
senders: senders.clone(),
|
||||||
plugin_id,
|
plugin_id,
|
||||||
client_id,
|
client_id,
|
||||||
store: store.clone(),
|
engine,
|
||||||
plugin,
|
plugin,
|
||||||
plugin_dir,
|
plugin_dir,
|
||||||
tab_index,
|
tab_index,
|
||||||
@ -393,7 +364,7 @@ impl<'a> PluginLoader<'a> {
|
|||||||
senders: &ThreadSenders,
|
senders: &ThreadSenders,
|
||||||
plugin_id: PluginId,
|
plugin_id: PluginId,
|
||||||
client_id: ClientId,
|
client_id: ClientId,
|
||||||
store: Arc<Mutex<Store>>,
|
engine: Engine,
|
||||||
plugin_dir: &'a PathBuf,
|
plugin_dir: &'a PathBuf,
|
||||||
path_to_default_shell: PathBuf,
|
path_to_default_shell: PathBuf,
|
||||||
zellij_cwd: PathBuf,
|
zellij_cwd: PathBuf,
|
||||||
@ -411,20 +382,20 @@ impl<'a> PluginLoader<'a> {
|
|||||||
.with_context(err_context)?
|
.with_context(err_context)?
|
||||||
};
|
};
|
||||||
let running_plugin = running_plugin.lock().unwrap();
|
let running_plugin = running_plugin.lock().unwrap();
|
||||||
let tab_index = running_plugin.plugin_env.tab_index;
|
let tab_index = running_plugin.store.data().tab_index;
|
||||||
let size = Size {
|
let size = Size {
|
||||||
rows: running_plugin.rows,
|
rows: running_plugin.rows,
|
||||||
cols: running_plugin.columns,
|
cols: running_plugin.columns,
|
||||||
};
|
};
|
||||||
let plugin_config = running_plugin.plugin_env.plugin.clone();
|
let plugin_config = running_plugin.store.data().plugin.clone();
|
||||||
loading_indication.set_name(running_plugin.plugin_env.name());
|
loading_indication.set_name(running_plugin.store.data().name());
|
||||||
PluginLoader::new(
|
PluginLoader::new(
|
||||||
plugin_cache,
|
plugin_cache,
|
||||||
loading_indication,
|
loading_indication,
|
||||||
senders,
|
senders,
|
||||||
plugin_id,
|
plugin_id,
|
||||||
client_id,
|
client_id,
|
||||||
store,
|
engine,
|
||||||
plugin_config,
|
plugin_config,
|
||||||
plugin_dir,
|
plugin_dir,
|
||||||
tab_index,
|
tab_index,
|
||||||
@ -445,7 +416,7 @@ impl<'a> PluginLoader<'a> {
|
|||||||
senders: &ThreadSenders,
|
senders: &ThreadSenders,
|
||||||
plugin_id: PluginId,
|
plugin_id: PluginId,
|
||||||
client_id: ClientId,
|
client_id: ClientId,
|
||||||
store: Arc<Mutex<Store>>,
|
engine: Engine,
|
||||||
plugin_dir: &'a PathBuf,
|
plugin_dir: &'a PathBuf,
|
||||||
path_to_default_shell: PathBuf,
|
path_to_default_shell: PathBuf,
|
||||||
zellij_cwd: PathBuf,
|
zellij_cwd: PathBuf,
|
||||||
@ -464,20 +435,20 @@ impl<'a> PluginLoader<'a> {
|
|||||||
.clone()
|
.clone()
|
||||||
};
|
};
|
||||||
let running_plugin = running_plugin.lock().unwrap();
|
let running_plugin = running_plugin.lock().unwrap();
|
||||||
let tab_index = running_plugin.plugin_env.tab_index;
|
let tab_index = running_plugin.store.data().tab_index;
|
||||||
let size = Size {
|
let size = Size {
|
||||||
rows: running_plugin.rows,
|
rows: running_plugin.rows,
|
||||||
cols: running_plugin.columns,
|
cols: running_plugin.columns,
|
||||||
};
|
};
|
||||||
let plugin_config = running_plugin.plugin_env.plugin.clone();
|
let plugin_config = running_plugin.store.data().plugin.clone();
|
||||||
loading_indication.set_name(running_plugin.plugin_env.name());
|
loading_indication.set_name(running_plugin.store.data().name());
|
||||||
PluginLoader::new(
|
PluginLoader::new(
|
||||||
plugin_cache,
|
plugin_cache,
|
||||||
loading_indication,
|
loading_indication,
|
||||||
senders,
|
senders,
|
||||||
plugin_id,
|
plugin_id,
|
||||||
client_id,
|
client_id,
|
||||||
store.clone(),
|
engine,
|
||||||
plugin_config,
|
plugin_config,
|
||||||
plugin_dir,
|
plugin_dir,
|
||||||
tab_index,
|
tab_index,
|
||||||
@ -527,9 +498,7 @@ impl<'a> PluginLoader<'a> {
|
|||||||
);
|
);
|
||||||
let (_wasm_bytes, cached_path) = self.plugin_bytes_and_cache_path()?;
|
let (_wasm_bytes, cached_path) = self.plugin_bytes_and_cache_path()?;
|
||||||
let timer = std::time::Instant::now();
|
let timer = std::time::Instant::now();
|
||||||
let module = unsafe {
|
let module = unsafe { Module::deserialize_file(&self.engine, &cached_path)? };
|
||||||
Module::deserialize_from_file(&self.store.lock().unwrap().as_store_ref(), &cached_path)?
|
|
||||||
};
|
|
||||||
log::info!(
|
log::info!(
|
||||||
"Loaded plugin '{}' from cache folder at '{}' in {:?}",
|
"Loaded plugin '{}' from cache folder at '{}' in {:?}",
|
||||||
self.plugin_path.display(),
|
self.plugin_path.display(),
|
||||||
@ -565,12 +534,11 @@ impl<'a> PluginLoader<'a> {
|
|||||||
.map_err(anyError::new)
|
.map_err(anyError::new)
|
||||||
.and_then(|_| {
|
.and_then(|_| {
|
||||||
// compile module
|
// compile module
|
||||||
Module::new(&self.store.lock().unwrap().as_store_ref(), &wasm_bytes)
|
Module::new(&self.engine, &wasm_bytes)
|
||||||
.map_err(anyError::new)
|
|
||||||
})
|
})
|
||||||
.and_then(|m| {
|
.and_then(|m| {
|
||||||
// serialize module to HD cache for faster loading in the future
|
// serialize module to HD cache for faster loading in the future
|
||||||
m.serialize_to_file(&cached_path).map_err(anyError::new)?;
|
fs::write(&cached_path, m.serialize()?).map_err(anyError::new)?;
|
||||||
log::info!(
|
log::info!(
|
||||||
"Compiled plugin '{}' in {:?}",
|
"Compiled plugin '{}' in {:?}",
|
||||||
self.plugin_path.display(),
|
self.plugin_path.display(),
|
||||||
@ -584,20 +552,19 @@ impl<'a> PluginLoader<'a> {
|
|||||||
pub fn create_plugin_environment(
|
pub fn create_plugin_environment(
|
||||||
&mut self,
|
&mut self,
|
||||||
module: Module,
|
module: Module,
|
||||||
) -> Result<(Store, Instance, PluginEnv, Arc<Mutex<Subscriptions>>)> {
|
) -> Result<(Store<PluginEnv>, Instance)> {
|
||||||
let (store, instance, plugin_env, subscriptions) =
|
let (store, instance) = self.create_plugin_instance_env(&module)?;
|
||||||
self.create_plugin_instance_env_and_subscriptions(&module)?;
|
|
||||||
// Only do an insert when everything went well!
|
// Only do an insert when everything went well!
|
||||||
let cloned_plugin = self.plugin.clone();
|
let cloned_plugin = self.plugin.clone();
|
||||||
self.plugin_cache
|
self.plugin_cache
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.insert(cloned_plugin.path, module);
|
.insert(cloned_plugin.path, module);
|
||||||
Ok((store, instance, plugin_env, subscriptions))
|
Ok((store, instance))
|
||||||
}
|
}
|
||||||
pub fn create_plugin_instance_and_wasi_env_for_worker(
|
pub fn create_plugin_instance_and_wasi_env_for_worker(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> Result<(Store, Instance, PluginEnv)> {
|
) -> Result<(Store<PluginEnv>, Instance)> {
|
||||||
let err_context = || {
|
let err_context = || {
|
||||||
format!(
|
format!(
|
||||||
"Failed to create instance and plugin env for worker {}",
|
"Failed to create instance and plugin env for worker {}",
|
||||||
@ -611,21 +578,17 @@ impl<'a> PluginLoader<'a> {
|
|||||||
.get(&self.plugin.path)
|
.get(&self.plugin.path)
|
||||||
.with_context(err_context)?
|
.with_context(err_context)?
|
||||||
.clone();
|
.clone();
|
||||||
let (store, instance, plugin_env, _subscriptions) =
|
let (store, instance) = self.create_plugin_instance_env(&module)?;
|
||||||
self.create_plugin_instance_env_and_subscriptions(&module)?;
|
Ok((store, instance))
|
||||||
Ok((store, instance, plugin_env))
|
|
||||||
}
|
}
|
||||||
pub fn load_plugin_instance(
|
pub fn load_plugin_instance(
|
||||||
&mut self,
|
&mut self,
|
||||||
store: Store,
|
mut store: Store<PluginEnv>,
|
||||||
instance: &Instance,
|
instance: &Instance,
|
||||||
plugin_env: &PluginEnv,
|
|
||||||
plugin_map: &Arc<Mutex<PluginMap>>,
|
plugin_map: &Arc<Mutex<PluginMap>>,
|
||||||
subscriptions: &Arc<Mutex<Subscriptions>>,
|
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let err_context = || format!("failed to load plugin from instance {instance:#?}");
|
let err_context = || format!("failed to load plugin from instance {instance:#?}");
|
||||||
let main_user_instance = instance.clone();
|
let main_user_instance = instance.clone();
|
||||||
let main_user_env = plugin_env.clone();
|
|
||||||
display_loading_stage!(
|
display_loading_stage!(
|
||||||
indicate_starting_plugin,
|
indicate_starting_plugin,
|
||||||
self.loading_indication,
|
self.loading_indication,
|
||||||
@ -633,39 +596,38 @@ impl<'a> PluginLoader<'a> {
|
|||||||
self.plugin_id
|
self.plugin_id
|
||||||
);
|
);
|
||||||
let start_function = instance
|
let start_function = instance
|
||||||
.exports
|
.get_typed_func::<(), ()>(&mut store, "_start")
|
||||||
.get_function("_start")
|
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
let load_function = instance
|
let load_function = instance
|
||||||
.exports
|
.get_typed_func::<(), ()>(&mut store, "load")
|
||||||
.get_function("load")
|
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
let mut workers = HashMap::new();
|
let mut workers = HashMap::new();
|
||||||
for (function_name, _exported_function) in instance.exports.iter().functions() {
|
for function_name in instance
|
||||||
|
.exports(&mut store)
|
||||||
|
.filter_map(|export| export.clone().into_func().map(|_| export.name()))
|
||||||
|
{
|
||||||
if function_name.ends_with("_worker") {
|
if function_name.ends_with("_worker") {
|
||||||
let plugin_config = self.plugin.clone();
|
let plugin_config = self.plugin.clone();
|
||||||
let (mut store, instance, plugin_env) =
|
let (mut store, instance) =
|
||||||
self.create_plugin_instance_and_wasi_env_for_worker()?;
|
self.create_plugin_instance_and_wasi_env_for_worker()?;
|
||||||
|
|
||||||
let start_function_for_worker = instance
|
let start_function_for_worker = instance
|
||||||
.exports
|
.get_typed_func::<(), ()>(&mut store, "_start")
|
||||||
.get_function("_start")
|
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
start_function_for_worker
|
start_function_for_worker
|
||||||
.call(&mut store, &[])
|
.call(&mut store, ())
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
|
|
||||||
let worker =
|
let worker = RunningWorker::new(store, instance, &function_name, plugin_config);
|
||||||
RunningWorker::new(store, instance, &function_name, plugin_config, plugin_env);
|
|
||||||
let worker_sender = plugin_worker(worker);
|
let worker_sender = plugin_worker(worker);
|
||||||
workers.insert(function_name.into(), worker_sender);
|
workers.insert(function_name.into(), worker_sender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let subscriptions = store.data().subscriptions.clone();
|
||||||
let plugin = Arc::new(Mutex::new(RunningPlugin::new(
|
let plugin = Arc::new(Mutex::new(RunningPlugin::new(
|
||||||
store,
|
store,
|
||||||
main_user_instance,
|
main_user_instance,
|
||||||
main_user_env,
|
|
||||||
self.size.rows,
|
self.size.rows,
|
||||||
self.size.cols,
|
self.size.cols,
|
||||||
)));
|
)));
|
||||||
@ -673,12 +635,12 @@ impl<'a> PluginLoader<'a> {
|
|||||||
self.plugin_id,
|
self.plugin_id,
|
||||||
self.client_id,
|
self.client_id,
|
||||||
plugin.clone(),
|
plugin.clone(),
|
||||||
subscriptions.clone(),
|
subscriptions,
|
||||||
workers,
|
workers,
|
||||||
);
|
);
|
||||||
|
|
||||||
start_function
|
start_function
|
||||||
.call(&mut plugin.lock().unwrap().store, &[])
|
.call(&mut plugin.lock().unwrap().store, ())
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
|
|
||||||
let protobuf_plugin_configuration: ProtobufPluginConfiguration = self
|
let protobuf_plugin_configuration: ProtobufPluginConfiguration = self
|
||||||
@ -689,13 +651,13 @@ impl<'a> PluginLoader<'a> {
|
|||||||
.map_err(|e| anyhow!("Failed to serialize user configuration: {:?}", e))?;
|
.map_err(|e| anyhow!("Failed to serialize user configuration: {:?}", e))?;
|
||||||
let protobuf_bytes = protobuf_plugin_configuration.encode_to_vec();
|
let protobuf_bytes = protobuf_plugin_configuration.encode_to_vec();
|
||||||
wasi_write_object(
|
wasi_write_object(
|
||||||
&plugin_env.wasi_env,
|
plugin.lock().unwrap().store.data(),
|
||||||
&protobuf_bytes,
|
&protobuf_bytes,
|
||||||
// &self.plugin.userspace_configuration.inner(),
|
// &self.plugin.userspace_configuration.inner(),
|
||||||
)
|
)
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
load_function
|
load_function
|
||||||
.call(&mut plugin.lock().unwrap().store, &[])
|
.call(&mut plugin.lock().unwrap().store, ())
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
|
|
||||||
display_loading_stage!(
|
display_loading_stage!(
|
||||||
@ -744,7 +706,7 @@ impl<'a> PluginLoader<'a> {
|
|||||||
&self.senders.clone(),
|
&self.senders.clone(),
|
||||||
self.plugin_id,
|
self.plugin_id,
|
||||||
*client_id,
|
*client_id,
|
||||||
self.store.clone(),
|
self.engine.clone(),
|
||||||
&self.plugin_dir,
|
&self.plugin_dir,
|
||||||
self.path_to_default_shell.clone(),
|
self.path_to_default_shell.clone(),
|
||||||
self.zellij_cwd.clone(),
|
self.zellij_cwd.clone(),
|
||||||
@ -757,14 +719,8 @@ impl<'a> PluginLoader<'a> {
|
|||||||
plugin_loader_for_client
|
plugin_loader_for_client
|
||||||
.load_module_from_memory()
|
.load_module_from_memory()
|
||||||
.and_then(|module| plugin_loader_for_client.create_plugin_environment(module))
|
.and_then(|module| plugin_loader_for_client.create_plugin_environment(module))
|
||||||
.and_then(|(store, instance, plugin_env, subscriptions)| {
|
.and_then(|(store, instance)| {
|
||||||
plugin_loader_for_client.load_plugin_instance(
|
plugin_loader_for_client.load_plugin_instance(store, &instance, plugin_map)
|
||||||
store,
|
|
||||||
&instance,
|
|
||||||
&plugin_env,
|
|
||||||
plugin_map,
|
|
||||||
&subscriptions,
|
|
||||||
)
|
|
||||||
})?
|
})?
|
||||||
}
|
}
|
||||||
display_loading_stage!(
|
display_loading_stage!(
|
||||||
@ -799,18 +755,13 @@ impl<'a> PluginLoader<'a> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn create_plugin_instance_env_and_subscriptions(
|
fn create_plugin_instance_env(&self, module: &Module) -> Result<(Store<PluginEnv>, Instance)> {
|
||||||
&self,
|
|
||||||
module: &Module,
|
|
||||||
) -> Result<(Store, Instance, PluginEnv, Arc<Mutex<Subscriptions>>)> {
|
|
||||||
let err_context = || {
|
let err_context = || {
|
||||||
format!(
|
format!(
|
||||||
"Failed to create instance, plugin env and subscriptions for plugin {}",
|
"Failed to create instance, plugin env and subscriptions for plugin {}",
|
||||||
self.plugin_id
|
self.plugin_id
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let mut store = get_store();
|
|
||||||
let store_mut = &mut store;
|
|
||||||
let dirs = vec![
|
let dirs = vec![
|
||||||
("/host".to_owned(), self.zellij_cwd.clone()),
|
("/host".to_owned(), self.zellij_cwd.clone()),
|
||||||
("/data".to_owned(), self.plugin_own_data_dir.clone()),
|
("/data".to_owned(), self.plugin_own_data_dir.clone()),
|
||||||
@ -824,22 +775,23 @@ impl<'a> PluginLoader<'a> {
|
|||||||
// there's no built-in solution
|
// there's no built-in solution
|
||||||
dir.try_exists().ok().unwrap_or(false)
|
dir.try_exists().ok().unwrap_or(false)
|
||||||
});
|
});
|
||||||
let mut wasi_env = WasiState::new("Zellij")
|
let mut wasi_ctx_builder = WasiCtxBuilder::new();
|
||||||
.env("CLICOLOR_FORCE", "1")
|
wasi_ctx_builder.env("CLICOLOR_FORCE", "1");
|
||||||
.map_dirs(dirs)
|
for (guest_path, host_path) in dirs {
|
||||||
.and_then(|wasi| {
|
wasi_ctx_builder
|
||||||
wasi.stdin(Box::new(Pipe::new()))
|
.preopened_dir(host_path, guest_path, DirPerms::all(), FilePerms::all())
|
||||||
.stdout(Box::new(Pipe::new()))
|
.with_context(err_context)?;
|
||||||
.stderr(Box::new(LoggingPipe::new(
|
}
|
||||||
&self.plugin.location.to_string(),
|
let stdin_pipe = Arc::new(Mutex::new(VecDeque::new()));
|
||||||
self.plugin_id,
|
let stdout_pipe = Arc::new(Mutex::new(VecDeque::new()));
|
||||||
)))
|
wasi_ctx_builder
|
||||||
.finalize(store_mut)
|
.stdin(VecDequeInputStream(stdin_pipe.clone()))
|
||||||
})
|
.stdout(WriteOutputStream(stdout_pipe.clone()))
|
||||||
.with_context(err_context)?;
|
.stderr(WriteOutputStream(Arc::new(Mutex::new(LoggingPipe::new(
|
||||||
let wasi = wasi_env
|
&self.plugin.location.to_string(),
|
||||||
.import_object(store_mut, &module)
|
self.plugin_id,
|
||||||
.with_context(err_context)?;
|
)))));
|
||||||
|
let wasi_ctx = wasi_ctx_builder.build_p1();
|
||||||
let mut mut_plugin = self.plugin.clone();
|
let mut mut_plugin = self.plugin.clone();
|
||||||
if let Some(tab_index) = self.tab_index {
|
if let Some(tab_index) = self.tab_index {
|
||||||
mut_plugin.set_tab_index(tab_index);
|
mut_plugin.set_tab_index(tab_index);
|
||||||
@ -850,7 +802,7 @@ impl<'a> PluginLoader<'a> {
|
|||||||
plugin: mut_plugin,
|
plugin: mut_plugin,
|
||||||
permissions: Arc::new(Mutex::new(None)),
|
permissions: Arc::new(Mutex::new(None)),
|
||||||
senders: self.senders.clone(),
|
senders: self.senders.clone(),
|
||||||
wasi_env: wasi_env.data_mut(store_mut).clone(),
|
wasi_ctx,
|
||||||
plugin_own_data_dir: self.plugin_own_data_dir.clone(),
|
plugin_own_data_dir: self.plugin_own_data_dir.clone(),
|
||||||
tab_index: self.tab_index,
|
tab_index: self.tab_index,
|
||||||
path_to_default_shell: self.path_to_default_shell.clone(),
|
path_to_default_shell: self.path_to_default_shell.clone(),
|
||||||
@ -862,18 +814,28 @@ impl<'a> PluginLoader<'a> {
|
|||||||
input_pipes_to_unblock: Arc::new(Mutex::new(HashSet::new())),
|
input_pipes_to_unblock: Arc::new(Mutex::new(HashSet::new())),
|
||||||
input_pipes_to_block: Arc::new(Mutex::new(HashSet::new())),
|
input_pipes_to_block: Arc::new(Mutex::new(HashSet::new())),
|
||||||
layout_dir: self.layout_dir.clone(),
|
layout_dir: self.layout_dir.clone(),
|
||||||
|
subscriptions: Arc::new(Mutex::new(HashSet::new())),
|
||||||
|
stdin_pipe,
|
||||||
|
stdout_pipe,
|
||||||
};
|
};
|
||||||
|
let mut store = Store::new(&self.engine, plugin_env);
|
||||||
|
|
||||||
let subscriptions = Arc::new(Mutex::new(HashSet::new()));
|
let mut linker = Linker::new(&self.engine);
|
||||||
|
wasmtime_wasi::preview1::add_to_linker_sync(&mut linker, |plugin_env: &mut PluginEnv| {
|
||||||
|
&mut plugin_env.wasi_ctx
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
zellij_exports(&mut linker);
|
||||||
|
|
||||||
let mut zellij = zellij_exports(store_mut, &plugin_env, &subscriptions);
|
let instance = linker
|
||||||
zellij.extend(&wasi);
|
.instantiate(&mut store, module)
|
||||||
|
.with_context(err_context)?;
|
||||||
|
|
||||||
let instance = Instance::new(store_mut, &module, &zellij).with_context(err_context)?;
|
if let Some(func) = instance.get_func(&mut store, "_initialize") {
|
||||||
|
func.typed::<(), ()>(&store)?.call(&mut store, ())?;
|
||||||
|
}
|
||||||
|
|
||||||
wasi_env.initialize(store_mut, &instance)?;
|
Ok((store, instance))
|
||||||
|
|
||||||
Ok((store, instance, plugin_env, subscriptions))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
use crate::plugins::plugin_worker::MessageToWorker;
|
use crate::plugins::plugin_worker::MessageToWorker;
|
||||||
use crate::plugins::PluginId;
|
use crate::plugins::PluginId;
|
||||||
|
use bytes::Bytes;
|
||||||
|
use std::io::Write;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet, VecDeque},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
use wasmer::{Instance, Store};
|
use wasmtime::{Instance, Store};
|
||||||
use wasmer_wasi::WasiEnv;
|
use wasmtime_wasi::preview1::WasiP1Ctx;
|
||||||
|
use wasmtime_wasi::{
|
||||||
|
HostInputStream, HostOutputStream, StdinStream, StdoutStream, StreamError, StreamResult,
|
||||||
|
Subscribe,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{thread_bus::ThreadSenders, ClientId};
|
use crate::{thread_bus::ThreadSenders, ClientId};
|
||||||
|
|
||||||
@ -165,9 +171,9 @@ impl PluginMap {
|
|||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, (running_plugin, _subscriptions, _workers))| {
|
.filter(|(_, (running_plugin, _subscriptions, _workers))| {
|
||||||
let running_plugin = running_plugin.lock().unwrap();
|
let running_plugin = running_plugin.lock().unwrap();
|
||||||
let running_plugin_location = &running_plugin.plugin_env.plugin.location;
|
let plugin_config = &running_plugin.store.data().plugin;
|
||||||
let running_plugin_configuration =
|
let running_plugin_location = &plugin_config.location;
|
||||||
&running_plugin.plugin_env.plugin.userspace_configuration;
|
let running_plugin_configuration = &plugin_config.userspace_configuration;
|
||||||
running_plugin_location == plugin_location
|
running_plugin_location == plugin_location
|
||||||
&& running_plugin_configuration == plugin_configuration
|
&& running_plugin_configuration == plugin_configuration
|
||||||
})
|
})
|
||||||
@ -188,9 +194,9 @@ impl PluginMap {
|
|||||||
> = HashMap::new();
|
> = HashMap::new();
|
||||||
for ((plugin_id, client_id), (running_plugin, _, _)) in self.plugin_assets.iter() {
|
for ((plugin_id, client_id), (running_plugin, _, _)) in self.plugin_assets.iter() {
|
||||||
let running_plugin = running_plugin.lock().unwrap();
|
let running_plugin = running_plugin.lock().unwrap();
|
||||||
let running_plugin_location = &running_plugin.plugin_env.plugin.location;
|
let plugin_config = &running_plugin.store.data().plugin;
|
||||||
let running_plugin_configuration =
|
let running_plugin_location = &plugin_config.location;
|
||||||
&running_plugin.plugin_env.plugin.userspace_configuration;
|
let running_plugin_configuration = &plugin_config.userspace_configuration;
|
||||||
match cloned_plugin_assets.get_mut(running_plugin_location) {
|
match cloned_plugin_assets.get_mut(running_plugin_location) {
|
||||||
Some(location_map) => match location_map.get_mut(running_plugin_configuration) {
|
Some(location_map) => match location_map.get_mut(running_plugin_configuration) {
|
||||||
Some(plugin_instances_info) => {
|
Some(plugin_instances_info) => {
|
||||||
@ -240,13 +246,10 @@ impl PluginMap {
|
|||||||
.find_map(|((p_id, _), (running_plugin, _, _))| {
|
.find_map(|((p_id, _), (running_plugin, _, _))| {
|
||||||
if *p_id == plugin_id {
|
if *p_id == plugin_id {
|
||||||
let running_plugin = running_plugin.lock().unwrap();
|
let running_plugin = running_plugin.lock().unwrap();
|
||||||
let run_plugin_location = running_plugin.plugin_env.plugin.location.clone();
|
let plugin_config = &running_plugin.store.data().plugin;
|
||||||
let run_plugin_configuration = running_plugin
|
let run_plugin_location = plugin_config.location.clone();
|
||||||
.plugin_env
|
let run_plugin_configuration = plugin_config.userspace_configuration.clone();
|
||||||
.plugin
|
let initial_cwd = plugin_config.initial_cwd.clone();
|
||||||
.userspace_configuration
|
|
||||||
.clone();
|
|
||||||
let initial_cwd = running_plugin.plugin_env.plugin.initial_cwd.clone();
|
|
||||||
Some(RunPlugin {
|
Some(RunPlugin {
|
||||||
_allow_exec_host_cmd: false,
|
_allow_exec_host_cmd: false,
|
||||||
location: run_plugin_location,
|
location: run_plugin_location,
|
||||||
@ -262,13 +265,12 @@ impl PluginMap {
|
|||||||
|
|
||||||
pub type Subscriptions = HashSet<EventType>;
|
pub type Subscriptions = HashSet<EventType>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct PluginEnv {
|
pub struct PluginEnv {
|
||||||
pub plugin_id: PluginId,
|
pub plugin_id: PluginId,
|
||||||
pub plugin: PluginConfig,
|
pub plugin: PluginConfig,
|
||||||
pub permissions: Arc<Mutex<Option<HashSet<PermissionType>>>>,
|
pub permissions: Arc<Mutex<Option<HashSet<PermissionType>>>>,
|
||||||
pub senders: ThreadSenders,
|
pub senders: ThreadSenders,
|
||||||
pub wasi_env: WasiEnv,
|
pub wasi_ctx: WasiP1Ctx,
|
||||||
pub tab_index: Option<usize>,
|
pub tab_index: Option<usize>,
|
||||||
pub client_id: ClientId,
|
pub client_id: ClientId,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -282,6 +284,80 @@ pub struct PluginEnv {
|
|||||||
pub plugin_cwd: PathBuf,
|
pub plugin_cwd: PathBuf,
|
||||||
pub input_pipes_to_unblock: Arc<Mutex<HashSet<String>>>,
|
pub input_pipes_to_unblock: Arc<Mutex<HashSet<String>>>,
|
||||||
pub input_pipes_to_block: Arc<Mutex<HashSet<String>>>,
|
pub input_pipes_to_block: Arc<Mutex<HashSet<String>>>,
|
||||||
|
pub subscriptions: Arc<Mutex<Subscriptions>>,
|
||||||
|
pub stdin_pipe: Arc<Mutex<VecDeque<u8>>>,
|
||||||
|
pub stdout_pipe: Arc<Mutex<VecDeque<u8>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct VecDequeInputStream(pub Arc<Mutex<VecDeque<u8>>>);
|
||||||
|
|
||||||
|
impl StdinStream for VecDequeInputStream {
|
||||||
|
fn stream(&self) -> Box<dyn wasmtime_wasi::HostInputStream> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isatty(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HostInputStream for VecDequeInputStream {
|
||||||
|
fn read(&mut self, size: usize) -> StreamResult<Bytes> {
|
||||||
|
let mut inner = self.0.lock().unwrap();
|
||||||
|
let len = std::cmp::min(size, inner.len());
|
||||||
|
Ok(Bytes::from_iter(inner.drain(0..len)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl Subscribe for VecDequeInputStream {
|
||||||
|
async fn ready(&mut self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WriteOutputStream<T>(pub Arc<Mutex<T>>);
|
||||||
|
|
||||||
|
impl<T> Clone for WriteOutputStream<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Write + Send + 'static> StdoutStream for WriteOutputStream<T> {
|
||||||
|
fn stream(&self) -> Box<dyn HostOutputStream> {
|
||||||
|
Box::new((*self).clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isatty(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Write + Send + 'static> HostOutputStream for WriteOutputStream<T> {
|
||||||
|
fn write(&mut self, bytes: Bytes) -> StreamResult<()> {
|
||||||
|
self.0
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.write_all(&*bytes)
|
||||||
|
.map_err(|e| StreamError::LastOperationFailed(e.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> StreamResult<()> {
|
||||||
|
self.0
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.flush()
|
||||||
|
.map_err(|e| StreamError::LastOperationFailed(e.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_write(&mut self) -> StreamResult<usize> {
|
||||||
|
Ok(usize::MAX)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<T: Send + 'static> Subscribe for WriteOutputStream<T> {
|
||||||
|
async fn ready(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PluginEnv {
|
impl PluginEnv {
|
||||||
@ -305,9 +381,8 @@ pub enum AtomicEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct RunningPlugin {
|
pub struct RunningPlugin {
|
||||||
pub store: Store,
|
pub store: Store<PluginEnv>,
|
||||||
pub instance: Instance,
|
pub instance: Instance,
|
||||||
pub plugin_env: PluginEnv,
|
|
||||||
pub rows: usize,
|
pub rows: usize,
|
||||||
pub columns: usize,
|
pub columns: usize,
|
||||||
next_event_ids: HashMap<AtomicEvent, usize>,
|
next_event_ids: HashMap<AtomicEvent, usize>,
|
||||||
@ -315,17 +390,10 @@ pub struct RunningPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RunningPlugin {
|
impl RunningPlugin {
|
||||||
pub fn new(
|
pub fn new(store: Store<PluginEnv>, instance: Instance, rows: usize, columns: usize) -> Self {
|
||||||
store: Store,
|
|
||||||
instance: Instance,
|
|
||||||
plugin_env: PluginEnv,
|
|
||||||
rows: usize,
|
|
||||||
columns: usize,
|
|
||||||
) -> Self {
|
|
||||||
RunningPlugin {
|
RunningPlugin {
|
||||||
store,
|
store,
|
||||||
instance,
|
instance,
|
||||||
plugin_env,
|
|
||||||
rows,
|
rows,
|
||||||
columns,
|
columns,
|
||||||
next_event_ids: HashMap::new(),
|
next_event_ids: HashMap::new(),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::plugins::plugin_map::PluginEnv;
|
use crate::plugins::plugin_map::PluginEnv;
|
||||||
use crate::plugins::zellij_exports::wasi_write_object;
|
use crate::plugins::zellij_exports::wasi_write_object;
|
||||||
use wasmer::{Instance, Store};
|
use wasmtime::{Instance, Store};
|
||||||
|
|
||||||
use zellij_utils::async_channel::{unbounded, Receiver, Sender};
|
use zellij_utils::async_channel::{unbounded, Receiver, Sender};
|
||||||
use zellij_utils::async_std::task;
|
use zellij_utils::async_std::task;
|
||||||
@ -13,24 +13,21 @@ pub struct RunningWorker {
|
|||||||
pub instance: Instance,
|
pub instance: Instance,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub plugin_config: PluginConfig,
|
pub plugin_config: PluginConfig,
|
||||||
pub plugin_env: PluginEnv,
|
pub store: Store<PluginEnv>,
|
||||||
store: Store,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunningWorker {
|
impl RunningWorker {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
store: Store,
|
store: Store<PluginEnv>,
|
||||||
instance: Instance,
|
instance: Instance,
|
||||||
name: &str,
|
name: &str,
|
||||||
plugin_config: PluginConfig,
|
plugin_config: PluginConfig,
|
||||||
plugin_env: PluginEnv,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
RunningWorker {
|
RunningWorker {
|
||||||
store,
|
store,
|
||||||
instance,
|
instance,
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
plugin_config,
|
plugin_config,
|
||||||
plugin_env,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn send_message(&mut self, message: String, payload: String) -> Result<()> {
|
pub fn send_message(&mut self, message: String, payload: String) -> Result<()> {
|
||||||
@ -43,12 +40,11 @@ impl RunningWorker {
|
|||||||
let protobuf_bytes = protobuf_message.encode_to_vec();
|
let protobuf_bytes = protobuf_message.encode_to_vec();
|
||||||
let work_function = self
|
let work_function = self
|
||||||
.instance
|
.instance
|
||||||
.exports
|
.get_typed_func::<(), ()>(&mut self.store, &self.name)
|
||||||
.get_function(&self.name)
|
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
wasi_write_object(&self.plugin_env.wasi_env, &protobuf_bytes).with_context(err_context)?;
|
wasi_write_object(self.store.data(), &protobuf_bytes).with_context(err_context)?;
|
||||||
work_function
|
work_function
|
||||||
.call(&mut self.store, &[])
|
.call(&mut self.store, ())
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ use insta::assert_snapshot;
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
use wasmer::Store;
|
use wasmtime::Engine;
|
||||||
use zellij_utils::data::{
|
use zellij_utils::data::{
|
||||||
BareKey, Event, KeyWithModifier, PermissionStatus, PermissionType, PluginCapabilities,
|
BareKey, Event, KeyWithModifier, PermissionStatus, PermissionType, PluginCapabilities,
|
||||||
};
|
};
|
||||||
@ -247,7 +247,7 @@ fn create_plugin_thread(
|
|||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.should_silently_fail();
|
.should_silently_fail();
|
||||||
let store = Store::new(wasmer::Singlepass::default());
|
let engine = Engine::new(wasmtime::Config::new().strategy(wasmtime::Strategy::Winch)).unwrap();
|
||||||
let data_dir = PathBuf::from(tempdir().unwrap().path());
|
let data_dir = PathBuf::from(tempdir().unwrap().path());
|
||||||
let default_shell = PathBuf::from(".");
|
let default_shell = PathBuf::from(".");
|
||||||
let plugin_capabilities = PluginCapabilities::default();
|
let plugin_capabilities = PluginCapabilities::default();
|
||||||
@ -270,7 +270,7 @@ fn create_plugin_thread(
|
|||||||
set_var("ZELLIJ_SESSION_NAME", "zellij-test");
|
set_var("ZELLIJ_SESSION_NAME", "zellij-test");
|
||||||
plugin_thread_main(
|
plugin_thread_main(
|
||||||
plugin_bus,
|
plugin_bus,
|
||||||
store,
|
engine,
|
||||||
data_dir,
|
data_dir,
|
||||||
Box::new(Layout::default()),
|
Box::new(Layout::default()),
|
||||||
None,
|
None,
|
||||||
@ -337,7 +337,7 @@ fn create_plugin_thread_with_server_receiver(
|
|||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.should_silently_fail();
|
.should_silently_fail();
|
||||||
let store = Store::new(wasmer::Singlepass::default());
|
let engine = Engine::new(wasmtime::Config::new().strategy(wasmtime::Strategy::Winch)).unwrap();
|
||||||
let data_dir = PathBuf::from(tempdir().unwrap().path());
|
let data_dir = PathBuf::from(tempdir().unwrap().path());
|
||||||
let default_shell = PathBuf::from(".");
|
let default_shell = PathBuf::from(".");
|
||||||
let plugin_capabilities = PluginCapabilities::default();
|
let plugin_capabilities = PluginCapabilities::default();
|
||||||
@ -349,7 +349,7 @@ fn create_plugin_thread_with_server_receiver(
|
|||||||
set_var("ZELLIJ_SESSION_NAME", "zellij-test");
|
set_var("ZELLIJ_SESSION_NAME", "zellij-test");
|
||||||
plugin_thread_main(
|
plugin_thread_main(
|
||||||
plugin_bus,
|
plugin_bus,
|
||||||
store,
|
engine,
|
||||||
data_dir,
|
data_dir,
|
||||||
Box::new(Layout::default()),
|
Box::new(Layout::default()),
|
||||||
None,
|
None,
|
||||||
@ -422,7 +422,7 @@ fn create_plugin_thread_with_pty_receiver(
|
|||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.should_silently_fail();
|
.should_silently_fail();
|
||||||
let store = Store::new(wasmer::Singlepass::default());
|
let engine = Engine::new(wasmtime::Config::new().strategy(wasmtime::Strategy::Winch)).unwrap();
|
||||||
let data_dir = PathBuf::from(tempdir().unwrap().path());
|
let data_dir = PathBuf::from(tempdir().unwrap().path());
|
||||||
let default_shell = PathBuf::from(".");
|
let default_shell = PathBuf::from(".");
|
||||||
let plugin_capabilities = PluginCapabilities::default();
|
let plugin_capabilities = PluginCapabilities::default();
|
||||||
@ -434,7 +434,7 @@ fn create_plugin_thread_with_pty_receiver(
|
|||||||
set_var("ZELLIJ_SESSION_NAME", "zellij-test");
|
set_var("ZELLIJ_SESSION_NAME", "zellij-test");
|
||||||
plugin_thread_main(
|
plugin_thread_main(
|
||||||
plugin_bus,
|
plugin_bus,
|
||||||
store,
|
engine,
|
||||||
data_dir,
|
data_dir,
|
||||||
Box::new(Layout::default()),
|
Box::new(Layout::default()),
|
||||||
None,
|
None,
|
||||||
@ -502,7 +502,7 @@ fn create_plugin_thread_with_background_jobs_receiver(
|
|||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.should_silently_fail();
|
.should_silently_fail();
|
||||||
let store = Store::new(wasmer::Singlepass::default());
|
let engine = Engine::new(wasmtime::Config::new().strategy(wasmtime::Strategy::Winch)).unwrap();
|
||||||
let data_dir = PathBuf::from(tempdir().unwrap().path());
|
let data_dir = PathBuf::from(tempdir().unwrap().path());
|
||||||
let default_shell = PathBuf::from(".");
|
let default_shell = PathBuf::from(".");
|
||||||
let plugin_capabilities = PluginCapabilities::default();
|
let plugin_capabilities = PluginCapabilities::default();
|
||||||
@ -514,7 +514,7 @@ fn create_plugin_thread_with_background_jobs_receiver(
|
|||||||
set_var("ZELLIJ_SESSION_NAME", "zellij-test");
|
set_var("ZELLIJ_SESSION_NAME", "zellij-test");
|
||||||
plugin_thread_main(
|
plugin_thread_main(
|
||||||
plugin_bus,
|
plugin_bus,
|
||||||
store,
|
engine,
|
||||||
data_dir,
|
data_dir,
|
||||||
Box::new(Layout::default()),
|
Box::new(Layout::default()),
|
||||||
None,
|
None,
|
||||||
|
@ -15,7 +15,7 @@ use std::{
|
|||||||
str::FromStr,
|
str::FromStr,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
use wasmer::{Module, Store, Value};
|
use wasmtime::{Engine, Module};
|
||||||
use zellij_utils::async_channel::Sender;
|
use zellij_utils::async_channel::Sender;
|
||||||
use zellij_utils::async_std::task::{self, JoinHandle};
|
use zellij_utils::async_std::task::{self, JoinHandle};
|
||||||
use zellij_utils::consts::ZELLIJ_CACHE_DIR;
|
use zellij_utils::consts::ZELLIJ_CACHE_DIR;
|
||||||
@ -77,7 +77,7 @@ impl PluginRenderAsset {
|
|||||||
pub struct WasmBridge {
|
pub struct WasmBridge {
|
||||||
connected_clients: Arc<Mutex<Vec<ClientId>>>,
|
connected_clients: Arc<Mutex<Vec<ClientId>>>,
|
||||||
senders: ThreadSenders,
|
senders: ThreadSenders,
|
||||||
store: Arc<Mutex<Store>>,
|
engine: Engine,
|
||||||
plugin_dir: PathBuf,
|
plugin_dir: PathBuf,
|
||||||
plugin_cache: Arc<Mutex<HashMap<PathBuf, Module>>>,
|
plugin_cache: Arc<Mutex<HashMap<PathBuf, Module>>>,
|
||||||
plugin_map: Arc<Mutex<PluginMap>>,
|
plugin_map: Arc<Mutex<PluginMap>>,
|
||||||
@ -107,7 +107,7 @@ pub struct WasmBridge {
|
|||||||
impl WasmBridge {
|
impl WasmBridge {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
senders: ThreadSenders,
|
senders: ThreadSenders,
|
||||||
store: Arc<Mutex<Store>>,
|
engine: Engine,
|
||||||
plugin_dir: PathBuf,
|
plugin_dir: PathBuf,
|
||||||
path_to_default_shell: PathBuf,
|
path_to_default_shell: PathBuf,
|
||||||
zellij_cwd: PathBuf,
|
zellij_cwd: PathBuf,
|
||||||
@ -125,7 +125,7 @@ impl WasmBridge {
|
|||||||
WasmBridge {
|
WasmBridge {
|
||||||
connected_clients,
|
connected_clients,
|
||||||
senders,
|
senders,
|
||||||
store,
|
engine,
|
||||||
plugin_dir,
|
plugin_dir,
|
||||||
plugin_cache,
|
plugin_cache,
|
||||||
plugin_map,
|
plugin_map,
|
||||||
@ -192,7 +192,7 @@ impl WasmBridge {
|
|||||||
let plugin_dir = self.plugin_dir.clone();
|
let plugin_dir = self.plugin_dir.clone();
|
||||||
let plugin_cache = self.plugin_cache.clone();
|
let plugin_cache = self.plugin_cache.clone();
|
||||||
let senders = self.senders.clone();
|
let senders = self.senders.clone();
|
||||||
let store = self.store.clone();
|
let engine = self.engine.clone();
|
||||||
let plugin_map = self.plugin_map.clone();
|
let plugin_map = self.plugin_map.clone();
|
||||||
let connected_clients = self.connected_clients.clone();
|
let connected_clients = self.connected_clients.clone();
|
||||||
let path_to_default_shell = self.path_to_default_shell.clone();
|
let path_to_default_shell = self.path_to_default_shell.clone();
|
||||||
@ -236,7 +236,7 @@ impl WasmBridge {
|
|||||||
plugin_dir,
|
plugin_dir,
|
||||||
plugin_cache,
|
plugin_cache,
|
||||||
senders.clone(),
|
senders.clone(),
|
||||||
store,
|
engine,
|
||||||
plugin_map,
|
plugin_map,
|
||||||
size,
|
size,
|
||||||
connected_clients.clone(),
|
connected_clients.clone(),
|
||||||
@ -291,7 +291,7 @@ impl WasmBridge {
|
|||||||
drop(worker_sender.send(MessageToWorker::Exit));
|
drop(worker_sender.send(MessageToWorker::Exit));
|
||||||
}
|
}
|
||||||
let running_plugin = running_plugin.lock().unwrap();
|
let running_plugin = running_plugin.lock().unwrap();
|
||||||
let cache_dir = running_plugin.plugin_env.plugin_own_data_dir.clone();
|
let cache_dir = running_plugin.store.data().plugin_own_data_dir.clone();
|
||||||
if let Err(e) = std::fs::remove_dir_all(cache_dir) {
|
if let Err(e) = std::fs::remove_dir_all(cache_dir) {
|
||||||
log::error!("Failed to remove cache dir for plugin: {:?}", e);
|
log::error!("Failed to remove cache dir for plugin: {:?}", e);
|
||||||
}
|
}
|
||||||
@ -330,7 +330,7 @@ impl WasmBridge {
|
|||||||
let plugin_dir = self.plugin_dir.clone();
|
let plugin_dir = self.plugin_dir.clone();
|
||||||
let plugin_cache = self.plugin_cache.clone();
|
let plugin_cache = self.plugin_cache.clone();
|
||||||
let senders = self.senders.clone();
|
let senders = self.senders.clone();
|
||||||
let store = self.store.clone();
|
let engine = self.engine.clone();
|
||||||
let plugin_map = self.plugin_map.clone();
|
let plugin_map = self.plugin_map.clone();
|
||||||
let connected_clients = self.connected_clients.clone();
|
let connected_clients = self.connected_clients.clone();
|
||||||
let path_to_default_shell = self.path_to_default_shell.clone();
|
let path_to_default_shell = self.path_to_default_shell.clone();
|
||||||
@ -346,7 +346,7 @@ impl WasmBridge {
|
|||||||
plugin_dir.clone(),
|
plugin_dir.clone(),
|
||||||
plugin_cache.clone(),
|
plugin_cache.clone(),
|
||||||
senders.clone(),
|
senders.clone(),
|
||||||
store.clone(),
|
engine.clone(),
|
||||||
plugin_map.clone(),
|
plugin_map.clone(),
|
||||||
connected_clients.clone(),
|
connected_clients.clone(),
|
||||||
&mut loading_indication,
|
&mut loading_indication,
|
||||||
@ -371,7 +371,7 @@ impl WasmBridge {
|
|||||||
plugin_dir.clone(),
|
plugin_dir.clone(),
|
||||||
plugin_cache.clone(),
|
plugin_cache.clone(),
|
||||||
senders.clone(),
|
senders.clone(),
|
||||||
store.clone(),
|
engine.clone(),
|
||||||
plugin_map.clone(),
|
plugin_map.clone(),
|
||||||
connected_clients.clone(),
|
connected_clients.clone(),
|
||||||
&mut loading_indication,
|
&mut loading_indication,
|
||||||
@ -423,7 +423,7 @@ impl WasmBridge {
|
|||||||
self.plugin_dir.clone(),
|
self.plugin_dir.clone(),
|
||||||
self.plugin_cache.clone(),
|
self.plugin_cache.clone(),
|
||||||
self.senders.clone(),
|
self.senders.clone(),
|
||||||
self.store.clone(),
|
self.engine.clone(),
|
||||||
self.plugin_map.clone(),
|
self.plugin_map.clone(),
|
||||||
self.connected_clients.clone(),
|
self.connected_clients.clone(),
|
||||||
&mut loading_indication,
|
&mut loading_indication,
|
||||||
@ -491,23 +491,17 @@ impl WasmBridge {
|
|||||||
let rendered_bytes = running_plugin
|
let rendered_bytes = running_plugin
|
||||||
.instance
|
.instance
|
||||||
.clone()
|
.clone()
|
||||||
.exports
|
.get_typed_func::<(i32, i32), ()>(
|
||||||
.get_function("render")
|
&mut running_plugin.store,
|
||||||
.map_err(anyError::new)
|
"render",
|
||||||
|
)
|
||||||
.and_then(|render| {
|
.and_then(|render| {
|
||||||
render
|
render.call(
|
||||||
.call(
|
&mut running_plugin.store,
|
||||||
&mut running_plugin.store,
|
(new_rows as i32, new_columns as i32),
|
||||||
&[
|
)
|
||||||
Value::I32(new_rows as i32),
|
|
||||||
Value::I32(new_columns as i32),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.map_err(anyError::new)
|
|
||||||
})
|
|
||||||
.and_then(|_| {
|
|
||||||
wasi_read_string(&running_plugin.plugin_env.wasi_env)
|
|
||||||
})
|
})
|
||||||
|
.and_then(|_| wasi_read_string(running_plugin.store.data()))
|
||||||
.with_context(err_context);
|
.with_context(err_context);
|
||||||
match rendered_bytes {
|
match rendered_bytes {
|
||||||
Ok(rendered_bytes) => {
|
Ok(rendered_bytes) => {
|
||||||
@ -1078,12 +1072,13 @@ impl WasmBridge {
|
|||||||
};
|
};
|
||||||
|
|
||||||
running_plugin
|
running_plugin
|
||||||
.plugin_env
|
.store
|
||||||
|
.data_mut()
|
||||||
.set_permissions(HashSet::from_iter(permissions.clone()));
|
.set_permissions(HashSet::from_iter(permissions.clone()));
|
||||||
|
|
||||||
let mut permission_cache = PermissionCache::from_path_or_default(cache_path);
|
let mut permission_cache = PermissionCache::from_path_or_default(cache_path);
|
||||||
permission_cache.cache(
|
permission_cache.cache(
|
||||||
running_plugin.plugin_env.plugin.location.to_string(),
|
running_plugin.store.data().plugin.location.to_string(),
|
||||||
permissions,
|
permissions,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1278,30 +1273,25 @@ pub fn apply_event_to_plugin(
|
|||||||
senders: ThreadSenders,
|
senders: ThreadSenders,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let instance = &running_plugin.instance;
|
let instance = &running_plugin.instance;
|
||||||
let plugin_env = &running_plugin.plugin_env;
|
|
||||||
let rows = running_plugin.rows;
|
let rows = running_plugin.rows;
|
||||||
let columns = running_plugin.columns;
|
let columns = running_plugin.columns;
|
||||||
|
|
||||||
let err_context = || format!("Failed to apply event to plugin {plugin_id}");
|
let err_context = || format!("Failed to apply event to plugin {plugin_id}");
|
||||||
match check_event_permission(plugin_env, event) {
|
match check_event_permission(running_plugin.store.data(), event) {
|
||||||
(PermissionStatus::Granted, _) => {
|
(PermissionStatus::Granted, _) => {
|
||||||
let protobuf_event: ProtobufEvent = event
|
let protobuf_event: ProtobufEvent = event
|
||||||
.clone()
|
.clone()
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|e| anyhow!("Failed to convert to protobuf: {:?}", e))?;
|
.map_err(|e| anyhow!("Failed to convert to protobuf: {:?}", e))?;
|
||||||
let update = instance
|
let update = instance
|
||||||
.exports
|
.get_typed_func::<(), i32>(&mut running_plugin.store, "update")
|
||||||
.get_function("update")
|
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
wasi_write_object(&plugin_env.wasi_env, &protobuf_event.encode_to_vec())
|
wasi_write_object(running_plugin.store.data(), &protobuf_event.encode_to_vec())
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
let update_return = update
|
let should_render = update
|
||||||
.call(&mut running_plugin.store, &[])
|
.call(&mut running_plugin.store, ())
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
let mut should_render = match update_return.get(0) {
|
let mut should_render = should_render == 1;
|
||||||
Some(Value::I32(n)) => *n == 1,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
if let Event::PermissionRequestResult(..) = event {
|
if let Event::PermissionRequestResult(..) = event {
|
||||||
// we always render in this case, otherwise the request permission screen stays on
|
// we always render in this case, otherwise the request permission screen stays on
|
||||||
// screen
|
// screen
|
||||||
@ -1309,18 +1299,11 @@ pub fn apply_event_to_plugin(
|
|||||||
}
|
}
|
||||||
if rows > 0 && columns > 0 && should_render {
|
if rows > 0 && columns > 0 && should_render {
|
||||||
let rendered_bytes = instance
|
let rendered_bytes = instance
|
||||||
.exports
|
.get_typed_func::<(i32, i32), ()>(&mut running_plugin.store, "render")
|
||||||
.get_function("render")
|
|
||||||
.map_err(anyError::new)
|
|
||||||
.and_then(|render| {
|
.and_then(|render| {
|
||||||
render
|
render.call(&mut running_plugin.store, (rows as i32, columns as i32))
|
||||||
.call(
|
|
||||||
&mut running_plugin.store,
|
|
||||||
&[Value::I32(rows as i32), Value::I32(columns as i32)],
|
|
||||||
)
|
|
||||||
.map_err(anyError::new)
|
|
||||||
})
|
})
|
||||||
.and_then(|_| wasi_read_string(&plugin_env.wasi_env))
|
.and_then(|_| wasi_read_string(running_plugin.store.data()))
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
let pipes_to_block_or_unblock = pipes_to_block_or_unblock(running_plugin, None);
|
let pipes_to_block_or_unblock = pipes_to_block_or_unblock(running_plugin, None);
|
||||||
let plugin_render_asset = PluginRenderAsset::new(
|
let plugin_render_asset = PluginRenderAsset::new(
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -68,15 +68,15 @@ pub fn configure_logger() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Set the default logging level to "info" and log it to zellij.log file
|
// Set the default logging level to "info" and log it to zellij.log file
|
||||||
// Decrease verbosity for `wasmer_compiler_cranelift` module because it has a lot of useless info logs
|
// Decrease verbosity for `wasmtime_wasi` module because it has a lot of useless info logs
|
||||||
// For `zellij_server::logging_pipe`, we use custom format as we use logging macros to forward stderr output from plugins
|
// For `zellij_server::logging_pipe`, we use custom format as we use logging macros to forward stderr output from plugins
|
||||||
let config = Config::builder()
|
let config = Config::builder()
|
||||||
.appender(Appender::builder().build("logFile", Box::new(log_file)))
|
.appender(Appender::builder().build("logFile", Box::new(log_file)))
|
||||||
.appender(Appender::builder().build("logPlugin", Box::new(log_plugin)))
|
.appender(Appender::builder().build("logPlugin", Box::new(log_plugin)))
|
||||||
.logger(
|
.logger(
|
||||||
Logger::builder()
|
Logger::builder()
|
||||||
.appender("logFile")
|
.appender("logPlugin")
|
||||||
.build("wasmer_compiler_cranelift", LevelFilter::Warn),
|
.build("wasmtime_wasi", LevelFilter::Warn),
|
||||||
)
|
)
|
||||||
.logger(
|
.logger(
|
||||||
Logger::builder()
|
Logger::builder()
|
||||||
|
Loading…
Reference in New Issue
Block a user