ouch_bindings_python 5.0.1

Python bindings for the OUCH protocol
Documentation
use links_bindings_python::prelude::*;
use links_nonblocking::prelude::*;
use log::info;
use ouch_connect_nonblocking::prelude::*;
use pyo3::{prelude::*, types::PyDict};
use serde::Serialize;
use std::{num::NonZeroUsize, time::Duration};

use crate::{DEFAULT_CONNECT_TIMEOUT, DEFAULT_IO_TIMEOUT, DEFAULT_MAX_CONNECTIONS, DEFAULT_MAX_HBEAT_INTERVAL, DEFAULT_USR_PWD};

create_callback_for_messenger!(SvcOuchProtocolManual, SvcOuchProtocolManualCallback);
create_svc_sender!(SvcManual, SvcOuchSender, SvcOuchProtocolManual, SvcOuchProtocolManualCallback, "ouch_connect");

#[derive(Serialize)]
struct SvcManualConfig {
    pub max_connections: NonZeroUsize,
    pub io_timeout: f64,
    pub name: String,
}
impl Default for SvcManualConfig {
    fn default() -> Self {
        Self {
            max_connections: DEFAULT_MAX_CONNECTIONS,
            io_timeout: DEFAULT_IO_TIMEOUT,
            name: asserted_short_name!("SvcManual", SvcManual).to_owned(),
        }
    }
}
impl From<&PyDict> for SvcManualConfig {
    fn from(py_dict: &PyDict) -> Self {
        let default = Self::default();
        let max_connections = py_dict.get_item("max_connections").unwrap().map_or(default.max_connections, |any| any.extract::<NonZeroUsize>().unwrap());
        let io_timeout = py_dict.get_item("io_timeout").unwrap().map_or(default.io_timeout, |any| any.extract::<f64>().unwrap());
        let name = py_dict.get_item("name").unwrap().map_or(default.name, |any| any.extract::<String>().unwrap());
        Self { max_connections, io_timeout, name }
    }
}

#[pymethods]
impl SvcManual {
    #[new]
    #[pyo3(signature = (host, callback, **kwargs))]
    fn new(_py: Python<'_>, host: &str, callback: PyObject, kwargs: Option<&PyDict>) -> PyResult<Py<Self>> {
        let config = kwargs.map_or(SvcManualConfig::default(), SvcManualConfig::from);
        info!("{}: effective config: {} with kwargs: {:?}", asserted_short_name!("SvcManual", Self), serde_json::to_string(&config).unwrap(), kwargs);
        let sender = {
            let svc_callback = SvcOuchProtocolManualCallback::new_ref(callback.clone());
            let protocol = SvcOuchProtocolManual::default();
            let sender = _py.allow_threads(move || SvcOuch::bind(host, config.max_connections, svc_callback, protocol, Some(&config.name)))?.into_sender_with_spawned_recver();
            let con_id = sender.con_id().clone();
            Py::new(
                _py,
                Self {
                    sender: Some(sender).into(),
                    con_id,
                    io_timeout: Some(config.io_timeout),
                },
            )?
        };
        patch_callback_if_settable_sender!(_py, sender, callback, asserted_short_name!("SvcManual", Self));

        Ok(sender)
    }
    #[classattr]
    fn msg_samples() -> Vec<String> {
        ouch_connect_nonblocking::prelude::svc_ouch_default_msgs().iter().map(|m| serde_json::to_string(m).unwrap()).collect::<Vec<_>>()
    }
}

create_callback_for_messenger!(SvcOuchProtocolAuto, SvcOuchProtocolAutoCallback);
create_svc_sender!(SvcAuto, SvcOuchSenderRef, SvcOuchProtocolAuto, SvcOuchProtocolAutoCallback, "ouch_connect");

