Browse Source

Add http fetch to eframe and implement it in egui_glium using ureq

pull/92/head
Emil Ernerfeldt 4 years ago
parent
commit
9db1b8dbf9
  1. 350
      Cargo.lock
  2. 2
      eframe/Cargo.toml
  3. 31
      eframe/src/lib.rs
  4. 5
      egui_glium/Cargo.toml
  5. 44
      egui_glium/src/http.rs
  6. 2
      egui_glium/src/lib.rs
  7. 29
      egui_web/src/http.rs
  8. 2
      egui_web/src/lib.rs
  9. 39
      epi/src/lib.rs
  10. 3
      example_web/Cargo.toml
  11. 7
      example_web/src/example_app.rs
  12. 1
      example_web/src/lib.rs
  13. 9
      example_web/src/main.rs

350
Cargo.lock

@ -103,6 +103,12 @@ dependencies = [
"rustc-demangle",
]
[[package]]
name = "base-x"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b"
[[package]]
name = "base64"
version = "0.13.0"
@ -231,10 +237,16 @@ dependencies = [
"libc",
"num-integer",
"num-traits",
"time",
"time 0.1.44",
"winapi 0.3.9",
]
[[package]]
name = "chunked_transfer"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7477065d45a8fe57167bf3cf8bcd3729b54cfcb81cca49bda2d038ea89ae82ca"
[[package]]
name = "clap"
version = "2.33.3"
@ -327,6 +339,33 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd51eab21ab4fd6a3bf889e2d0958c0a6e3a61ad04260325e919e652a2a62826"
[[package]]
name = "cookie"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784ad0fbab4f3e9cef09f20e0aea6000ae08d2cb98ac4c0abc53df18803d702f"
dependencies = [
"percent-encoding",
"time 0.2.23",
"version_check",
]
[[package]]
name = "cookie_store"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3818dfca4b0cb5211a659bbcbb94225b7127407b2b135e650d717bfb78ab10d3"
dependencies = [
"cookie",
"idna",
"log",
"publicsuffix",
"serde",
"serde_json",
"time 0.2.23",
"url",
]
[[package]]
name = "core-foundation"
version = "0.7.0"
@ -599,6 +638,12 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "discard"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
[[package]]
name = "dispatch"
version = "0.2.0"
@ -671,6 +716,7 @@ dependencies = [
"glium",
"serde",
"serde_json",
"ureq",
"webbrowser",
]
@ -703,18 +749,24 @@ dependencies = [
"serde_json",
]
[[package]]
name = "error-chain"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
dependencies = [
"version_check",
]
[[package]]
name = "example_web"
version = "0.1.0"
dependencies = [
"eframe",
"egui_web",
"image",
"js-sys",
"serde",
"serde_json",
"syntect",
"wasm-bindgen",
]
[[package]]
@ -760,6 +812,16 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "form_urlencoded"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
@ -933,6 +995,17 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "image"
version = "0.23.12"
@ -1102,6 +1175,12 @@ dependencies = [
"libc",
]
[[package]]
name = "matches"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
[[package]]
name = "maybe-uninit"
version = "2.0.0"
@ -1494,6 +1573,12 @@ dependencies = [
"toml",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
version = "1.0.24"
@ -1503,6 +1588,28 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "publicsuffix"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b"
dependencies = [
"error-chain",
"idna",
"lazy_static",
"regex",
"url",
]
[[package]]
name = "qstring"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e"
dependencies = [
"percent-encoding",
]
[[package]]
name = "quote"
version = "1.0.8"
@ -1589,6 +1696,21 @@ version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
[[package]]
name = "ring"
version = "0.16.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "024a1e66fea74c66c66624ee5622a7ff0e4b73a13b4f5c326ddb50c708944226"
dependencies = [
"cc",
"libc",
"once_cell",
"spin",
"untrusted",
"web-sys",
"winapi 0.3.9",
]
[[package]]
name = "rustc-demangle"
version = "0.1.18"
@ -1604,6 +1726,19 @@ dependencies = [
"semver",
]
[[package]]
name = "rustls"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "064fd21ff87c6e87ed4506e68beb42459caa4a0e2eb144932e6776768556980b"
dependencies = [
"base64",
"log",
"ring",
"sct",
"webpki",
]
[[package]]
name = "rusttype"
version = "0.9.2"
@ -1647,6 +1782,16 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "sct"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "semver"
version = "0.9.0"
@ -1703,6 +1848,12 @@ dependencies = [
"serde",
]
[[package]]
name = "sha1"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
[[package]]
name = "shared_library"
version = "0.1.9"
@ -1745,6 +1896,70 @@ dependencies = [
"wayland-protocols",
]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "standback"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf906c8b8fc3f6ecd1046e01da1d8ddec83e48c8b08b84dcc02b585a6bedf5a8"
dependencies = [
"version_check",
]
[[package]]
name = "stdweb"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5"
dependencies = [
"discard",
"rustc_version",
"stdweb-derive",
"stdweb-internal-macros",
"stdweb-internal-runtime",
"wasm-bindgen",
]
[[package]]
name = "stdweb-derive"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
dependencies = [
"proc-macro2",
"quote",
"serde",
"serde_derive",
"syn",
]
[[package]]
name = "stdweb-internal-macros"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
dependencies = [
"base-x",
"proc-macro2",
"quote",
"serde",
"serde_derive",
"serde_json",
"sha1",
"syn",
]
[[package]]
name = "stdweb-internal-runtime"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
[[package]]
name = "strsim"
version = "0.9.3"
@ -1839,6 +2054,44 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "time"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcdaeea317915d59b2b4cd3b5efcd156c309108664277793f5351700c02ce98b"
dependencies = [
"const_fn",
"libc",
"standback",
"stdweb",
"time-macros",
"version_check",
"winapi 0.3.9",
]
[[package]]
name = "time-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1"
dependencies = [
"proc-macro-hack",
"time-macros-impl",
]
[[package]]
name = "time-macros-impl"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa"
dependencies = [
"proc-macro-hack",
"proc-macro2",
"quote",
"standback",
"syn",
]
[[package]]
name = "tinytemplate"
version = "1.1.0"
@ -1849,6 +2102,21 @@ dependencies = [
"serde_json",
]
[[package]]
name = "tinyvec"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "toml"
version = "0.5.8"
@ -1864,6 +2132,24 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc"
[[package]]
name = "unicode-bidi"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
dependencies = [
"matches",
]
[[package]]
name = "unicode-normalization"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-width"
version = "0.1.8"
@ -1876,6 +2162,43 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "ureq"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "294b85ef5dbc3670a72e82a89971608a1fcc4ed5c7c5a2895230d31a95f0569b"
dependencies = [
"base64",
"chunked_transfer",
"cookie",
"cookie_store",
"log",
"once_cell",
"qstring",
"rustls",
"url",
"webpki",
"webpki-roots",
]
[[package]]
name = "url"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",
]
[[package]]
name = "version_check"
version = "0.9.2"
@ -2075,6 +2398,25 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "webpki"
version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "webpki-roots"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82015b7e0b8bad8185994674a13a93306bea76cf5a16c5a181382fd3a5ec2376"
dependencies = [
"webpki",
]
[[package]]
name = "widestring"
version = "0.4.3"

