use crate::py_element::PyElement;
use crate::py_stream::PyStream;
use pyo3::prelude::*;
use pyo3::types::{PyBytes, PyList};
use std::rc::Rc;
use std::time::Duration;
use wingfoil::adapters::aeron::{
AeronHandle, AeronMode, AeronPub, AeronSubOptions, FragmentBuffer, TransportError,
aeron_sub_fragment,
};
use wingfoil::{Burst, Node, Stream, StreamOperators};
#[pyclass(eq, eq_int, name = "AeronMode", from_py_object)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PyAeronMode {
Spin,
Threaded,
}
impl From<PyAeronMode> for AeronMode {
fn from(m: PyAeronMode) -> Self {
match m {
PyAeronMode::Spin => AeronMode::Spin,
PyAeronMode::Threaded => AeronMode::Threaded,
}
}
}
fn connect_timeout(timeout_secs: f64) -> Duration {
Duration::from_secs_f64(timeout_secs)
}
#[pyfunction]
#[pyo3(signature = (channel, stream_id, mode=PyAeronMode::Spin, timeout_secs=5.0))]
pub fn py_aeron_sub(
channel: String,
stream_id: i32,
mode: PyAeronMode,
timeout_secs: f64,
) -> PyResult<PyStream> {
let handle = AeronHandle::connect()
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
let subscriber = handle
.subscription(&channel, stream_id, connect_timeout(timeout_secs))
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
let data: Rc<dyn Stream<Burst<Vec<u8>>>> = aeron_sub_fragment(
subscriber,
|f: &FragmentBuffer<'_>| -> Result<Option<Vec<u8>>, TransportError> {
Ok(Some(f.as_ref().to_vec()))
},
AeronSubOptions {
mode: mode.into(),
..Default::default()
},
);
let data_py = data.map(|burst| {
Python::attach(|py| {
let items: Vec<Py<PyAny>> = burst
.into_iter()
.map(|b| PyBytes::new(py, &b).into_any().unbind())
.collect();
PyElement::new(PyList::new(py, items).unwrap().into_any().unbind())
})
});
Ok(PyStream(data_py))
}
pub fn py_aeron_pub_inner(
stream: &Rc<dyn Stream<PyElement>>,
channel: String,
stream_id: i32,
timeout_secs: f64,
) -> PyResult<Rc<dyn Node>> {
let handle = AeronHandle::connect()
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
let publisher = handle
.publication(&channel, stream_id, connect_timeout(timeout_secs))
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
let bytes_stream: Rc<dyn Stream<Vec<u8>>> = stream.map(|elem| {
Python::attach(|py| {
elem.as_ref().extract::<Vec<u8>>(py).unwrap_or_else(|e| {
log::error!("aeron_pub: stream value is not bytes: {e}");
Vec::new()
})
})
});
let burst_stream: Rc<dyn Stream<Burst<Vec<u8>>>> =
bytes_stream.map(|b| std::iter::once(b).collect::<Burst<Vec<u8>>>());
Ok(burst_stream.aeron_pub(publisher, |b: &Vec<u8>| b.clone()))
}