comfyui_api/api/
mod.rs

1use reqwest::Url;
2
3pub mod history;
4pub mod prompt;
5pub mod upload;
6pub mod view;
7pub mod websocket;
8
9pub use history::*;
10pub use prompt::*;
11pub use upload::*;
12pub use view::*;
13pub use websocket::*;
14
15/// Errors that can occur opening API endpoints.
16#[derive(thiserror::Error, Debug)]
17#[non_exhaustive]
18pub enum ApiError {
19    /// Error parsing endpoint URL
20    #[error("Failed to parse endpoint URL")]
21    ParseError(#[from] url::ParseError),
22    /// Error creating Prompt API
23    #[error("Failed create prompt API")]
24    CreatePromptApiFailed(#[from] PromptApiError),
25    /// Error creating History API
26    #[error("Failed create history API")]
27    CreateHistoryApiFailed(#[from] HistoryApiError),
28    /// Error creating Upload API
29    #[error("Failed create upload API")]
30    CreateUploadApiFailed(#[from] UploadApiError),
31    /// Error creating View API
32    #[error("Failed create view API")]
33    CreateViewApiFailed(#[from] ViewApiError),
34    /// Error parsing WebSocket endpoint API
35    #[error("Failed parse websocket endpoint URL")]
36    ParseWebSocketEndpointError(#[source] url::ParseError),
37    /// Error setting WebSocket scheme
38    #[error("Failed to set scheme: ws://{url}")]
39    SetWebSocketSchemeFailed { url: url::Url },
40}
41
42type Result<T> = std::result::Result<T, ApiError>;
43
44/// Struct representing a connection to a ComfyUI API.
45#[derive(Clone, Debug)]
46pub struct Api {
47    client: reqwest::Client,
48    url: Url,
49    client_id: uuid::Uuid,
50}
51
52impl Default for Api {
53    fn default() -> Self {
54        Self::new().expect("Failed to parse default URL")
55    }
56}
57
58impl Api {
59    /// Returns a new `Api` instance with default settings.
60    pub fn new() -> Result<Self> {
61        Ok(Self {
62            client: reqwest::Client::new(),
63            url: Url::parse("http://localhost:8188")?,
64            client_id: uuid::Uuid::new_v4(),
65        })
66    }
67
68    /// Returns a new `Api` instance with the given URL as a string value.
69    ///
70    /// # Arguments
71    ///
72    /// * `url` - A string that specifies the ComfyUI API URL endpoint.
73    ///
74    /// # Errors
75    ///
76    /// If the URL fails to parse, an error will be returned.
77    pub fn new_with_url<S>(url: S) -> Result<Self>
78    where
79        S: AsRef<str>,
80    {
81        Ok(Self {
82            url: Url::parse(url.as_ref())?,
83            ..Default::default()
84        })
85    }
86
87    /// Returns a new `Api` instance with the given `reqwest::Client` and URL as a string value.
88    ///
89    /// # Arguments
90    ///
91    /// * `client` - An instance of `reqwest::Client`.
92    /// * `url` - A string that specifies the ComfyUI API URL endpoint.
93    ///
94    /// # Errors
95    ///
96    /// If the URL fails to parse, an error will be returned.
97    pub fn new_with_client_and_url<S>(client: reqwest::Client, url: S) -> Result<Self>
98    where
99        S: AsRef<str>,
100    {
101        Ok(Self {
102            client,
103            url: Url::parse(url.as_ref())?,
104            ..Default::default()
105        })
106    }
107
108    /// Returns a new instance of `PromptApi` with the API's cloned
109    /// `reqwest::Client` and the URL for the `prompt` endpoint.
110    ///
111    /// # Errors
112    ///
113    /// If the URL fails to parse, an error will be returned.
114    pub fn prompt(&self) -> Result<PromptApi> {
115        self.prompt_with_client(self.client_id)
116    }
117
118    /// Returns a new instance of `PromptApi` with the API's cloned
119    /// `reqwest::Client` and the URL for the `prompt` endpoint and the
120    /// specified client id.
121    ///
122    /// # Arguments
123    ///
124    /// * `client_id` - A `uuid::Uuid` representing the client id to use for the request.
125    ///
126    /// # Errors
127    ///
128    /// If the URL fails to parse, an error will be returned.
129    pub fn prompt_with_client(&self, client_id: uuid::Uuid) -> Result<PromptApi> {
130        Ok(PromptApi::new_with_url(
131            self.client.clone(),
132            self.url.join("prompt")?,
133            client_id,
134        ))
135    }
136
137    /// Returns a new instance of `HistoryApi` with the API's cloned
138    /// `reqwest::Client` and the URL for the `history` endpoint.
139    ///
140    /// # Errors
141    ///
142    /// If the URL fails to parse, an error will be returned.
143    pub fn history(&self) -> Result<HistoryApi> {
144        Ok(HistoryApi::new_with_url(
145            self.client.clone(),
146            self.url.join("history/")?,
147        ))
148    }
149
150    /// Returns a new instance of `UploadApi` with the API's cloned
151    /// `reqwest::Client` and the URL for the `view` endpoint.
152    ///
153    /// # Errors
154    ///
155    /// If the URL fails to parse, an error will be returned.
156    pub fn upload(&self) -> Result<UploadApi> {
157        Ok(UploadApi::new_with_url(
158            self.client.clone(),
159            self.url.join("upload/")?,
160        ))
161    }
162
163    /// Returns a new instance of `ViewApi` with the API's cloned
164    /// `reqwest::Client` and the URL for the `view` endpoint.
165    ///
166    /// # Errors
167    ///
168    /// If the URL fails to parse, an error will be returned.
169    pub fn view(&self) -> Result<ViewApi> {
170        Ok(ViewApi::new_with_url(
171            self.client.clone(),
172            self.url.join("view")?,
173        ))
174    }
175
176    /// Returns a new instance of `WebsocketApi` with the API's cloned
177    /// `reqwest::Client` and the URL for the `ws` endpoint.
178    ///
179    /// # Errors
180    ///
181    /// * If the URL fails to parse, an error will be returned.
182    /// * On failure to set the `ws://` scheme on the URL, an error will be returned.
183    pub fn websocket(&self) -> Result<WebsocketApi> {
184        self.websocket_with_client(self.client_id)
185    }
186
187    /// Returns a new instance of `WebsocketApi` with the API's cloned
188    /// `reqwest::Client` and the URL for the `ws` endpoint and the specified
189    /// client id.
190    ///
191    /// # Arguments
192    ///
193    /// * `client_id` - A `uuid::Uuid` representing the client id to use for the request.
194    ///
195    /// # Errors
196    ///
197    /// * If the URL fails to parse, an error will be returned.
198    /// * On failure to set the `ws://` scheme on the URL, an error will be returned.
199    pub fn websocket_with_client(&self, client_id: uuid::Uuid) -> Result<WebsocketApi> {
200        let mut url = self
201            .url
202            .clone()
203            .join("ws")
204            .map_err(ApiError::ParseWebSocketEndpointError)?;
205        url.set_scheme("ws")
206            .map_err(|_| ApiError::SetWebSocketSchemeFailed { url: url.clone() })?;
207        url.set_query(Some(format!("clientId={}", client_id).as_str()));
208        Ok(WebsocketApi::new_with_url(url))
209    }
210}