2
eframe/Cargo.toml

@ -20,7 +20,7 @@ epi = { version = "0.6.0", path = "../epi", features = ["serde", "serde_json"] }
# For compiling natively:
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
egui_glium = { path = "../egui_glium" }
egui_glium = { path = "../egui_glium", features = ["http"] }
# For compiling to web:
[target.'cfg(target_arch = "wasm32")'.dependencies]

31
eframe/src/lib.rs

@ -52,3 +52,34 @@ pub fn start_web(canvas_id: &str, app: Box<dyn epi::App>) -> Result<(), wasm_bin
pub fn run_native(app: Box<dyn epi::App>) {
egui_glium::run(app)
}
// ----------------------------------------------------------------------------
pub mod http {
pub use epi::http::*;
/// Do a HTTP request and call the callback when done.
pub fn fetch(
request: Request,
on_done: impl 'static + Send + FnOnce(Result<Response, String>),
) {
fetch_dyn(request, Box::new(on_done))
}
fn fetch_dyn(request: Request, on_done: Box<dyn FnOnce(Result<Response, String>) + Send>) {
#[cfg(target_arch = "wasm32")]
{
egui_web::spawn_future(async move {
let result = egui_web::http::fetch_async(&request).await;
on_done(result)
});
}
#[cfg(not(target_arch = "wasm32"))]
{
std::thread::spawn(move || {
let result = egui_glium::http::fetch_blocking(&request);
on_done(result)
});
}
}
}

5
egui_glium/Cargo.toml

@ -21,4 +21,9 @@ epi = { version = "0.6.0", path = "../epi", features = ["serde", "serde_json"] }
glium = "0.29"
serde = "1"
serde_json = "1"
ureq = { version = "1.5", optional = true }
webbrowser = "0.5"
[features]
default = []
http = ["ureq"]

44
egui_glium/src/http.rs

@ -0,0 +1,44 @@
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<Response, String> {
let Request { method, url } = request;
let resp = ureq::request(method, url).set("Accept", "*/*").call();
if let Some(error) = resp.synthetic_error() {
return Err(error.to_string());
}
let url = resp.get_url().to_owned();
let ok = resp.ok();
let status = resp.status();
let status_text = resp.status_text().to_owned();
let header_content_type = resp.header("Content-Type").unwrap_or_default().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 text = if header_content_type.starts_with("text")
|| header_content_type == "application/javascript"
{
String::from_utf8(bytes.clone()).ok()
} else {
None
};
let response = Response {
url,
ok,
status,
status_text,
header_content_type,
bytes,
text,
};
Ok(response)
}