#[derive(Serialize)]
struct SvcAutoConfig {
    pub username: String,
    pub password: String,
    pub session_id: String,
    pub clt_max_hbeat_interval: f64,
    pub svc_max_hbeat_interval: f64,
    pub connect_timeout: f64,
    pub max_connections: NonZeroUsize,
    pub io_timeout: f64,
    pub name: String,
}
impl Default for SvcAutoConfig {
    fn default() -> Self {
        Self {
            username: DEFAULT_USR_PWD.to_owned(),
            password: DEFAULT_USR_PWD.to_owned(),
            session_id: "".to_owned(),
            clt_max_hbeat_interval: DEFAULT_MAX_HBEAT_INTERVAL,
            svc_max_hbeat_interval: DEFAULT_MAX_HBEAT_INTERVAL,
            connect_timeout: DEFAULT_CONNECT_TIMEOUT,
            max_connections: DEFAULT_MAX_CONNECTIONS,
            io_timeout: DEFAULT_IO_TIMEOUT,
            name: asserted_short_name!("SvcAuto", SvcAuto).to_owned(),
        }
    }
}
impl From<&PyDict> for SvcAutoConfig {
    fn from(value: &PyDict) -> Self {
        let default = Self::default();
        let username = value.get_item("username").unwrap().map_or(default.username, |any| any.extract::<String>().unwrap());
        let password = value.get_item("password").unwrap().map_or(default.password, |any| any.extract::<String>().unwrap());
        let session_id = value.get_item("session_id").unwrap().map_or(default.session_id, |any| any.extract::<String>().unwrap());
        let clt_max_hbeat_interval = value.get_item("clt_max_hbeat_interval").unwrap().map_or(default.clt_max_hbeat_interval, |any| any.extract::<f64>().unwrap());
        let svc_max_hbeat_interval = value.get_item("svc_max_hbeat_interval").unwrap().map_or(default.svc_max_hbeat_interval, |any| any.extract::<f64>().unwrap());
        let connect_timeout = value.get_item("connect_timeout").unwrap().map_or(default.connect_timeout, |any| any.extract::<f64>().unwrap());
        let max_connections = value.get_item("max_connections").unwrap().map_or(default.max_connections, |any| any.extract::<NonZeroUsize>().unwrap());
        let io_timeout = value.get_item("io_timeout").unwrap().map_or(default.io_timeout, |any| any.extract::<f64>().unwrap());
        let name = value.get_item("name").unwrap().map_or(default.name, |any| any.extract::<String>().unwrap());
        Self {
            username,
            password,
            session_id,
            clt_max_hbeat_interval,
            svc_max_hbeat_interval,
            connect_timeout,
            max_connections,
            io_timeout,
            name,
        }
    }
}

#[pymethods]
impl SvcAuto {
    #[new]
    #[pyo3(signature = (host, callback, **kwargs))]
    fn new(_py: Python<'_>, host: &str, callback: PyObject, kwargs: Option<&PyDict>) -> PyResult<Py<Self>> {
        let config = kwargs.map_or(SvcAutoConfig::default(), SvcAutoConfig::from);
        info!("{}: effective config: {} with kwargs: {:?}", asserted_short_name!("SvcAuto", Self), serde_json::to_string(&config).unwrap(), kwargs);
        let sender = {
            // let max_connections = max_connections.unwrap_or(NonZeroUsize::new(1).unwrap());
            let callback = SvcOuchProtocolAutoCallback::new_ref(callback.clone());
            let protocol = SvcOuchProtocolAuto::new(
                UserName::from(config.username.as_str()),
                Password::from(config.password.as_str()),
                SessionId::from(config.session_id.as_str()),
                Duration::from_secs_f64(config.io_timeout),
                Duration::from_secs_f64(config.clt_max_hbeat_interval),
                Duration::from_secs_f64(config.svc_max_hbeat_interval),
            );
            let sender = _py.allow_threads(move || SvcOuch::bind(host, config.max_connections, callback, protocol, Some(&config.name)))?.into_sender_with_spawned_recver_ref();
            let con_id = sender.con_id().clone();
            Py::new(
                _py,
                Self {
                    sender: Some(sender).into(),
                    con_id,
                    io_timeout: Some(config.io_timeout),
                },
            )?
        };
        patch_callback_if_settable_sender!(_py, sender, callback, asserted_short_name!("SvcAuto", Self));
        Ok(sender)
    }

    #[classattr]
    fn msg_samples() -> Vec<String> {
        ouch_connect_nonblocking::prelude::svc_ouch_default_msgs().iter().map(|m| serde_json::to_string(m).unwrap()).collect::<Vec<_>>()
    }
}