initial commit

This commit is contained in:
Stefan Bühler 2019-09-28 12:16:55 +02:00
commit b9de50bb2b
40 changed files with 4203 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
**/*.rs.bk

607
Cargo.lock generated Normal file
View File

@ -0,0 +1,607 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "anymap"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "autocfg"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "backtrace"
version = "0.3.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace-sys"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "base-x"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bincode"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "boolinator"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bumpalo"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bytes"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cc"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "chrono"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "discard"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "failure"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure_derive"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fnv"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "galmon-web"
version = "0.1.0"
dependencies = [
"chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"stdweb 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)",
"yew 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "http"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "indexmap"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "iovec"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro-hack"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro-nested"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc-demangle"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ryu"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_repr"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "sha1"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "slab"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "stdweb"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"stdweb-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"stdweb-internal-macros 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"stdweb-internal-runtime 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "stdweb-derive"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "stdweb-internal-macros"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"base-x 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "stdweb-internal-runtime"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "0.15.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "synstructure"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "time"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wasm-bindgen"
version = "0.2.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"wasm-bindgen-macro 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-shared 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-macro-support 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-backend 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-shared 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "yew"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-nested 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"stdweb 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"yew-macro 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "yew-macro"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"boolinator 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
"checksum anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344"
"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875"
"checksum backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "690a62be8920ccf773ee00ef0968649b0e724cda8bd5b12286302b4ae955fdf5"
"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b"
"checksum base-x 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "76f4eae81729e69bb1819a26c6caac956cc429238388091f98cb6cd858f16443"
"checksum bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f2fb9e29e72fd6bc12071533d5dc7664cb01480c59406f656d7ac25c7bd8ff7"
"checksum boolinator 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9"
"checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68"
"checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "372bcb56f939e449117fb0869c2e8fd8753a8223d92a172c6e808cf123a5b6e4"
"checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
"checksum proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e688f31d92ffd7c1ddc57a1b4e6d773c0f2a14ee437a4b0a4f5a69c80eb221c8"
"checksum proc-macro-nested 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "369a6ed065f249a159e06c45752c780bda2fb53c995718f9e484d08daa9eb42e"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc"
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
"checksum serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573"
"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum stdweb 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a68c0ce28cf7400ed022e18da3c4591e14e1df02c70e93573cc59921b3923aeb"
"checksum stdweb-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e21ebd9179de08f2300a65454268a17ea3de204627458588c84319c4def3930"
"checksum stdweb-internal-macros 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e68f7d08b76979a43e93fe043b66d2626e35d41d68b0b85519202c6dd8ac59fa"
"checksum stdweb-internal-runtime 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d52317523542cc0af5b7e31017ad0f7d1e78da50455e38d5657cd17754f617da"
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ffde3534e5fa6fd936e3260cd62cd644b8656320e369388f9303c955895e35d4"
"checksum wasm-bindgen-backend 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "40c0543374a7ae881cdc5d32d19de28d1d1929e92263ffa7e31712cc2d53f9f1"
"checksum wasm-bindgen-macro 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "f914c94c2c5f4c9364510ca2429e59c92157ec89429243bcc245e983db990a71"
"checksum wasm-bindgen-macro-support 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "9168c413491e4233db7b6884f09a43beb00c14d11d947ffd165242daa48a2385"
"checksum wasm-bindgen-shared 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "326c32126e1a157b6ced7400061a84ac5b11182b2cda6edad7314eb3ae9ac9fe"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum yew 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479f32df0b06ef05893cbb3c195a0ae92b10587e2eff1969f1a7741d3fb96666"
"checksum yew-macro 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92d6380df5f9c5d4cfd1191bd31ed44299f302e6040126d602ee8b262252cb7e"

14
Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "galmon-web"
version = "0.1.0"
authors = ["Stefan Bühler <stbuehler@web.de>"]
edition = "2018"
[dependencies]
chrono = { version = "0.4.9", features = ["serde"] }
failure = "0.1.5"
percent-encoding = "2.1.0"
serde = { version = "1.0.99", features = ["rc"] }
serde_repr = "0.1.5"
stdweb = "0.4.18"
yew = "0.8.0"

3
README.md Normal file
View File

@ -0,0 +1,3 @@
Experimental, alternative frontend (written in rust) for https://galmon.eu
Code and algorithms for map rendering heavily inspired (read "copied") from [d3-geo](https://github.com/d3/d3-geo).

106
src/api/adapter_macro.rs Normal file
View File

@ -0,0 +1,106 @@
// build adapter with custom serialization names / grouping of (flattened) optional entries
macro_rules! adapter {
(
$adapter:ident => Option<$base:ident> {
$(
$(#[$field_meta:meta])*
$field:ident: $field_ty:ty,
)*
}
) => {
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct $adapter {
$(
$(#[$field_meta])*
#[serde(default, skip_serializing_if = "Option::is_none")]
$field: Option<$field_ty>,
)*
}
impl $adapter {
pub fn serialize<S>(value: &Option<$base>, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
Self::from(value.clone()).serialize(serializer)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<$base>, D::Error>
where
D: serde::Deserializer<'de>,
{
<$adapter as serde::Deserialize>::deserialize(deserializer).map(Option::<$base>::from)
}
}
impl From<Option<$base>> for $adapter {
fn from(base: Option<$base>) -> Self {
if let Some(base) = base {
Self {
$($field: Some(base.$field),)*
}
} else {
Self {
$($field: None,)*
}
}
}
}
impl From<$adapter> for Option<$base> {
fn from(adapter: $adapter) -> Self {
Option::Some($base {
$($field: adapter.$field?,)*
})
}
}
};
(
$adapter:ident => $base:ident {
$(
$(#[$field_meta:meta])*
$field:ident: $field_ty:ty,
)*
}
) => {
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct $adapter {
$(
$(#[$field_meta])*
$field: $field_ty,
)*
}
impl $adapter {
pub fn serialize<S>(value: &$base, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
Self::from(value.clone()).serialize(serializer)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<$base, D::Error>
where
D: serde::Deserializer<'de>,
{
<$adapter as serde::Deserialize>::deserialize(deserializer).map($base::from)
}
}
impl From<$base> for $adapter {
fn from(base: $base) -> Self {
Self {
$($field: base.$field,)*
}
}
}
impl From<$adapter> for $base {
fn from(adapter: $adapter) -> Self {
Self {
$($field: adapter.$field,)*
}
}
}
};
}

111
src/api/apiservice.rs Normal file
View File

@ -0,0 +1,111 @@
use failure::{format_err, Error, ResultExt};
use serde::Deserialize;
use std::cell::{Cell, RefCell};
use std::fmt;
use yew::prelude::*;
use yew::{
format::{Json, Nothing, Text},
services::fetch::{Request, Response, FetchService, FetchTask as YewFetchTask},
};
use crate::config::Config;
pub struct FetchTask {
_task: YewFetchTask,
}
impl FetchTask {
fn new(task: YewFetchTask) -> Self {
Self { _task: task }
}
}
impl fmt::Debug for FetchTask {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("FetchTask")
}
}
pub struct APIService<Message: 'static> {
send_message: Callback<Message>,
fetch_service: RefCell<FetchService>,
}
impl APIService<()> {
pub fn new_no_message() -> Self {
Self::new(Callback::from(|()| ()))
}
}
impl<Message: 'static> APIService<Message> {
pub fn new(send_message: Callback<Message>) -> Self
{
Self {
send_message,
fetch_service: RefCell::new(FetchService::new()),
}
}
pub fn fetch<T, F, IN>(&self, req: Request<IN>, callback: F) -> Option<FetchTask>
where
T: for<'de> Deserialize<'de>,
F: FnOnce(Result<T, Error>) -> Message + 'static,
IN: Into<Text>,
{
let method = req.method().clone();
let url = req.uri().clone();
let callback = Cell::new(Some(callback));
let send_message = self.send_message.clone();
let decode_response = move |response: Response<Text>| {
// only works once
let callback = callback.replace(None).unwrap();
let (parts, body) = response.into_parts();
if !parts.status.is_success() {
if parts.headers.is_empty() {
// CORS failure
jslog!("{} {:?} failed due to CORS, can't see real error (status: {})", method, url, parts.status);
return send_message.emit(callback(Err(format_err!("{} {:?} failed due to CORS", method, url))));
}
let e = format!("{} {:?} failed with {}", method, url, parts.status);
crate::log(&e);
return send_message.emit(callback(Err(failure::err_msg(e))));
}
let body = match body {
Err(e) => {
let e = format!("{} {:?} failed request body although status {} is fine: {}", method, url, parts.status, e);
crate::log(&e);
return send_message.emit(callback(Err(failure::err_msg(e))));
},
Ok(v) => v
};
send_message.emit(callback(Json::<Result<T, Error>>::from(Ok(body)).0.with_context(|e| format!("parsing response failed: {}", e)).map_err(Error::from)));
};
let mut service = self.fetch_service.borrow_mut();
Some(FetchTask::new(service.fetch(req, Callback::<Response<Text>>::from(decode_response))))
}
pub fn get<T, F>(&self, url: &str, callback: F) -> Option<FetchTask>
where
T: for<'de> Deserialize<'de>,
F: FnOnce(Result<T, Error>) -> Message + 'static,
{
self.fetch(Request::get(url).body(Nothing).unwrap(), callback)
}
pub fn api_get<T, F>(&self, config: &Config, path: fmt::Arguments<'_>, callback: F) -> Option<FetchTask>
where
T: for<'de> Deserialize<'de>,
F: FnOnce(Result<T, Error>) -> Message + 'static,
{
let url = format!("{}{}", config.base_url, path);
let req = Request::get(url).body(Nothing).unwrap();
self.fetch(req, callback)
}
}
impl<Message> fmt::Debug for APIService<Message> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("APIService")
}
}

375
src/api/mod.rs Normal file
View File

@ -0,0 +1,375 @@
use failure::Error;
use serde::{Serialize, Deserialize};
use std::collections::HashMap;
use std::time::SystemTime;
#[macro_use]
mod adapter_macro;
mod apiservice;
pub mod world_geo;
pub use self::apiservice::{APIService, FetchTask};
use crate::config::Config;
impl<Message: 'static> APIService<Message> {
pub fn api_world_geo<F>(&self, config: &Config, callback: F) -> Option<FetchTask>
where
F: FnOnce(Result<world_geo::FeatureCollection, Error>) -> Message + 'static,
{
self.api_get(config, format_args!("/geo/world.geojson"), callback)
}
}
pub type DateTime = chrono::DateTime<chrono::Utc>;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Global {
#[serde(rename = "gps-offset-ns")]
pub gps_offset_ns: f64,
#[serde(rename = "gps-utc-offset-ns")]
pub gps_utc_offset_ns: f64,
#[serde(rename = "last-seen", with = "chrono::serde::ts_seconds")]
pub last_seen: DateTime,
#[serde(rename = "leap-second-planned")]
pub leap_second_planned: bool,
#[serde(rename = "leap-seconds")]
pub leap_seconds: f64,
#[serde(rename = "utc-offset-ns")]
pub utc_offset_ns: f64,
}
impl<Message: 'static> APIService<Message> {
pub fn api_global<F>(&self, config: &Config, callback: F) -> Option<FetchTask>
where
F: FnOnce(Result<Global, Error>) -> Message + 'static,
{
self.api_get(config, format_args!("/global.json"), callback)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Debug, serde_repr::Serialize_repr, serde_repr::Deserialize_repr)]
#[repr(u8)]
pub enum GNS {
GPS = 0, // US
Galileo = 2, // EU
BeiDou = 3, // CN
Glonass = 6, // RU
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AlmanacEntry {
// NOT in Glonass
#[serde(rename = "eph-ecefX")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub eph_ecef_x: Option<f64>,
#[serde(rename = "eph-ecefY")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub eph_ecef_y: Option<f64>,
#[serde(rename = "eph-ecefZ")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub eph_ecef_z: Option<f64>,
// optional in Glonass
#[serde(rename = "eph-latitude")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub eph_latitude: Option<f64>,
#[serde(rename = "eph-longitude")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub eph_longitude: Option<f64>,
// NOT in Glonass
pub t: Option<f64>,
pub t0e: Option<f64>,
// all
pub gnssid: GNS,
pub name: String,
pub observed: bool,
pub inclination: f64,
}
pub type Almanac = HashMap<String, AlmanacEntry>;
impl<Message: 'static> APIService<Message> {
pub fn api_almanac<F>(&self, config: &Config, callback: F) -> Option<FetchTask>
where
F: FnOnce(Result<Almanac, Error>) -> Message + 'static,
{
self.api_get(config, format_args!("/almanac.json"), callback)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Observer {
pub id: u32,
#[serde(rename = "last-seen", with = "chrono::serde::ts_seconds")]
pub last_seen: DateTime,
pub latitude: f64,
pub longitude: f64,
#[serde(rename = "svs")]
pub satellite_vehicles: HashMap<String, ObservedSatelliteVehicle>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ObservedSatelliteVehicle {
#[serde(rename = "age-s")]
pub age_s: f32, // u32?
pub azi: f64,
pub db: u32,
pub elev: f64,
#[serde(rename = "fullName")]
pub full_name: String,
pub gnss: GNS,
#[serde(rename = "last-seen")]
pub last_seen: i64,
pub name: String,
pub prres: f64,
pub sigid: u32,
pub sv: u32,
}
pub type ObserverList = Vec<Observer>;
impl<Message: 'static> APIService<Message> {
pub fn api_observers<F>(&self, config: &Config, callback: F) -> Option<FetchTask>
where
F: FnOnce(Result<ObserverList, Error>) -> Message + 'static,
{
self.api_get(config, format_args!("/observers.json"), callback)
}
}
#[derive(Clone, Copy, Debug)]
/// A certain point in time in some reference system, in seconds
pub struct Instant {
pub week_number: u16, // depending on source only might have rolled on 8-bit
pub time_of_week: u32,
}
impl Instant {
pub fn system_time(self) -> SystemTime {
SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(self.epoch())
}
pub fn unroll_weeknumber(self) -> u32 {
let current_epoch = SystemTime::now().duration_since(SystemTime::now()).expect("before 1970-01-01").as_secs();
let current_wn = (current_epoch / (86400*7)) as u32;
let wn = self.week_number as u32;
let wn_bits = (16 - self.week_number.leading_zeros()).min(8); // assume at least 8-bit precision in weeknumber
let wn_mask = !0u32 << wn_bits;
let round_up = 1 << (wn_bits - 1); // if we already reached "halftime" round up
wn + ((current_wn + round_up) & wn_mask) // add bits from current_wn
}
pub fn epoch(self) -> u64 {
self.unroll_weeknumber() as u64 * (86400*7) + self.time_of_week as u64
}
}
#[derive(Clone, Copy, Debug)]
pub struct Vec3 {
pub x: f64,
pub y: f64,
pub z: f64,
}
#[derive(Clone, Debug)]
pub struct ReferenceTimeOffset {
/// offset in 2**(-30) seconds at base Instant (close to nanoseconds)
pub base_offset: i32,
/// correction in 2**(-50) seconds per second since base Instant
pub correction: i32,
/// time at which constant offset was measured
pub base: Instant,
/// text describing delta for some "current" (last_seen) Instant in nanoseconds offset and change in nanoseconds per day.
pub delta: String,
}
mod sv {
use super::*;
adapter!{
LastSeen => Instant {
#[serde(rename = "wn")]
week_number: u16,
#[serde(rename = "tow")]
time_of_week: u32,
}
}
adapter!{
Position => Option<Vec3> {
x: f64,
y: f64,
z: f64,
}
}
adapter!{
UtcOffsetInstant => Option<Instant> {
#[serde(rename = "wn0t")]
week_number: u16,
#[serde(rename = "t0t")]
time_of_week: u32,
}
}
adapter!{
// bug https://github.com/ahupowerdns/galmon/issues/8: Glonass sends a0 and a1, but not the other values
UtcOffset => Option<ReferenceTimeOffset> {
#[serde(rename = "a0")]
base_offset: i32,
#[serde(rename = "a1")]
correction: i32,
#[serde(flatten, with = "UtcOffsetInstant")]
base: Instant,
#[serde(rename = "delta-utc")]
delta: String,
}
}
adapter!{
GpsOffsetInstant => Option<Instant> {
#[serde(rename = "wn0g")]
week_number: u16,
#[serde(rename = "t0g")]
time_of_week: u32,
}
}
adapter!{
GpsOffset => Option<ReferenceTimeOffset> {
#[serde(rename = "a0g")]
base_offset: i32,
#[serde(rename = "a1g")]
correction: i32,
#[serde(flatten, with = "GpsOffsetInstant")]
base: Instant,
#[serde(rename = "delta-gps")]
delta: String,
}
}
}
// TODO: "undo" flatten #[serde(default, skip_serializing_if = "Option::is_none")]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SatelliteVehicle {
/* Identification: */
gnssid: GNS,
svid: u32, /* vehicle id; can be moved between satellites */
sigid: u32, /* "signal", also appended as "@{sigid}" to the full name */
/* Data: */
/// Signal In Space Accuracy
#[serde(default, skip_serializing_if = "Option::is_none")]
sisa: Option<String>,
#[serde(rename = "eph-age-m", default, skip_serializing_if = "Option::is_none")]
/// Age of ephemeris in minutes
eph_age_m: Option<f32>,
#[serde(rename = "best-tle", default, skip_serializing_if = "Option::is_none")]
best_tle: Option<String>,
#[serde(rename = "best-tle-dist", default, skip_serializing_if = "Option::is_none")]
best_tle_dist: Option<f64>,
#[serde(rename = "best-tle-int-desig", default, skip_serializing_if = "Option::is_none")]
best_tle_int_desig: Option<String>,
#[serde(rename = "best-tle-norad", default, skip_serializing_if = "Option::is_none")]
best_tle_norad: Option<i32>,
#[serde(rename = "alma-dist", default, skip_serializing_if = "Option::is_none")]
alma_dist: Option<f64>, // distance from almanac position in kilometers
#[serde(default, skip_serializing_if = "Option::is_none")]
aode: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
aodc: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
iod: Option<u16>,
// IOD data:
#[serde(default, skip_serializing_if = "Option::is_none")]
af0: Option<i32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
af1: Option<i32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
af2: Option<u8>,
#[serde(default, skip_serializing_if = "Option::is_none")]
t0c: Option<u16>, // clock epoch
#[serde(flatten, with = "sv::Position")]
position: Option<Vec3>,
// utc offset (all but Glonass): combined data
#[serde(flatten, with = "sv::UtcOffset")]
utc_offset: Option<ReferenceTimeOffset>,
// GPS offset (only Galileo and BeiDou)
#[serde(flatten, with = "sv::GpsOffset")]
gpc_offset: Option<ReferenceTimeOffset>,
#[serde(rename = "dtLS")]
dt_ls: i8,
#[serde(default, skip_serializing_if = "Option::is_none")]
health: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
healthissue: Option<u32>, // some codes?
// Galileo only: Health flags for E1 (common) and E5 (uncommon) frequencies.
#[serde(default, skip_serializing_if = "Option::is_none")]
e1bhs: Option<u8>,
#[serde(default, skip_serializing_if = "Option::is_none")]
e1bdvs: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
e5bhs: Option<u8>,
#[serde(default, skip_serializing_if = "Option::is_none")]
e5bdvs: Option<bool>,
#[serde(rename = "latest-disco", default, skip_serializing_if = "Option::is_none")]
latest_disco: Option<f64>,
#[serde(rename = "latest-disco-age", default, skip_serializing_if = "Option::is_none")]
latest_disco_age: Option<f64>,
#[serde(rename = "time-disco", default, skip_serializing_if = "Option::is_none")]
time_disco: Option<f64>,
#[serde(flatten, with = "sv::LastSeen")]
last_seen: Instant,
/// Number of seconds since we've last received from this SV. A satellite can be out of sight for a long time
#[serde(rename = "last-seen-s")]
last_seen_s: i64,
#[serde(rename = "fullName")]
full_name: String, // format!("{}@{}", self.name, self.sigid)
name: String,
perrecv: HashMap<u32, SatelliteVehiclePerReceiver>, // keys: Observer `id`
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SatelliteVehiclePerReceiver {
#[serde(rename = "elev")]
elevation: f64,
#[serde(rename = "azi", default, skip_serializing_if = "Option::is_none")]
azimuth: Option<f64>,
db: i32,
#[serde(rename = "last-seen-s")]
last_seen_s: i64,
prres: f64,
delta_hz: Option<f64>,
delta_hz_corr: Option<f64>,
}
pub type SatelliteVehicles = HashMap<String, SatelliteVehicle>;
impl<Message: 'static> APIService<Message> {
pub fn api_satellite_vehicles<F>(&self, config: &Config, callback: F) -> Option<FetchTask>
where
F: FnOnce(Result<SatelliteVehicles, Error>) -> Message + 'static,
{
self.api_get(config, format_args!("/svs.json"), callback)
}
}

