diff --git a/Cargo.lock b/Cargo.lock index dfdaf3ec..86aeeb95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,12 +23,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arc-swap" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "arrayref" -version = "0.3.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -40,9 +35,14 @@ dependencies = [ ] [[package]] -name = "arrayvec" -version = "0.5.1" +name = "async-trait" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "atom" @@ -111,11 +111,6 @@ name = "base64" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "bitflags" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "bitflags" version = "1.2.1" @@ -129,45 +124,11 @@ dependencies = [ "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "blake2b_simd" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "bumpalo" version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byteorder" version = "1.3.4" @@ -179,7 +140,6 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -242,11 +202,6 @@ dependencies = [ "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "core-foundation" version = "0.7.0" @@ -293,14 +248,6 @@ dependencies = [ "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-queue" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam-queue" version = "0.2.1" @@ -329,15 +276,6 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crypto-mac" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "debugid" version = "0.7.2" @@ -358,34 +296,11 @@ dependencies = [ "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "dirs" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "dtoa" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "either" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "encoding_rs" version = "0.8.22" @@ -426,11 +341,6 @@ dependencies = [ "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "fnv" version = "1.0.6" @@ -501,15 +411,6 @@ name = "futures-core" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "futures-cpupool" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "futures-executor" version = "0.3.4" @@ -565,14 +466,6 @@ dependencies = [ "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "generic-array" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "getrandom" version = "0.1.14" @@ -583,28 +476,6 @@ dependencies = [ "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "glib" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "glib-sys" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "glib-sys" version = "0.9.1" @@ -614,172 +485,6 @@ dependencies = [ "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "gobject-sys" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gstreamer" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "muldiv 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gstreamer-app" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-app-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-base 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-base-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gstreamer-app-sys" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-base-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gstreamer-audio-sys" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-base-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gstreamer-base" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-base-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gstreamer-base-sys" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gstreamer-pbutils" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-pbutils-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gstreamer-pbutils-sys" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-audio-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-video-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gstreamer-sys" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gstreamer-video-sys" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-base-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "h2" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "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)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "h2" version = "0.2.4" @@ -806,20 +511,6 @@ dependencies = [ "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "hex" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "hmac" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "hostname" version = "0.3.1" @@ -850,17 +541,6 @@ dependencies = [ "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "http-body" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "http-body" version = "0.3.1" @@ -888,35 +568,6 @@ dependencies = [ "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "hyper" -version = "0.12.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "hyper" version = "0.13.5" @@ -940,18 +591,6 @@ dependencies = [ "want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "hyper-tls" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "hyper-tls" version = "0.4.1" @@ -1018,30 +657,20 @@ name = "janus-conference" version = "0.6.3" dependencies = [ "anyhow 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "async-trait 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", "atom 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "config 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-app 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-base 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-pbutils 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "janus-plugin 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "janus-plugin-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "janus-plugin-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "multimap 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rumqtt 0.30.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rusoto_core 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rusoto_credential 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rusoto_s3 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rusoto_signature 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)", "sentry 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1049,6 +678,7 @@ dependencies = [ "svc-agent 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "svc-error 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1067,15 +697,6 @@ dependencies = [ "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "janus-plugin-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "glib-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jansson-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "janus-plugin-sys" version = "0.7.0" @@ -1183,11 +804,6 @@ name = "maybe-uninit" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "md5" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "memchr" version = "2.3.3" @@ -1240,7 +856,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1267,7 +883,7 @@ dependencies = [ [[package]] name = "miow" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1284,11 +900,6 @@ dependencies = [ "failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "muldiv" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "multimap" version = "0.8.1" @@ -1348,16 +959,6 @@ dependencies = [ "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "num-rational" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "num-traits" version = "0.1.43" @@ -1383,11 +984,6 @@ dependencies = [ "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "openssl" version = "0.10.29" @@ -1697,16 +1293,6 @@ name = "redox_syscall" version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "redox_users" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "regex" version = "1.3.7" @@ -1804,95 +1390,6 @@ dependencies = [ "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rusoto_core" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-tls 0.3.2 (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)", - "rusoto_credential 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rusoto_signature 0.42.0 (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.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "xml-rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rusoto_credential" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", - "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-process 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rusoto_s3" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "rusoto_core 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)", - "xml-rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rusoto_signature" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "md5 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rusoto_credential 0.42.0 (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.106 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rust-argon2" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rust-ini" version = "0.13.0" @@ -2090,28 +1587,12 @@ dependencies = [ "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "sha2" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "shlex" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "signal-hook-registry" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arc-swap 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "arc-swap 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2158,19 +1639,6 @@ name = "static_assertions" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "string" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "subtle" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "svc-agent" version = "0.7.3" @@ -2309,21 +1777,16 @@ dependencies = [ "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", + "mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-buf" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2374,24 +1837,6 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio-process" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-signal 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tokio-reactor" version = "0.1.12" @@ -2421,22 +1866,6 @@ dependencies = [ "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio-signal" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tokio-sync" version = "0.1.8" @@ -2648,16 +2077,6 @@ name = "version_check" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "want" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "want" version = "0.3.0" @@ -2806,11 +2225,6 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "xml-rs" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "yaml-rust" version = "0.4.3" @@ -2823,10 +2237,9 @@ dependencies = [ "checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum anyhow 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f" -"checksum arc-swap 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b585a98a234c46fc563103e9278c9391fde1f4e6850334da895d27edb9580f62" -"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +"checksum arc-swap 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" +"checksum async-trait 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a265e3abeffdce30b2e26b7a11b222fe37c6067404001b434101457d0385eb92" "checksum atom 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3c86699c3f02778ec07158376991c8f783dd1f2f95c579ffaf0738dc984b2fe2" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" @@ -2836,14 +2249,9 @@ dependencies = [ "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" -"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum bitmaps 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" -"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" -"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" "checksum bumpalo 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" -"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" @@ -2853,28 +2261,21 @@ dependencies = [ "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" "checksum config 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3" -"checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" "checksum core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" "checksum core-foundation-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" "checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" "checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" "checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" -"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" "checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" "checksum debugid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f91cf5a8c2f2097e2a32627123508635d47ce10563d999ec1a95addf08b502ba" "checksum derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f57d78cf3bd45270dad4e70c21ec77a960b36c7a841ff9db76aaa775a8fb871" -"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -"checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" "checksum dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" -"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28" "checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" "checksum failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" "checksum failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" -"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" @@ -2885,45 +2286,24 @@ dependencies = [ "checksum futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780" "checksum futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8" "checksum futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" -"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" "checksum futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6" "checksum futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7" "checksum futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" "checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" "checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" -"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "be27232841baa43e0fd5ae003f7941925735b2f733a336dc75f07b9eff415e7b" -"checksum glib-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd7d911c5dc610aabe37caae7d3b9d2cfe6d8f4c85ff4c062f3d6f490e75067" "checksum glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "95856f3802f446c05feffa5e24859fe6a183a7cb849c8449afc35c86b1e316e2" -"checksum gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31d1a804f62034eccf370006ccaef3708a71c31d561fee88564abe71177553d9" -"checksum gstreamer 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa91e470b0cd4b05611f7d0e89caf76e39752156440877f04c23ad34ffc9761c" -"checksum gstreamer-app 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a85485c2db4149ccb24d0b3c6598725743dec254bf757ac7a3684e62b9822c27" -"checksum gstreamer-app-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf869ce152c23bca5d761ab62146b47f750d0b28d4d499731857532897d48167" -"checksum gstreamer-audio-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bbc91f53eec49fc31d6e0aea7502c4c4b502a4164e351b97fe81677f8a0ebce7" -"checksum gstreamer-base 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "37ed3ddb8f1a65e401340afb5657d2107d78c82f06a081e19393fc8d4c5ee720" -"checksum gstreamer-base-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ba384f52174b3c586593fca32642680a9e67961fea9f4cd8419f678965023bed" -"checksum gstreamer-pbutils 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17713f529d92459d5a5e4aa81a2d6778502ce2b6f92968645a7f1eedc811b155" -"checksum gstreamer-pbutils-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4eb7a9e68b2e09fa2889119ea4243c1cce83008a92d25d78f9324495707d8de8" -"checksum gstreamer-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d18da01b97d0ab5896acd5151e4c155acefd0e6c03c3dd24dd133ba054053db" -"checksum gstreamer-video-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "615f4298f842f4b4581606e13cf52e1710e2130d989bb99161a5665aa3ccb7cc" -"checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" "checksum h2 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "377038bf3c89d18d6ca1431e7a5027194fbd724ca10592b9487ede5e8e144f42" "checksum hermit-abi 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4" -"checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" -"checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" "checksum hostname 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" "checksum http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0" "checksum http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" -"checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" "checksum http-body 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" "checksum httpdate 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -"checksum hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)" = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6" "checksum hyper 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96816e1d921eca64d208a85aab4f7798455a8e34229ee5a88c935bdee1b78b14" -"checksum hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f" "checksum hyper-tls 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3adcd308402b9553630734e9c36b77a7e48b3821251ca2493e8cd596763aafaa" "checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" "checksum im 14.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "696059c87b83c5a258817ecd67c3af915e3ed141891fc35a1e79908801cf0ce7" @@ -2932,7 +2312,6 @@ dependencies = [ "checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" "checksum jansson-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8c71b62bcd47246aeb80d8559cfda53c85b494f5c31eb814113fef51afe67e2a" "checksum janus-plugin 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "36e6b8a13ccdb245ea249504599568faeac6994ae19fd6ed0a0c6e7fd57c9568" -"checksum janus-plugin-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4d3254f8932fbe67089748198c54ae06cff16b33503be38b6581adb0fe6678a7" "checksum janus-plugin-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fc7630a60f06d7faa936de0ec123d37ef45caad83c7e45e2ce9f9f5a332a502" "checksum js-sys 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "0b823ebafcee1632403f2782d28728aab353f7881547a700043ef455c078326f" "checksum jsonwebtoken 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8d438ea707d465c230305963b67f8357a1d56fcfad9434797d7cb1c46c2e41df" @@ -2947,7 +2326,6 @@ dependencies = [ "checksum match_cfg 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" -"checksum md5 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" "checksum mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" @@ -2956,20 +2334,17 @@ dependencies = [ "checksum mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f5e374eff525ce1c5b7687c4cef63943e7686524a387933ad27ca7ec43779cb3" "checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" +"checksum miow 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e" "checksum mqtt311 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6ab68ed965d1989c683d3c930998d8c816d024182f89303205a8864d5ef0d4e" -"checksum muldiv 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0419348c027fa7be448d2ae7ea0e4e04c2334c31dc4e74ab29f00a2a7ca69204" "checksum multimap 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d8883adfde9756c1d30b0f519c9b8c502a94b41ac62f696453c37c7fc0a958ce" "checksum native-tls 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum nom 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b471253da97532da4b61552249c521e01e736071f71c1a4f7ebbfbf0a06aad6" "checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" -"checksum num-rational 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" "checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" "checksum openssl 0.10.29 (registry+https://github.com/rust-lang/crates.io-index)" = "cee6d85f4cb4c4f59a6a85d5b68a233d280c82e29e822913b9c8b129fbf20bdd" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" "checksum openssl-sys 0.9.55 (registry+https://github.com/rust-lang/crates.io-index)" = "7717097d810a0f2e2323f9e5d11e71608355e24828410b55b9d4f18aa5f9a5d8" @@ -3007,18 +2382,12 @@ dependencies = [ "checksum rand_xoshiro 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" "checksum regex 1.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692" "checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum reqwest 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b81e49ddec5109a9dcfc5f2a317ff53377c915e9ae9d4f2fb50914b85614e2" "checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" "checksum rumqtt 0.30.1 (registry+https://github.com/rust-lang/crates.io-index)" = "beda95afe12940a77d9738b56401419867dc38ff99267cac6232989851b2d11c" -"checksum rusoto_core 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1d1ecfe8dac29878a713fbc4c36b0a84a48f7a6883541841cdff9fdd2ba7dfb" -"checksum rusoto_credential 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8632e41d289db90dd40d0389c71a23c5489e3afd448424226529113102e2a002" -"checksum rusoto_s3 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fedcadf3d73c2925b05d547b66787f2219c5e727a98c893fff5cf2197dbd678" -"checksum rusoto_signature 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7063a70614eb4b36f49bcf4f6f6bb30cc765e3072b317d6afdfe51e7a9f482d1" -"checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" "checksum rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" "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" @@ -3041,8 +2410,6 @@ dependencies = [ "checksum serde_json 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)" = "a7894c8ed05b7a3a279aeb79025fdec1d3158080b75b98a08faf2806bb799edd" "checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" "checksum serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" -"checksum sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0" -"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" "checksum sized-chunks 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d59044ea371ad781ff976f7b06480b9f0180e834eda94114f2afb4afc12b7718" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" @@ -3050,8 +2417,6 @@ dependencies = [ "checksum smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" "checksum socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" "checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3" -"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" -"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum svc-agent 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bce3898db7a4583857a33a1023f6180f50fe9970ebf405e0407e875df0cadc92" "checksum svc-authn 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c51fec691ede0761eec4f0195ae64219da96597e4944cd3a3c229587049eae" "checksum svc-error 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b9841fba75aaebf5ac0e2e82610d757e62ea7e094e0ab1130494f7be921acd0d" @@ -3064,16 +2429,13 @@ dependencies = [ "checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" "checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" "checksum tokio 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "05c1d570eb1a36f0345a5ce9c6c6e665b70b73d11236912c0b477616aeec47b1" -"checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" "checksum tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" "checksum tokio-current-thread 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" "checksum tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" "checksum tokio-fs 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" "checksum tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" -"checksum tokio-process 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "382d90f43fa31caebe5d3bc6cfd854963394fff3b8cb59d5146607aaae7e7e43" "checksum tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" "checksum tokio-rustls 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04a5c8de3797c207c574495724eb77ded1a150160a2db0936c751bf49003c84e" -"checksum tokio-signal 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c34c6e548f101053321cba3da7cbb87a610b85555884c41b07da2eb91aff12" "checksum tokio-sync 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" "checksum tokio-tcp 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" "checksum tokio-threadpool 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" @@ -3098,7 +2460,6 @@ dependencies = [ "checksum uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" "checksum vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" "checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" -"checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" "checksum want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" "checksum wasm-bindgen 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)" = "f56e97dbea16d5f56549d6c8ea7f36efb6be98507308650c1a5970574b3941b9" @@ -3117,5 +2478,4 @@ dependencies = [ "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -"checksum xml-rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" "checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" diff --git a/Cargo.toml b/Cargo.toml index 94832e89..f5ee9194 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] +async-trait = "0.1" anyhow = "1.0" chrono = "0.4" janus-plugin-sys = "0.7" @@ -20,21 +21,12 @@ lazy_static = "1.4" libc = "0.2" atom = "0.3" multimap = "0.8" -glib-sys = "0.9" -glib = "0.8" -gstreamer = "0.14" -gstreamer-app = "0.14" -gstreamer-base = "0.14" -gstreamer-pbutils="0.14" -rusoto_core = "0.42" -rusoto_credential = "0.42" -rusoto_s3 = "0.42" -rusoto_signature = "0.42" http = "0.1" futures = { version = "0.3", features = ["thread-pool"] } futures-channel = "0.3" svc-error = { version = "0.1", features = ["sentry-extension"] } sentry = "0.18" +tokio = { version = "0.2", features = ["process"] } uuid = { version = "0.8", features = ["serde", "v4"] } [dev-dependencies] @@ -42,4 +34,4 @@ rand = "0.6" rumqtt = "0.30" svc-agent = "0.7" tempfile = "3.0" -janus-plugin-sys = "0.6" +janus-plugin-sys = "0.7" diff --git a/docker/Dockerfile b/docker/Dockerfile index 6c6c8a17..35eaaf25 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -9,22 +9,17 @@ RUN set -xe \ && apt-get -y --no-install-recommends install \ autoconf \ automake \ + awscli \ ca-certificates \ curl \ ffmpeg \ gengetopt \ git \ - gstreamer1.0-libav \ - gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-base \ - gstreamer1.0-plugins-good \ - gstreamer1.0-plugins-ugly \ + libavformat-dev \ + libavcodec-dev \ libconfig-dev \ libcurl4-openssl-dev \ libglib2.0-dev \ - libgstreamer1.0-dev \ - libgstreamer-plugins-base1.0-dev \ - libgstrtspserver-1.0-dev \ libjansson-dev \ libmicrohttpd-dev \ libogg-dev \ @@ -90,7 +85,7 @@ RUN set -xe \ && git clone 'https://github.com/netology-group/janus-gateway' . \ && git checkout "${JANUS_GATEWAY_COMMIT}" \ && ./autogen.sh \ - && ./configure --prefix=/opt/janus \ + && ./configure --prefix=/opt/janus --enable-post-processing \ && make -j $(nproc) \ && make install \ && make configs \ @@ -134,11 +129,7 @@ RUN set -eux; \ RUN set -xe \ && apt-get update \ - && apt-get -y --no-install-recommends install \ - libjansson-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ - gstreamer1.0-plugins-base gstreamer1.0-plugins-good \ - gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \ - gstreamer1.0-libav libgstrtspserver-1.0-dev + && apt-get -y --no-install-recommends install libjansson-dev WORKDIR /build COPY . . @@ -151,3 +142,4 @@ FROM build-janus ARG PLUGIN=libjanus_conference.so WORKDIR /opt/janus COPY --from=build-plugin-deploy /build/target/release/${PLUGIN} ./lib/janus/plugins/${PLUGIN} +COPY ./scripts/upload_record.sh /opt/janus/bin/upload_record.sh diff --git a/docker/develop.dockerfile b/docker/develop.dockerfile index 474ea7b2..bfd185de 100644 --- a/docker/develop.dockerfile +++ b/docker/develop.dockerfile @@ -9,22 +9,17 @@ RUN set -xe \ && apt-get -y --no-install-recommends install \ autoconf \ automake \ + awscli \ ca-certificates \ curl \ ffmpeg \ gengetopt \ git \ - gstreamer1.0-libav \ - gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-base \ - gstreamer1.0-plugins-good \ - gstreamer1.0-plugins-ugly \ + libavformat-dev \ + libavcodec-dev \ libconfig-dev \ libcurl4-openssl-dev \ libglib2.0-dev \ - libgstreamer1.0-dev \ - libgstreamer-plugins-base1.0-dev \ - libgstrtspserver-1.0-dev \ libjansson-dev \ libmicrohttpd-dev \ libogg-dev \ @@ -110,7 +105,7 @@ RUN set -xe \ && git clone 'https://github.com/netology-group/janus-gateway' . \ && git checkout "${JANUS_GATEWAY_COMMIT}" \ && ./autogen.sh \ - && ./configure --prefix=/opt/janus \ + && ./configure --prefix=/opt/janus --enable-post-processing \ && make -j $(nproc) \ && make install \ && make configs \ diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 61d4e30a..6aef6bc1 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -13,6 +13,7 @@ services: - ..:/build - ../recordings:/recordings - janus-conference-cargo:/usr/local/cargo + - ../scripts/upload_record.sh:/opt/janus/bin/upload_record.sh env_file: janus.plugin.conference.environment links: - vernemq diff --git a/examples/src/sdp.js b/examples/src/sdp.js index 71336c3a..e6e3908d 100644 --- a/examples/src/sdp.js +++ b/examples/src/sdp.js @@ -37,7 +37,7 @@ export function transformOfferSDP (sdp, opts) { modifiedPayload: 109, }, video: { - codecName: 'H264', + codecName: 'VP8', modifiedPayload: 126, } } diff --git a/scripts/upload_record.sh b/scripts/upload_record.sh new file mode 100755 index 00000000..8750cda8 --- /dev/null +++ b/scripts/upload_record.sh @@ -0,0 +1,60 @@ +#!/bin/bash -e + +function REPORT_ERROR() { >&2 echo ${@}; } + +# Arguments. +RTC_ID=$1 +BUCKET=$2 +OBJECT=$3 + +if [[ ! ${RTC_ID} ]]; then $(REPORT_ERROR "RTC_ID isn't specified"); exit 1; fi +if [[ ! ${BUCKET} ]]; then $(REPORT_ERROR "BUCKET isn't specified"); exit 1; fi +if [[ ! ${OBJECT} ]]; then $(REPORT_ERROR "OBJECT isn't specified"); exit 1; fi + +# Environment. +if [[ ! ${APP_UPLOADING__ACCESS_KEY_ID} ]]; then $(REPORT_ERROR "APP_UPLOADING__ACCESS_KEY_ID isn't specified"); exit 1; fi +if [[ ! ${APP_UPLOADING__SECRET_ACCESS_KEY} ]]; then $(REPORT_ERROR "APP_UPLOADING__SECRET_ACCESS_KEY isn't specified"); exit 1; fi +if [[ ! ${APP_UPLOADING__ENDPOINT} ]]; then $(REPORT_ERROR "APP_UPLOADING__ENDPOINT isn't specified"); exit 1; fi +if [[ ! ${APP_UPLOADING__REGION} ]]; then $(REPORT_ERROR "APP_UPLOADING__REGION isn't specified"); exit 1; fi + +export AWS_ACCESS_KEY_ID=${APP_UPLOADING__ACCESS_KEY_ID} +export AWS_SECRET_ACCESS_KEY=${APP_UPLOADING__SECRET_ACCESS_KEY} +export AWS_ENDPOINT=${APP_UPLOADING__ENDPOINT} +export AWS_REGION=${APP_UPLOADING__REGION} + +# Working directory. +cd /recordings/${RTC_ID} + +# Convert video .mjr dumps into .webm files. +for FILE in *.video.mjr; do + /opt/janus/bin/janus-pp-rec $FILE ${FILE%.*}.webm + echo "file '${FILE%.*}.webm'" >> video_sources.txt +done + +# Get video segments durations and write to segments.csv file. +for FILE in *.video.webm; do + DURATION=$(ffprobe -i ${FILE} -show_entries format=duration -v quiet -of csv="p=0") + echo "${FILE%%.*},${DURATION}" >> segments.csv +done + +# Concat video segments into a single .webm file. +ffmpeg -f concat -i video_sources.txt -c copy -y concat.webm + +# Convert audio .mjr dumps into .opus files. +for FILE in *.audio.mjr; do + /opt/janus/bin/janus-pp-rec $FILE ${FILE%.*}.opus + echo "file '${FILE%.*}.opus'" >> audio_sources.txt +done + +# Concat audio segments into a single .opus file. +ffmpeg -f concat -i audio_sources.txt -c copy -y concat.opus + +# Mux video & audio into a single .webm file. +ffmpeg -i concat.webm -i concat.opus -c copy full.webm + +# Upload record. +aws --endpoint-url=${AWS_ENDPOINT} --region=${AWS_REGION} s3 cp full.webm s3://${BUCKET}/${OBJECT} + +# Clean up. +cd .. +rm -rf ./${RTC_ID} diff --git a/src/app.rs b/src/app.rs index 5327e1a2..5372f0ec 100644 --- a/src/app.rs +++ b/src/app.rs @@ -7,7 +7,6 @@ use chrono::Duration; use crate::conf::Config; use crate::message_handler::{JanusSender, MessageHandlingLoop}; use crate::switchboard::LockedSwitchboard as Switchboard; -use crate::uploader::Uploader; lazy_static! { pub static ref APP: AtomSetOnce> = AtomSetOnce::empty(); @@ -25,7 +24,6 @@ pub struct App { pub config: Config, pub switchboard: Switchboard, pub message_handling_loop: MessageHandlingLoop, - pub uploader: Uploader, } impl App { @@ -58,13 +56,10 @@ impl App { } pub fn new(config: Config) -> Result { - let uploader = Uploader::build(config.uploading.clone())?; - Ok(Self { config, switchboard: Switchboard::new(), message_handling_loop: MessageHandlingLoop::new(JanusSender::new()), - uploader, }) } } diff --git a/src/conf.rs b/src/conf.rs index 6ffe182e..0b0355e9 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -4,7 +4,6 @@ use anyhow::Result; use config; use crate::recorder; -use crate::uploader; const CONFIG_FILE_NAME: &str = "janus.plugin.conference.toml"; @@ -12,7 +11,6 @@ const CONFIG_FILE_NAME: &str = "janus.plugin.conference.toml"; pub struct Config { pub general: General, pub recordings: recorder::Config, - pub uploading: uploader::Config, pub constraint: Constraint, pub sentry: Option, } diff --git a/src/janus_recorder.rs b/src/janus_recorder.rs index 1c745e15..0ef92cf3 100644 --- a/src/janus_recorder.rs +++ b/src/janus_recorder.rs @@ -4,7 +4,6 @@ use std::ffi::CString; use std::os::raw::{c_char, c_int, c_long, c_uint}; use anyhow::{bail, format_err, Context, Result}; -use glib_sys::gboolean; use janus_plugin_sys::janus_refcount; use libc::{pthread_mutex_t, FILE}; @@ -77,6 +76,7 @@ impl Drop for JanusRecorder<'_> { /////////////////////////////////////////////////////////////////////////////// +type gboolean = c_int; type gint = c_int; type gint64 = c_long; type janus_mutex = pthread_mutex_t; diff --git a/src/lib.rs b/src/lib.rs index d62085f1..e9c38099 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,7 +35,6 @@ mod switchboard; mod utils; #[cfg(test)] mod test_stubs; -mod uploader; use app::App; use conf::Config; diff --git a/src/message_handler/generic/mod.rs b/src/message_handler/generic/mod.rs index 8653932c..56a4a821 100644 --- a/src/message_handler/generic/mod.rs +++ b/src/message_handler/generic/mod.rs @@ -7,7 +7,7 @@ use std::marker::PhantomData; use std::sync::mpsc; use anyhow::{format_err, Error}; -use futures::{executor::ThreadPool, future::lazy}; +use futures::executor::ThreadPool; use http::StatusCode; use janus::JanssonValue; use serde_json::Value as JsonValue; @@ -41,7 +41,7 @@ pub struct MessageHandlingLoop { impl MessageHandlingLoop where R: Router, - S: 'static + Clone + Send + Sender, + S: 'static + Clone + Send + Sync + Sender, { pub fn new(sender: S) -> Self { let (tx, rx) = mpsc::sync_channel(10); @@ -67,9 +67,9 @@ where janus_info!("[CONFERENCE] Scheduling request handling"); let handler = handler.clone(); - self.thread_pool.spawn_ok(lazy(move |_| { - handler.handle_request(operation, request); - })); + self.thread_pool.spawn_ok(async move { + handler.handle_request(operation, request).await; + }); } Some(Message::Response(response)) => { handler.handle_response(response); @@ -137,7 +137,7 @@ impl MessageHandler { } /// Handles JSEP if needed, calls the operation and schedules its response. - fn handle_request(&self, operation: Box, request: Request) { + async fn handle_request(&self, operation: Box, request: Request) { janus_info!("[CONFERENCE] Handling request"); let jsep_answer_result = match operation.is_handle_jsep() { @@ -149,7 +149,7 @@ impl MessageHandler { Ok(jsep_answer) => { janus_info!("[CONFERENCE] Calling operation"); - let payload = match operation.call(&request) { + let payload = match operation.call(&request).await { Ok(payload) => JsonValue::from(payload).into(), Err(err) => { self.notify_error(&err); @@ -195,7 +195,7 @@ impl MessageHandler { .unwrap_or_else(|err| janus_err!("[CONFERENCE] Error sending response: {}", err)); } - /// Builds a response object for the reuqest and pushes it to the message handling queue. + /// Builds a response object for the request and pushes it to the message handling queue. fn schedule_response( &self, request: Request, @@ -276,12 +276,13 @@ pub trait Sender { #[cfg(test)] mod tests { - use std::sync::mpsc; + use std::sync::{mpsc, Arc, Mutex}; use std::thread; use std::time::Duration; use anyhow::{bail, format_err, Result}; - use serde_json::json; + use async_trait::async_trait; + use serde_json::{json, Value as JsonValue}; use super::MessageHandlingLoop; use super::Router; @@ -298,8 +299,9 @@ mod tests { session_id: String, } + #[async_trait] impl Operation for PingRequest { - fn call(&self, request: &Request) -> OperationResult { + async fn call(&self, request: &Request) -> OperationResult { Ok(PingResponse { message: String::from("pong"), session_id: request.session_id().to_string(), @@ -332,19 +334,24 @@ mod tests { struct TestResponse { session_id: SessionId, transaction: String, - payload: Option, - jsep_answer: Option, + payload: Option, + jsep_answer: Option, } #[derive(Clone)] struct TestSender { - tx: mpsc::Sender, + tx: Arc>>, } impl TestSender { fn new() -> (Self, mpsc::Receiver) { let (tx, rx) = mpsc::channel(); - (Self { tx }, rx) + + let object = Self { + tx: Arc::new(Mutex::new(tx)), + }; + + (object, rx) } } @@ -356,14 +363,27 @@ mod tests { payload: Option, jsep_answer: Option, ) -> Result<()> { - self.tx - .send(TestResponse { - session_id, - transaction: transaction.to_owned(), - payload, - jsep_answer, - }) - .map_err(|err| format_err!("Failed to send test response: {}", err)) + let payload = payload.map(|json| { + let json = json.to_libcstring(JanssonEncodingFlags::empty()); + let json = json.to_string_lossy(); + serde_json::from_str(&json).unwrap() + }); + + let jsep_answer = jsep_answer.map(|json| { + let json = json.to_libcstring(JanssonEncodingFlags::empty()); + let json = json.to_string_lossy(); + serde_json::from_str(&json).unwrap() + }); + + let tx = self.tx.lock().unwrap(); + + tx.send(TestResponse { + session_id, + transaction: transaction.to_owned(), + payload, + jsep_answer, + }) + .map_err(|err| format_err!("Failed to send test response: {}", err)) } } @@ -394,19 +414,14 @@ mod tests { match response.payload { None => bail!("Missing payload"), - Some(jansson_value) => { - let json_str = jansson_value.to_libcstring( - JanssonEncodingFlags::JSON_COMPACT | JanssonEncodingFlags::JSON_PRESERVE_ORDER, - ); - - let expected_json = json!({ + Some(json) => assert_eq!( + json, + json!({ "message": "pong", "session_id": session_id.to_string(), - "status": "200" - }); - - assert_eq!(json_str.to_string_lossy(), expected_json.to_string()); - } + "status": "200", + }) + ), } Ok(()) diff --git a/src/message_handler/generic/operation.rs b/src/message_handler/generic/operation.rs index b1427031..5ea2216a 100644 --- a/src/message_handler/generic/operation.rs +++ b/src/message_handler/generic/operation.rs @@ -1,12 +1,14 @@ use std::fmt; +use async_trait::async_trait; use serde::Serialize; use serde_json::Value as JsonValue; use svc_error::Error as SvcError; -pub trait Operation: fmt::Debug + Send { +#[async_trait] +pub trait Operation: fmt::Debug + Send + Sync { /// Operation implementation - fn call(&self, request: &super::Request) -> self::Result; + async fn call(&self, request: &super::Request) -> self::Result; /// Whether MessageHandler should process SDP offer/answer before calling this operation. fn is_handle_jsep(&self) -> bool; diff --git a/src/message_handler/operations/agent_leave.rs b/src/message_handler/operations/agent_leave.rs index 855515ee..7888deac 100644 --- a/src/message_handler/operations/agent_leave.rs +++ b/src/message_handler/operations/agent_leave.rs @@ -1,4 +1,5 @@ use anyhow::{format_err, Error}; +use async_trait::async_trait; use http::StatusCode; use svc_error::Error as SvcError; @@ -13,8 +14,9 @@ pub struct Request { #[derive(Serialize)] struct Response {} +#[async_trait] impl super::Operation for Request { - fn call(&self, request: &super::Request) -> super::OperationResult { + async fn call(&self, request: &super::Request) -> super::OperationResult { janus_info!("[CONFERENCE] Calling agent.leave operation"); let error = |status: StatusCode, err: Error| { diff --git a/src/message_handler/operations/stream_create.rs b/src/message_handler/operations/stream_create.rs index 3fcbee0a..3b9d8341 100644 --- a/src/message_handler/operations/stream_create.rs +++ b/src/message_handler/operations/stream_create.rs @@ -1,4 +1,5 @@ use anyhow::{format_err, Error}; +use async_trait::async_trait; use http::StatusCode; use svc_error::Error as SvcError; @@ -14,8 +15,9 @@ pub struct Request { #[derive(Serialize)] struct Response {} +#[async_trait] impl super::Operation for Request { - fn call(&self, request: &super::Request) -> super::OperationResult { + async fn call(&self, request: &super::Request) -> super::OperationResult { janus_info!( "[CONFERENCE] Calling stream.create operation with id {}", self.id diff --git a/src/message_handler/operations/stream_read.rs b/src/message_handler/operations/stream_read.rs index de0e422e..21af564c 100644 --- a/src/message_handler/operations/stream_read.rs +++ b/src/message_handler/operations/stream_read.rs @@ -1,4 +1,5 @@ use anyhow::Error; +use async_trait::async_trait; use http::StatusCode; use svc_error::Error as SvcError; @@ -13,8 +14,9 @@ pub struct Request { #[derive(Serialize)] struct Response {} +#[async_trait] impl super::Operation for Request { - fn call(&self, request: &super::Request) -> super::OperationResult { + async fn call(&self, request: &super::Request) -> super::OperationResult { janus_info!( "[CONFERENCE] Calling stream.read operation with id {}", self.id diff --git a/src/message_handler/operations/stream_upload.rs b/src/message_handler/operations/stream_upload.rs index 81beac0d..5c55e9a0 100644 --- a/src/message_handler/operations/stream_upload.rs +++ b/src/message_handler/operations/stream_upload.rs @@ -1,10 +1,14 @@ -use anyhow::{format_err, Error}; +use std::fs::File; +use std::io::{BufRead, BufReader}; + +use anyhow::{bail, format_err, Context, Error, Result}; +use async_trait::async_trait; use http::StatusCode; use svc_error::Error as SvcError; +use tokio::process::Command; // No async-std equivalent yet. -use crate::recorder::{Recorder, RecorderError}; +use crate::recorder::{Config as RecorderConfig, Recorder}; use crate::switchboard::StreamId; -use crate::uploader::Uploader; #[derive(Clone, Debug, Deserialize)] pub struct Request { @@ -20,16 +24,17 @@ struct Response { time: Vec<(u64, u64)>, } +#[async_trait] impl super::Operation for Request { - fn call(&self, _request: &super::Request) -> super::OperationResult { + async fn call(&self, _request: &super::Request) -> super::OperationResult { janus_info!( "[CONFERENCE] Calling stream.upload operation with id {}", self.id ); - let app = app!().map_err(internal_error)?; - - app.switchboard + app!() + .map_err(internal_error)? + .switchboard .with_write_lock(|mut switchboard| { // The stream still may be ongoing and we must stop it gracefully. if let Some(publisher) = switchboard.publisher_of(self.id) { @@ -48,27 +53,15 @@ impl super::Operation for Request { }) .map_err(internal_error)?; - janus_info!("[CONFERENCE] Finishing record"); - let mut recorder = Recorder::new(&app.config.recordings, self.id); - let (started_at, time) = recorder.finish_record().map_err(recorder_error)?; - - janus_info!("[CONFERENCE] Uploading record"); - let uploader = Uploader::build(app.config.uploading.clone()) - .map_err(|err| internal_error(format_err!("Failed to init uploader: {}", err)))?; - - let path = recorder.get_full_record_path(); - - uploader - .upload_file(&path, &self.bucket, &self.object) + let (started_at, segments) = upload_record(&self) + .await + .and_then(|_| parse_segments(self.id, &app!()?.config.recordings)) .map_err(internal_error)?; - janus_info!("[CONFERENCE] Uploading finished, deleting source files"); - recorder.delete_record().map_err(recorder_error)?; - Ok(Response { id: self.id, started_at, - time, + time: segments, } .into()) } @@ -93,14 +86,85 @@ fn internal_error(err: Error) -> SvcError { error(StatusCode::INTERNAL_SERVER_ERROR, err) } -fn recorder_error(err: RecorderError) -> SvcError { - match err { - RecorderError::InternalError(cause) => internal_error(cause), - RecorderError::IoError(cause) => { - internal_error(format_err!("Recorder IO error: {}", cause)) - } - RecorderError::RecordingMissing => { - error(StatusCode::NOT_FOUND, format_err!("Record not found")) +/////////////////////////////////////////////////////////////////////////////// + +async fn upload_record(request: &Request) -> Result<()> { + janus_info!("[CONFERENCE] Preparing & uploading record"); + + let mut command = Command::new("/opt/janus/bin/upload_record.sh"); + let stream_id = request.id.to_string(); + command.args(&[&stream_id, &request.bucket, &request.object]); + janus_verb!("[CONFERENCE] {:?}", command); + + command + .status() + .await + .map_err(|err| format_err!("Failed to run upload_record.sh, return code = '{}'", err)) + .and_then(|status| { + if status.success() { + janus_info!( + "[CONFERENCE] Record {} successfully uploaded to {}/{}", + request.id, + request.bucket, + request.object + ); + + Ok(()) + } else { + Err(format_err!("Failed to prepare & upload record: {}", status)) + } + }) +} + +fn parse_segments( + stream_id: StreamId, + recorder_config: &RecorderConfig, +) -> Result<(u64, Vec<(u64, u64)>)> { + let recorder = Recorder::new(recorder_config, stream_id); + + let mut path = recorder.get_records_dir(); + path.push("segments.csv"); + + let file = File::open(&path)?; + let mut segments = vec![]; + + for read_result in BufReader::new(file).lines() { + let line = match read_result { + Ok(line) => line, + Err(err) => bail!(err), + }; + + // "123456789,123.45" => (123456789, 123.45) + match line.splitn(2, ',').collect::>().as_slice() { + [started_at, duration] => { + let parsed_started_at = started_at + .parse::() + .context("Failed to parse started_at")?; + + let parsed_duration = duration + .parse::() + .context("Failed to parse duration")?; + + segments.push((parsed_started_at, parsed_duration)) + } + _ => bail!("Failed to split line: {}", line), } } + + let absolute_started_at = match segments.first() { + None => bail!("No segments parsed"), + Some((started_at, _)) => started_at.to_owned(), + }; + + // [(123456789, 123.45), (123470134, 456.78)] => [(0, 12345), (13345, 59023)] + let relative_segments = segments + .into_iter() + .map(|(started_at, duration_sec)| { + let relative_started_at = started_at - absolute_started_at; + let duration_ms = (duration_sec * 1000.0) as u64; + (relative_started_at, relative_started_at + duration_ms) + }) + .collect(); + + Ok((absolute_started_at, relative_segments)) } diff --git a/src/recorder.rs b/src/recorder.rs index 1b4f42b9..531507f2 100644 --- a/src/recorder.rs +++ b/src/recorder.rs @@ -1,15 +1,11 @@ use std::error::Error as StdError; use std::fmt; -use std::io::{BufWriter, Write}; use std::path::{Path, PathBuf}; -use std::process::Command; -use std::result::Result as StdResult; use std::sync::mpsc; use std::{fs, io, thread}; use anyhow::{bail, format_err, Context, Error, Result}; use chrono::Utc; -use gstreamer as gst; use crate::janus_recorder::{Codec, JanusRecorder}; use crate::switchboard::StreamId; @@ -37,10 +33,6 @@ impl Config { } } -const WEBM_EXTENSION: &str = "webm"; -const DISCOVERER_TIMEOUT: u64 = 15; -const FULL_RECORD_FILENAME: &str = "full"; - #[derive(Debug)] enum RecorderMsg { Stop, @@ -67,12 +59,6 @@ pub struct Recorder { /// /// Recorder runs in separate thread. /// You're able to write buffers using `record_packet` method. -/// -/// It's possible to make a full concatenated record -/// (e.g. stream is over and you need to pass full record -/// to some external service). Use method `finish_record` -/// for that. - impl Recorder { pub fn new(config: &Config, stream_id: StreamId) -> Self { let (sender, recv): (mpsc::Sender, _) = mpsc::channel(); @@ -96,95 +82,6 @@ impl Recorder { self.sender.send(msg).context("Failed to send packet") } - pub fn finish_record(&mut self) -> StdResult<(u64, Vec<(u64, u64)>), RecorderError> { - let records_dir = self.get_records_dir(); - - if !records_dir.is_dir() { - return Err(RecorderError::RecordingMissing); - } - - let mut parts: Vec = fs::read_dir(&records_dir)? - .filter_map(|maybe_dir_entry| { - maybe_dir_entry - .ok() - .and_then(|dir_entry| RecordPart::from_path(dir_entry.path())) - }) - .collect(); - - if parts.is_empty() { - return Err(RecorderError::RecordingMissing); - } - - parts.sort_by_key(|part| part.start); - - let absolute_started_at = parts[0].start; - let mut relative_timestamps: Vec<(u64, u64)> = Vec::with_capacity(parts.len()); - let files_list_path = records_dir.join("parts.txt"); - - { - let files_list = fs::File::create(files_list_path.as_path())?; - let mut files_list_writer = BufWriter::new(&files_list); - - for part in parts { - // file '/recordings/123/1234567890.webm' - let filename = part.path.as_path().to_string_lossy().into_owned(); - writeln!(&mut files_list_writer, "file '{}'", filename)?; - - let start = part.start - absolute_started_at; - let stop = start + part.duration; - relative_timestamps.push((start, stop)); - } - } - - let full_record_path = self.get_full_record_path().to_string_lossy().into_owned(); - - janus_info!( - "[CONFERENCE] Concatenating full record to {}", - full_record_path - ); - - // Use ffmpeg for concatenation because it doesn't hang on corrupted videos. - // No transcoding is made here because it would create a peak load on the server. - // - // ffmpeg -f concat -safe 0 -i /recordings/123/parts.txt -c copy -y /recordings/123/full.webm - let mut command = Command::new("ffmpeg"); - - command.args(&[ - "-f", - "concat", - "-safe", - "0", - "-i", - &files_list_path.to_string_lossy().into_owned(), - "-c", - "copy", - "-y", - "-strict", - "-2", - &full_record_path, - ]); - - janus_info!("[CONFERENCE] {:?}", command); - let status = command.status()?; - - if status.success() { - janus_info!( - "[CONFERENCE] Full record concatenated to {}", - full_record_path - ); - - Ok((absolute_started_at, relative_timestamps)) - } else { - let err = format_err!( - "Failed to concatenate full record {} ({})", - full_record_path, - status - ); - - Err(err.into()) - } - } - pub fn start_recording(&mut self) -> Result<()> { janus_info!("[CONFERENCE] Start recording"); let dir = self.create_records_dir().to_string_lossy().into_owned(); @@ -252,14 +149,7 @@ impl Recorder { Ok(()) } - pub fn get_full_record_path(&self) -> PathBuf { - let mut path = self.get_records_dir(); - path.push(FULL_RECORD_FILENAME); - path.set_extension(WEBM_EXTENSION); - path - } - - fn get_records_dir(&self) -> PathBuf { + pub fn get_records_dir(&self) -> PathBuf { let mut path = PathBuf::new(); path.push(&self.save_root_dir); path.push(&self.stream_id.to_string()); @@ -278,108 +168,12 @@ impl Recorder { path } - - pub fn delete_record(&self) -> StdResult<(), RecorderError> { - let records_dir = self.get_records_dir(); - - fs::remove_dir_all(records_dir).map_err(|err| match err.kind() { - io::ErrorKind::NotFound => RecorderError::RecordingMissing, - _ => RecorderError::IoError(err), - }) - } -} - -struct RecordPart { - path: PathBuf, - start: u64, - duration: u64, -} - -impl RecordPart { - pub fn new(path: PathBuf, start: u64, duration: u64) -> Self { - Self { - path, - start, - duration, - } - } - - pub fn from_path(path: PathBuf) -> Option { - if !Self::is_valid_file(&path) { - return None; - } - - Self::parse_start_timestamp(&path).and_then(|start| match Self::discover_duration(&path) { - Ok(duration) => Some(Self::new(path, start, duration)), - Err(err) => { - janus_err!( - "[CONFERENCE] Failed to get duration for {}: {}. Skipping part.", - path.as_path().to_string_lossy(), - err - ); - - None - } - }) - } - - fn is_valid_file(path: &PathBuf) -> bool { - let extension = match path.extension() { - Some(extension) => extension, - None => return false, - }; - - if extension != WEBM_EXTENSION { - return false; - } - - let stem = match path.as_path().file_stem() { - Some(stem) => stem, - None => return false, - }; - - if stem.to_string_lossy().starts_with(".") { - return false; - } - - if stem == FULL_RECORD_FILENAME { - return false; - } - - match path.metadata() { - Ok(metadata) => metadata.is_file() && metadata.len() > 0, - Err(err) => { - janus_err!( - "[CONFERENCE] Failed to get metadata for {}: {}", - path.as_path().to_string_lossy(), - err - ); - - false - } - } - } - - fn parse_start_timestamp(path: &PathBuf) -> Option { - path.as_path() - .file_stem() - .and_then(|stem| stem.to_string_lossy().parse::().ok()) - } - - fn discover_duration(path: &PathBuf) -> Result { - gstreamer_pbutils::Discoverer::new(gst::ClockTime::from_seconds(DISCOVERER_TIMEOUT))? - .discover_uri(&format!("file://{}", path.as_path().to_string_lossy()))? - .get_duration() - .mseconds() - .ok_or_else(|| format_err!("Empty duration")) - } } #[derive(Debug)] pub enum RecorderError { InternalError(Error), IoError(io::Error), - RecordingMissing, } impl fmt::Display for RecorderError { @@ -387,7 +181,6 @@ impl fmt::Display for RecorderError { match self { Self::InternalError(source) => write!(f, "{}", source), Self::IoError(source) => write!(f, "{}", source), - Self::RecordingMissing => write!(f, "Recording missing"), } } } @@ -397,7 +190,6 @@ impl StdError for RecorderError { match self { Self::InternalError(source) => Some(source.as_ref()), Self::IoError(source) => Some(source), - Self::RecordingMissing => None, } } } diff --git a/src/uploader.rs b/src/uploader.rs deleted file mode 100644 index 349c55c1..00000000 --- a/src/uploader.rs +++ /dev/null @@ -1,145 +0,0 @@ -use std::fmt; -use std::fs::File; -use std::io::Read; -use std::path::Path; -use std::result::Result as StdResult; - -use anyhow::{bail, format_err, Context, Result}; -use rusoto_core::request::HttpClient; -use rusoto_credential::StaticProvider; -use rusoto_s3::{ - AbortMultipartUploadRequest, CompleteMultipartUploadRequest, CompletedMultipartUpload, - CompletedPart, CreateMultipartUploadRequest, S3Client, UploadPartRequest, S3, -}; -use rusoto_signature::Region; - -#[derive(Deserialize, Debug, Default, Clone)] -pub struct Config { - pub region: String, - pub endpoint: String, - pub access_key_id: String, - pub secret_access_key: String, -} - -pub struct Uploader { - client: S3Client, -} - -impl fmt::Debug for Uploader { - fn fmt(&self, formatter: &mut fmt::Formatter) -> StdResult<(), fmt::Error> { - write!(formatter, "<>")?; - Ok(()) - } -} - -const PART_SIZE: usize = 1024 * 1024 * 100; - -impl Uploader { - pub fn build(config: Config) -> Result { - let region = Region::Custom { - name: config.region, - endpoint: config.endpoint, - }; - - let client = S3Client::new_with( - HttpClient::new()?, - StaticProvider::new_minimal(config.access_key_id, config.secret_access_key), - region, - ); - - Ok(Self { client }) - } - - pub fn upload_file(&self, path: &Path, bucket: &str, object: &str) -> Result<()> { - let mut file = File::open(&path).context("Failed to open source file for upload")?; - - let create_req = CreateMultipartUploadRequest { - bucket: bucket.to_owned(), - key: object.to_owned(), - ..Default::default() - }; - - let upload_id = self - .client - .create_multipart_upload(create_req) - .sync() - .context("S3 multipart upload creation error")? - .upload_id - .ok_or_else(|| format_err!("S3 multipart creation response missing upload id"))?; - - match self.upload_parts(&mut file, bucket, object, &upload_id) { - Ok(parts) => { - let complete_req = CompleteMultipartUploadRequest { - bucket: bucket.to_owned(), - key: object.to_owned(), - upload_id, - multipart_upload: Some(CompletedMultipartUpload { parts: Some(parts) }), - ..Default::default() - }; - - self.client - .complete_multipart_upload(complete_req) - .sync() - .context("Failed to complete S3 uploading")?; - - Ok(()) - } - Err(err) => { - let abort_req = AbortMultipartUploadRequest { - bucket: bucket.to_owned(), - key: object.to_owned(), - upload_id, - ..Default::default() - }; - - if let Err(err) = self.client.abort_multipart_upload(abort_req).sync() { - janus_err!("Failed to abort S3 upload: {:?}", err); - } - - bail!("S3 upload failed: {}", err); - } - } - } - - fn upload_parts( - &self, - file: &mut File, - bucket: &str, - object: &str, - upload_id: &str, - ) -> Result> { - let mut parts = Vec::new(); - - for part_number in 1.. { - let mut buffer = vec![0; PART_SIZE]; - - let size = file - .read(&mut buffer[..]) - .context("Error reading source file for upload")?; - - if size == 0 { - break; - } - - buffer.truncate(size); - - let upload_req = UploadPartRequest { - bucket: bucket.to_owned(), - key: object.to_owned(), - upload_id: upload_id.to_owned(), - part_number, - body: Some(buffer.into()), - ..Default::default() - }; - - let part = self.client.upload_part(upload_req).sync()?; - - parts.push(CompletedPart { - part_number: Some(part_number), - e_tag: part.e_tag, - }); - } - - Ok(parts) - } -} diff --git a/tests/files/recording/1560489452218.mkv b/tests/files/recording/1560489452218.mkv deleted file mode 100644 index 6bb3429c..00000000 Binary files a/tests/files/recording/1560489452218.mkv and /dev/null differ diff --git a/tests/files/recording/1560489460900.mkv b/tests/files/recording/1560489460900.mkv deleted file mode 100644 index 16486fbd..00000000 Binary files a/tests/files/recording/1560489460900.mkv and /dev/null differ diff --git a/tests/janus_client.rs b/tests/janus_client.rs deleted file mode 100644 index 28e04fb7..00000000 --- a/tests/janus_client.rs +++ /dev/null @@ -1,271 +0,0 @@ -use std::time::Duration; - -use anyhow::{bail, format_err, Context, Result}; -use rand::Rng; -use serde::{Deserialize, Serialize}; -use serde_json::json; - -use svc_agent::mqtt::compat::IntoEnvelope; -use svc_agent::mqtt::{ - Agent, AgentBuilder, AgentConfig, ConnectionMode, Notification, OutgoingRequest, - OutgoingRequestProperties, QoS, -}; -use svc_agent::{AccountId, AgentId, Subscription}; - -const MQTT_BROKER_URL: &str = "localhost:1883"; -const AGENT_VERSION: &str = "v1"; -const AGENT_ID_LABEL: &str = "alpha"; -const JANUS_ACCOUNT_LABEL: &str = "janus-gateway"; -const CONFERENCE_ACCOUNT_LABEL: &str = "conference"; -const AUDIENCE: &str = "svc.example.org"; -const PLUGIN: &str = "janus.plugin.conference"; -const RESPONSE_TIMEOUT: u64 = 5; -const RESPONSE_SKIP_MAX: usize = 10; -const IGNORE: &str = "ignore"; - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct SessionId(u64); - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct HandleId(u64); - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct Transaction(String); - -pub struct JanusClient { - agent: Agent, - receiver: rumqtt::Receiver, - janus_agent_id: AgentId, - session_id: Option, - handle_id: Option, -} - -impl JanusClient { - /// Initializes the client. - /// Connects to the broker, subscribes to responses topic. - /// Then obtains session id and handle id for `PLUGIN`. - /// Returns the client that is set up for sending messages to the plugin handle. - pub fn new() -> Result { - let agent_config: AgentConfig = serde_json::from_value(json!({ - "uri": MQTT_BROKER_URL, - "clean_session": true, - }))?; - - let account_id = AccountId::new(CONFERENCE_ACCOUNT_LABEL, AUDIENCE); - let agent_id = AgentId::new(AGENT_ID_LABEL, account_id); - - let (mut agent, receiver) = AgentBuilder::new(agent_id) - .version(AGENT_VERSION) - .mode(ConnectionMode::Service) - .start(&agent_config)?; - - let janus_account_id = AccountId::new(JANUS_ACCOUNT_LABEL, AUDIENCE); - let janus_agent_id = AgentId::new(AGENT_ID_LABEL, janus_account_id); - - let subscription = Subscription::broadcast_events(&janus_agent_id, "responses"); - agent.subscribe(&subscription, QoS::AtLeastOnce, None)?; - - let mut janus_client = Self { - agent, - receiver, - janus_agent_id: janus_agent_id.clone(), - session_id: None, - handle_id: None, - }; - - janus_client.session_id = Some(janus_client.init_session()?); - janus_client.handle_id = Some(janus_client.init_handle()?); - Ok(janus_client) - } - - fn init_session(&mut self) -> Result { - let response: SessionOrHandleResponse = self.request(&json!({"janus": "create"}))?; - - if response.janus == "success" { - Ok(SessionId(response.data.id)) - } else { - Err(format_err!("Unsuccessful response: {}", response.janus)) - } - } - - fn init_handle(&mut self) -> Result { - let session_id = self.session_id()?; - - let response: SessionOrHandleResponse = self.request(&json!({ - "janus": "attach", - "session_id": session_id, - "plugin": PLUGIN, - }))?; - - if response.janus == "success" { - Ok(HandleId(response.data.id)) - } else { - Err(format_err!("Unsuccessful response: {}", response.janus)) - } - } - - /// Returns session id if present. - pub fn session_id(&self) -> Result { - self.session_id - .clone() - .ok_or_else(|| format_err!("Session is not initialized")) - } - - /// Returns handle id for the `PLUGIN` if present. - pub fn handle_id(&self) -> Result { - self.handle_id - .clone() - .ok_or_else(|| format_err!("Handle is not initialized")) - } - - /// Publish a message to Janus. - pub fn publish(&mut self, payload: &T) -> Result<()> { - let outgoing_request = OutgoingRequest::unicast( - payload, - OutgoingRequestProperties::new(IGNORE, IGNORE, IGNORE), - &self.janus_agent_id, - ); - - self.agent - .publish(&outgoing_request.into_envelope()?) - .context("Failed to publish") - } - - /// Publish a message to Janus and wait for response on it. - /// It adds `transaction` field to the `payload` with random number to match the response. - /// Returns the response deserialized to `R` type. - pub fn request(&mut self, payload: &T) -> Result - where - T: Serialize, - for<'de> R: Deserialize<'de>, - { - let mut payload = serde_json::to_value(payload)?; - - let mut rng = rand::thread_rng(); - let transaction = Transaction(rng.gen::().to_string()); - - payload - .as_object_mut() - .ok_or_else(|| format_err!("Payload is not a JSON object"))? - .insert(String::from("transaction"), json!(transaction)); - - self.publish(&payload)?; - self.wait_for_response(&transaction, Duration::from_secs(RESPONSE_TIMEOUT)) - } - - /// Wait for response for the given `transaction` and deserialize it to `R` type. - /// Skips intermediate messages that are unrelated to the `transaction`. - /// Returns deserialized response on success. - /// Returns error on timeout or intermediate messagees limit excess – `RESPONSE_SKIP_MAX`. - pub fn wait_for_response(&self, transaction: &Transaction, timeout: Duration) -> Result - where - for<'de> R: Deserialize<'de>, - { - let mut skip_counter: usize = 0; - - loop { - if skip_counter == RESPONSE_SKIP_MAX { - bail!( - "Skipped {} messages, but no one is a response on {:?}", - RESPONSE_SKIP_MAX, - transaction, - ); - } - - match self.receiver.recv_timeout(timeout) { - Ok(Notification::Publish(publish)) => { - let payload = Self::parse_response(&publish.payload.as_slice())?; - - if Self::is_expected_transaction(&payload, transaction) { - let err = serde_json::from_value::(payload.to_owned()); - return err.context("Failed to typify message"); - } else { - skip_counter += 1; - } - } - Ok(_) => (), - Err(_) => bail!("Timed out waiting for the response on {:?}", transaction), - } - } - } - - fn parse_response(payload: &[u8]) -> Result { - let json = serde_json::from_slice::(payload)?; - - let payload_str = json - .get("payload") - .ok_or_else(|| format_err!("Missing payload in response"))? - .as_str() - .ok_or_else(|| format_err!("Response payload is not a string"))?; - - serde_json::from_str::(payload_str).context("Failed to parse message") - } - - fn is_expected_transaction(payload: &serde_json::Value, transaction: &Transaction) -> bool { - payload - .get("transaction") - .and_then(|value| value.as_str()) - .map(|value| Transaction(String::from(value))) - .filter(|value| *value == *transaction) - .is_some() - } - - /// Convenience wrapper around `request` to send send a message to the plugin handle. - pub fn request_message(&mut self, body: T) -> Result - where - T: Serialize, - for<'de> R: Deserialize<'de>, - { - let session_id = self.session_id()?; - let handle_id = self.handle_id()?; - - self.request(&json!({ - "janus": "message", - "session_id": session_id, - "handle_id": handle_id, - "body": body, - })) - } - - fn graceful_disconnect(&mut self) -> Result<()> { - if let Some(session_id) = self.session_id.clone() { - if let Some(handle_id) = self.handle_id.clone() { - let _response: IgnoredResponse = self.request(&json!({ - "janus": "detach", - "session_id": session_id, - "handle_id": handle_id, - }))?; - } - - let _response: IgnoredResponse = self.request(&json!({ - "janus": "destroy", - "session_id": session_id, - }))?; - } - - Ok(()) - } -} - -impl Drop for JanusClient { - fn drop(&mut self) { - if let Err(err) = self.graceful_disconnect() { - eprintln!("Failed to disconnect MQTT client: {}", err); - } - } -} - -// JSON responses -#[derive(Deserialize)] -struct SessionOrHandleResponse { - janus: String, - data: SessionOrHandleResponseData, -} - -#[derive(Deserialize)] -struct SessionOrHandleResponseData { - id: u64, -} - -#[derive(Deserialize)] -struct IgnoredResponse; diff --git a/tests/upload_test.rs b/tests/upload_test.rs deleted file mode 100644 index a6cd636e..00000000 --- a/tests/upload_test.rs +++ /dev/null @@ -1,229 +0,0 @@ -// Full record upload functional test. -// -// 1. Copy test videos from ./tests/files/recording to ./recordings/ where is random number. -// 2. Send `stream.upload` request for that with MQTT, get ack response. -// 3. Janus concatenates videos and uploads it to S3 then sends the second response. -// 4. When this response arrives ensure that it's successful. -// 5. Download the full video from S3 to temporary file. Delete the original from S3 to keep it clean. -// 6. Check the duration of the downloaded full video to make sure that it's really concatenated. -// 7. The response also contains start/stop timestamps of the original parts. Ensure that they're OK. -// 8. Cleanup: delete ./recordings/ and the downloaded full record. - -include!("./janus_client.rs"); - -extern crate gstreamer; -extern crate gstreamer_pbutils; -extern crate rusoto_s3; -extern crate rusoto_signature; -extern crate tempfile; - -use std::path::{Path, PathBuf}; -use std::{env, fs, io}; - -use gstreamer as gst; -use gstreamer_pbutils::prelude::*; -use rusoto_core::request::HttpClient; -use rusoto_credential::StaticProvider; -use rusoto_s3::{DeleteObjectRequest, GetObjectRequest, S3Client, S3}; -use rusoto_signature::Region; -use tempfile::TempDir; - -const BUCKET: &str = "origin.webinar.example.org"; -const TEST_RECORDING_PATH: &str = "./tests/files/recording"; -const RECORDINGS_DIR: &str = "./recordings"; -const DISCOVERER_TIMEOUT: u64 = 15; - -#[test] -fn it_uploads_full_record() { - // Setup - gst::init().expect("Failed to initialize GStreamer"); - let mut janus_client = JanusClient::new().expect("Failed to initialize Janus client"); - let s3_client = S3ClientWrapper::new().expect("Failed to build S3 client"); - let recording = TestRecording::new().expect("Failed to initialize test recording"); - let object_id = format!("{}.test.mp4", recording.id); - - // Send `stream.upload` request and expect ack response. - let ack_response: UploadAckResponse = janus_client - .request_message(json!({ - "method": "stream.upload", - "id": recording.id, - "bucket": BUCKET, - "object": object_id, - })) - .expect("Failed `stream.upload` request"); - - assert_eq!(ack_response.janus, "ack"); - - // When upload finishes expect the second response. - let response: UploadResponse = janus_client - .wait_for_response(&ack_response.transaction, Duration::from_secs(30)) - .expect("Failed to wait for upload response"); - - assert_eq!(response.janus, "event"); - assert_eq!(response.plugindata.data.status, 200); - drop(janus_client); - - // Download the full record file from S3 and delete it from there. - let temp_dir = TempDir::new().expect("Failed to create temp file"); - let record_path = temp_dir.into_path().join(&object_id); - - s3_client - .get_object(BUCKET, &object_id, &record_path) - .expect("Failed to download record from S3"); - - s3_client - .delete_object(BUCKET, &object_id) - .expect("Failed to delete record from S3"); - - // Assert downloaded file duration to ensure that it's really concatenated video. - let duration = discover_duration(&record_path).expect("Failed to get video duration"); - assert_eq!(duration, 3633); - - // Assert part timestamps from the response after removing the file from S3 to keep it clean - // even in case of failure. - assert_eq!(response.plugindata.data.id, recording.id); - assert_eq!(response.plugindata.data.started_at, 1560489452218); - - assert_eq!( - response.plugindata.data.time, - vec![(0, 1633), (8682, 10682)] - ); -} - -// Test recording directory with some video files. Gets deleted after the test. -struct TestRecording { - id: String, - path: PathBuf, -} - -impl TestRecording { - fn new() -> Result { - let mut rng = rand::thread_rng(); - let id = rng.gen::().to_string(); - let path = Path::new(RECORDINGS_DIR).join(&id); - fs::create_dir(&path)?; - Self::copy_test_files(&path)?; - Ok(Self { id, path }) - } - - fn copy_test_files(destination_path: &PathBuf) -> Result<()> { - for entry in fs::read_dir(TEST_RECORDING_PATH)? { - let entry = entry?; - let path = entry.path(); - - if path.is_file() && path.extension().and_then(|e| e.to_str()) == Some("mkv") { - let name = path - .file_name() - .ok_or_else(|| format_err!("Failed to get file name"))?; - - fs::copy(&path, &destination_path.join(&name))?; - } - } - - Ok(()) - } -} - -impl Drop for TestRecording { - fn drop(&mut self) { - if let Err(err) = fs::remove_dir_all(&self.path) { - panic!("Failed to cleanup test recording: {}", err); - } - } -} - -// A wrapper for S3 client with more concise API for readability. -struct S3ClientWrapper { - client: S3Client, -} - -impl S3ClientWrapper { - fn new() -> Result { - let region = Region::Custom { - name: env::var("APP_UPLOADING__REGION")?, - endpoint: env::var("APP_UPLOADING__ENDPOINT")?, - }; - - let access_key_id = env::var("APP_UPLOADING__ACCESS_KEY_ID")?; - let secret_access_key = env::var("APP_UPLOADING__SECRET_ACCESS_KEY")?; - - let client = S3Client::new_with( - HttpClient::new()?, - StaticProvider::new_minimal(access_key_id, secret_access_key), - region, - ); - - Ok(Self { client }) - } - - fn get_object

(&self, bucket: &str, object: &str, destination: P) -> Result<()> - where - P: AsRef, - { - let request = GetObjectRequest { - bucket: bucket.to_owned(), - key: object.to_owned(), - ..Default::default() - }; - - let mut resp = self.client.get_object(request).sync()?; - let body = resp.body.take().context("Missing response body")?; - - let mut target = fs::OpenOptions::new() - .write(true) - .create_new(true) - .open(destination) - .context("Failed to open destination file")?; - - io::copy(&mut body.into_blocking_read(), &mut target) - .context("Failed to write downloaded file")?; - - Ok(()) - } - - fn delete_object(&self, bucket: &str, object: &str) -> Result<()> { - let request = DeleteObjectRequest { - bucket: bucket.to_owned(), - key: object.to_owned(), - ..Default::default() - }; - - self.client.delete_object(request).sync()?; - Ok(()) - } -} - -// Helper function for discovering video file duration using gstreamer discoverer. -fn discover_duration(path: &PathBuf) -> Result { - gstreamer_pbutils::Discoverer::new(gst::ClockTime::from_seconds(DISCOVERER_TIMEOUT))? - .discover_uri(&format!("file://{}", path.as_path().to_string_lossy()))? - .get_duration() - .mseconds() - .ok_or_else(|| format_err!("Empty duration")) -} - -// JSON responses -#[derive(Deserialize)] -struct UploadAckResponse { - janus: String, - transaction: Transaction, -} - -#[derive(Deserialize)] -struct UploadResponse { - janus: String, - plugindata: UploadResponsePluginData, -} - -#[derive(Deserialize)] -struct UploadResponsePluginData { - data: UploadResponsePluginDataData, -} - -#[derive(Deserialize)] -struct UploadResponsePluginDataData { - id: String, - status: usize, - started_at: u64, - time: Vec<(u64, u64)>, -}