1use crate::Pyo3Docker;
2use chrono::{DateTime, Utc};
3use docker_api::opts::{LogsOpts, ServiceListOpts};
4use docker_api::{Service, Services};
5use futures_util::stream::StreamExt;
6use pyo3::exceptions;
7use pyo3::prelude::*;
8use pyo3::types::PyDateTime;
9use pythonize::pythonize;
10
11#[pymodule]
12pub fn service(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
13 m.add_class::<Pyo3Services>()?;
14 m.add_class::<Pyo3Service>()?;
15 Ok(())
16}
17
18#[derive(Debug)]
22#[pyclass(name = "Services")]
23pub struct Pyo3Services {
24 services: Services,
25}
26
27#[derive(Debug)]
31#[pyclass(name = "Service")]
32pub struct Pyo3Service {
33 service: Service,
34}
35
36#[pymethods]
37impl Pyo3Services {
38 #[new]
39 pub fn new(docker: Pyo3Docker) -> Self {
40 Pyo3Services {
41 services: Services::new(docker.0),
42 }
43 }
44
45 pub fn get(&self, id: &str) -> Pyo3Service {
53 Pyo3Service {
54 service: self.services.get(id),
55 }
56 }
57
58 pub fn list(&self) -> PyResult<Py<PyAny>> {
66 let rv = __services_list(&self.services, &Default::default());
67
68 match rv {
69 Ok(rv) => Ok(pythonize_this!(rv)),
70 Err(rv) => Err(py_sys_exception!(rv)),
71 }
72 }
73}
74
75#[tokio::main]
76async fn __services_list(
77 services: &Services,
78 opts: &ServiceListOpts,
79) -> Result<Vec<docker_api::models::Service>, docker_api::Error> {
80 services.list(opts).await
81}
82
83#[pymethods]
84impl Pyo3Service {
85 #[new]
86 pub fn new(docker: Pyo3Docker, id: &str) -> Self {
87 Pyo3Service {
88 service: Service::new(docker.0, id),
89 }
90 }
91
92 pub fn id(&self) -> String {
97 self.service.name().to_string()
98 }
99
100 pub fn inspect(&self) -> PyResult<Py<PyAny>> {
108 let rv = __service_inspect(&self.service);
109
110 match rv {
111 Ok(rv) => Ok(pythonize_this!(rv)),
112 Err(rv) => Err(py_sys_exception!(rv)),
113 }
114 }
115
116 pub fn delete(&self) -> PyResult<()> {
124 let rv = __service_delete(&self.service);
125 match rv {
126 Ok(rv) => Ok(rv),
127 Err(rv) => Err(py_sys_exception!(rv)),
128 }
129 }
130
131 #[pyo3(signature = (stdout=None, stderr=None, timestamps=None, n_lines=None, all=None, since=None))]
144 pub fn logs(
145 &self,
146 stdout: Option<bool>,
147 stderr: Option<bool>,
148 timestamps: Option<bool>,
149 n_lines: Option<usize>,
150 all: Option<bool>,
151 since: Option<&Bound<'_, PyDateTime>>,
152 ) -> String {
153 let mut log_opts = LogsOpts::builder();
154
155 bo_setter!(stdout, log_opts);
156 bo_setter!(stderr, log_opts);
157 bo_setter!(timestamps, log_opts);
158 bo_setter!(n_lines, log_opts);
159
160 if all.is_some() && all.unwrap() {
161 log_opts = log_opts.all();
162 }
163
164 if since.is_some() {
165 let rs_since: DateTime<Utc> = since.unwrap().extract().unwrap();
166 log_opts = log_opts.since(&rs_since);
167 }
168
169 __service_logs(&self.service, &log_opts.build())
170 }
171}
172
173#[tokio::main]
174async fn __service_inspect(
175 service: &Service,
176) -> Result<docker_api::models::Service, docker_api::Error> {
177 service.inspect().await
178}
179
180#[tokio::main]
181async fn __service_delete(service: &Service) -> Result<(), docker_api::Error> {
182 service.delete().await
183}
184
185#[tokio::main]
186async fn __service_logs(service: &Service, log_opts: &LogsOpts) -> String {
187 let log_stream = service.logs(log_opts);
188
189 let log = log_stream
190 .map(|chunk| match chunk {
191 Ok(chunk) => chunk.to_vec(),
192 Err(e) => {
193 eprintln!("Error: {e}");
194 vec![]
195 }
196 })
197 .collect::<Vec<_>>()
198 .await
199 .into_iter()
200 .flatten()
201 .collect::<Vec<_>>();
202
203 format!("{}", String::from_utf8_lossy(&log))
204}