wasmer_cli/commands/run/
runtime.rs1use std::{sync::Arc, time::Duration};
4
5use anyhow::Error;
6use futures::future::BoxFuture;
7use indicatif::ProgressBar;
8use std::io::IsTerminal as _;
9use wasmer::{Engine, Module};
10use wasmer_config::package::PackageSource;
11use wasmer_types::ModuleHash;
12use wasmer_wasix::{
13 SpawnError,
14 bin_factory::{BinaryPackage, BinaryPackageCommand},
15 runtime::{
16 ModuleInput,
17 module_cache::{
18 HashedModuleData,
19 progress::{ModuleLoadProgress, ModuleLoadProgressReporter},
20 },
21 resolver::{PackageSummary, QueryError},
22 },
23};
24use webc::Container;
25
26#[derive(Debug)]
31pub struct MonitoringRuntime<R> {
32 pub runtime: Arc<R>,
33 progress: ProgressBar,
34 quiet_mode: bool,
35}
36
37impl<R> MonitoringRuntime<R> {
38 pub fn new(runtime: R, progress: ProgressBar, quiet_mode: bool) -> Self {
39 MonitoringRuntime {
40 runtime: Arc::new(runtime),
41 progress,
42 quiet_mode,
43 }
44 }
45}
46
47impl<R: wasmer_wasix::Runtime + Send + Sync> wasmer_wasix::Runtime for MonitoringRuntime<R> {
48 fn networking(&self) -> &virtual_net::DynVirtualNetworking {
49 self.runtime.networking()
50 }
51
52 fn task_manager(&self) -> &Arc<dyn wasmer_wasix::VirtualTaskManager> {
53 self.runtime.task_manager()
54 }
55
56 fn package_loader(
57 &self,
58 ) -> Arc<dyn wasmer_wasix::runtime::package_loader::PackageLoader + Send + Sync> {
59 let inner = self.runtime.package_loader();
60 Arc::new(MonitoringPackageLoader {
61 inner,
62 progress: self.progress.clone(),
63 })
64 }
65
66 fn module_cache(
67 &self,
68 ) -> Arc<dyn wasmer_wasix::runtime::module_cache::ModuleCache + Send + Sync> {
69 self.runtime.module_cache()
70 }
71
72 fn source(&self) -> Arc<dyn wasmer_wasix::runtime::resolver::Source + Send + Sync> {
73 let inner = self.runtime.source();
74 Arc::new(MonitoringSource {
75 inner,
76 progress: self.progress.clone(),
77 })
78 }
79
80 fn engine(&self) -> Engine {
81 self.runtime.engine()
82 }
83
84 fn new_store(&self) -> wasmer::Store {
85 self.runtime.new_store()
86 }
87
88 fn http_client(&self) -> Option<&wasmer_wasix::http::DynHttpClient> {
89 self.runtime.http_client()
90 }
91
92 fn tty(&self) -> Option<&(dyn wasmer_wasix::os::TtyBridge + Send + Sync)> {
93 self.runtime.tty()
94 }
95
96 fn additional_imports(
97 &self,
98 module: &Module,
99 store: &mut wasmer::StoreMut,
100 ) -> anyhow::Result<(wasmer::Imports, wasmer_wasix::runtime::InstantiationState)> {
101 self.runtime.additional_imports(module, store)
102 }
103
104 fn prepare_imports(
105 &self,
106 module: &Module,
107 store: &mut wasmer::StoreMut,
108 imports: &mut wasmer::Imports,
109 ) -> anyhow::Result<wasmer_wasix::runtime::InstantiationState> {
110 self.runtime.prepare_imports(module, store, imports)
111 }
112
113 fn configure_new_instance(
114 &self,
115 module: &Module,
116 store: &mut wasmer::StoreMut,
117 instance: &wasmer::Instance,
118 imported_memory: Option<&wasmer::Memory>,
119 state: wasmer_wasix::runtime::InstantiationState,
120 ) -> anyhow::Result<()> {
121 self.runtime
122 .configure_new_instance(module, store, instance, imported_memory, state)
123 }
124
125 #[cfg(feature = "journal")]
126 fn read_only_journals<'a>(
127 &'a self,
128 ) -> Box<dyn Iterator<Item = Arc<wasmer_wasix::journal::DynReadableJournal>> + 'a> {
129 self.runtime.read_only_journals()
130 }
131
132 #[cfg(feature = "journal")]
133 fn writable_journals<'a>(
134 &'a self,
135 ) -> Box<dyn Iterator<Item = Arc<wasmer_wasix::journal::DynJournal>> + 'a> {
136 self.runtime.writable_journals()
137 }
138
139 #[cfg(feature = "journal")]
140 fn active_journal(&self) -> Option<&'_ wasmer_wasix::journal::DynJournal> {
141 self.runtime.active_journal()
142 }
143
144 fn resolve_module<'a>(
145 &'a self,
146 input: ModuleInput<'a>,
147 engine: Option<&Engine>,
148 on_progress: Option<ModuleLoadProgressReporter>,
149 ) -> BoxFuture<'a, Result<Module, SpawnError>> {
150 if on_progress.is_some() || self.quiet_mode {
153 return self.runtime.resolve_module(input, engine, on_progress);
154 }
155
156 use std::fmt::Write as _;
159
160 let short_hash = input.hash().short_hash();
161 let progress_msg = match &input {
162 ModuleInput::Bytes(_) | ModuleInput::Hashed(_) => {
163 format!("Compiling module ({short_hash})")
164 }
165 ModuleInput::Command(cmd) => format!("Compiling {}", cmd.name()),
166 };
167
168 let pb = self.progress.clone();
169
170 let on_progress = Some(ModuleLoadProgressReporter::new({
171 let base_msg = progress_msg.clone();
172 move |prog| {
173 let msg = match prog {
174 ModuleLoadProgress::CompilingModule(c) => {
175 let mut msg = base_msg.clone();
176 if let (Some(step), Some(step_count)) =
177 (c.phase_step(), c.phase_step_count())
178 {
179 pb.set_length(step_count);
180 pb.set_position(step);
181 if step_count != 0 {
183 write!(
184 &mut msg,
185 " ({:.0}%)",
186 100.0 * step as f32 / step_count as f32
187 )
188 .unwrap();
189 }
190 };
191 pb.tick();
192
193 msg
194 }
195 _ => base_msg.clone(),
196 };
197
198 pb.set_message(msg);
199 Ok(())
200 }
201 }));
202
203 let engine = engine.cloned();
204
205 let style = indicatif::ProgressStyle::default_bar()
206 .template("{spinner} {wide_bar:.cyan/blue} {msg}")
207 .expect("invalid progress bar template");
208 self.progress.set_style(style);
209
210 self.progress.reset();
211 if self.progress.is_hidden() {
212 self.progress
213 .set_draw_target(indicatif::ProgressDrawTarget::stderr());
214 }
215 self.progress.set_message(progress_msg);
216
217 let f = async move {
218 let res = self
219 .runtime
220 .resolve_module(input, engine.as_ref(), on_progress)
221 .await;
222
223 self.progress
226 .set_style(indicatif::ProgressStyle::default_spinner());
227 self.progress.reset();
228 self.progress.finish_and_clear();
229
230 res
231 };
232
233 Box::pin(f)
234 }
235}
236
237#[derive(Debug)]
238struct MonitoringSource {
239 inner: Arc<dyn wasmer_wasix::runtime::resolver::Source + Send + Sync>,
240 progress: ProgressBar,
241}
242
243#[async_trait::async_trait]
244impl wasmer_wasix::runtime::resolver::Source for MonitoringSource {
245 async fn query(&self, package: &PackageSource) -> Result<Vec<PackageSummary>, QueryError> {
246 self.progress.set_message(format!("Looking up {package}"));
247 self.inner.query(package).await
248 }
249}
250
251#[derive(Debug)]
252struct MonitoringPackageLoader {
253 inner: Arc<dyn wasmer_wasix::runtime::package_loader::PackageLoader + Send + Sync>,
254 progress: ProgressBar,
255}
256
257#[async_trait::async_trait]
258impl wasmer_wasix::runtime::package_loader::PackageLoader for MonitoringPackageLoader {
259 async fn load(&self, summary: &PackageSummary) -> Result<Container, Error> {
260 let pkg_id = summary.package_id();
261 self.progress.set_message(format!("Downloading {pkg_id}"));
262
263 self.inner.load(summary).await
264 }
265
266 async fn load_package_tree(
267 &self,
268 root: &Container,
269 resolution: &wasmer_wasix::runtime::resolver::Resolution,
270 root_is_local_dir: bool,
271 ) -> Result<BinaryPackage, Error> {
272 self.inner
273 .load_package_tree(root, resolution, root_is_local_dir)
274 .await
275 }
276}