rktk_rrp_client_webhid/
lib.rs1use 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}