use reqwest::blocking::Client;
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
pub struct HttpClient {
inner: Client,
}
impl HttpClient {
pub fn new() -> Self {
Self {
inner: Client::builder()
.https_only(true) .build()
.expect("Failed to initialize privacy HTTP client"),
}
}
fn apply_privacy_rules(&self, headers: HashMap<String, String>) -> HashMap<String, String> {
let blacklist = ["Cookie", "Referer", "X-Forwarded-For", "CF-Connecting-IP"];
headers.into_iter()
.filter(|(k, _)| !blacklist.iter().any(|&b| b.eq_ignore_ascii_case(k)))
.collect()
}
pub fn get(&self, url: &str, headers: HashMap<String, String>) -> Result<String, String> {
let filtered_headers = self.apply_privacy_rules(headers);
let mut request = self.inner.get(url);
for (k, v) in filtered_headers {
request = request.header(k, v);
}
request.send()
.map_err(|e| e.to_string())?
.text()
.map_err(|e| e.to_string())
}
pub fn post(&self, url: &str, headers: HashMap<String, String>, body: &str) -> Result<String, String> {
let filtered_headers = self.apply_privacy_rules(headers);
let mut request = self.inner.post(url);
for (k, v) in filtered_headers {
request = request.header(k, v);
}
request.body(body.to_string())
.send()
.map_err(|e| e.to_string())?
.text()
.map_err(|e| e.to_string())
}
pub fn generate_image(&self, prompt: &str, width: i32, height: i32, steps: i32, output_path: &str) -> Result<(), String> {
let mut headers = HashMap::new();
headers.insert("Content-Type".to_string(), "application/json".to_string());
let body = format!(
r#"{{"prompt": "{}", "width": {}, "height": {}, "steps": {}}}"#,
prompt, width, height, steps
);
let response = self.post("http://127.0.0.1:8080/txt2img", headers, &body)?;
let v: serde_json::Value = serde_json::from_str(&response).map_err(|e| e.to_string())?;
let image_base64 = v["image"].as_str().ok_or("Missing image data")?;
let bytes = base64::decode(image_base64).map_err(|e| e.to_string())?;
let mut file = File::create(output_path).map_err(|e| e.to_string())?;
file.write_all(&bytes).map_err(|e| e.to_string())?;
Ok(())
}
}
#[cxx::bridge(namespace = "privacy_http_sdk")]
mod ffi {
struct Header {
key: String,
value: String,
}
extern "Rust" {
type HttpClient;
fn new_http_client() -> Box<HttpClient>;
#[rust_name = "get_ffi"]
fn get(self: &HttpClient, url: &str, headers: Vec<Header>) -> String;
#[rust_name = "post_ffi"]
fn post(self: &HttpClient, url: &str, headers: Vec<Header>, body: &str) -> String;
#[rust_name = "generate_image_ffi"]
fn generate_image(self: &HttpClient, prompt: &str, width: i32, height: i32, steps: i32, output_path: &str) -> String;
}
}
fn new_http_client() -> Box<HttpClient> {
Box::new(HttpClient::new())
}
impl HttpClient {
fn get_ffi(&self, url: &str, headers: Vec<ffi::Header>) -> String {
let map: HashMap<String, String> = headers.into_iter().map(|h| (h.key, h.value)).collect();
self.get(url, map).unwrap_or_else(|e| format!("Error: {}", e))
}
fn post_ffi(&self, url: &str, headers: Vec<ffi::Header>, body: &str) -> String {
let map: HashMap<String, String> = headers.into_iter().map(|h| (h.key, h.value)).collect();
self.post(url, map, body).unwrap_or_else(|e| format!("Error: {}", e))
}
fn generate_image_ffi(&self, prompt: &str, width: i32, height: i32, steps: i32, output_path: &str) -> String {
self.generate_image(prompt, width, height, steps, output_path)
.map(|_| "Success".to_string()).unwrap_or_else(|e| format!("Error: {}", e))
}
}
#[cfg(feature = "python")]
use pyo3::prelude::*;
#[cfg(feature = "python")]
#[pyclass]
pub struct HttpClientPy {
client: HttpClient,
}
#[cfg(feature = "python")]
#[pymethods]
impl HttpClientPy {
#[new]
fn new() -> Self {
HttpClientPy { client: HttpClient::new() }
}
fn get(&self, url: &str, headers: HashMap<String, String>) -> PyResult<String> {
self.client.get(url, headers).map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e))
}
fn post(&self, url: &str, headers: HashMap<String, String>, body: String) -> PyResult<String> {
self.client.post(url, headers, &body).map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e))
}
fn generate_image(&self, prompt: &str, width: i32, height: i32, steps: i32, output_path: &str) -> PyResult<()> {
self.client.generate_image(prompt, width, height, steps, output_path)
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e))
}
}