use eframe::egui;
use std::sync::mpsc::{channel, Receiver, Sender};
pub(crate) fn query_component(text: &str) -> String {
let mut out = String::with_capacity(text.len());
for byte in text.bytes() {
match byte {
b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'.' | b'_' | b'~' => out.push(byte as char),
_ => out.push_str(&format!("%{byte:02X}")),
}
}
out
}
pub(crate) fn fetch_text(ctx: &egui::Context, url: String) -> Receiver<Result<String, String>> {
let (tx, rx) = channel();
fetch_text_into(ctx, url, tx);
rx
}
pub(crate) fn fetch_text_into(ctx: &egui::Context, url: String, tx: Sender<Result<String, String>>) {
fetch_into(ctx, url, text_of, tx);
}
fn text_of(response: ehttp::Response) -> String {
response
.text()
.map(str::to_owned)
.unwrap_or_else(|| String::from_utf8_lossy(&response.bytes).into_owned())
}
pub(crate) fn fetch_bytes(ctx: &egui::Context, url: String) -> Receiver<Result<Vec<u8>, String>> {
fetch(ctx, url, |response| response.bytes)
}
fn fetch<T: Send + 'static>(
ctx: &egui::Context,
url: String,
decode: impl FnOnce(ehttp::Response) -> T + Send + 'static,
) -> Receiver<Result<T, String>> {
let (tx, rx) = channel();
fetch_into(ctx, url, decode, tx);
rx
}
fn fetch_into<T: Send + 'static>(
ctx: &egui::Context,
url: String,
decode: impl FnOnce(ehttp::Response) -> T + Send + 'static,
tx: Sender<Result<T, String>>,
) {
let ctx = ctx.clone();
ehttp::fetch(ehttp::Request::get(url), move |result| {
let out = match result {
Ok(response) if response.ok => Ok(decode(response)),
Ok(response) => Err(format!("HTTP {} {}", response.status, response.status_text)),
Err(error) => Err(error),
};
let _ = tx.send(out);
ctx.request_repaint();
});
}