rktk_rrp_client_webhid/
lib.rs

1use async_lock::Mutex;
2use client::{HidReader, HidWriter};
3use futures::StreamExt;
4
5use log::info;
6use rktk_rrp::endpoints::*;
7use wasm_bindgen::prelude::*;
8use web_sys::HidDevice;
9
10mod client;
11
12#[wasm_bindgen(start)]
13pub fn main() {
14    use log::Level;
15    console_log::init_with_level(Level::Trace).expect("error initializing log");
16    info!("rrp-client-web started!");
17}
18
19#[wasm_bindgen]
20pub struct Client {
21    client: Mutex<rktk_rrp::client::Client<HidReader, HidWriter, 1024>>,
22}
23
24#[derive(serde::Serialize, serde::Deserialize, tsify_next::Tsify)]
25#[tsify(into_wasm_abi, from_wasm_abi)]
26pub struct VecGetKeymapsStreamResponse(pub Vec<KeyActionLoc>);
27
28#[derive(serde::Serialize, serde::Deserialize, tsify_next::Tsify, Default)]
29pub struct LogEntry {
30    time: u64,
31    level: get_log::LogLevel,
32    message: String,
33    line: Option<u32>,
34}
35#[derive(serde::Serialize, serde::Deserialize, tsify_next::Tsify)]
36#[tsify(into_wasm_abi, from_wasm_abi)]
37pub struct VecLogEntry(pub Vec<LogEntry>);
38
39#[wasm_bindgen]
40impl Client {
41    #[wasm_bindgen(constructor)]
42    pub fn new(device: HidDevice) -> Self {
43        Client {
44            client: Mutex::new(rktk_rrp::client::Client::new(
45                HidReader::new(device.clone()),
46                HidWriter::new(device.clone()),
47            )),
48        }
49    }
50
51    #[wasm_bindgen]
52    pub async fn get_keyboard_info(&self) -> Result<get_keyboard_info::Response, String> {
53        self.client
54            .lock()
55            .await
56            .get_keyboard_info(())
57            .await
58            .map_err(|e| format!("{:?}", e))
59    }
60
61    #[wasm_bindgen]
62    pub async fn get_keymaps(&self) -> Result<VecGetKeymapsStreamResponse, String> {
63        let mut serial = self.client.lock().await;
64        let stream = serial
65            .get_keymaps(())
66            .await
67            .map_err(|e| format!("{:?}", e))?;
68        Ok(VecGetKeymapsStreamResponse(
69            stream
70                .filter_map(|i| async { i.ok() })
71                .collect::<Vec<_>>()
72                .await,
73        ))
74    }
75
76    #[wasm_bindgen]
77    pub async fn get_layout_json(&self) -> Result<String, String> {
78        let mut serial = self.client.lock().await;
79        let stream = serial
80            .get_layout_json(())
81            .await
82            .map_err(|e| format!("{:?}", e))?;
83        let mut stream = core::pin::pin!(stream);
84
85        let mut chunks = vec![];
86        while let Some(res) = stream.next().await {
87            match res {
88                Ok(chunk) => {
89                    chunks.extend_from_slice(&chunk);
90                }
91                Err(e) => {
92                    return Err(format!("{:?}", e));
93                }
94            }
95        }
96
97        let string = String::from_utf8(chunks).map_err(|e| e.to_string())?;
98
99        Ok(string)
100    }
101
102    #[wasm_bindgen]
103    pub async fn set_keymaps(&mut self, keymaps: Vec<set_keymaps::Request>) -> Result<(), String> {
104        let mut serial = self.client.lock().await;
105        serial
106            .set_keymaps(futures::stream::iter(keymaps.into_iter()))
107            .await
108            .map_err(|e| format!("{:?}", e))?;
109        Ok(())
110    }
111
112    #[wasm_bindgen]
113    pub async fn get_keymap_config(&self) -> Result<get_keymap_config::Response, String> {
114        let mut serial = self.client.lock().await;
115        serial
116            .get_keymap_config(())
117            .await
118            .map_err(|e| format!("{:?}", e))
119    }
120
121    #[wasm_bindgen]
122    pub async fn set_keymap_config(
123        &mut self,
124        keymap_config: set_keymap_config::Request,
125    ) -> Result<set_keymap_config::Response, String> {
126        let mut serial = self.client.lock().await;
127        serial
128            .set_keymap_config(keymap_config)
129            .await
130            .map_err(|e| format!("{:?}", e))
131    }
132
133    #[wasm_bindgen]
134    pub async fn get_now(&self) -> Result<u64, String> {
135        let mut serial = self.client.lock().await;
136        serial.get_now(()).await.map_err(|e| format!("{:?}", e))
137    }
138
139    #[wasm_bindgen]
140    pub async fn get_log(&self) -> Result<VecLogEntry, String> {
141        let mut serial = self.client.lock().await;
142        let stream = serial.get_log(()).await.map_err(|e| format!("{:?}", e))?;
143        let mut stream = std::pin::pin!(stream);
144
145        let mut logs = Vec::new();
146        let mut log = LogEntry::default();
147        let mut log_bytes = Vec::new();
148        while let Some(Ok(chunk)) = stream.next().await {
149            match chunk {
150                get_log::LogChunk::Start { time, level, line } => {
151                    log.time = time;
152                    log.level = level;
153                    log.line = line;
154                }
155                get_log::LogChunk::Bytes { bytes, len } => {
156                    log_bytes.extend_from_slice(&bytes[..len as usize]);
157                }
158                get_log::LogChunk::End => {
159                    let Ok(message) =
160                        String::from_utf8(log_bytes.clone()).map_err(|e| e.to_string())
161                    else {
162                        continue;
163                    };
164                    log.message = message;
165                    logs.push(log);
166
167                    log = LogEntry::default();
168                    log_bytes.clear();
169                }
170            }
171        }
172        Ok(VecLogEntry(logs))
173    }
174}