bulletin_board_client/
lib.rs

1use std::time::Duration;
2use bbclient::{adaptor::VecShape, DataType};
3use num_complex::Complex64;
4use pyo3::prelude::*;
5
6/// Sets the server address.
7#[pyfunction]
8fn set_addr(addr: String) -> PyResult<()> {
9    bbclient::set_addr(&addr);
10    Ok(())
11}
12
13/// Sets timeout for TCP connections in msec. If the argument is None, timeout is disabled (default).
14#[pyfunction]
15#[pyo3(signature = (timeout=None))]
16fn set_timeout(timeout: Option<u64>) -> PyResult<()> {
17    bbclient::set_timeout(timeout.map(|t| Duration::from_millis(t)));
18    Ok(())
19}
20
21#[pyfunction]
22fn post_integer(title: String, tag: String, val: i128) -> PyResult<()> {
23    let obj = val.try_into().unwrap();
24    bbclient::post(&title, &tag, obj).unwrap();
25    Ok(())
26}
27
28#[pyfunction]
29fn post_real(title: String, tag: String, val: f64) -> PyResult<()> {
30    let obj = val.try_into().unwrap();
31    bbclient::post(&title, &tag, obj).unwrap();
32    Ok(())
33}
34
35#[pyfunction]
36fn post_complex(title: String, tag: String, val: Complex64) -> PyResult<()> {
37    let obj = val.try_into().unwrap();
38    bbclient::post(&title, &tag, obj).unwrap();
39    Ok(())
40}
41
42#[pyfunction]
43fn post_string(title: String, tag: String, val: String) -> PyResult<()> {
44    let obj = val.try_into().unwrap();
45    bbclient::post(&title, &tag, obj).unwrap();
46    Ok(())
47}
48
49#[pyfunction]
50fn post_integer_array(title: String, tag: String, val: Vec<i128>, shape: Vec<u64>) -> PyResult<()> {
51    let obj = VecShape(val, shape).try_into().unwrap();
52    bbclient::post(&title, &tag, obj).unwrap();
53    Ok(())
54}
55
56#[pyfunction]
57fn post_real_array(title: String, tag: String, val: Vec<f64>, shape: Vec<u64>) -> PyResult<()> {
58    let obj = VecShape(val, shape).try_into().unwrap();
59    bbclient::post(&title, &tag, obj).unwrap();
60    Ok(())
61}
62
63#[pyfunction]
64fn post_complex_array(
65    title: String,
66    tag: String,
67    val: Vec<Complex64>,
68    shape: Vec<u64>,
69) -> PyResult<()> {
70    let obj = VecShape(val, shape).try_into().unwrap();
71    bbclient::post(&title, &tag, obj).unwrap();
72    Ok(())
73}
74
75#[pyfunction]
76fn post_string_array(
77    title: String,
78    tag: String,
79    val: Vec<String>,
80    shape: Vec<u64>,
81) -> PyResult<()> {
82    let obj = VecShape(val, shape).try_into().unwrap();
83    bbclient::post(&title, &tag, obj).unwrap();
84    Ok(())
85}
86
87#[pyfunction]
88#[pyo3(signature = (title, tag=None, revisions=None))]
89fn read_raw(
90    py: Python<'_>,
91    title: String,
92    tag: Option<String>,
93    revisions: Option<Vec<u64>>,
94) -> PyResult<PyObject> {
95    let revisions = match revisions {
96        Some(rev) => rev,
97        None => vec![],
98    };
99
100    let list = bbclient::read(&title, tag.as_deref(), revisions).unwrap();
101    let mut res = vec![];
102    for elem in list {
103        match elem.datatype() {
104            DataType::UnsignedInteger => {
105                if elem.dimension() == 0 {
106                    let val: u128 = elem.try_into().unwrap();
107                    res.push(val.to_object(py));
108                } else {
109                    let VecShape::<u128>(val, shape) = elem.try_into().unwrap();
110                    let shape: Vec<usize> =
111                        shape.into_iter().map(|x| x.try_into().unwrap()).collect();
112                    res.push((val, shape).to_object(py));
113                }
114            }
115            DataType::SignedInteger => {
116                if elem.dimension() == 0 {
117                    let val: i128 = elem.try_into().unwrap();
118                    res.push(val.to_object(py));
119                } else {
120                    let VecShape::<i128>(val, shape) = elem.try_into().unwrap();
121                    let shape: Vec<usize> =
122                        shape.into_iter().map(|x| x.try_into().unwrap()).collect();
123                    res.push((val, shape).to_object(py));
124                }
125            }
126            DataType::Real => {
127                if elem.dimension() == 0 {
128                    let val: f64 = elem.try_into().unwrap();
129                    res.push(val.to_object(py));
130                } else {
131                    let VecShape::<f64>(val, shape) = elem.try_into().unwrap();
132                    let shape: Vec<usize> =
133                        shape.into_iter().map(|x| x.try_into().unwrap()).collect();
134                    res.push((val, shape).to_object(py));
135                }
136            }
137            DataType::Complex => {
138                if elem.dimension() == 0 {
139                    let val: Complex64 = elem.try_into().unwrap();
140                    res.push(val.to_object(py));
141                } else {
142                    let VecShape::<Complex64>(val, shape) = elem.try_into().unwrap();
143                    res.push((val, shape).to_object(py));
144                }
145            }
146            DataType::String => {
147                if elem.dimension() == 0 {
148                    let val: String = elem.try_into().unwrap();
149                    res.push(val.to_object(py));
150                } else {
151                    let VecShape::<String>(val, shape) = elem.try_into().unwrap();
152                    res.push((val, shape).to_object(py));
153                }
154            }
155        }
156    }
157    Ok(res.to_object(py))
158}
159
160/// Relabels a bulletin.
161#[pyfunction]
162#[pyo3(signature = (title_from, tag_from=None, title_to=None, tag_to=None))]
163fn relabel(
164    title_from: String,
165    tag_from: Option<String>,
166    title_to: Option<String>,
167    tag_to: Option<String>,
168) -> PyResult<()> {
169    bbclient::relabel(
170        &title_from,
171        tag_from.as_deref(),
172        title_to.as_deref(),
173        tag_to.as_deref(),
174    )
175    .unwrap();
176    Ok(())
177}
178
179/// Returns the version of the client.
180#[pyfunction]
181fn client_version(py: Python<'_>) -> PyResult<PyObject> {
182    let client_version = env!("CARGO_PKG_VERSION").to_string();
183    Ok(client_version.to_object(py))
184}
185
186/// Returns the version of the server.
187#[pyfunction]
188fn server_version(py: Python<'_>) -> PyResult<PyObject> {
189    let server_version = bbclient::server_version().unwrap();
190    Ok(server_version.to_object(py))
191}
192
193/// Returns the status of the server.
194#[pyfunction]
195fn status_raw(py: Python<'_>) -> PyResult<PyObject> {
196    Ok(bbclient::status().unwrap().to_object(py))
197}
198
199/// Returns the log of the server.
200#[pyfunction]
201fn log(py: Python<'_>) -> PyResult<PyObject> {
202    Ok(bbclient::log().unwrap().to_object(py))
203}
204
205#[pyfunction]
206fn view_board_raw(py: Python<'_>) -> PyResult<PyObject> {
207    Ok(bbclient::view_board().unwrap().to_object(py))
208}
209
210#[pyfunction]
211#[pyo3(signature = (title, tag=None))]
212fn get_info_raw(py: Python<'_>, title: String, tag: Option<String>) -> PyResult<PyObject> {
213    Ok(bbclient::get_info(&title, tag.as_deref())
214        .unwrap()
215        .to_object(py))
216}
217
218#[pyfunction]
219#[pyo3(signature = (title, revisions, tag=None))]
220fn clear_revisions_raw(title: String, revisions: Vec<u64>, tag: Option<String>) -> PyResult<()> {
221    bbclient::clear_revisions(&title, tag.as_deref(), revisions).unwrap();
222    Ok(())
223}
224
225/// Removes all the revisions and the database entry of a bulletin.
226#[pyfunction]
227#[pyo3(signature = (title, tag=None))]
228fn remove(title: String, tag: Option<String>) -> PyResult<()> {
229    bbclient::remove(&title, tag.as_deref()).unwrap();
230    Ok(())
231}
232
233/// Moves a bulletin to a persistent archive.
234#[pyfunction]
235#[pyo3(signature = (acv_name, title, tag=None))]
236fn archive(acv_name: String, title: String, tag: Option<String>) -> PyResult<()> {
237    bbclient::archive(&acv_name, &title, tag.as_deref()).unwrap();
238    Ok(())
239}
240
241/// Loads or reloads an archive. The data is directly read from the archive file and a suffix "acv_name:" is added to the tag.
242#[pyfunction]
243fn load(acv_name: String) -> PyResult<()> {
244    bbclient::load(&acv_name).unwrap();
245    Ok(())
246}
247
248/// Shows the list of archive.
249#[pyfunction]
250fn list_archive(py: Python<'_>) -> PyResult<PyObject> {
251    Ok(bbclient::list_archive().unwrap().to_object(py))
252}
253
254/// Renames an archive. This will be applied after after calling reset_server.
255#[pyfunction]
256fn rename_archive(name_from: String, name_to: String) -> PyResult<()> {
257    bbclient::rename_archive(&name_from, &name_to).unwrap();
258    Ok(())
259}
260
261/// Deletes an archive. This will be applied after after calling reset_server.
262#[pyfunction]
263fn delete_archive(acv_name: String) -> PyResult<()> {
264    bbclient::delete_archive(&acv_name).unwrap();
265    Ok(())
266}
267
268/// Dumps all the unarchived data into an archive.
269#[pyfunction]
270fn dump(acv_name: String) -> PyResult<()> {
271    bbclient::dump(&acv_name).unwrap();
272    Ok(())
273}
274
275/// Delete all the temporary data and restores data from an archive. Each data is copied to memory or a separate file. No suffix is added to the tag.
276#[pyfunction]
277fn restore(acv_name: String) -> PyResult<()> {
278    bbclient::restore(&acv_name).unwrap();
279    Ok(())
280}
281
282/// Clears the log file of the server.
283#[pyfunction]
284fn clear_log() -> PyResult<()> {
285    bbclient::clear_log().unwrap();
286    Ok(())
287}
288
289/// Resets and clears the data. The archived data is not affected, but must be loaded before use.
290#[pyfunction]
291fn reset_server() -> PyResult<()> {
292    bbclient::reset_server().unwrap();
293    Ok(())
294}
295
296/// Terminates the server.
297#[pyfunction]
298fn terminate_server() -> PyResult<()> {
299    bbclient::terminate_server().unwrap();
300    Ok(())
301}
302
303/// BulletinBoard python client
304#[pymodule]
305fn bulletin_board_client(m: &Bound<'_, PyModule>) -> PyResult<()> {
306    m.add_function(wrap_pyfunction!(set_addr, m)?)?;
307    m.add_function(wrap_pyfunction!(set_timeout, m)?)?;
308    m.add_function(wrap_pyfunction!(post_integer, m)?)?;
309    m.add_function(wrap_pyfunction!(post_real, m)?)?;
310    m.add_function(wrap_pyfunction!(post_complex, m)?)?;
311    m.add_function(wrap_pyfunction!(post_string, m)?)?;
312    m.add_function(wrap_pyfunction!(post_integer_array, m)?)?;
313    m.add_function(wrap_pyfunction!(post_real_array, m)?)?;
314    m.add_function(wrap_pyfunction!(post_complex_array, m)?)?;
315    m.add_function(wrap_pyfunction!(post_string_array, m)?)?;
316    m.add_function(wrap_pyfunction!(read_raw, m)?)?;
317    m.add_function(wrap_pyfunction!(relabel, m)?)?;
318    m.add_function(wrap_pyfunction!(client_version, m)?)?;
319    m.add_function(wrap_pyfunction!(server_version, m)?)?;
320    m.add_function(wrap_pyfunction!(status_raw, m)?)?;
321    m.add_function(wrap_pyfunction!(log, m)?)?;
322    m.add_function(wrap_pyfunction!(view_board_raw, m)?)?;
323    m.add_function(wrap_pyfunction!(get_info_raw, m)?)?;
324    m.add_function(wrap_pyfunction!(clear_revisions_raw, m)?)?;
325    m.add_function(wrap_pyfunction!(remove, m)?)?;
326    m.add_function(wrap_pyfunction!(archive, m)?)?;
327    m.add_function(wrap_pyfunction!(load, m)?)?;
328    m.add_function(wrap_pyfunction!(list_archive, m)?)?;
329    m.add_function(wrap_pyfunction!(rename_archive, m)?)?;
330    m.add_function(wrap_pyfunction!(delete_archive, m)?)?;
331    m.add_function(wrap_pyfunction!(dump, m)?)?;
332    m.add_function(wrap_pyfunction!(restore, m)?)?;
333    m.add_function(wrap_pyfunction!(clear_log, m)?)?;
334    m.add_function(wrap_pyfunction!(reset_server, m)?)?;
335    m.add_function(wrap_pyfunction!(terminate_server, m)?)?;
336    Ok(())
337}