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}