1use log::error;
24use nuts_backend::{Backend, Binary, Create, IdSize, Open, ReceiveHeader, HEADER_MAX_SIZE};
25use nuts_tool_api::tool::{Plugin, PluginConnection, PluginError};
26use std::cell::RefCell;
27use std::collections::HashMap;
28use std::str::FromStr;
29use std::{cmp, fmt};
30
31thread_local! {
32 static ID_SIZE: RefCell<usize> = RefCell::new(0);
33 static CONN: RefCell<Option<PluginConnection>> = RefCell::new(None);
34}
35
36fn setup_connection(mut connection: PluginConnection) -> Result<(), PluginError> {
37 let id_size = connection.id_size()?;
38
39 ID_SIZE.with(|size| *size.borrow_mut() = id_size);
40 CONN.with(|cell| *cell.borrow_mut() = Some(connection));
41
42 Ok(())
43}
44
45fn with_connection<T, F: FnOnce(&mut PluginConnection) -> Result<T, PluginError>>(
46 f: F,
47) -> Result<T, PluginError> {
48 CONN.with_borrow_mut(|opt| match opt.as_mut() {
49 Some(conn) => f(conn),
50 None => Err(PluginError::NotConnected),
51 })
52}
53
54#[derive(Clone, Debug)]
55pub struct PluginSettings(Vec<u8>);
56
57impl Binary for PluginSettings {
58 fn from_bytes(bytes: &[u8]) -> Option<PluginSettings> {
59 Some(PluginSettings(bytes.to_vec()))
60 }
61
62 fn as_bytes(&self) -> Vec<u8> {
63 self.0.clone()
64 }
65}
66
67#[derive(Clone, Debug, PartialEq)]
68pub struct PluginId(Vec<u8>);
69
70impl Binary for PluginId {
71 fn from_bytes(bytes: &[u8]) -> Option<PluginId> {
72 Some(PluginId(bytes.to_vec()))
73 }
74
75 fn as_bytes(&self) -> Vec<u8> {
76 self.0.clone()
77 }
78}
79
80impl IdSize for PluginId {
81 fn size() -> usize {
82 ID_SIZE.with(|n| *n.borrow())
83 }
84}
85
86impl FromStr for PluginId {
87 type Err = PluginError;
88
89 fn from_str(s: &str) -> Result<PluginId, PluginError> {
90 let bytes = with_connection(|conn| conn.id_string_to_bytes(s.to_string()))?;
91
92 Ok(PluginId(bytes))
93 }
94}
95
96impl fmt::Display for PluginId {
97 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
98 match with_connection(|conn| conn.id_bytes_to_string(self.0.clone())) {
99 Ok(s) => fmt.write_str(&s),
100 Err(_) => fmt.write_str("???"),
101 }
102 }
103}
104
105pub struct PluginBackendOpenBuilder;
106
107impl PluginBackendOpenBuilder {
108 pub fn new(
109 plugin: Plugin,
110 name: &str,
111 verbose: u8,
112 ) -> Result<PluginBackendOpenBuilder, PluginError> {
113 setup_connection(plugin.open(name, verbose)?)?;
114
115 Ok(PluginBackendOpenBuilder)
116 }
117}
118
119impl ReceiveHeader<PluginBackend> for PluginBackendOpenBuilder {
120 fn get_header_bytes(&mut self, bytes: &mut [u8; HEADER_MAX_SIZE]) -> Result<(), PluginError> {
121 let header = with_connection(|conn| conn.read_header())?;
122
123 bytes.copy_from_slice(&header[..HEADER_MAX_SIZE]);
124
125 Ok(())
126 }
127}
128
129impl Open<PluginBackend> for PluginBackendOpenBuilder {
130 fn build(self, settings: PluginSettings) -> Result<PluginBackend, PluginError> {
131 with_connection(|conn| conn.open(settings.0.clone()))?;
132
133 PluginBackend::new()
134 }
135}
136
137pub struct PluginBackendCreateBuilder {
138 settings: Vec<u8>,
139}
140
141impl PluginBackendCreateBuilder {
142 pub fn new(
143 plugin: Plugin,
144 name: &str,
145 verbose: u8,
146 extra_args: &[String],
147 ) -> Result<PluginBackendCreateBuilder, PluginError> {
148 setup_connection(plugin.create(name, verbose, extra_args)?)?;
149
150 let settings = with_connection(|conn| conn.settings())?;
151
152 Ok(PluginBackendCreateBuilder { settings })
153 }
154}
155
156impl Create<PluginBackend> for PluginBackendCreateBuilder {
157 fn settings(&self) -> PluginSettings {
158 PluginSettings(self.settings.clone())
159 }
160
161 fn build(
162 self,
163 header: [u8; HEADER_MAX_SIZE],
164 overwrite: bool,
165 ) -> Result<PluginBackend, PluginError> {
166 with_connection(|conn| conn.create(header.to_vec(), overwrite))?;
167
168 PluginBackend::new()
169 }
170}
171
172#[derive(Debug)]
173pub struct PluginBackend {
174 block_size: u32,
175}
176
177impl PluginBackend {
178 fn new() -> Result<PluginBackend, PluginError> {
179 let block_size = with_connection(|conn| conn.block_size())?;
180
181 Ok(PluginBackend { block_size })
182 }
183}
184
185impl ReceiveHeader<PluginBackend> for PluginBackend {
186 fn get_header_bytes(&mut self, bytes: &mut [u8; HEADER_MAX_SIZE]) -> Result<(), PluginError> {
187 let header = with_connection(|conn| conn.read_header())?;
188
189 bytes.copy_from_slice(&header[..HEADER_MAX_SIZE]);
190
191 Ok(())
192 }
193}
194
195impl Backend for PluginBackend {
196 type Settings = PluginSettings;
197 type Err = PluginError;
198 type Id = PluginId;
199 type Info = HashMap<String, String>;
200
201 fn info(&self) -> Result<Self::Info, PluginError> {
202 with_connection(|conn| conn.info())
203 }
204
205 fn block_size(&self) -> u32 {
206 self.block_size
207 }
208
209 fn aquire(&mut self, buf: &[u8]) -> Result<PluginId, PluginError> {
210 let id = with_connection(|conn| conn.aquire(buf.to_vec()))?;
211
212 Ok(PluginId(id))
213 }
214
215 fn release(&mut self, id: PluginId) -> Result<(), PluginError> {
216 with_connection(|conn| conn.release(id.0))
217 }
218
219 fn read(&mut self, id: &PluginId, buf: &mut [u8]) -> Result<usize, PluginError> {
220 let bytes = with_connection(|conn| conn.read(id.0.clone()))?;
221
222 let n = cmp::min(bytes.len(), buf.len());
223 buf.copy_from_slice(&bytes);
224
225 Ok(n)
226 }
227
228 fn write(&mut self, id: &PluginId, buf: &[u8]) -> Result<usize, PluginError> {
229 with_connection(|conn| conn.write(id.0.clone(), buf.to_vec()))
230 }
231
232 fn write_header(&mut self, buf: &[u8; HEADER_MAX_SIZE]) -> Result<(), PluginError> {
233 with_connection(|conn| conn.write_header(buf.to_vec()))
234 }
235
236 fn delete(self) {
237 if let Err(err) = with_connection(|conn| conn.delete()) {
238 error!("failed to delete backend instance: {}", err);
239 }
240 }
241}
242
243impl Drop for PluginBackend {
244 fn drop(&mut self) {
245 if let Err(err) = with_connection(|conn| conn.quit()) {
246 error!("failed to quit connection to plugin: {}", err);
247 };
248 }
249}