use pyo3::{Borrowed, FromPyObject, PyAny, PyErr, PyResult, types::PyAnyMethods};
use crate::py_value_err;
pub struct ServeConfigArg(pub tailscale::ServeConfig);
impl<'py> FromPyObject<'_, 'py> for ServeConfigArg {
type Error = PyErr;
fn extract(ob: Borrowed<'_, 'py, PyAny>) -> PyResult<Self> {
let name: String = ob.get_item("name")?.extract()?;
let port: u16 = ob.get_item("port")?.extract()?;
let target_item = ob.get_item("target")?;
let target = extract_target(target_item.as_borrowed())?;
Ok(ServeConfigArg(tailscale::ServeConfig {
name,
port,
target,
}))
}
}
fn extract_target(ob: Borrowed<'_, '_, PyAny>) -> PyResult<tailscale::ServeTarget> {
if let Ok(s) = ob.extract::<String>() {
return match s.as_str() {
"accept" => Ok(tailscale::ServeTarget::Accept),
other => Err(py_value_err(format!(
"unknown serve target {other:?}; expected \"accept\" or {{\"proxy\": \"host:port\"}}"
))),
};
}
if let Ok(to_item) = ob.get_item("proxy") {
let to: String = to_item.extract()?;
return Ok(tailscale::ServeTarget::Proxy { to });
}
Err(py_value_err(
"serve target must be \"accept\" or {\"proxy\": \"host:port\"}",
))
}
pub struct ServiceModeArg(pub tailscale::ServiceMode);
impl<'py> FromPyObject<'_, 'py> for ServiceModeArg {
type Error = PyErr;
fn extract(ob: Borrowed<'_, 'py, PyAny>) -> PyResult<Self> {
let port: u16 = ob.get_item("port")?.extract()?;
let mode: String = ob.get_item("mode")?.extract()?;
let mode = match mode.as_str() {
"tcp" => tailscale::ServiceMode::Tcp { port },
"http" => tailscale::ServiceMode::Http { port },
other => {
return Err(py_value_err(format!(
"unknown service mode {other:?}; expected \"tcp\" or \"http\""
)));
}
};
Ok(ServiceModeArg(mode))
}
}