2
egui_glium/src/lib.rs

@ -4,6 +4,8 @@
#![allow(clippy::single_match)]
mod backend;
#[cfg(feature = "http")]
pub mod http;
mod painter;
pub mod storage;

29
egui_web/src/fetch.rs → egui_web/src/http.rs

@ -1,39 +1,20 @@
use wasm_bindgen::prelude::*;
pub struct Response {
pub url: String,
pub ok: bool,
pub status: u16,
pub status_text: String,
/// Content-Type header, or empty string if missing
pub header_content_type: String,
/// The raw bytes
pub bytes: Vec<u8>,
/// UTF-8 decoded version of bytes.
/// ONLY if `header_content_type` starts with "text" and bytes is UTF-8.
pub text: Option<String>,
}
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(method: &str, url: &str) -> Result<Response, String> {
fetch_jsvalue(method, url)
pub async fn fetch_async(request: &Request) -> Result<Response, String> {
fetch_jsvalue(request)
.await
.map_err(|err| err.as_string().unwrap_or_default())
}
/// NOTE: Ok(..) is returned on network error.
/// Err is only for failure to use the fetch api.
pub async fn get(url: &str) -> Result<Response, String> {
fetch("GET", url).await
}
async fn fetch_jsvalue(request: &Request) -> Result<Response, JsValue> {
let Request { method, url } = request;
/// NOTE: Ok(..) is returned on network error.
/// Err is only for failure to use the fetch api.
async fn fetch_jsvalue(method: &str, url: &str) -> Result<Response, JsValue> {
// https://rustwasm.github.io/wasm-bindgen/examples/fetch.html
use wasm_bindgen::JsCast;

2
egui_web/src/lib.rs

@ -3,7 +3,7 @@
#![warn(clippy::all)]
pub mod backend;
pub mod fetch;
pub mod http;
pub mod webgl;
pub use backend::*;

39
epi/src/lib.rs

@ -207,3 +207,42 @@ pub fn set_value<T: serde::Serialize>(storage: &mut dyn Storage, key: &str, valu
/// storage key used for app
pub const APP_KEY: &str = "app";
// ----------------------------------------------------------------------------
pub mod http {
pub struct Request {
/// "GET", …
pub method: String,
/// https://…
pub url: String,
}
impl Request {
pub fn get(url: String) -> Self {
Self {
method: "GET".to_owned(),
url,
}
}
}
/// Response from an HTTP request for a very simple HTTP fetch API in `eframe`.
pub struct Response {
/// The URL we ended up at. This can differ from the request url when we have followed redirects.
pub url: String,
pub ok: bool,
pub status: u16,
pub status_text: String,
/// Content-Type header, or empty string if missing.
pub header_content_type: String,
/// The raw bytes.
pub bytes: Vec<u8>,
/// UTF-8 decoded version of bytes.
/// ONLY if `header_content_type` starts with "text" and bytes is UTF-8.
pub text: Option<String>,
}
}

3
example_web/Cargo.toml

@ -10,10 +10,7 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
eframe = { path = "../eframe" }
egui_web = { path = "../egui_web" }
image = { version = "0.23", default_features = false, features = ["jpeg", "png"] }
js-sys = "0.3"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
syntect = { version = "4", default_features = false, features = ["default-fancy"] }
wasm-bindgen = "0.2"

7
example_web/src/example_app.rs

@ -1,5 +1,5 @@
use eframe::{egui, epi};
use egui_web::fetch::Response;
use epi::http::Response;
use std::sync::mpsc::Receiver;
struct Resource {
@ -76,8 +76,9 @@ impl epi::App for ExampleApp {
let repaint_signal = integration_context.repaint_signal.clone();
let (sender, receiver) = std::sync::mpsc::channel();
self.in_progress = Some(receiver);
egui_web::spawn_future(async move {
sender.send(egui_web::fetch::get(&url).await).ok();
eframe::http::fetch(eframe::http::Request::get(url), move |response| {
sender.send(response).ok();
repaint_signal.request_repaint();
});
}

1
example_web/src/lib.rs

@ -3,6 +3,7 @@
#![warn(clippy::all)]
mod example_app;
pub use example_app::ExampleApp;
#[cfg(target_arch = "wasm32")]
use eframe::wasm_bindgen::{self, prelude::*};

9
example_web/src/main.rs

@ -0,0 +1,9 @@
#![forbid(unsafe_code)]
#![cfg_attr(not(debug_assertions), deny(warnings))] // Forbid warnings in release builds
#![warn(clippy::all)]
// When compiling natively:
fn main() {
let app = example_web::ExampleApp::default();
eframe::run_native(Box::new(app));
}
Loading…
Cancel
Save