feat: add wasm support
This commit is contained in:
parent
acfae81284
commit
f61747d0e2
|
@ -1 +1,3 @@
|
|||
/target
|
||||
/docs/*.js
|
||||
/docs/*.wasm
|
||||
|
|
|
@ -150,12 +150,6 @@ version = "3.7.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
|
||||
|
||||
[[package]]
|
||||
name = "cairo-sys-rs"
|
||||
version = "0.14.0"
|
||||
|
@ -273,6 +267,16 @@ dependencies = [
|
|||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console_error_panic_hook"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "copypasta"
|
||||
version = "0.7.1"
|
||||
|
@ -605,15 +609,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "epaint"
|
||||
version = "0.13.0"
|
||||
|
@ -968,31 +963,6 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "825343c4eef0b63f541f8903f395dc5beb362a979b5799a84062527ef1e37726"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
|
@ -1011,79 +981,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "399c583b2979440c60be0821a6199eca73bc3c8dcd9d070d75ac726e2c6186e5"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b61cf2d1aebcf6e6352c97b81dc2244ca29194be1b276f5d8ad5c6330fffb11"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-rustls"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"hyper",
|
||||
"log",
|
||||
"rustls",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
|
@ -1101,16 +998,6 @@ dependencies = [
|
|||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.10"
|
||||
|
@ -1120,12 +1007,6 @@ dependencies = [
|
|||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.1"
|
||||
|
@ -1294,12 +1175,6 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.4"
|
||||
|
@ -1720,42 +1595,6 @@ dependencies = [
|
|||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "246e9f61b9bb77df069a947682be06e31ac43ea37862e244a69f177694ea6d22"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"hyper-rustls",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"mime",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustls",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"webpki-roots",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rfd"
|
||||
version = "0.4.2"
|
||||
|
@ -1811,18 +1650,24 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"console_error_panic_hook",
|
||||
"eframe",
|
||||
"futures",
|
||||
"itertools",
|
||||
"js-sys",
|
||||
"livesplit",
|
||||
"nom",
|
||||
"quick-xml",
|
||||
"reqwest",
|
||||
"rfd",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"toml",
|
||||
"ureq",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1922,18 +1767,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shared_library"
|
||||
version = "0.1.9"
|
||||
|
@ -2002,16 +1835,6 @@ dependencies = [
|
|||
"wayland-client",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "765f090f0e423d2b55843402a07915add955e7d60657db13707a159727326cad"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
|
@ -2141,38 +1964,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "4b7b349f11a7047e6d1276853e612d152f5e8a352c61917887cc2169e2366b4c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
"libc",
|
||||
"memchr",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6"
|
||||
dependencies = [
|
||||
"rustls",
|
||||
"tokio",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2184,38 +1977,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"pin-project-lite",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.6.2"
|
||||
|
@ -2275,6 +2036,8 @@ dependencies = [
|
|||
"log",
|
||||
"once_cell",
|
||||
"rustls",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"url",
|
||||
"webpki",
|
||||
"webpki-roots",
|
||||
|
@ -2315,16 +2078,6 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"try-lock",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
|
@ -2338,8 +2091,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "b608ecc8f4198fe8680e2ed18eccab5f0cd4caaf3d83516fa5fb2e927fda2586"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
|
@ -2591,15 +2342,6 @@ dependencies = [
|
|||
"x11-dl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.2.0"
|
||||
|
|
18
Cargo.toml
18
Cargo.toml
|
@ -14,7 +14,7 @@ anyhow = "1"
|
|||
eframe = "0.13"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
livesplit = { path = "../livesplit-rs" }
|
||||
quick-xml = { version = "0.21", features = [ "serialize" ] }
|
||||
quick-xml = { version = "0.21", features = ["serialize"] }
|
||||
nom = "6"
|
||||
url = "2"
|
||||
toml = "0.5"
|
||||
|
@ -22,20 +22,28 @@ futures = "0.3"
|
|||
itertools = "0.10"
|
||||
rfd = "0.4"
|
||||
|
||||
[dependencies.reqwest]
|
||||
version = "0.11"
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.ureq]
|
||||
version = "2"
|
||||
default-features = false
|
||||
features = ["json", "rustls-tls-webpki-roots"]
|
||||
features = ["json", "tls"]
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1"
|
||||
features = ["derive"]
|
||||
|
||||
[dependencies.tokio]
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.tokio]
|
||||
version = "1"
|
||||
default-features = false
|
||||
features = ["rt-multi-thread"]
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
console_error_panic_hook = "0.1"
|
||||
wasm-bindgen = { version = "0.2" }
|
||||
wasm-bindgen-futures = "0.4"
|
||||
serde_json = "1"
|
||||
web-sys = { version = "0.3", features = ["Headers", "Response", "Request", "RequestInit", "RequestMode", "Window"] }
|
||||
js-sys = "0.3"
|
||||
|
||||
[features]
|
||||
default = ["persistence"]
|
||||
http = ["eframe/http"] # Enable if you want to do http requests
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<!-- Disable zooming: -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
|
||||
<head>
|
||||
<title>Twitch Run Highlighter</title>
|
||||
<style>
|
||||
html {
|
||||
/* Remove touch delay: */
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
body {
|
||||
/* Background color for what is not covered by the egui canvas,
|
||||
or where the egui canvas is translucent. */
|
||||
background: #404040;
|
||||
}
|
||||
|
||||
/* Allow canvas to fill entire web page: */
|
||||
html,
|
||||
body {
|
||||
overflow: hidden;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* Position canvas in center-top: */
|
||||
canvas {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0%);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- The WASM code will resize this canvas to cover the entire screen -->
|
||||
<canvas id="the_canvas_id"></canvas>
|
||||
|
||||
<script>
|
||||
// The `--no-modules`-generated JS from `wasm-bindgen` attempts to use
|
||||
// `WebAssembly.instantiateStreaming` to instantiate the wasm module,
|
||||
// but this doesn't work with `file://` urls. This example is frequently
|
||||
// viewed by simply opening `index.html` in a browser (with a `file://`
|
||||
// url), so it would fail if we were to call this function!
|
||||
//
|
||||
// Work around this for now by deleting the function to ensure that the
|
||||
// `no_modules.js` script doesn't have access to it. You won't need this
|
||||
// hack when deploying over HTTP.
|
||||
delete WebAssembly.instantiateStreaming;
|
||||
</script>
|
||||
|
||||
<!-- This is the JS generated by the `wasm-bindgen` CLI tool -->
|
||||
<script src="runhighlighter.js"></script>
|
||||
|
||||
<script>
|
||||
// We'll defer our execution until the wasm is ready to go.
|
||||
// Here we tell bindgen the path to the wasm file so it can start
|
||||
// initialization and return to us a promise when it's done.
|
||||
wasm_bindgen("./runhighlighter_bg.wasm")
|
||||
.then(on_wasm_loaded)["catch"](console.error);
|
||||
|
||||
function on_wasm_loaded() {
|
||||
// This call installs a bunch of callbacks and then returns.
|
||||
wasm_bindgen.start("the_canvas_id");
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
<!-- Powered by egui: https://github.com/emilk/egui/ -->
|
143
src/app.rs
143
src/app.rs
|
@ -3,7 +3,9 @@ use chrono::{Duration, Local, Utc, TimeZone, FixedOffset, DateTime};
|
|||
use std::{
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
io::Cursor,
|
||||
sync::{
|
||||
Arc,
|
||||
atomic::{AtomicBool, Ordering},
|
||||
mpsc::{SyncSender, Receiver},
|
||||
},
|
||||
|
@ -17,11 +19,10 @@ use url::Url;
|
|||
use eframe::{
|
||||
egui, epi,
|
||||
egui::{CtxRef, Sense, Rgba, Widget},
|
||||
epi::{Frame, Storage},
|
||||
epi::{Frame, RepaintSignal, Storage},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use itertools::Itertools;
|
||||
use std::io::Cursor;
|
||||
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
|
@ -123,7 +124,7 @@ impl epi::App for App {
|
|||
|
||||
let repaint_signal = frame.repaint_signal();
|
||||
let sender = self.state.channel.0.clone();
|
||||
tokio::task::spawn(async move {
|
||||
self.spawn(async move {
|
||||
let res: Result<Run> = try {
|
||||
let bytes = Cursor::new(data);
|
||||
let run: Run = quick_xml::de::from_reader(bytes)?;
|
||||
|
@ -210,22 +211,7 @@ impl epi::App for App {
|
|||
|
||||
let repaint_signal = frame.repaint_signal();
|
||||
let sender = self.state.channel.0.clone();
|
||||
tokio::task::spawn(async move {
|
||||
let handle = rfd::AsyncFileDialog::default()
|
||||
.add_filter("LiveSplit splits", &["lss"])
|
||||
.pick_file()
|
||||
.await;
|
||||
let data = match handle {
|
||||
Some(handle) => {
|
||||
let name = handle.file_name();
|
||||
let data = handle.read().await;
|
||||
Some((name, data))
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
sender.send(Message::SplitsPath(data)).ok();
|
||||
repaint_signal.request_repaint();
|
||||
});
|
||||
self.spawn(Self::choose_splits(sender, repaint_signal));
|
||||
}
|
||||
|
||||
if let Some(name) = &self.state.splits_file_name {
|
||||
|
@ -294,7 +280,7 @@ impl epi::App for App {
|
|||
let repaint_signal = frame.repaint_signal();
|
||||
let client_id = self.config.client.id.clone();
|
||||
let client_secret = self.config.client.secret.clone();
|
||||
tokio::task::spawn(async move {
|
||||
self.spawn(async move {
|
||||
let res = get_videos(&channel.unwrap(), client_id, client_secret).await;
|
||||
sender.send(Message::Videos(id, res)).ok();
|
||||
repaint_signal.request_repaint();
|
||||
|
@ -319,7 +305,8 @@ impl epi::App for App {
|
|||
#[cfg(feature = "persistence")]
|
||||
fn setup(&mut self, _ctx: &egui::CtxRef, _frame: &mut epi::Frame<'_>, storage: Option<&dyn epi::Storage>) {
|
||||
if let Some(storage) = storage {
|
||||
*self = epi::get_value(storage, epi::APP_KEY).unwrap_or_default();
|
||||
let loaded: Self = epi::get_value(storage, epi::APP_KEY).unwrap_or_default();
|
||||
self.config = loaded.config;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,6 +375,90 @@ impl App {
|
|||
.append_pair("title", &format!("{} PB in {}", splits.game_name, to_string(&run_time)));
|
||||
self.state.highlight_urls.borrow_mut().insert(attempt.id, url);
|
||||
}
|
||||
|
||||
async fn choose_splits(sender: SyncSender<Message>, repaint_signal: Arc<dyn RepaintSignal>) {
|
||||
let handle = rfd::AsyncFileDialog::default()
|
||||
.add_filter("LiveSplit splits", &["lss"])
|
||||
.pick_file()
|
||||
.await;
|
||||
let data = match handle {
|
||||
Some(handle) => {
|
||||
let name = handle.file_name();
|
||||
let data = handle.read().await;
|
||||
Some((name, data))
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
sender.send(Message::SplitsPath(data)).ok();
|
||||
repaint_signal.request_repaint();
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn spawn<F>(&self, fut: F) where F: std::future::Future<Output=()> + Send + 'static {
|
||||
tokio::task::spawn(fut);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn spawn<F>(&self, fut: F) where F: std::future::Future<Output=()> + 'static {
|
||||
use futures::FutureExt;
|
||||
let _ = wasm_bindgen_futures::future_to_promise(fut.then(|()| async { Ok(wasm_bindgen::JsValue::undefined()) }));
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
async fn send_request<S, D>(method: &str, url: S, headers: &[(String, String)]) -> Result<D>
|
||||
where S: AsRef<str> + Send + Sync,
|
||||
D: serde::de::DeserializeOwned + Send + 'static,
|
||||
{
|
||||
let method = method.to_string();
|
||||
let url = url.as_ref().to_string();
|
||||
let headers = headers.to_vec();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let mut req = ureq::request(&method, &url);
|
||||
for (name, value) in headers {
|
||||
req = req.set(&name, &value);
|
||||
}
|
||||
let d: D = req.call()?.into_json()?;
|
||||
Ok(d)
|
||||
}).await.unwrap()
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
async fn send_request<S, D>(method: &str, url: S, headers: &[(String, String)]) -> Result<D>
|
||||
where S: AsRef<str>,
|
||||
D: serde::de::DeserializeOwned,
|
||||
{
|
||||
use wasm_bindgen::JsCast;
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
|
||||
let mut opts = web_sys::RequestInit::new();
|
||||
opts.method(method);
|
||||
opts.mode(web_sys::RequestMode::Cors);
|
||||
|
||||
let request = web_sys::Request::new_with_str_and_init(url.as_ref(), &opts)
|
||||
.map_err(|e| anyhow::anyhow!("couldn't make request: {:?}", e))?;
|
||||
request.headers().set("Accept", "*/*").map_err(|e| anyhow::anyhow!("couldn't make request: {:?}", e))?;
|
||||
|
||||
for (name, value) in headers {
|
||||
request.headers().set(name, value).map_err(|e| anyhow::anyhow!("couldn't make request: {:?}", e))?;
|
||||
}
|
||||
|
||||
let window = web_sys::window().unwrap();
|
||||
let response = JsFuture::from(window.fetch_with_request(&request)).await
|
||||
.map_err(|e| anyhow::anyhow!("couldn't make request: {:?}", e))?;
|
||||
assert!(response.is_instance_of::<web_sys::Response>());
|
||||
let response: web_sys::Response = response.dyn_into().unwrap();
|
||||
|
||||
let array_buffer = response.array_buffer()
|
||||
.map_err(|e| anyhow::anyhow!("couldn't make request: {:?}", e))?;
|
||||
let array_buffer = JsFuture::from(array_buffer).await
|
||||
.map_err(|e| anyhow::anyhow!("couldn't make request: {:?}", e))?;
|
||||
let uint8_array = js_sys::Uint8Array::new(&array_buffer);
|
||||
let bytes = uint8_array.to_vec();
|
||||
|
||||
let d: D = serde_json::from_slice(&bytes)?;
|
||||
Ok(d)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -420,30 +491,22 @@ struct VideosResponseVideo {
|
|||
}
|
||||
|
||||
async fn get_videos(channel: &str, client_id: String, client_secret: String) -> Result<Vec<VideosResponseVideo>> {
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let mut token_url = Url::parse("https://id.twitch.tv/oauth2/token").unwrap();
|
||||
token_url.query_pairs_mut()
|
||||
.append_pair("client_id", &client_id)
|
||||
.append_pair("client_secret", &client_secret)
|
||||
.append_pair("grant_type", "client_credentials");
|
||||
let creds: AppCredentials = client.post(token_url)
|
||||
.send()
|
||||
.await?
|
||||
.json()
|
||||
.await?;
|
||||
let creds: AppCredentials = App::send_request("POST", token_url, &[]).await?;
|
||||
|
||||
let headers = &[
|
||||
("Client-ID".into(), client_id),
|
||||
("Authorization".into(), format!("Bearer {}", creds.access_token)),
|
||||
][..];
|
||||
|
||||
let mut user_url = Url::parse("https://api.twitch.tv/helix/users").unwrap();
|
||||
user_url.query_pairs_mut()
|
||||
.append_pair("login", channel);
|
||||
let users: UsersResponse = client.get(user_url)
|
||||
.header("Client-ID", &client_id)
|
||||
.header("Authorization", format!("Bearer {}", creds.access_token))
|
||||
.send()
|
||||
.await?
|
||||
.json()
|
||||
.await?;
|
||||
|
||||
let users: UsersResponse = App::send_request("GET", user_url, &headers).await?;
|
||||
if users.data.is_empty() {
|
||||
anyhow::bail!("no such twitch channel");
|
||||
}
|
||||
|
@ -453,13 +516,7 @@ async fn get_videos(channel: &str, client_id: String, client_secret: String) ->
|
|||
let mut vids_url = Url::parse("https://api.twitch.tv/helix/videos").unwrap();
|
||||
vids_url.query_pairs_mut()
|
||||
.append_pair("user_id", &user.id);
|
||||
let videos: VideosResponse = client.get(vids_url)
|
||||
.header("Client-ID", &client_id)
|
||||
.header("Authorization", format!("Bearer {}", creds.access_token))
|
||||
.send()
|
||||
.await?
|
||||
.json()
|
||||
.await?;
|
||||
let videos: VideosResponse = App::send_request("GET", vids_url, &headers).await?;
|
||||
|
||||
Ok(videos.data)
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@ use eframe::wasm_bindgen::{self, prelude::*};
|
|||
/// You can add more callbacks like this if you want to call in to your code.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[wasm_bindgen]
|
||||
pub async fn start(canvas_id: &str) -> Result<(), eframe::wasm_bindgen::JsValue> {
|
||||
pub fn start(canvas_id: &str) -> Result<(), eframe::wasm_bindgen::JsValue> {
|
||||
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
|
||||
let app = App::default();
|
||||
eframe::start_web(canvas_id, Box::new(app))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue