1use crate::child_process::{
5 ChildProcess, KillSignal, SpawnArgs, SpawnOptions, spawn_with_args_and_options,
6};
7use crate::error::Error;
8use crate::node_sys::*;
9use crate::result::Result;
10use borsh::{BorshDeserialize, BorshSerialize};
11use futures::{FutureExt, select};
12use serde::{Deserialize, Serialize};
13use std::collections::VecDeque;
14use std::path::PathBuf;
15use std::sync::atomic::{AtomicBool, Ordering};
16use std::sync::{Arc, Mutex};
17use std::time::Duration;
18use wasm_bindgen::prelude::*;
19use workflow_core::channel::{Channel, Receiver, Sender, oneshot};
20use workflow_core::task::*;
21use workflow_core::time::Instant;
22use workflow_log::*;
23use workflow_task::*;
24use workflow_wasm::callback::*;
25use workflow_wasm::jserror::*;
26
27pub struct Version {
29 pub major: u64,
31 pub minor: u64,
33 pub patch: u64,
35 pub none: bool,
37}
38
39impl Version {
40 pub fn new(major: u64, minor: u64, patch: u64) -> Version {
42 Version {
43 major,
44 minor,
45 patch,
46 none: false,
47 }
48 }
49
50 pub fn none() -> Version {
52 Version {
53 major: 0,
54 minor: 0,
55 patch: 0,
56 none: true,
57 }
58 }
59}
60
61impl std::fmt::Display for Version {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 if self.none {
64 write!(f, "n/a")
65 } else {
66 write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
67 }
68 }
69}
70
71pub struct ExecutionResult {
73 pub termination: Termination,
75 pub stdout: String,
77 pub stderr: String,
79}
80
81impl ExecutionResult {
82 pub fn is_error(&self) -> bool {
84 matches!(self.termination, Termination::Error(_))
85 }
86}
87
88pub enum Termination {
90 Exit(u32),
92 Error(String),
94}
95
96#[derive(Debug, Clone, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
98pub enum Event {
99 Start,
101 Exit(u32),
103 Error(String),
105 Stdout(String),
107 Stderr(String),
109}
110
111pub struct Options {
113 argv: Vec<String>,
115 cwd: Option<PathBuf>,
117 restart: bool,
119 restart_delay: Duration,
121 use_force: bool,
126 use_force_delay: Duration,
128 events: Channel<Event>,
132 muted_buffer_capacity: Option<usize>,
133 mute: bool,
134}
135
136#[allow(clippy::too_many_arguments)]
137impl Options {
138 pub fn new(
142 argv: &[&str],
143 cwd: Option<PathBuf>,
144 restart: bool,
145 restart_delay: Option<Duration>,
146 use_force: bool,
147 use_force_delay: Option<Duration>,
148 events: Channel<Event>,
149 muted_buffer_capacity: Option<usize>,
150 mute: bool,
151 ) -> Options {
152 let argv = argv.iter().map(|s| s.to_string()).collect::<Vec<_>>();
153
154 Options {
155 argv,
156 cwd,
157 restart,
158 restart_delay: restart_delay.unwrap_or_default(),
159 use_force,
160 use_force_delay: use_force_delay.unwrap_or(Duration::from_millis(10_000)),
161 events,
162 muted_buffer_capacity,
163 mute,
164 }
165 }
166}
167
168impl Default for Options {
169 fn default() -> Self {
170 Self {
171 argv: Vec::new(),
172 cwd: None,
173 restart: true,
174 restart_delay: Duration::from_millis(3_000),
175 use_force: false,
176 use_force_delay: Duration::from_millis(10_000),
177 events: Channel::unbounded(),
178 muted_buffer_capacity: None,
179 mute: false,
180 }
181 }
182}
183
184struct Inner {
185 argv: Mutex<Vec<String>>,
186 cwd: Mutex<Option<PathBuf>>,
187 running: AtomicBool,
188 restart: AtomicBool,
189 restart_delay: Mutex<Duration>,
190 use_force: AtomicBool,
191 use_force_delay: Mutex<Duration>,
192 events: Channel<Event>,
193 proc: Arc<Mutex<Option<Arc<ChildProcess>>>>,
194 callbacks: CallbackMap,
195 start_time: Arc<Mutex<Option<Instant>>>,
196 mute: Arc<AtomicBool>,
197 muted_buffer_capacity: Option<usize>,
198 muted_buffer_stdout: Arc<Mutex<VecDeque<String>>>,
199 muted_buffer_stderr: Arc<Mutex<VecDeque<String>>>,
200}
201
202unsafe impl Send for Inner {}
203unsafe impl Sync for Inner {}
204
205impl Inner {
206 pub fn new(options: Options) -> Inner {
207 Inner {
208 argv: Mutex::new(options.argv),
209 cwd: Mutex::new(options.cwd),
210 running: AtomicBool::new(false),
211 restart: AtomicBool::new(options.restart),
212 restart_delay: Mutex::new(options.restart_delay),
213 use_force: AtomicBool::new(options.use_force),
214 use_force_delay: Mutex::new(options.use_force_delay),
215 events: options.events,
216 proc: Arc::new(Mutex::new(None)),
217 callbacks: CallbackMap::new(),
218 start_time: Arc::new(Mutex::new(None)),
219 mute: Arc::new(AtomicBool::new(options.mute)),
220 muted_buffer_capacity: options.muted_buffer_capacity,
221 muted_buffer_stdout: Arc::new(Mutex::new(VecDeque::default())),
222 muted_buffer_stderr: Arc::new(Mutex::new(VecDeque::default())),
223 }
224 }
225
226 fn program(&self) -> String {
227 self.argv.lock().unwrap().first().unwrap().clone()
228 }
229
230 fn args(&self) -> Vec<String> {
231 self.argv.lock().unwrap()[1..].to_vec()
232 }
233
234 fn cwd(&self) -> Option<PathBuf> {
235 self.cwd.lock().unwrap().clone()
236 }
237
238 pub fn uptime(&self) -> Option<Duration> {
239 if self.running.load(Ordering::SeqCst) {
240 self.start_time.lock().unwrap().map(|ts| ts.elapsed())
241 } else {
242 None
243 }
244 }
245
246 fn buffer_muted(&self, data: buffer::Buffer, muted_buffer: &Arc<Mutex<VecDeque<String>>>) {
247 let muted_buffer_capacity = self.muted_buffer_capacity.unwrap_or_default();
248 if muted_buffer_capacity > 0 {
249 let mut muted_buffer = muted_buffer.lock().unwrap();
250 let buffer = String::from(data.to_string(None, None, None));
251 let lines = buffer.split('\n').collect::<Vec<_>>();
252 for line in lines {
253 let line = line.trim();
254 if !line.is_empty() {
255 muted_buffer.push_back(trim(line.to_string()));
256 }
257 }
258 while muted_buffer.len() > muted_buffer_capacity {
259 muted_buffer.pop_front();
260 }
261 }
262 }
263
264 fn drain_muted(
265 &self,
266 acc: &Arc<Mutex<VecDeque<String>>>,
267 sender: &Sender<Event>,
268 stdout: bool,
269 ) -> Result<()> {
270 let mut acc = acc.lock().unwrap();
271 if stdout {
272 acc.drain(..).for_each(|line| {
273 sender.try_send(Event::Stdout(line)).unwrap();
274 });
275 } else {
276 acc.drain(..).for_each(|line| {
277 sender.try_send(Event::Stderr(line)).unwrap();
278 });
279 }
280 Ok(())
281 }
282
283 pub fn toggle_mute(&self) -> Result<bool> {
284 if self.mute.load(Ordering::SeqCst) {
285 self.mute.store(false, Ordering::SeqCst);
286 self.drain_muted(&self.muted_buffer_stdout, &self.events.sender, true)?;
287 self.drain_muted(&self.muted_buffer_stderr, &self.events.sender, false)?;
288 Ok(false)
289 } else {
290 self.mute.store(true, Ordering::SeqCst);
291 Ok(true)
292 }
293 }
294
295 pub fn mute(&self, mute: bool) -> Result<()> {
296 if mute != self.mute.load(Ordering::SeqCst) {
297 self.mute.store(mute, Ordering::SeqCst);
298 if !mute {
299 self.drain_muted(&self.muted_buffer_stdout, &self.events.sender, true)?;
300 self.drain_muted(&self.muted_buffer_stderr, &self.events.sender, false)?;
301 }
302 }
303
304 Ok(())
305 }
306
307 pub async fn run(self: &Arc<Self>, stop: Receiver<()>) -> Result<()> {
308 if self.running.load(Ordering::SeqCst) {
309 return Err(Error::AlreadyRunning);
310 }
311
312 'outer: loop {
313 let termination = Channel::<Termination>::oneshot();
314
315 self.start_time.lock().unwrap().replace(Instant::now());
316
317 let proc = {
318 let program = self.program();
319 let args = &self.args();
320
321 let args: SpawnArgs = args.as_slice().into();
322 let options = SpawnOptions::new();
323 if let Some(cwd) = &self.cwd() {
324 options.cwd(cwd.as_os_str().to_str().unwrap_or_else(|| {
325 panic!("Process::exec_with_args(): invalid path: {}", cwd.display())
326 }));
327 }
328
329 Arc::new(spawn_with_args_and_options(&program, &args, &options))
330 };
331
332 let this = self.clone();
333 let exit_sender = termination.sender.clone();
334 let exit = callback!(move |code: JsValue| {
335 let code = code.as_f64().unwrap_or_default() as u32;
336 this.events.sender.try_send(Event::Exit(code)).ok();
337 exit_sender
338 .try_send(Termination::Exit(code))
339 .expect("unable to send close notification");
340 });
341 proc.on("exit", exit.as_ref());
342 self.callbacks.retain(exit.clone())?;
343
344 let this = self.clone();
345 let error_sender = termination.sender.clone();
346 let error = callback!(move |err: JsValue| {
347 let msg = JsErrorData::from(err);
348 this.events
349 .sender
350 .try_send(Event::Error(msg.to_string()))
351 .ok();
352 error_sender
353 .try_send(Termination::Error(msg.to_string()))
354 .expect("unable to send close notification");
355 });
356 proc.on("error", error.as_ref());
357 self.callbacks.retain(error.clone())?;
358
359 let this = self.clone();
360 let stdout_cb = callback!(move |data: buffer::Buffer| {
361 if this.mute.load(Ordering::SeqCst) {
362 this.buffer_muted(data, &this.muted_buffer_stdout);
363 } else {
364 this.events
365 .sender
366 .try_send(Event::Stdout(String::from(
367 data.to_string(None, None, None),
368 )))
369 .unwrap();
370 }
371 });
372 proc.stdout().on("data", stdout_cb.as_ref());
373 self.callbacks.retain(stdout_cb)?;
374
375 let this = self.clone();
376 let stderr_cb = callback!(move |data: buffer::Buffer| {
377 if this.mute.load(Ordering::SeqCst) {
378 this.buffer_muted(data, &this.muted_buffer_stderr);
379 } else {
380 this.events
381 .sender
382 .try_send(Event::Stderr(String::from(
383 data.to_string(None, None, None),
384 )))
385 .unwrap();
386 }
387 });
388 proc.stderr().on("data", stderr_cb.as_ref());
389 self.callbacks.retain(stderr_cb)?;
390
391 *self.proc.lock().unwrap() = Some(proc.clone());
392 self.running.store(true, Ordering::SeqCst);
393
394 self.events.sender.try_send(Event::Start).unwrap();
395
396 let kill = select! {
397 e = termination.receiver.recv().fuse() => {
399
400 if matches!(e,Ok(Termination::Error(_))) {
402 break;
403 }
404
405 if !self.restart.load(Ordering::SeqCst) {
407 break;
408 } else {
409 let restart_delay = *self.restart_delay.lock().unwrap();
411 select! {
412 _ = sleep(restart_delay).fuse() => {
414 false
415 },
416 _ = stop.recv().fuse() => {
418 break;
419 }
420 }
421 }
422 },
423 _ = stop.recv().fuse() => {
425 true
426 }
427 };
428
429 if kill {
430 self.restart.store(false, Ordering::SeqCst);
432 proc.kill_with_signal(KillSignal::SIGTERM);
433 if !self.use_force.load(Ordering::SeqCst) {
435 termination.receiver.recv().await?;
436 break;
437 } else {
438 let use_force_delay = sleep(*self.use_force_delay.lock().unwrap());
440 select! {
441 _ = termination.receiver.recv().fuse() => {
443 break 'outer;
444 },
445 _ = use_force_delay.fuse() => {
447 proc.kill_with_signal(KillSignal::SIGKILL);
448 termination.receiver.recv().await?;
449 break 'outer;
450 },
451 }
452 }
453 }
454 }
455
456 self.callbacks.clear();
457 *self.proc.lock().unwrap() = None;
458 self.running.store(false, Ordering::SeqCst);
459
460 Ok(())
461 }
462}
463
464#[derive(Clone)]
469pub struct Process {
470 inner: Arc<Inner>,
471 task: Arc<Task<Arc<Inner>, ()>>,
472}
473
474unsafe impl Send for Process {}
475unsafe impl Sync for Process {}
476
477impl Process {
478 pub fn new(options: Options) -> Process {
480 let inner = Arc::new(Inner::new(options));
481
482 let task = task!(|inner: Arc<Inner>, stop| async move {
483 inner.run(stop).await.ok();
484 });
485
486 Process {
487 inner,
488 task: Arc::new(task),
489 }
490 }
491
492 pub fn new_once(path: &str) -> Process {
495 let options = Options::new(
496 &[path],
497 None,
498 false,
499 None,
500 false,
501 None,
504 Channel::unbounded(),
505 None,
506 false,
507 );
508
509 Self::new(options)
510 }
511
512 pub async fn version(path: &str) -> Result<Version> {
514 version(path).await
515 }
516
517 pub fn is_running(&self) -> bool {
519 self.inner.running.load(Ordering::SeqCst)
520 }
521
522 pub fn mute(&self, mute: bool) -> Result<()> {
524 self.inner.mute(mute)
525 }
526
527 pub fn toggle_mute(&self) -> Result<bool> {
529 self.inner.toggle_mute()
530 }
531
532 pub fn uptime(&self) -> Option<Duration> {
534 self.inner.uptime()
535 }
536
537 pub fn events(&self) -> Receiver<Event> {
540 self.inner.events.receiver.clone()
541 }
542
543 pub fn replace_argv(&self, argv: Vec<String>) {
545 *self.inner.argv.lock().unwrap() = argv;
546 }
547
548 pub fn run(&self) -> Result<()> {
552 self.task.run(self.inner.clone())?;
553 Ok(())
554 }
555
556 pub fn kill(&self) -> Result<()> {
558 if !self.inner.running.load(Ordering::SeqCst) {
559 Err(Error::NotRunning)
560 } else if let Some(proc) = self.inner.proc.lock().unwrap().as_ref() {
561 self.inner.restart.store(false, Ordering::SeqCst);
562 proc.kill_with_signal(KillSignal::SIGKILL);
563 Ok(())
564 } else {
565 Err(Error::ProcIsAbsent)
566 }
567 }
568
569 pub fn restart(&self) -> Result<()> {
572 if !self.inner.running.load(Ordering::SeqCst) {
573 Err(Error::NotRunning)
574 } else if let Some(proc) = self.inner.proc.lock().unwrap().as_ref() {
575 proc.kill_with_signal(KillSignal::SIGTERM);
576 Ok(())
577 } else {
578 Err(Error::ProcIsAbsent)
579 }
580 }
581
582 pub fn stop(&self) -> Result<()> {
586 if self.inner.running.load(Ordering::SeqCst) {
587 self.inner.restart.store(false, Ordering::SeqCst);
588 self.task.stop()?;
589 }
590
591 Ok(())
592 }
593
594 pub async fn join(&self) -> Result<()> {
597 if self.task.is_running() {
598 self.task.join().await?;
599 }
600 Ok(())
601 }
602
603 pub async fn stop_and_join(&self) -> Result<()> {
605 self.stop()?;
606 self.join().await?;
607 Ok(())
608 }
609}
610
611pub async fn exec(
615 argv: &[&str],
617 cwd: Option<PathBuf>,
618) -> Result<ExecutionResult> {
619 let proc = *argv.first().unwrap();
620
621 let args: SpawnArgs = argv[1..].into();
622 let options = SpawnOptions::new();
623 if let Some(cwd) = cwd {
624 options.cwd(cwd.as_os_str().to_str().unwrap_or_else(|| {
625 panic!("Process::exec_with_args(): invalid path: {}", cwd.display())
626 }));
627 }
628
629 let termination = Channel::<Termination>::oneshot();
630 let (stdout_tx, stdout_rx) = oneshot();
631 let (stderr_tx, stderr_rx) = oneshot();
632
633 let cp = spawn_with_args_and_options(proc, &args, &options);
634
635 let exit = termination.sender.clone();
636 let exit = callback!(move |code: u32| {
637 exit.try_send(Termination::Exit(code))
638 .expect("unable to send close notification");
639 });
640 cp.on("exit", exit.as_ref());
641
642 let error = termination.sender.clone();
643 let error = callback!(move |err: JsValue| {
644 error
645 .try_send(Termination::Error(format!("{:?}", err)))
646 .expect("unable to send close notification");
647 });
648 cp.on("error", error.as_ref());
649
650 let stdout_cb = callback!(move |data: buffer::Buffer| {
651 stdout_tx
652 .try_send(String::from(data.to_string(None, None, None)))
653 .expect("unable to send stdout data");
654 });
655 cp.stdout().on("data", stdout_cb.as_ref());
656
657 let stderr_cb = callback!(move |data: buffer::Buffer| {
658 stderr_tx
659 .try_send(String::from(data.to_string(None, None, None)))
660 .expect("unable to send stderr data");
661 });
662 cp.stderr().on("data", stderr_cb.as_ref());
663
664 let termination = termination.recv().await?;
665
666 let mut stdout = String::new();
667 for _ in 0..stdout_rx.len() {
668 stdout.push_str(&stdout_rx.try_recv()?);
669 }
670
671 let mut stderr = String::new();
672 for _ in 0..stderr_rx.len() {
673 stderr.push_str(&stdout_rx.try_recv()?);
674 }
675
676 Ok(ExecutionResult {
677 termination,
678 stdout,
679 stderr,
680 })
681}
682
683pub async fn version(proc: &str) -> Result<Version> {
685 let text = exec([proc, "--version"].as_slice(), None).await?.stdout;
686 let vstr = if let Some(vstr) = text.split_whitespace().last() {
687 vstr
688 } else {
689 return Ok(Version::none());
690 };
691
692 let v = vstr
693 .split('.')
694 .flat_map(|v| v.parse::<u64>())
695 .collect::<Vec<_>>();
696
697 if v.len() != 3 {
698 return Ok(Version::none());
699 }
700
701 Ok(Version::new(v[0], v[1], v[2]))
702}
703
704pub fn trim(mut s: String) -> String {
706 if s.ends_with('\n') {
708 s.pop();
709 if s.ends_with('\r') {
710 s.pop();
711 }
712 }
713 s
714}
715
716pub async fn test_child_process() {
719 log_info!("running rust test() fn");
720 workflow_wasm::panic::init_console_panic_hook();
721
722 let proc = Process::new(Options::new(
723 &["/Users/aspect/dev/kaspa-dev/kaspad/kaspad"],
724 None,
725 true,
726 Some(Duration::from_millis(3000)),
727 true,
728 Some(Duration::from_millis(100)),
729 Channel::unbounded(),
730 None,
731 false,
732 ));
733 let task = task!(|events: Receiver<Event>, stop: Receiver<()>| async move {
735 loop {
736 select! {
737 v = events.recv().fuse() => {
738 if let Ok(v) = v {
739 log_info!("| {:?}",v);
740 }
741 },
742 _ = stop.recv().fuse() => {
743 log_info!("stop...");
744 break;
745 }
746 }
747 log_info!("in loop");
748 }
749 });
750 task.run(proc.events()).expect("task.run()");
751
752 proc.run().expect("proc.run()");
753
754 sleep(Duration::from_millis(5_000)).await;
755
756 proc.stop_and_join()
757 .await
758 .expect("proc.stop_and_join() failure");
759 task.stop_and_join()
760 .await
761 .expect("task.stop_and_join() failure");
762}