wapc/wapchost/
modulestate_async.rs

1use log::info;
2use tokio::sync::RwLock;
3
4use crate::{HostCallbackAsync, Invocation};
5
6#[derive(Default)]
7/// Module state is essentially a 'handle' that is passed to a runtime engine to allow it
8/// to read and write relevant data as different low-level functions are executed during
9/// a waPC conversation
10///
11/// This version of `ModuleState` is designed for use in async contexts
12pub struct ModuleStateAsync {
13  pub(crate) guest_request: RwLock<Option<Invocation>>,
14  pub(crate) guest_response: RwLock<Option<Vec<u8>>>,
15  pub(crate) host_response: RwLock<Option<Vec<u8>>>,
16  pub(crate) guest_error: RwLock<Option<String>>,
17  pub(crate) host_error: RwLock<Option<String>>,
18  pub(crate) host_callback: Option<Box<HostCallbackAsync>>,
19  pub(crate) id: u64,
20}
21
22impl ModuleStateAsync {
23  pub(crate) fn new(host_callback: Option<Box<HostCallbackAsync>>, id: u64) -> ModuleStateAsync {
24    ModuleStateAsync {
25      host_callback,
26      id,
27      guest_request: RwLock::new(None),
28      guest_response: RwLock::new(None),
29      host_response: RwLock::new(None),
30      guest_error: RwLock::new(None),
31      host_error: RwLock::new(None),
32    }
33  }
34}
35
36impl ModuleStateAsync {
37  /// Retrieves the value, if any, of the current guest request
38  pub async fn get_guest_request(&self) -> Option<Invocation> {
39    self.guest_request.read().await.clone()
40  }
41
42  /// Retrieves the value of the current host response
43  pub async fn get_host_response(&self) -> Option<Vec<u8>> {
44    self.host_response.read().await.clone()
45  }
46
47  /// Sets a value indicating that an error occurred inside the execution of a guest call
48  pub async fn set_guest_error(&self, error: String) {
49    *self.guest_error.write().await = Some(error);
50  }
51
52  /// Sets the value indicating the response data from a guest call
53  pub async fn set_guest_response(&self, response: Vec<u8>) {
54    *self.guest_response.write().await = Some(response);
55  }
56
57  /// Queries the value of the current guest response
58  pub async fn get_guest_response(&self) -> Option<Vec<u8>> {
59    self.guest_response.read().await.clone()
60  }
61
62  /// Queries the value of the current host error
63  pub async fn get_host_error(&self) -> Option<String> {
64    self.host_error.read().await.clone()
65  }
66
67  /// Invoked when the guest module wishes to make a call on the host
68  pub async fn do_host_call(
69    &self,
70    binding: String,
71    namespace: String,
72    operation: String,
73    payload: Vec<u8>,
74  ) -> Result<i32, Box<dyn std::error::Error>> {
75    let id = {
76      *self.host_response.write().await = None;
77      *self.host_error.write().await = None;
78      self.id
79    };
80    let result = match self.host_callback.as_ref() {
81      None => Err("Missing host callback function!".into()),
82      Some(f) => f(id, binding, namespace, operation, payload).await,
83    };
84    Ok(match result {
85      Ok(v) => {
86        *self.host_response.write().await = Some(v);
87        1
88      }
89      Err(e) => {
90        *self.host_error.write().await = Some(format!("{}", e));
91        0
92      }
93    })
94  }
95
96  /// Invoked when the guest module wants to write a message to the host's `stdout`
97  pub fn do_console_log(&self, msg: &str) {
98    info!("Guest module {}: {}", self.id, msg);
99  }
100}
101
102impl std::fmt::Debug for ModuleStateAsync {
103  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104    f.debug_struct("ModuleState")
105      .field("guest_request", &self.guest_request)
106      .field("guest_response", &self.guest_response)
107      .field("host_response", &self.host_response)
108      .field("guest_error", &self.guest_error)
109      .field("host_error", &self.host_error)
110      .field("host_callback", &self.host_callback.as_ref().map(|_| Some("Some(Fn)")))
111      .field("id", &self.id)
112      .finish()
113  }
114}