From 9598596bdc61dcf7ae5f14681863e3c97f9e1013 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 3 Sep 2021 21:04:43 +0200 Subject: [PATCH] Replace all http code in epi/eframe/egui_glium/egui_web with ehttp (#697) I've extracted all the http request code and turned it into its own crate at . There was never a reason for the HTTP request library to be part of `eframe`. Much better to have it as its own crate! --- Cargo.lock | 15 ++- eframe/CHANGELOG.md | 1 + eframe/Cargo.toml | 1 - egui/Cargo.toml | 3 + egui_demo_app/Cargo.toml | 2 +- egui_demo_lib/Cargo.toml | 3 +- egui_demo_lib/src/apps/demo/code_editor.rs | 2 +- egui_demo_lib/src/apps/http_app.rs | 28 +++-- egui_glium/CHANGELOG.md | 1 + egui_glium/Cargo.toml | 4 - egui_glium/src/backend.rs | 9 -- egui_glium/src/http.rs | 70 ------------- egui_glium/src/lib.rs | 2 - egui_web/CHANGELOG.md | 1 + egui_web/Cargo.toml | 8 -- egui_web/src/backend.rs | 8 -- egui_web/src/http.rs | 97 ----------------- egui_web/src/lib.rs | 2 - emath/Cargo.toml | 3 + epaint/Cargo.toml | 3 + epi/Cargo.toml | 1 - epi/src/lib.rs | 115 +-------------------- 22 files changed, 49 insertions(+), 330 deletions(-) delete mode 100644 egui_glium/src/http.rs delete mode 100644 egui_web/src/http.rs diff --git a/Cargo.lock b/Cargo.lock index a60eace9..08f52b1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -810,6 +810,7 @@ version = "0.14.0" dependencies = [ "criterion", "egui", + "ehttp", "epi", "image", "serde", @@ -830,7 +831,6 @@ dependencies = [ "ron", "serde", "tts", - "ureq", "webbrowser", ] @@ -849,6 +849,19 @@ dependencies = [ "web-sys", ] +[[package]] +name = "ehttp" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b078e2305de4c998700ac152b3e7a358d7fbe77e15b3b1cd2c44a8b82176124f" +dependencies = [ + "js-sys", + "ureq", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "either" version = "1.6.1" diff --git a/eframe/CHANGELOG.md b/eframe/CHANGELOG.md index 87011ed9..19963ba3 100644 --- a/eframe/CHANGELOG.md +++ b/eframe/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to the `eframe` crate. ## Unreleased +* Remove "http" feature (use https://github.com/emilk/ehttp instead!). ## 0.14.0 - 2021-08-24 diff --git a/eframe/Cargo.toml b/eframe/Cargo.toml index fd2d8782..352bfe4c 100644 --- a/eframe/Cargo.toml +++ b/eframe/Cargo.toml @@ -40,7 +40,6 @@ default = ["default_fonts"] # If set, egui will use `include_bytes!` to bundle some fonts. # If you plan on specifying your own fonts you may disable this feature. default_fonts = ["egui/default_fonts"] -http = ["egui_glium/http", "egui_web/http"] persistence = ["epi/persistence", "egui_glium/persistence", "egui_web/persistence"] screen_reader = ["egui_glium/screen_reader", "egui_web/screen_reader"] # experimental time = ["egui_glium/time"] # for seconds_since_midnight diff --git a/egui/Cargo.toml b/egui/Cargo.toml index 917aa294..0ee258a0 100644 --- a/egui/Cargo.toml +++ b/egui/Cargo.toml @@ -17,6 +17,9 @@ include = [ "Cargo.toml", ] +[package.metadata.docs.rs] +all-features = true + [lib] [dependencies] diff --git a/egui_demo_app/Cargo.toml b/egui_demo_app/Cargo.toml index 8b8ec3d6..f056cbf8 100644 --- a/egui_demo_app/Cargo.toml +++ b/egui_demo_app/Cargo.toml @@ -15,7 +15,7 @@ egui_demo_lib = { version = "0.14.0", path = "../egui_demo_lib", features = ["ex [features] default = ["persistence"] -http = ["eframe/http", "egui_demo_lib/http"] +http = ["egui_demo_lib/http"] persistence = ["eframe/persistence", "egui_demo_lib/persistence"] screen_reader = ["eframe/screen_reader"] # experimental syntax_highlighting = ["egui_demo_lib/syntax_highlighting"] diff --git a/egui_demo_lib/Cargo.toml b/egui_demo_lib/Cargo.toml index 983d9ea1..945b8f78 100644 --- a/egui_demo_lib/Cargo.toml +++ b/egui_demo_lib/Cargo.toml @@ -28,6 +28,7 @@ epi = { version = "0.14.0", path = "../epi" } unicode_names2 = { version = "0.4.0", default-features = false } # feature "http": +ehttp = { version = "0.1.0", optional = true } image = { version = "0.23", default-features = false, features = ["jpeg", "png"], optional = true } # feature "syntax_highlighting": @@ -41,7 +42,7 @@ criterion = { version = "0.3", default-features = false } [features] default = [] -http = ["image", "epi/http"] +http = ["ehttp", "image"] persistence = ["egui/persistence", "epi/persistence", "serde"] syntax_highlighting = ["syntect"] diff --git a/egui_demo_lib/src/apps/demo/code_editor.rs b/egui_demo_lib/src/apps/demo/code_editor.rs index c23c11f1..00395596 100644 --- a/egui_demo_lib/src/apps/demo/code_editor.rs +++ b/egui_demo_lib/src/apps/demo/code_editor.rs @@ -65,7 +65,7 @@ impl super::View for CodeEditor { } else { ui.horizontal_wrapped(|ui|{ ui.spacing_mut().item_spacing.x = 0.0; - ui.label("Compile the demo with the 'syntect' feature to enable much nicer syntax highlighting using "); + ui.label("Compile the demo with the 'syntax_highlighting' feature to enable much nicer syntax highlighting using "); ui.hyperlink_to("syntect", "https://github.com/trishume/syntect"); ui.label("."); }); diff --git a/egui_demo_lib/src/apps/http_app.rs b/egui_demo_lib/src/apps/http_app.rs index 8737fbf0..4e66ad09 100644 --- a/egui_demo_lib/src/apps/http_app.rs +++ b/egui_demo_lib/src/apps/http_app.rs @@ -1,9 +1,8 @@ -use epi::http::{Request, Response}; use std::sync::mpsc::Receiver; struct Resource { /// HTTP response - response: Response, + response: ehttp::Response, text: Option, @@ -15,7 +14,7 @@ struct Resource { } impl Resource { - fn from_response(response: Response) -> Self { + fn from_response(response: ehttp::Response) -> Self { let content_type = response.content_type().unwrap_or_default(); let image = if content_type.starts_with("image/") { Image::decode(&response.bytes) @@ -54,7 +53,7 @@ pub struct HttpApp { request_body: String, #[cfg_attr(feature = "persistence", serde(skip))] - in_progress: Option>>, + in_progress: Option>>, #[cfg_attr(feature = "persistence", serde(skip))] result: Option>, @@ -94,9 +93,15 @@ impl epi::App for HttpApp { egui::CentralPanel::default().show(ctx, |ui| { ui.heading("HTTP Fetch Example"); + ui.horizontal(|ui| { + ui.spacing_mut().item_spacing.x = 0.0; + ui.label("HTTP requests made using "); + ui.hyperlink_to("ehttp", "https://www.github.com/emilk/ehttp"); + ui.label("."); + }); ui.add(egui::github_link_file!( "https://github.com/emilk/egui/blob/master/", - "(source code)" + "(demo source code)" )); if let Some(request) = ui_url( @@ -110,7 +115,7 @@ impl epi::App for HttpApp { let (sender, receiver) = std::sync::mpsc::channel(); self.in_progress = Some(receiver); - frame.http_fetch(request, move |response| { + ehttp::fetch(request, move |response| { sender.send(response).ok(); repaint_signal.request_repaint(); }); @@ -144,7 +149,7 @@ fn ui_url( url: &mut String, method: &mut Method, request_body: &mut String, -) -> Option { +) -> Option { let mut trigger_fetch = false; egui::Grid::new("request_params").show(ui, |ui| { @@ -202,8 +207,8 @@ fn ui_url( if trigger_fetch { Some(match *method { - Method::Get => Request::get(url), - Method::Post => Request::post(url, request_body), + Method::Get => ehttp::Request::get(url), + Method::Post => ehttp::Request::post(url, request_body), }) } else { None @@ -284,7 +289,7 @@ fn ui_resource( // Syntax highlighting: #[cfg(feature = "syntect")] -fn syntax_highlighting(response: &Response, text: &str) -> Option { +fn syntax_highlighting(response: &ehttp::Response, text: &str) -> Option { let extension_and_rest: Vec<&str> = response.url.rsplitn(2, '.').collect(); let extension = extension_and_rest.get(0)?; ColoredText::text_with_extension(text, extension) @@ -361,6 +366,7 @@ impl ColoredText { } } +#[cfg(feature = "syntect")] fn as_byte_range(whole: &str, range: &str) -> std::ops::Range { let whole_start = whole.as_ptr() as usize; let range_start = range.as_ptr() as usize; @@ -371,7 +377,7 @@ fn as_byte_range(whole: &str, range: &str) -> std::ops::Range { } #[cfg(not(feature = "syntect"))] -fn syntax_highlighting(_: &Response, _: &str) -> Option { +fn syntax_highlighting(_: &ehttp::Response, _: &str) -> Option { None } #[cfg(not(feature = "syntect"))] diff --git a/egui_glium/CHANGELOG.md b/egui_glium/CHANGELOG.md index 445a8028..86918f88 100644 --- a/egui_glium/CHANGELOG.md +++ b/egui_glium/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to the `egui_glium` integration will be noted in this file. ## Unreleased +* Remove "http" feature (use https://github.com/emilk/ehttp instead!). ## 0.14.0 - 2021-08-24 diff --git a/egui_glium/Cargo.toml b/egui_glium/Cargo.toml index e8da0691..c4479d8e 100644 --- a/egui_glium/Cargo.toml +++ b/egui_glium/Cargo.toml @@ -28,9 +28,6 @@ epi = { version = "0.14.0", path = "../epi" } glium = "0.30" webbrowser = "0.5" -# feature "http": -ureq = { version = "2.0", optional = true } - # feature "persistence": directories-next = { version = "2", optional = true } ron = { version = "0.6", optional = true } @@ -48,7 +45,6 @@ default = ["default_fonts"] # If set, egui will use `include_bytes!` to bundle some fonts. # If you plan on specifying your own fonts you may disable this feature. default_fonts = ["egui/default_fonts"] -http = ["epi/http", "ureq"] persistence = [ "directories-next", "egui/persistence", diff --git a/egui_glium/src/backend.rs b/egui_glium/src/backend.rs index 243c1825..952e6d66 100644 --- a/egui_glium/src/backend.rs +++ b/egui_glium/src/backend.rs @@ -177,9 +177,6 @@ pub fn run(mut app: Box, native_options: epi::NativeOptions) { #[allow(unused_mut)] let mut storage = create_storage(app.name()); - #[cfg(feature = "http")] - let http = std::sync::Arc::new(crate::http::GliumHttp {}); - let window_settings = deserialize_window_settings(&storage); let mut event_loop = glutin::event_loop::EventLoop::with_user_event(); let icon = native_options.icon_data.clone().and_then(load_icon); @@ -198,8 +195,6 @@ pub fn run(mut app: Box, native_options: epi::NativeOptions) { let mut frame = epi::backend::FrameBuilder { info: integration_info(&display, None), tex_allocator: painter, - #[cfg(feature = "http")] - http: http.clone(), output: &mut app_output, repaint_signal: repaint_signal.clone(), } @@ -222,8 +217,6 @@ pub fn run(mut app: Box, native_options: epi::NativeOptions) { let mut frame = epi::backend::FrameBuilder { info: integration_info(&display, None), tex_allocator: painter, - #[cfg(feature = "http")] - http: http.clone(), output: &mut app_output, repaint_signal: repaint_signal.clone(), } @@ -319,8 +312,6 @@ pub fn run(mut app: Box, native_options: epi::NativeOptions) { let mut frame = epi::backend::FrameBuilder { info: integration_info(&display, previous_frame_time), tex_allocator: painter, - #[cfg(feature = "http")] - http: http.clone(), output: &mut app_output, repaint_signal: repaint_signal.clone(), } diff --git a/egui_glium/src/http.rs b/egui_glium/src/http.rs deleted file mode 100644 index 3c500e5c..00000000 --- a/egui_glium/src/http.rs +++ /dev/null @@ -1,70 +0,0 @@ -use std::collections::BTreeMap; - -pub use epi::http::{Request, Response}; - -/// NOTE: Ok(..) is returned on network error. -/// Err is only for failure to use the fetch api. -pub fn fetch_blocking(request: &Request) -> Result { - let mut req = ureq::request(&request.method, &request.url); - - for header in &request.headers { - req = req.set(header.0, header.1); - } - - let resp = if request.body.is_empty() { - req.call() - } else { - req.send_bytes(&request.body) - }; - - let (ok, resp) = match resp { - Ok(resp) => (true, resp), - Err(ureq::Error::Status(_, resp)) => (false, resp), // Still read the body on e.g. 404 - Err(ureq::Error::Transport(error)) => return Err(error.to_string()), - }; - - let url = resp.get_url().to_owned(); - let status = resp.status(); - let status_text = resp.status_text().to_owned(); - let mut headers = BTreeMap::new(); - for key in &resp.headers_names() { - if let Some(value) = resp.header(key) { - // lowercase for easy lookup - headers.insert(key.to_ascii_lowercase(), value.to_owned()); - } - } - - let mut reader = resp.into_reader(); - let mut bytes = vec![]; - use std::io::Read; - reader - .read_to_end(&mut bytes) - .map_err(|err| err.to_string())?; - - let response = Response { - url, - ok, - status, - status_text, - bytes, - headers, - }; - Ok(response) -} - -// ---------------------------------------------------------------------------- - -pub(crate) struct GliumHttp {} - -impl epi::backend::Http for GliumHttp { - fn fetch_dyn( - &self, - request: Request, - on_done: Box) + Send>, - ) { - std::thread::spawn(move || { - let result = crate::http::fetch_blocking(&request); - on_done(result) - }); - } -} diff --git a/egui_glium/src/lib.rs b/egui_glium/src/lib.rs index 7b232750..58102c17 100644 --- a/egui_glium/src/lib.rs +++ b/egui_glium/src/lib.rs @@ -19,8 +19,6 @@ #![allow(clippy::manual_range_contains, clippy::single_match)] mod backend; -#[cfg(feature = "http")] -pub mod http; mod painter; #[cfg(feature = "persistence")] pub mod persistence; diff --git a/egui_web/CHANGELOG.md b/egui_web/CHANGELOG.md index d56df482..aa5bea9d 100644 --- a/egui_web/CHANGELOG.md +++ b/egui_web/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to the `egui_web` integration will be noted in this file. ## Unreleased +* Remove "http" feature (use https://github.com/emilk/ehttp instead!). ## 0.14.1 - 2021-08-28 diff --git a/egui_web/Cargo.toml b/egui_web/Cargo.toml index 64df1885..1503d36a 100644 --- a/egui_web/Cargo.toml +++ b/egui_web/Cargo.toml @@ -42,14 +42,6 @@ default = ["default_fonts"] # If set, egui will use `include_bytes!` to bundle some fonts. # If you plan on specifying your own fonts you may disable this feature. default_fonts = ["egui/default_fonts"] -http = [ - "epi/http", - "web-sys/Headers", - "web-sys/Request", - "web-sys/RequestInit", - "web-sys/RequestMode", - "web-sys/Response", -] persistence = ["egui/persistence", "ron", "serde"] screen_reader = ["tts"] # experimental diff --git a/egui_web/src/backend.rs b/egui_web/src/backend.rs index a9d30653..5bd3e447 100644 --- a/egui_web/src/backend.rs +++ b/egui_web/src/backend.rs @@ -137,8 +137,6 @@ pub struct AppRunner { prefer_dark_mode: Option, last_save_time: f64, screen_reader: crate::screen_reader::ScreenReader, - #[cfg(feature = "http")] - http: Arc, pub(crate) last_text_cursor_pos: Option, } @@ -165,8 +163,6 @@ impl AppRunner { prefer_dark_mode, last_save_time: now_sec(), screen_reader: Default::default(), - #[cfg(feature = "http")] - http: Arc::new(http::WebHttp {}), last_text_cursor_pos: None, }; @@ -175,8 +171,6 @@ impl AppRunner { let mut frame = epi::backend::FrameBuilder { info: runner.integration_info(), tex_allocator: runner.web_backend.painter.as_tex_allocator(), - #[cfg(feature = "http")] - http: runner.http.clone(), output: &mut app_output, repaint_signal: runner.needs_repaint.clone(), } @@ -247,8 +241,6 @@ impl AppRunner { let mut frame = epi::backend::FrameBuilder { info: self.integration_info(), tex_allocator: self.web_backend.painter.as_tex_allocator(), - #[cfg(feature = "http")] - http: self.http.clone(), output: &mut app_output, repaint_signal: self.needs_repaint.clone(), } diff --git a/egui_web/src/http.rs b/egui_web/src/http.rs deleted file mode 100644 index 13026d51..00000000 --- a/egui_web/src/http.rs +++ /dev/null @@ -1,97 +0,0 @@ -use wasm_bindgen::prelude::*; - -pub use epi::http::{Request, Response}; - -/// NOTE: Ok(..) is returned on network error. -/// Err is only for failure to use the fetch api. -pub async fn fetch_async(request: &Request) -> Result { - fetch_jsvalue(request) - .await - .map_err(|err| err.as_string().unwrap_or(format!("{:#?}", err))) -} - -/// NOTE: Ok(..) is returned on network error. -/// Err is only for failure to use the fetch api. -async fn fetch_jsvalue(request: &Request) -> Result { - // https://rustwasm.github.io/wasm-bindgen/examples/fetch.html - // https://github.com/seanmonstar/reqwest/blob/master/src/wasm/client.rs - - use wasm_bindgen::JsCast; - use wasm_bindgen_futures::JsFuture; - - let mut opts = web_sys::RequestInit::new(); - opts.method(&request.method); - opts.mode(web_sys::RequestMode::Cors); - - if !request.body.is_empty() { - let body_bytes: &[u8] = &request.body; - let body_array: js_sys::Uint8Array = body_bytes.into(); - let js_value: &JsValue = body_array.as_ref(); - opts.body(Some(js_value)); - } - - let js_request = web_sys::Request::new_with_str_and_init(&request.url, &opts)?; - - for h in &request.headers { - js_request.headers().set(h.0, h.1)?; - } - - let window = web_sys::window().unwrap(); - let response = JsFuture::from(window.fetch_with_request(&js_request)).await?; - let response: web_sys::Response = response.dyn_into()?; - - let array_buffer = JsFuture::from(response.array_buffer()?).await?; - let uint8_array = js_sys::Uint8Array::new(&array_buffer); - let bytes = uint8_array.to_vec(); - - // https://developer.mozilla.org/en-US/docs/Web/API/Headers - // "Note: When Header values are iterated over, [...] values from duplicate header names are combined." - let mut headers = std::collections::BTreeMap::::new(); - let js_headers: web_sys::Headers = response.headers(); - let js_iter = js_sys::try_iter(&js_headers) - .expect("headers try_iter") - .expect("headers have an iterator"); - - for item in js_iter { - let item = item.expect("headers iterator"); - let array: js_sys::Array = item.into(); - let v: Vec = array.to_vec(); - - let mut key = v[0] - .as_string() - .ok_or_else(|| JsValue::from_str("headers name"))?; - let value = v[1] - .as_string() - .ok_or_else(|| JsValue::from_str("headers value"))?; - - // for easy lookup - key.make_ascii_lowercase(); - headers.insert(key, value); - } - - Ok(Response { - url: response.url(), - ok: response.ok(), - status: response.status(), - status_text: response.status_text(), - bytes, - headers, - }) -} - -// ---------------------------------------------------------------------------- - -pub(crate) struct WebHttp {} - -impl epi::backend::Http for WebHttp { - fn fetch_dyn( - &self, - request: Request, - on_done: Box) + Send>, - ) { - crate::spawn_future(async move { - let result = crate::http::fetch_async(&request).await; - on_done(result) - }); - } -} diff --git a/egui_web/src/lib.rs b/egui_web/src/lib.rs index 620dcd2c..6b5a19ca 100644 --- a/egui_web/src/lib.rs +++ b/egui_web/src/lib.rs @@ -22,8 +22,6 @@ #![warn(clippy::all, rust_2018_idioms)] pub mod backend; -#[cfg(feature = "http")] -pub mod http; mod painter; pub mod screen_reader; pub mod webgl1; diff --git a/emath/Cargo.toml b/emath/Cargo.toml index 1b6d1116..1127e968 100644 --- a/emath/Cargo.toml +++ b/emath/Cargo.toml @@ -17,6 +17,9 @@ include = [ "Cargo.toml", ] +[package.metadata.docs.rs] +all-features = true + [lib] [dependencies] diff --git a/epaint/Cargo.toml b/epaint/Cargo.toml index 622f9095..9a07d2db 100644 --- a/epaint/Cargo.toml +++ b/epaint/Cargo.toml @@ -19,6 +19,9 @@ include = [ "fonts/*.txt", ] +[package.metadata.docs.rs] +all-features = true + [lib] [dependencies] diff --git a/epi/Cargo.toml b/epi/Cargo.toml index a2893829..6f907f1b 100644 --- a/epi/Cargo.toml +++ b/epi/Cargo.toml @@ -29,5 +29,4 @@ serde = { version = "1", optional = true } [features] default = [] -http = [] persistence = ["ron", "serde"] diff --git a/epi/src/lib.rs b/epi/src/lib.rs index 7c718332..8bb8f701 100644 --- a/epi/src/lib.rs +++ b/epi/src/lib.rs @@ -1,6 +1,6 @@ //! Backend-agnostic interface for writing apps using [`egui`]. //! -//! `epi` provides interfaces for window management, serialization and http requests. +//! `epi` provides interfaces for window management and serialization. //! An app written for `epi` can then be plugged into [`eframe`](https://docs.rs/eframe), //! the egui framework crate. //! @@ -221,7 +221,7 @@ pub struct IconData { /// Represents the surroundings of your app. /// /// It provides methods to inspect the surroundings (are we on the web?), -/// allocate textures, do http requests, and change settings (e.g. window size). +/// allocate textures, and change settings (e.g. window size). pub struct Frame<'a>(backend::FrameBuilder<'a>); impl<'a> Frame<'a> { @@ -255,19 +255,6 @@ impl<'a> Frame<'a> { pub fn repaint_signal(&self) -> std::sync::Arc { self.0.repaint_signal.clone() } - - /// Very simple Http fetch API. - /// Calls the given callback when done. - /// - /// You must enable the "http" feature for this. - #[cfg(feature = "http")] - pub fn http_fetch( - &self, - request: http::Request, - on_done: impl 'static + Send + FnOnce(Result), - ) { - self.0.http.fetch_dyn(request, Box::new(on_done)) - } } /// Information about the web environment (if applicable). @@ -374,114 +361,16 @@ pub const APP_KEY: &str = "app"; // ---------------------------------------------------------------------------- -#[cfg(feature = "http")] -/// `epi` supports simple HTTP requests with [`Frame::http_fetch`]. -/// -/// You must enable the "http" feature for this. -pub mod http { - use std::collections::BTreeMap; - - /// A simple http request. - pub struct Request { - /// "GET", … - pub method: String, - /// https://… - pub url: String, - /// The raw bytes. - pub body: Vec, - /// ("Accept", "*/*"), … - pub headers: BTreeMap, - } - - impl Request { - pub fn create_headers_map(headers: &[(&str, &str)]) -> BTreeMap { - headers - .iter() - .map(|e| (e.0.to_owned(), e.1.to_owned())) - .collect() - } - - /// Create a `GET` request with the given url. - #[allow(clippy::needless_pass_by_value)] - pub fn get(url: impl ToString) -> Self { - Self { - method: "GET".to_owned(), - url: url.to_string(), - body: vec![], - headers: Request::create_headers_map(&[("Accept", "*/*")]), - } - } - - /// Create a `POST` request with the given url and body. - #[allow(clippy::needless_pass_by_value)] - pub fn post(url: impl ToString, body: impl ToString) -> Self { - Self { - method: "POST".to_owned(), - url: url.to_string(), - body: body.to_string().into_bytes(), - headers: Request::create_headers_map(&[ - ("Accept", "*/*"), - ("Content-Type", "text/plain; charset=utf-8"), - ]), - } - } - } - - /// Response from a completed HTTP request. - pub struct Response { - /// The URL we ended up at. This can differ from the request url when we have followed redirects. - pub url: String, - /// Did we get a 2xx response code? - pub ok: bool, - /// Status code (e.g. `404` for "File not found"). - pub status: u16, - /// Status text (e.g. "File not found" for status code `404`). - pub status_text: String, - /// The raw bytes. - pub bytes: Vec, - - pub headers: BTreeMap, - } - - impl Response { - pub fn text(&self) -> Option { - String::from_utf8(self.bytes.clone()).ok() - } - - pub fn content_type(&self) -> Option { - self.headers.get("content-type").cloned() - } - } - /// Possible errors does NOT include e.g. 404, which is NOT considered an error. - pub type Error = String; -} - -// ---------------------------------------------------------------------------- - /// You only need to look here if you are writing a backend for `epi`. pub mod backend { use super::*; - /// Implements `Http` requests. - #[cfg(feature = "http")] - pub trait Http { - /// Calls the given callback when done. - fn fetch_dyn( - &self, - request: http::Request, - on_done: Box) + Send>, - ); - } - /// The data required by [`Frame`] each frame. pub struct FrameBuilder<'a> { /// Information about the integration. pub info: IntegrationInfo, /// A way to allocate textures (on integrations that support it). pub tex_allocator: &'a mut dyn TextureAllocator, - /// Do http requests. - #[cfg(feature = "http")] - pub http: std::sync::Arc, /// Where the app can issue commands back to the integration. pub output: &'a mut AppOutput, /// If you need to request a repaint from another thread, clone this and send it to that other thread.