108
src/api/world_geo.rs Normal file
View File

@ -0,0 +1,108 @@
use serde::{Serialize, Deserialize};
use std::fmt;
macro_rules! tagtype {
($name:ident: $tag:literal) => {
#[derive(Clone, Copy, Default, Debug)]
pub struct $name;
impl Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str($tag)
}
}
impl<'de> Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct Visitor;
impl serde::de::Visitor<'_> for Visitor {
type Value = $name;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "tag type {:?}", $tag)
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
if v != $tag {
return Err(E::invalid_value(serde::de::Unexpected::Str(v), &$tag));
}
Ok($name)
}
}
deserializer.deserialize_str(Visitor)
}
}
};
}
tagtype!(TagFeatureCollection: "FeatureCollection");
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FeatureCollection {
pub r#type: TagFeatureCollection,
pub features: Vec<Feature>,
}
tagtype!(TagFeature: "Feature");
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Feature {
pub r#type: TagFeature,
pub id: String,
pub properties: FeatureProperties,
pub geometry: Geometry,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FeatureProperties {
pub name: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum Geometry {
Polygon {
coordinates: PolygonData,
},
MultiPolygon {
coordinates: Vec<PolygonData>,
},
}
// first list of points is outer "hull" (should be clockwise), remaining list of points are holes (counterclockwise)
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PolygonData(pub Vec<Vec<Position>>);
#[derive(Clone, Copy, Debug)]
pub struct Position {
pub longitude: f32,
pub latitude: f32,
}
impl Serialize for Position {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
(self.longitude, self.latitude).serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Position {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
<(f32, f32)>::deserialize(deserializer).map(|(longitude, latitude)| Position { longitude, latitude })
}
}

9
src/config.rs Normal file
View File

@ -0,0 +1,9 @@
use serde::{Serialize, Deserialize};
use std::rc::Rc;
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct ConfigData {
pub base_url: String,
}
pub type Config = Rc<ConfigData>;

42
src/main.rs Normal file
View File

@ -0,0 +1,42 @@
#![recursion_limit="512"]
#[macro_use]
extern crate stdweb;
#[allow(unused_macros)]
macro_rules! jslog {
($($tt:tt)*) => {
$crate::log(&format!($($tt)*));
};
}
#[allow(unused_macros)]
macro_rules! jserror {
($($tt:tt)*) => {
$crate::error(&format!($($tt)*));
};
}
pub mod api;
pub mod config;
pub mod models;
pub mod ui;
pub mod uitools;
pub mod utils;
#[inline(never)]
fn log(message: &str) {
yew::services::ConsoleService::new().log(message);
}
#[inline(never)]
#[allow(unused)]
fn error(message: &str) {
yew::services::ConsoleService::new().error(message);
}
fn main() {
yew::start_app::<ui::app::MainApp>();
}
// https://galmon.eu/observers.json

48
src/models/almanac.rs Normal file
View File

@ -0,0 +1,48 @@
use crate::api;
use crate::config::Config;
use crate::models::helper::*;
#[derive(Debug)]
pub struct AlmanacT {
config: Config,
}
impl Model for AlmanacT {
type FetchData = api::Almanac;
const NAME: &'static str = "Almanac";
fn refresh(sr: &ModelHandle<Self>) -> Option<api::FetchTask> {
let sref = sr.clone();
let sd = sr.data();
sr.service().api_almanac(&sd.config, move |result| {
sref.set_received(result);
})
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Almanac(pub(super) ModelHandle<AlmanacT>);
impl std::ops::Deref for Almanac {
type Target = ModelHandle<AlmanacT>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Almanac {
pub fn new(config: Config) -> Self {
Self(ModelHandle::new(
AlmanacT { config },
(),
))
}
pub(super) fn new_shared(config: Config, base: ModelBase) -> Self {
Self(ModelHandle::new(
AlmanacT { config },
base,
))
}
}

122
src/models/base.rs Normal file
View File

@ -0,0 +1,122 @@
use crate::config::Config;
use crate::models::almanac::Almanac;
use crate::models::global::Global;
use crate::models::helper::{Callbacks, CallbackRegistration, ModelBase};
use crate::models::observers::Observers;
use std::cell::Cell;
use std::rc::Rc;
#[derive(Debug)]
struct Watch {
almanac: Almanac,
almanac_waiting: Cell<bool>,
global: Global,
global_waiting: Cell<bool>,
observers: Observers,
observers_waiting: Cell<bool>,
callbacks: Callbacks,
}
impl Watch {
fn on_almanac_update(&self) {
self.almanac_waiting.set(false);
self.on_generic_update();
}
fn on_global_update(&self) {
self.global_waiting.set(false);
self.on_generic_update();
}
fn on_observers_update(&self) {
self.observers_waiting.set(false);
self.on_generic_update();
}
fn on_generic_update(&self) {
if !self.almanac_waiting.get() && !self.global_waiting.get() && !self.observers_waiting.get() {
self.callbacks.emit();
}
}
}
#[derive(Debug)]
pub struct Inner {
watch: Rc<Watch>,
_almanac_cbr: CallbackRegistration,
_global_cbr: CallbackRegistration,
_observers_cbr: CallbackRegistration,
}
/// All basic data
#[derive(Clone, Debug)]
pub struct Base(Rc<Inner>);
impl Base {
pub fn new(config: Config) -> Self {
let base = ModelBase::from(());
let watch = Rc::new(Watch {
almanac: Almanac::new_shared(config.clone(), base.clone()),
almanac_waiting: Cell::new(true),
global: Global::new_shared(config.clone(), base.clone()),
global_waiting: Cell::new(true),
observers: Observers::new_shared(config, base),
observers_waiting: Cell::new(true),
callbacks: Callbacks::new(),
});
let _almanac_cbr = watch.almanac.register(yew::Callback::from({
let watch = watch.clone();
move |()| watch.on_almanac_update()
}));
let _global_cbr = watch.global.register(yew::Callback::from({
let watch = watch.clone();
move |()| watch.on_global_update()
}));
let _observers_cbr = watch.observers.register(yew::Callback::from({
let watch = watch.clone();
move |()| watch.on_observers_update()
}));
let inner = Rc::new(Inner {
watch,
_almanac_cbr,
_global_cbr,
_observers_cbr,
});
Self(inner)
}
pub fn register(&self, callback: yew::Callback<()>) -> CallbackRegistration {
self.0.watch.callbacks.register(callback)
}
pub fn refresh(&self) {
self.0.watch.almanac_waiting.set(true);
self.0.watch.global_waiting.set(true);
self.0.watch.observers_waiting.set(true);
self.0.watch.almanac.refresh();
self.0.watch.global.refresh();
self.0.watch.observers.refresh();
}
pub fn is_pending(&self) -> bool {
self.0.watch.almanac.is_pending()
|| self.0.watch.global.is_pending()
|| self.0.watch.observers.is_pending()
}
pub fn almanac(&self) -> &Almanac {
&self.0.watch.almanac
}
pub fn global(&self) -> &Global {
&self.0.watch.global
}