diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c0dcb0af1..19d333b65 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -302,16 +302,6 @@ jobs: killall -q ui || true chmod +x ./server/ui && ./server/ui & bundle exec rspec - - name: Run tests (Axum) - env: - PLAYGROUND_UI_ROOT: server/build/ - PLAYGROUND_CORS_ENABLED: true - PLAYGROUND_GITHUB_TOKEN: "${{ secrets.PLAYGROUND_GITHUB_TOKEN }}" - PLAYGROUND_SERVER_AXUM: true - run: |- - killall -q ui || true - chmod +x ./server/ui && ./server/ui & - bundle exec rspec - name: Preserve screenshots if: "${{ failure() }}" uses: actions/upload-artifact@v2 diff --git a/ci/workflows.yml b/ci/workflows.yml index a4a278d7f..a97eef939 100644 --- a/ci/workflows.yml +++ b/ci/workflows.yml @@ -423,17 +423,6 @@ workflows: chmod +x ./server/ui && ./server/ui & bundle exec rspec - - name: "Run tests (Axum)" - env: - PLAYGROUND_UI_ROOT: server/build/ - PLAYGROUND_CORS_ENABLED: true - PLAYGROUND_GITHUB_TOKEN: ${{ secrets.PLAYGROUND_GITHUB_TOKEN }} - PLAYGROUND_SERVER_AXUM: true - run: |- - killall -q ui || true - chmod +x ./server/ui && ./server/ui & - bundle exec rspec - - name: "Preserve screenshots" if: ${{ failure() }} uses: actions/upload-artifact@v2 diff --git a/tests/Gemfile.lock b/tests/Gemfile.lock index cba071b6c..a6042e9b3 100644 --- a/tests/Gemfile.lock +++ b/tests/Gemfile.lock @@ -22,15 +22,15 @@ GEM matrix (0.4.2) mini_mime (1.1.2) mini_portile2 (2.8.0) - nokogiri (1.13.3) + nokogiri (1.13.4) mini_portile2 (~> 2.8.0) racc (~> 1.4) - public_suffix (4.0.6) + public_suffix (4.0.7) racc (1.6.0) rack (2.2.3) rack-test (1.1.0) rack (>= 1.0, < 3) - regexp_parser (2.2.1) + regexp_parser (2.3.1) rexml (3.2.5) rspec (3.11.0) rspec-core (~> 3.11.0) diff --git a/ui/Cargo.lock b/ui/Cargo.lock index 88d0660d1..8cfb43eda 100644 --- a/ui/Cargo.lock +++ b/ui/Cargo.lock @@ -23,7 +23,7 @@ version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ - "memchr 2.4.1", + "memchr", ] [[package]] @@ -54,15 +54,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "autocfg" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" -dependencies = [ - "autocfg 1.1.0", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -71,9 +62,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.5.0" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5611d4977882c5af1c0f7a34d51b5d87f784f86912bb543986b014ea4995ef93" +checksum = "f4af7447fc1214c1f3a1ace861d0216a6c8bb13965b64bbad9650f375b67689a" dependencies = [ "async-trait", "axum-core", @@ -83,12 +74,12 @@ dependencies = [ "headers", "http", "http-body", - "hyper 0.14.18", + "hyper", "itoa", "matchit", - "memchr 2.4.1", - "mime 0.3.16", - "percent-encoding 2.1.0", + "memchr", + "mime", + "percent-encoding", "pin-project-lite", "serde", "serde_json", @@ -103,23 +94,23 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95cd109b3e93c9541dcce5b0219dcf89169dcc58c1bebed65082808324258afb" +checksum = "3bdc19781b16e32f8a7200368a336fa4509d4b72ef15dd4e41df5290855ee1e6" dependencies = [ "async-trait", "bytes", "futures-util", "http", "http-body", - "mime 0.3.16", + "mime", ] [[package]] name = "backtrace" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f" +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" dependencies = [ "addr2line", "cc", @@ -130,22 +121,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base64" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" -dependencies = [ - "byteorder", - "safemem", -] - -[[package]] -name = "base64" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" - [[package]] name = "base64" version = "0.13.0" @@ -167,31 +142,12 @@ dependencies = [ "generic-array", ] -[[package]] -name = "bodyparser" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f023abfa58aad6f6bc4ae0630799e24d5ee0ab8bb2e49f651d9b1f9aa4f52f30" -dependencies = [ - "iron", - "persistent", - "plugin", - "serde", - "serde_json", -] - [[package]] name = "bumpalo" version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - [[package]] name = "bytes" version = "1.1.0" @@ -220,19 +176,10 @@ dependencies = [ "num-integer", "num-traits", "serde", - "time", + "time 0.1.44", "winapi", ] -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags", -] - [[package]] name = "core-foundation" version = "0.9.3" @@ -249,18 +196,6 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" -[[package]] -name = "corsware" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cf279de149958038acd43c7fa6d3d24bcffe01f9808dfc6278aa7585a8e8937" -dependencies = [ - "hyper 0.10.16", - "iron", - "unicase 1.4.2", - "url 1.7.2", -] - [[package]] name = "cpufeatures" version = "0.2.2" @@ -280,17 +215,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "csv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef22b37c7a51c564a365892c012dc0271221fdcc64c69b19ba4d6fa8bd96d9c" -dependencies = [ - "byteorder", - "memchr 1.0.2", - "rustc-serialize", -] - [[package]] name = "digest" version = "0.10.3" @@ -315,9 +239,9 @@ checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" [[package]] name = "encoding_rs" -version = "0.8.30" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" dependencies = [ "cfg-if", ] @@ -330,7 +254,7 @@ checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" dependencies = [ "atty", "humantime", - "log 0.4.16", + "log", "regex", "termcolor", ] @@ -378,15 +302,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ "matches", - "percent-encoding 2.1.0", + "percent-encoding", ] -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - [[package]] name = "futures" version = "0.3.21" @@ -470,7 +388,7 @@ dependencies = [ "futures-macro", "futures-sink", "futures-task", - "memchr 2.4.1", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -483,7 +401,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" dependencies = [ "typenum", - "version_check 0.9.4", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", ] [[package]] @@ -523,13 +452,13 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" dependencies = [ - "base64 0.13.0", + "base64", "bitflags", "bytes", "headers-core", "http", "httpdate", - "mime 0.3.16", + "mime", "sha-1", ] @@ -568,9 +497,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb" dependencies = [ "bytes", "fnv", @@ -596,9 +525,9 @@ checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" [[package]] name = "httparse" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" [[package]] name = "httpdate" @@ -612,25 +541,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "hyper" -version = "0.10.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" -dependencies = [ - "base64 0.9.3", - "httparse", - "language-tags 0.2.2", - "log 0.3.9", - "mime 0.2.6", - "num_cpus", - "time", - "traitobject", - "typeable", - "unicase 1.4.2", - "url 1.7.2", -] - [[package]] name = "hyper" version = "0.14.18" @@ -662,7 +572,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.18", + "hyper", "native-tls", "tokio", "tokio-native-tls", @@ -674,25 +584,14 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5617e92fc2f2501c3e2bc6ce547cad841adba2bae5b921c7e52510beca6d084c" dependencies = [ - "base64 0.13.0", + "base64", "bytes", "http", "httpdate", - "language-tags 0.3.2", - "mime 0.3.16", - "percent-encoding 2.1.0", - "unicase 2.6.0", -] - -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", + "language-tags", + "mime", + "percent-encoding", + "unicase", ] [[package]] @@ -712,7 +611,7 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" dependencies = [ - "autocfg 1.1.0", + "autocfg", "hashbrown", ] @@ -727,25 +626,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e70ee094dc02fd9c13fdad4940090f22dbd6ac7c9e7094a46cf0232a50bc7c" - -[[package]] -name = "iron" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6d308ca2d884650a8bf9ed2ff4cb13fbb2207b71f64cda11dc9b892067295e8" -dependencies = [ - "hyper 0.10.16", - "log 0.3.9", - "mime_guess 1.8.8", - "modifier", - "num_cpus", - "plugin", - "typemap", - "url 1.7.2", -] +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" [[package]] name = "itoa" @@ -755,20 +638,20 @@ checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "js-sys" -version = "0.3.56" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" dependencies = [ "wasm-bindgen", ] [[package]] name = "jsonwebtoken" -version = "7.2.0" +version = "8.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afabcc15e437a6484fc4f12d0fd63068fe457bf93f1c148d3d9649c60b103f32" +checksum = "cc9051c17f81bae79440afa041b3a278e1de71bfb96d32454b477fd4703ccb6f" dependencies = [ - "base64 0.12.3", + "base64", "pem", "ring", "serde", @@ -776,12 +659,6 @@ dependencies = [ "simple_asn1", ] -[[package]] -name = "language-tags" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" - [[package]] name = "language-tags" version = "0.3.2" @@ -796,9 +673,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.121" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" [[package]] name = "lock_api" @@ -806,19 +683,10 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" dependencies = [ - "autocfg 1.1.0", + "autocfg", "scopeguard", ] -[[package]] -name = "log" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -dependencies = [ - "log 0.4.16", -] - [[package]] name = "log" version = "0.4.16" @@ -842,27 +710,9 @@ checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" [[package]] name = "memchr" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" -dependencies = [ - "libc", -] - -[[package]] -name = "memchr" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" - -[[package]] -name = "mime" -version = "0.2.6" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" -dependencies = [ - "log 0.3.9", -] +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mime" @@ -870,36 +720,23 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" -[[package]] -name = "mime_guess" -version = "1.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216929a5ee4dd316b1702eedf5e74548c123d370f47841ceaac38ca154690ca3" -dependencies = [ - "mime 0.2.6", - "phf", - "phf_codegen", - "unicase 1.4.2", -] - [[package]] name = "mime_guess" version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" dependencies = [ - "mime 0.3.16", - "unicase 2.6.0", + "mime", + "unicase", ] [[package]] name = "miniz_oxide" -version = "0.4.4" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" dependencies = [ "adler", - "autocfg 1.1.0", ] [[package]] @@ -909,7 +746,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" dependencies = [ "libc", - "log 0.4.16", + "log", "miow", "ntapi", "wasi 0.11.0+wasi-snapshot-preview1", @@ -925,22 +762,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "modifier" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f5c9112cb662acd3b204077e0de5bc66305fa8df65c8019d5adb10e9ab6e58" - -[[package]] -name = "mount" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25c06012941aaf8c75f2eaf7ec5c48cf69f9fc489ab3eb3589edc107e386f0b" -dependencies = [ - "iron", - "sequence_trie", -] - [[package]] name = "native-tls" version = "0.2.10" @@ -949,7 +770,7 @@ checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" dependencies = [ "lazy_static", "libc", - "log 0.4.16", + "log", "openssl", "openssl-probe", "openssl-sys", @@ -970,22 +791,22 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.2.6" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" dependencies = [ - "autocfg 1.1.0", + "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ - "autocfg 1.1.0", + "autocfg", "num-traits", ] @@ -995,7 +816,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg 1.1.0", + "autocfg", ] [[package]] @@ -1008,35 +829,45 @@ dependencies = [ "libc", ] +[[package]] +name = "num_threads" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0" +dependencies = [ + "libc", +] + [[package]] name = "object" -version = "0.27.1" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +checksum = "40bec70ba014595f99f7aa110b84331ffe1ee9aece7fe6f387cc7e3ecda4d456" dependencies = [ - "memchr 2.4.1", + "memchr", ] [[package]] name = "octocrab" -version = "0.15.4" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afcfecea7633fbd11141b7ce1cc4e49e01566570dd5d995ee1edb497dd340082" +checksum = "8d3731cf8af31e9df81c7f529d3907f8a01c6ffea0cb8a989a637f66a9201a23" dependencies = [ "arc-swap", "async-trait", - "base64 0.13.0", + "base64", "bytes", "chrono", "hyperx", "jsonwebtoken", "once_cell", "reqwest", + "secrecy", "serde", "serde_json", "serde_path_to_error", "snafu", - "url 2.2.2", + "url", ] [[package]] @@ -1071,7 +902,7 @@ version = "0.9.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" dependencies = [ - "autocfg 1.1.0", + "autocfg", "cc", "libc", "pkg-config", @@ -1105,37 +936,19 @@ dependencies = [ [[package]] name = "pem" -version = "0.8.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb" +checksum = "e9a3b09a20e374558580a4914d3b7d89bd61b954a5a5e1dcbea98753addb1947" dependencies = [ - "base64 0.13.0", - "once_cell", - "regex", + "base64", ] -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" - [[package]] name = "percent-encoding" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" -[[package]] -name = "persistent" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8fa0009c4f3d350281309909c618abddf10bb7e3145f28410782f6a5ec74c5" -dependencies = [ - "iron", - "plugin", -] - [[package]] name = "petgraph" version = "0.6.0" @@ -1146,45 +959,6 @@ dependencies = [ "indexmap", ] -[[package]] -name = "phf" -version = "0.7.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_codegen" -version = "0.7.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" -dependencies = [ - "phf_generator", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.7.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" -dependencies = [ - "phf_shared", - "rand 0.6.5", -] - -[[package]] -name = "phf_shared" -version = "0.7.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" -dependencies = [ - "siphasher", - "unicase 1.4.2", -] - [[package]] name = "pin-project" version = "1.0.10" @@ -1207,9 +981,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -1223,35 +997,11 @@ version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" -[[package]] -name = "playground-middleware" -version = "0.1.0" -source = "git+https://github.com/integer32llc/playground-middleware#146df5e79210fc21ded487cf41fcb4e1ae1a347a" -dependencies = [ - "csv", - "iron", - "log 0.3.9", - "mime 0.2.6", - "mime_guess 1.8.8", - "rustc-serialize", - "time", - "url 1.7.2", -] - -[[package]] -name = "plugin" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a6a0dc3910bc8db877ffed8e457763b317cf880df4ae19109b9f77d277cf6e0" -dependencies = [ - "typemap", -] - [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" dependencies = [ "unicode-xid", ] @@ -1265,7 +1015,7 @@ dependencies = [ "cfg-if", "fnv", "lazy_static", - "memchr 2.4.1", + "memchr", "parking_lot", "protobuf", "thiserror", @@ -1278,140 +1028,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf7e6d18738ecd0902d30d1ad232c9125985a3422929b16c65517b38adc14f96" [[package]] -name = "quote" -version = "1.0.17" +name = "quickcheck" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" dependencies = [ - "proc-macro2", + "rand", ] [[package]] -name = "rand" -version = "0.4.6" +name = "quote" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "rdrand", - "winapi", + "proc-macro2", ] [[package]] name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.8", - "libc", - "rand_chacha", - "rand_core 0.4.2", - "rand_hc", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift", - "winapi", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.3.1", -] - -[[package]] -name = "rand_core" -version = "0.3.1" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "rand_core 0.4.2", + "rand_core", ] [[package]] name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "autocfg 0.1.8", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", + "getrandom", ] [[package]] @@ -1430,7 +1079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", - "memchr 2.4.1", + "memchr", "regex-syntax", ] @@ -1455,7 +1104,7 @@ version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46a1f7aa4f35e5e8b4160449f51afc758f0ce6454315a9fa7d0d113e958c41eb" dependencies = [ - "base64 0.13.0", + "base64", "bytes", "encoding_rs", "futures-core", @@ -1463,22 +1112,22 @@ dependencies = [ "h2", "http", "http-body", - "hyper 0.14.18", + "hyper", "hyper-tls", "ipnet", "js-sys", "lazy_static", - "log 0.4.16", - "mime 0.3.16", + "log", + "mime", "native-tls", - "percent-encoding 2.1.0", + "percent-encoding", "pin-project-lite", "serde", "serde_json", "serde_urlencoded", "tokio", "tokio-native-tls", - "url 2.2.2", + "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -1500,35 +1149,12 @@ dependencies = [ "winapi", ] -[[package]] -name = "route-recognizer" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea509065eb0b3c446acdd0102f0d46567dc30902dc0be91d6552035d92b0f4f8" - -[[package]] -name = "router" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc63b6f3b8895b0d04e816b2b1aa58fdba2d5acca3cbb8f0ab8e017347d57397" -dependencies = [ - "iron", - "route-recognizer", - "url 1.7.2", -] - [[package]] name = "rustc-demangle" version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" - [[package]] name = "rustversion" version = "1.0.6" @@ -1541,12 +1167,6 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - [[package]] name = "schannel" version = "0.1.19" @@ -1563,6 +1183,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] + [[package]] name = "security-framework" version = "2.6.1" @@ -1586,12 +1215,6 @@ dependencies = [ "libc", ] -[[package]] -name = "sequence_trie" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee22067b7ccd072eeb64454b9c6e1b33b61cd0d49e895fd48676a184580e0c3" - [[package]] name = "serde" version = "1.0.136" @@ -1666,26 +1289,21 @@ dependencies = [ [[package]] name = "simple_asn1" -version = "0.4.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b" +checksum = "4a762b1c38b9b990c694b9c2f8abe3372ce6a9ceaae6bca39cfc46e054f45745" dependencies = [ - "chrono", "num-bigint", "num-traits", + "thiserror", + "time 0.3.9", ] -[[package]] -name = "siphasher" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" - [[package]] name = "slab" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" [[package]] name = "smallvec" @@ -1756,9 +1374,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.90" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f" +checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" dependencies = [ "proc-macro2", "quote", @@ -1771,16 +1389,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" -[[package]] -name = "tempdir" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -dependencies = [ - "rand 0.4.6", - "remove_dir_all", -] - [[package]] name = "tempfile" version = "3.3.0" @@ -1835,11 +1443,30 @@ dependencies = [ "winapi", ] +[[package]] +name = "time" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +dependencies = [ + "itoa", + "libc", + "num_threads", + "quickcheck", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + [[package]] name = "tinyvec" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -1852,13 +1479,13 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +checksum = "0f48b6d60512a392e34dbf7fd456249fd2de3c83669ab642e021903f4015185b" dependencies = [ "bytes", "libc", - "memchr 2.4.1", + "memchr", "mio", "num_cpus", "once_cell", @@ -1923,9 +1550,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.2.5" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aba3f3efabf7fb41fae8534fc20a817013dd1c12cb45441efb6c82e6556b4cd8" +checksum = "e980386f06883cf4d0578d6c9178c81f68b45d77d00f2c2c1bc034b3439c2c56" dependencies = [ "bitflags", "bytes", @@ -1935,9 +1562,9 @@ dependencies = [ "http-body", "http-range-header", "httpdate", - "mime 0.3.16", - "mime_guess 2.0.4", - "percent-encoding 2.1.0", + "mime", + "mime_guess", + "percent-encoding", "pin-project-lite", "tokio", "tokio-util", @@ -1961,12 +1588,12 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.32" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" +checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" dependencies = [ "cfg-if", - "log 0.4.16", + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1974,9 +1601,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" +checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" dependencies = [ "proc-macro2", "quote", @@ -1985,40 +1612,19 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c" +checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" dependencies = [ "lazy_static", ] -[[package]] -name = "traitobject" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" - [[package]] name = "try-lock" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" -[[package]] -name = "typeable" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" - -[[package]] -name = "typemap" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "653be63c80a3296da5551e1bfd2cca35227e13cdd08c6668903ae2f4f77aa1f6" -dependencies = [ - "unsafe-any", -] - [[package]] name = "typenum" version = "1.15.0" @@ -2031,56 +1637,41 @@ version = "0.1.0" dependencies = [ "async-trait", "axum", - "bodyparser", - "corsware", "dotenv", "env_logger", "futures", - "iron", "lazy_static", - "log 0.4.16", - "mount", + "log", "octocrab", "openssl-probe", "petgraph", - "playground-middleware", "prometheus", "regex", - "router", "rustc-demangle", "serde", "serde_derive", "serde_json", "snafu", "strum", - "tempdir", + "tempfile", "tokio", "tower-http", ] -[[package]] -name = "unicase" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" -dependencies = [ - "version_check 0.1.5", -] - [[package]] name = "unicase" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" dependencies = [ - "version_check 0.9.4", + "version_check", ] [[package]] name = "unicode-bidi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-normalization" @@ -2103,32 +1694,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" -[[package]] -name = "unsafe-any" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f" -dependencies = [ - "traitobject", -] - [[package]] name = "untrusted" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -dependencies = [ - "idna 0.1.5", - "matches", - "percent-encoding 1.0.1", -] - [[package]] name = "url" version = "2.2.2" @@ -2136,9 +1707,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", - "idna 0.2.3", + "idna", "matches", - "percent-encoding 2.1.0", + "percent-encoding", "serde", ] @@ -2148,12 +1719,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" - [[package]] name = "version_check" version = "0.9.4" @@ -2166,7 +1731,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" dependencies = [ - "log 0.4.16", + "log", "try-lock", ] @@ -2184,9 +1749,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2194,13 +1759,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" dependencies = [ "bumpalo", "lazy_static", - "log 0.4.16", + "log", "proc-macro2", "quote", "syn", @@ -2209,9 +1774,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.29" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395" +checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" dependencies = [ "cfg-if", "js-sys", @@ -2221,9 +1786,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2231,9 +1796,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" dependencies = [ "proc-macro2", "quote", @@ -2244,15 +1809,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" [[package]] name = "web-sys" -version = "0.3.56" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" dependencies = [ "js-sys", "wasm-bindgen", @@ -2297,3 +1862,9 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] + +[[package]] +name = "zeroize" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb5728b8afd3f280a869ce1d4c554ffaed35f45c231fc41bfbd0381bef50317" diff --git a/ui/Cargo.toml b/ui/Cargo.toml index 042b742d3..b38e2cc49 100644 --- a/ui/Cargo.toml +++ b/ui/Cargo.toml @@ -11,30 +11,22 @@ fork-bomb-prevention = [] [dependencies] async-trait = "0.1.52" axum = { version = "0.5", features = ["headers"] } -bodyparser = "0.8.0" -corsware = "0.2.0" dotenv = "0.15.0" env_logger = "0.9.0" futures = "0.3.21" -iron = "0.6.0" lazy_static = "1.0.0" log = "0.4.0" -mount = "0.4.0" -octocrab = "0.15.0" +octocrab = "0.16" openssl-probe = "0.1.2" petgraph = "0.6.0" prometheus = "0.13.0" regex = "1.0.0" -router = "0.6.0" rustc-demangle = "0.1.5" -serde = "1.0" +serde = { version = "1.0", features = ["rc"] } serde_derive = "1.0" serde_json = "1.0" snafu = "0.7.0" strum = { version = "0.24.0", features = ["derive"] } -tempdir = "0.3.7" +tempfile = "3" tokio = { version = "1.9", features = ["macros", "time", "process", "rt-multi-thread"] } -tower-http = { version = "0.2.2", features = ["cors", "fs", "set-header", "trace"] } - -[dependencies.playground-middleware] -git = "https://github.com/integer32llc/playground-middleware" +tower-http = { version = "0.3", features = ["cors", "fs", "set-header", "trace"] } diff --git a/ui/README.md b/ui/README.md index 27cb1add4..eb4e67e56 100644 --- a/ui/README.md +++ b/ui/README.md @@ -12,7 +12,6 @@ of choice. | `PLAYGROUND_GITHUB_TOKEN` | **Yes** | | The [GitHub API token][gist] to read and write Gists | | `PLAYGROUND_UI_ADDRESS` | No | 127.0.0.1 | The address to listen on | | `PLAYGROUND_UI_PORT` | No | 5000 | The port to listen on | -| `PLAYGROUND_LOG_FILE` | No | access-log.csv | The file to record accesses | | `PLAYGROUND_METRICS_TOKEN` | No | | If set, will require authentication for the metrics endpoint | | `PLAYGROUND_CORS_ENABLED` | No | | If set, will enable CORS support | | `TMPDIR` | No | system-provided | Where compilation artifacts will be saved. Must be accessible to Docker | diff --git a/ui/src/asm_cleanup.rs b/ui/src/asm_cleanup.rs index 892ee3e44..d8f2c6d63 100644 --- a/ui/src/asm_cleanup.rs +++ b/ui/src/asm_cleanup.rs @@ -96,7 +96,7 @@ pub fn filter_asm(block: &str) -> String { line_info.push(LabelDecl(label_decl_cap.as_str())); labels.insert(label_decl_cap.as_str()); current_label = label_decl_cap.as_str(); - } else if DATA_REGEX.is_match(line) && current_label != "" { + } else if DATA_REGEX.is_match(line) && !current_label.is_empty() { line_info.push(Data(current_label)); // These will be checked for references to other labels later on // Skip the data type, just capture its reference diff --git a/ui/src/gist.rs b/ui/src/gist.rs index 2221a3168..6ca7e4895 100644 --- a/ui/src/gist.rs +++ b/ui/src/gist.rs @@ -35,14 +35,6 @@ impl From for Gist { } } -#[tokio::main] -pub async fn create(token: String, code: String) -> Gist { - create_future(token, code) - .await - .expect("Unable to create gist") - // TODO: Better reporting of failures -} - pub async fn create_future(token: String, code: String) -> octocrab::Result { github(token)? .gists() @@ -55,12 +47,6 @@ pub async fn create_future(token: String, code: String) -> octocrab::Result Gist { - load_future(token, id).await.expect("Unable to load gist") - // TODO: Better reporting of a 404 -} - pub async fn load_future(token: String, id: &str) -> octocrab::Result { let github = github(token)?; diff --git a/ui/src/main.rs b/ui/src/main.rs index ce3cd154e..4b9341d78 100644 --- a/ui/src/main.rs +++ b/ui/src/main.rs @@ -8,25 +8,16 @@ use std::{ net::SocketAddr, path::{Path, PathBuf}, sync::Arc, - time::Duration, }; const DEFAULT_ADDRESS: &str = "127.0.0.1"; const DEFAULT_PORT: u16 = 5000; -const DEFAULT_LOG_FILE: &str = "access-log.csv"; mod asm_cleanup; mod gist; +mod metrics; mod sandbox; mod server_axum; -mod server_iron; - -const ONE_HOUR_IN_SECONDS: u32 = 60 * 60; -const ONE_HOUR: Duration = Duration::from_secs(ONE_HOUR_IN_SECONDS as u64); -const ONE_DAY: Duration = Duration::from_secs(60 * 60 * 24); -const ONE_YEAR: Duration = Duration::from_secs(60 * 60 * 24 * 365); - -const SANDBOX_CACHE_TIME_TO_LIVE: Duration = ONE_HOUR; fn main() { // Dotenv may be unable to load environment variables, but that's ok in production @@ -35,20 +26,13 @@ fn main() { env_logger::init(); let config = Config::from_env(); - - if config.use_axum() { - server_axum::serve(config); - } else { - server_iron::serve(config); - } + server_axum::serve(config); } struct Config { - axum_enabled: bool, address: String, cors_enabled: bool, gh_token: String, - logfile: String, metrics_token: Option, port: u16, root: PathBuf, @@ -71,28 +55,18 @@ impl Config { env::var("PLAYGROUND_GITHUB_TOKEN").expect("Must specify PLAYGROUND_GITHUB_TOKEN"); let metrics_token = env::var("PLAYGROUND_METRICS_TOKEN").ok(); - let logfile = - env::var("PLAYGROUND_LOG_FILE").unwrap_or_else(|_| DEFAULT_LOG_FILE.to_string()); let cors_enabled = env::var_os("PLAYGROUND_CORS_ENABLED").is_some(); - let axum_enabled = env::var_os("PLAYGROUND_SERVER_AXUM").is_some(); - Self { address, - axum_enabled, cors_enabled, gh_token, - logfile, metrics_token, port, root, } } - fn use_axum(&self) -> bool { - self.axum_enabled - } - fn root_path(&self) -> &Path { &self.root } @@ -106,11 +80,11 @@ impl Config { } fn metrics_token(&self) -> Option { - self.metrics_token.clone().map(|t| MetricsToken(t.into())) + self.metrics_token.as_deref().map(MetricsToken::new) } fn github_token(&self) -> GhToken { - GhToken(self.gh_token.clone().into()) + GhToken::new(&self.gh_token) } fn server_socket_addr(&self) -> SocketAddr { @@ -123,8 +97,8 @@ impl Config { struct GhToken(Arc); impl GhToken { - fn new(token: String) -> Self { - GhToken(Arc::new(token)) + fn new(token: impl Into) -> Self { + GhToken(Arc::new(token.into())) } } @@ -132,527 +106,8 @@ impl GhToken { struct MetricsToken(Arc); impl MetricsToken { - fn new(token: String) -> Self { - MetricsToken(Arc::new(token)) - } -} - -mod metrics { - use futures::future::BoxFuture; - use lazy_static::lazy_static; - use prometheus::{self, register_histogram_vec, HistogramVec}; - use regex::Regex; - use std::{future::Future, time::Instant}; - - use crate::sandbox::{self, Channel, CompileTarget, CrateType, Edition, Mode}; - - lazy_static! { - pub(crate) static ref REQUESTS: HistogramVec = register_histogram_vec!( - "playground_request_duration_seconds", - "Number of requests made", - Labels::LABELS, - vec![0.1, 1.0, 2.5, 5.0, 10.0, 15.0] - ) - .unwrap(); - } - - #[derive(Debug, Copy, Clone, strum::IntoStaticStr)] - pub(crate) enum Endpoint { - Compile, - Execute, - Format, - Miri, - Clippy, - MacroExpansion, - MetaCrates, - MetaVersionStable, - MetaVersionBeta, - MetaVersionNightly, - MetaVersionRustfmt, - MetaVersionClippy, - MetaVersionMiri, - Evaluate, - } - - #[derive(Debug, Copy, Clone, strum::IntoStaticStr)] - pub(crate) enum Outcome { - Success, - ErrorServer, - ErrorTimeoutSoft, - ErrorTimeoutHard, - ErrorUserCode, - } - - #[derive(Debug, Copy, Clone)] - pub(crate) struct Labels { - endpoint: Endpoint, - outcome: Outcome, - - target: Option, - channel: Option, - mode: Option, - edition: Option>, - crate_type: Option, - tests: Option, - backtrace: Option, - } - - impl Labels { - const COUNT: usize = 9; - - const LABELS: &'static [&'static str; Self::COUNT] = &[ - "endpoint", - "outcome", - "target", - "channel", - "mode", - "edition", - "crate_type", - "tests", - "backtrace", - ]; - - fn to_values(&self) -> [&'static str; Self::COUNT] { - let Self { - endpoint, - outcome, - target, - channel, - mode, - edition, - crate_type, - tests, - backtrace, - } = *self; - - fn b(v: Option) -> &'static str { - v.map_or("", |v| if v { "true" } else { "false" }) - } - - let target = target.map_or("", Into::into); - let channel = channel.map_or("", Into::into); - let mode = mode.map_or("", Into::into); - let edition = match edition { - None => "", - Some(None) => "Unspecified", - Some(Some(v)) => v.into(), - }; - let crate_type = crate_type.map_or("", Into::into); - let tests = b(tests); - let backtrace = b(backtrace); - - [ - endpoint.into(), - outcome.into(), - target, - channel, - mode, - edition, - crate_type, - tests, - backtrace, - ] - } - } - - pub(crate) trait GenerateLabels { - fn generate_labels(&self, outcome: Outcome) -> Labels; - } - - impl GenerateLabels for &'_ T - where - T: GenerateLabels, - { - fn generate_labels(&self, outcome: Outcome) -> Labels { - T::generate_labels(self, outcome) - } - } - - impl GenerateLabels for sandbox::CompileRequest { - fn generate_labels(&self, outcome: Outcome) -> Labels { - let Self { - target, - channel, - crate_type, - mode, - edition, - tests, - backtrace, - code: _, - } = *self; - - Labels { - endpoint: Endpoint::Compile, - outcome, - - target: Some(target), - channel: Some(channel), - mode: Some(mode), - edition: Some(edition), - crate_type: Some(crate_type), - tests: Some(tests), - backtrace: Some(backtrace), - } - } - } - - impl GenerateLabels for sandbox::ExecuteRequest { - fn generate_labels(&self, outcome: Outcome) -> Labels { - let Self { - channel, - mode, - edition, - crate_type, - tests, - backtrace, - code: _, - } = *self; - - Labels { - endpoint: Endpoint::Execute, - outcome, - - target: None, - channel: Some(channel), - mode: Some(mode), - edition: Some(edition), - crate_type: Some(crate_type), - tests: Some(tests), - backtrace: Some(backtrace), - } - } - } - - impl GenerateLabels for sandbox::FormatRequest { - fn generate_labels(&self, outcome: Outcome) -> Labels { - let Self { edition, code: _ } = *self; - - Labels { - endpoint: Endpoint::Format, - outcome, - - target: None, - channel: None, - mode: None, - edition: Some(edition), - crate_type: None, - tests: None, - backtrace: None, - } - } - } - - impl GenerateLabels for sandbox::ClippyRequest { - fn generate_labels(&self, outcome: Outcome) -> Labels { - let Self { - code: _, - edition, - crate_type, - } = *self; - - Labels { - endpoint: Endpoint::Clippy, - outcome, - - target: None, - channel: None, - mode: None, - edition: Some(edition), - crate_type: Some(crate_type), - tests: None, - backtrace: None, - } - } - } - - impl GenerateLabels for sandbox::MiriRequest { - fn generate_labels(&self, outcome: Outcome) -> Labels { - let Self { code: _, edition } = *self; - - Labels { - endpoint: Endpoint::Miri, - outcome, - - target: None, - channel: None, - mode: None, - edition: Some(edition), - crate_type: None, - tests: None, - backtrace: None, - } - } - } - - impl GenerateLabels for sandbox::MacroExpansionRequest { - fn generate_labels(&self, outcome: Outcome) -> Labels { - let Self { code: _, edition } = *self; - - Labels { - endpoint: Endpoint::MacroExpansion, - outcome, - - target: None, - channel: None, - mode: None, - edition: Some(edition), - crate_type: None, - tests: None, - backtrace: None, - } - } - } - - pub(crate) trait SuccessDetails: Sized { - fn success_details(&self) -> Outcome; - - fn for_sandbox_result(r: &Result) -> Outcome { - use sandbox::Error::*; - - match r { - Ok(v) => v.success_details(), - Err(CompilerExecutionTimedOut { .. }) => Outcome::ErrorTimeoutHard, - Err(_) => Outcome::ErrorServer, - } - } - } - - fn common_success_details(success: bool, stderr: &str) -> Outcome { - lazy_static! { - // Memory allocation failures are "Aborted" - static ref SOFT_TIMEOUT_REGEX: Regex = Regex::new("entrypoint.sh.*Killed.*timeout").unwrap(); - } - - match success { - true => Outcome::Success, - false => { - if stderr - .lines() - .next_back() - .map_or(false, |l| SOFT_TIMEOUT_REGEX.is_match(l)) - { - Outcome::ErrorTimeoutSoft - } else { - Outcome::ErrorUserCode - } - } - } - } - - impl SuccessDetails for sandbox::CompileResponse { - fn success_details(&self) -> Outcome { - common_success_details(self.success, &self.stderr) - } - } - - impl SuccessDetails for sandbox::ExecuteResponse { - fn success_details(&self) -> Outcome { - common_success_details(self.success, &self.stderr) - } - } - - impl SuccessDetails for sandbox::FormatResponse { - fn success_details(&self) -> Outcome { - common_success_details(self.success, &self.stderr) - } - } - - impl SuccessDetails for sandbox::ClippyResponse { - fn success_details(&self) -> Outcome { - common_success_details(self.success, &self.stderr) - } - } - - impl SuccessDetails for sandbox::MiriResponse { - fn success_details(&self) -> Outcome { - common_success_details(self.success, &self.stderr) - } - } - - impl SuccessDetails for sandbox::MacroExpansionResponse { - fn success_details(&self) -> Outcome { - common_success_details(self.success, &self.stderr) - } - } - - impl SuccessDetails for Vec { - fn success_details(&self) -> Outcome { - Outcome::Success - } - } - - impl SuccessDetails for sandbox::Version { - fn success_details(&self) -> Outcome { - Outcome::Success - } - } - - pub(crate) fn track_metric(request: Req, body: B) -> sandbox::Result - where - Req: GenerateLabels, - B: FnOnce(&Req) -> sandbox::Result, - Resp: SuccessDetails, - { - track_metric_common(request, body, |_| {}) - } - - pub(crate) fn track_metric_force_endpoint( - request: Req, - endpoint: Endpoint, - body: B, - ) -> sandbox::Result - where - Req: GenerateLabels, - B: FnOnce(&Req) -> sandbox::Result, - Resp: SuccessDetails, - { - track_metric_common(request, body, |labels| labels.endpoint = endpoint) - } - - fn track_metric_common(request: Req, body: B, f: F) -> sandbox::Result - where - Req: GenerateLabels, - B: FnOnce(&Req) -> sandbox::Result, - Resp: SuccessDetails, - F: FnOnce(&mut Labels), - { - let start = Instant::now(); - let response = body(&request); - let elapsed = start.elapsed(); - - let outcome = SuccessDetails::for_sandbox_result(&response); - let mut labels = request.generate_labels(outcome); - f(&mut labels); - let values = &labels.to_values(); - - let histogram = REQUESTS.with_label_values(values); - - histogram.observe(elapsed.as_secs_f64()); - - response - } - - pub(crate) async fn track_metric_async( - request: Req, - body: B, - ) -> sandbox::Result - where - Req: GenerateLabels, - for<'req> B: FnOnce(&'req Req) -> BoxFuture<'req, sandbox::Result>, - Resp: SuccessDetails, - { - track_metric_common_async(request, body, |_| {}).await - } - - pub(crate) async fn track_metric_force_endpoint_async( - request: Req, - endpoint: Endpoint, - body: B, - ) -> sandbox::Result - where - Req: GenerateLabels, - for<'req> B: FnOnce(&'req Req) -> BoxFuture<'req, sandbox::Result>, - Resp: SuccessDetails, - { - track_metric_common_async(request, body, |labels| labels.endpoint = endpoint).await - } - - async fn track_metric_common_async( - request: Req, - body: B, - f: F, - ) -> sandbox::Result - where - Req: GenerateLabels, - for<'req> B: FnOnce(&'req Req) -> BoxFuture<'req, sandbox::Result>, - Resp: SuccessDetails, - F: FnOnce(&mut Labels), - { - let start = Instant::now(); - let response = body(&request).await; - let elapsed = start.elapsed(); - - let outcome = SuccessDetails::for_sandbox_result(&response); - let mut labels = request.generate_labels(outcome); - f(&mut labels); - let values = &labels.to_values(); - - let histogram = REQUESTS.with_label_values(values); - - histogram.observe(elapsed.as_secs_f64()); - - response - } - - pub(crate) fn track_metric_no_request( - endpoint: Endpoint, - body: B, - ) -> crate::Result - where - B: FnOnce() -> crate::Result, - { - let start = Instant::now(); - let response = body(); - let elapsed = start.elapsed(); - - let outcome = if response.is_ok() { - Outcome::Success - } else { - Outcome::ErrorServer - }; - let labels = Labels { - endpoint, - outcome, - target: None, - channel: None, - mode: None, - edition: None, - crate_type: None, - tests: None, - backtrace: None, - }; - let values = &labels.to_values(); - let histogram = REQUESTS.with_label_values(values); - - histogram.observe(elapsed.as_secs_f64()); - - response - } - - pub(crate) async fn track_metric_no_request_async( - endpoint: Endpoint, - body: B, - ) -> crate::Result - where - B: FnOnce() -> Fut, - Fut: Future>, - { - let start = Instant::now(); - let response = body().await; - let elapsed = start.elapsed(); - - let outcome = if response.is_ok() { - Outcome::Success - } else { - Outcome::ErrorServer - }; - let labels = Labels { - endpoint, - outcome, - target: None, - channel: None, - mode: None, - edition: None, - crate_type: None, - tests: None, - backtrace: None, - }; - let values = &labels.to_values(); - let histogram = REQUESTS.with_label_values(values); - - histogram.observe(elapsed.as_secs_f64()); - - response + fn new(token: impl Into) -> Self { + MetricsToken(Arc::new(token.into())) } } @@ -682,8 +137,6 @@ pub enum Error { GistLoading { source: octocrab::Error }, #[snafu(display("Unable to serialize response: {}", source))] Serialization { source: serde_json::Error }, - #[snafu(display("Unable to deserialize request: {}", source))] - Deserialization { source: bodyparser::BodyError }, #[snafu(display("The value {:?} is not a valid target", value))] InvalidTarget { value: String }, #[snafu(display("The value {:?} is not a valid assembly flavor", value))] @@ -708,9 +161,6 @@ pub enum Error { type Result = ::std::result::Result; -const FATAL_ERROR_JSON: &str = - r#"{"error": "Multiple cascading errors occurred, abandon all hope"}"#; - #[derive(Debug, Clone, Serialize)] struct ErrorJson { error: String, @@ -825,23 +275,23 @@ struct MacroExpansionResponse { stderr: String, } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, PartialEq, Serialize)] struct CrateInformation { name: String, version: String, id: String, } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, PartialEq, Serialize)] struct MetaCratesResponse { - crates: Vec, + crates: Arc<[CrateInformation]>, } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, PartialEq, Serialize)] struct MetaVersionResponse { - version: String, - hash: String, - date: String, + version: Arc, + hash: Arc, + date: Arc, } #[derive(Debug, Clone, Deserialize)] @@ -1057,9 +507,9 @@ impl From> for MetaCratesResponse { impl From for MetaVersionResponse { fn from(me: sandbox::Version) -> Self { MetaVersionResponse { - version: me.release, - hash: me.commit_hash, - date: me.commit_date, + version: me.release.into(), + hash: me.commit_hash.into(), + date: me.commit_date.into(), } } } diff --git a/ui/src/metrics.rs b/ui/src/metrics.rs new file mode 100644 index 000000000..f7d2a6bb0 --- /dev/null +++ b/ui/src/metrics.rs @@ -0,0 +1,433 @@ +use futures::future::BoxFuture; +use lazy_static::lazy_static; +use prometheus::{self, register_histogram_vec, HistogramVec}; +use regex::Regex; +use std::{future::Future, time::Instant}; + +use crate::sandbox::{self, Channel, CompileTarget, CrateType, Edition, Mode}; + +lazy_static! { + pub(crate) static ref REQUESTS: HistogramVec = register_histogram_vec!( + "playground_request_duration_seconds", + "Number of requests made", + Labels::LABELS, + vec![0.1, 1.0, 2.5, 5.0, 10.0, 15.0] + ) + .unwrap(); +} + +#[derive(Debug, Copy, Clone, strum::IntoStaticStr)] +pub(crate) enum Endpoint { + Compile, + Execute, + Format, + Miri, + Clippy, + MacroExpansion, + MetaCrates, + MetaVersionStable, + MetaVersionBeta, + MetaVersionNightly, + MetaVersionRustfmt, + MetaVersionClippy, + MetaVersionMiri, + Evaluate, +} + +#[derive(Debug, Copy, Clone, strum::IntoStaticStr)] +pub(crate) enum Outcome { + Success, + ErrorServer, + ErrorTimeoutSoft, + ErrorTimeoutHard, + ErrorUserCode, +} + +#[derive(Debug, Copy, Clone)] +pub(crate) struct Labels { + endpoint: Endpoint, + outcome: Outcome, + + target: Option, + channel: Option, + mode: Option, + edition: Option>, + crate_type: Option, + tests: Option, + backtrace: Option, +} + +impl Labels { + const COUNT: usize = 9; + + const LABELS: &'static [&'static str; Self::COUNT] = &[ + "endpoint", + "outcome", + "target", + "channel", + "mode", + "edition", + "crate_type", + "tests", + "backtrace", + ]; + + fn as_values(&self) -> [&'static str; Self::COUNT] { + let Self { + endpoint, + outcome, + target, + channel, + mode, + edition, + crate_type, + tests, + backtrace, + } = *self; + + fn b(v: Option) -> &'static str { + v.map_or("", |v| if v { "true" } else { "false" }) + } + + let target = target.map_or("", Into::into); + let channel = channel.map_or("", Into::into); + let mode = mode.map_or("", Into::into); + let edition = match edition { + None => "", + Some(None) => "Unspecified", + Some(Some(v)) => v.into(), + }; + let crate_type = crate_type.map_or("", Into::into); + let tests = b(tests); + let backtrace = b(backtrace); + + [ + endpoint.into(), + outcome.into(), + target, + channel, + mode, + edition, + crate_type, + tests, + backtrace, + ] + } +} + +pub(crate) trait GenerateLabels { + fn generate_labels(&self, outcome: Outcome) -> Labels; +} + +impl GenerateLabels for &'_ T +where + T: GenerateLabels, +{ + fn generate_labels(&self, outcome: Outcome) -> Labels { + T::generate_labels(self, outcome) + } +} + +impl GenerateLabels for sandbox::CompileRequest { + fn generate_labels(&self, outcome: Outcome) -> Labels { + let Self { + target, + channel, + crate_type, + mode, + edition, + tests, + backtrace, + code: _, + } = *self; + + Labels { + endpoint: Endpoint::Compile, + outcome, + + target: Some(target), + channel: Some(channel), + mode: Some(mode), + edition: Some(edition), + crate_type: Some(crate_type), + tests: Some(tests), + backtrace: Some(backtrace), + } + } +} + +impl GenerateLabels for sandbox::ExecuteRequest { + fn generate_labels(&self, outcome: Outcome) -> Labels { + let Self { + channel, + mode, + edition, + crate_type, + tests, + backtrace, + code: _, + } = *self; + + Labels { + endpoint: Endpoint::Execute, + outcome, + + target: None, + channel: Some(channel), + mode: Some(mode), + edition: Some(edition), + crate_type: Some(crate_type), + tests: Some(tests), + backtrace: Some(backtrace), + } + } +} + +impl GenerateLabels for sandbox::FormatRequest { + fn generate_labels(&self, outcome: Outcome) -> Labels { + let Self { edition, code: _ } = *self; + + Labels { + endpoint: Endpoint::Format, + outcome, + + target: None, + channel: None, + mode: None, + edition: Some(edition), + crate_type: None, + tests: None, + backtrace: None, + } + } +} + +impl GenerateLabels for sandbox::ClippyRequest { + fn generate_labels(&self, outcome: Outcome) -> Labels { + let Self { + code: _, + edition, + crate_type, + } = *self; + + Labels { + endpoint: Endpoint::Clippy, + outcome, + + target: None, + channel: None, + mode: None, + edition: Some(edition), + crate_type: Some(crate_type), + tests: None, + backtrace: None, + } + } +} + +impl GenerateLabels for sandbox::MiriRequest { + fn generate_labels(&self, outcome: Outcome) -> Labels { + let Self { code: _, edition } = *self; + + Labels { + endpoint: Endpoint::Miri, + outcome, + + target: None, + channel: None, + mode: None, + edition: Some(edition), + crate_type: None, + tests: None, + backtrace: None, + } + } +} + +impl GenerateLabels for sandbox::MacroExpansionRequest { + fn generate_labels(&self, outcome: Outcome) -> Labels { + let Self { code: _, edition } = *self; + + Labels { + endpoint: Endpoint::MacroExpansion, + outcome, + + target: None, + channel: None, + mode: None, + edition: Some(edition), + crate_type: None, + tests: None, + backtrace: None, + } + } +} + +pub(crate) trait SuccessDetails: Sized { + fn success_details(&self) -> Outcome; + + fn for_sandbox_result(r: &Result) -> Outcome { + use sandbox::Error::*; + + match r { + Ok(v) => v.success_details(), + Err(CompilerExecutionTimedOut { .. }) => Outcome::ErrorTimeoutHard, + Err(_) => Outcome::ErrorServer, + } + } +} + +fn common_success_details(success: bool, stderr: &str) -> Outcome { + lazy_static! { + // Memory allocation failures are "Aborted" + static ref SOFT_TIMEOUT_REGEX: Regex = Regex::new("entrypoint.sh.*Killed.*timeout").unwrap(); + } + + match success { + true => Outcome::Success, + false => { + if stderr + .lines() + .next_back() + .map_or(false, |l| SOFT_TIMEOUT_REGEX.is_match(l)) + { + Outcome::ErrorTimeoutSoft + } else { + Outcome::ErrorUserCode + } + } + } +} + +impl SuccessDetails for sandbox::CompileResponse { + fn success_details(&self) -> Outcome { + common_success_details(self.success, &self.stderr) + } +} + +impl SuccessDetails for sandbox::ExecuteResponse { + fn success_details(&self) -> Outcome { + common_success_details(self.success, &self.stderr) + } +} + +impl SuccessDetails for sandbox::FormatResponse { + fn success_details(&self) -> Outcome { + common_success_details(self.success, &self.stderr) + } +} + +impl SuccessDetails for sandbox::ClippyResponse { + fn success_details(&self) -> Outcome { + common_success_details(self.success, &self.stderr) + } +} + +impl SuccessDetails for sandbox::MiriResponse { + fn success_details(&self) -> Outcome { + common_success_details(self.success, &self.stderr) + } +} + +impl SuccessDetails for sandbox::MacroExpansionResponse { + fn success_details(&self) -> Outcome { + common_success_details(self.success, &self.stderr) + } +} + +impl SuccessDetails for Vec { + fn success_details(&self) -> Outcome { + Outcome::Success + } +} + +impl SuccessDetails for sandbox::Version { + fn success_details(&self) -> Outcome { + Outcome::Success + } +} + +pub(crate) async fn track_metric_async(request: Req, body: B) -> sandbox::Result +where + Req: GenerateLabels, + for<'req> B: FnOnce(&'req Req) -> BoxFuture<'req, sandbox::Result>, + Resp: SuccessDetails, +{ + track_metric_common_async(request, body, |_| {}).await +} + +pub(crate) async fn track_metric_force_endpoint_async( + request: Req, + endpoint: Endpoint, + body: B, +) -> sandbox::Result +where + Req: GenerateLabels, + for<'req> B: FnOnce(&'req Req) -> BoxFuture<'req, sandbox::Result>, + Resp: SuccessDetails, +{ + track_metric_common_async(request, body, |labels| labels.endpoint = endpoint).await +} + +async fn track_metric_common_async( + request: Req, + body: B, + f: F, +) -> sandbox::Result +where + Req: GenerateLabels, + for<'req> B: FnOnce(&'req Req) -> BoxFuture<'req, sandbox::Result>, + Resp: SuccessDetails, + F: FnOnce(&mut Labels), +{ + let start = Instant::now(); + let response = body(&request).await; + let elapsed = start.elapsed(); + + let outcome = SuccessDetails::for_sandbox_result(&response); + let mut labels = request.generate_labels(outcome); + f(&mut labels); + let values = &labels.as_values(); + + let histogram = REQUESTS.with_label_values(values); + + histogram.observe(elapsed.as_secs_f64()); + + response +} + +pub(crate) async fn track_metric_no_request_async( + endpoint: Endpoint, + body: B, +) -> crate::Result +where + B: FnOnce() -> Fut, + Fut: Future>, +{ + let start = Instant::now(); + let response = body().await; + let elapsed = start.elapsed(); + + let outcome = if response.is_ok() { + Outcome::Success + } else { + Outcome::ErrorServer + }; + let labels = Labels { + endpoint, + outcome, + target: None, + channel: None, + mode: None, + edition: None, + crate_type: None, + tests: None, + backtrace: None, + }; + let values = &labels.as_values(); + let histogram = REQUESTS.with_label_values(values); + + histogram.observe(elapsed.as_secs_f64()); + + response +} diff --git a/ui/src/sandbox.rs b/ui/src/sandbox.rs index c77daebba..ffe11962f 100644 --- a/ui/src/sandbox.rs +++ b/ui/src/sandbox.rs @@ -1,10 +1,7 @@ use serde_derive::Deserialize; use snafu::{ResultExt, Snafu}; use std::{ffi::OsStr, fmt, io, os::unix::fs::PermissionsExt, string, time::Duration}; -use tokio::{ - process::Command, - runtime::{Builder, Runtime}, -}; +use tokio::process::Command; const DOCKER_PROCESS_TIMEOUT_SOFT: Duration = Duration::from_secs(10); const DOCKER_PROCESS_TIMEOUT_HARD: Duration = Duration::from_secs(12); @@ -84,11 +81,6 @@ pub enum Error { pub type Result = ::std::result::Result; -pub struct Sandbox { - runtime: Runtime, - sandbox: fut::Sandbox, -} - fn vec_to_str(v: Vec) -> Result { String::from_utf8(v).context(OutputNotUtf8Snafu) } @@ -103,62 +95,6 @@ fn wide_open_permissions() -> std::fs::Permissions { PermissionsExt::from_mode(0o777) } -impl Sandbox { - pub fn new() -> Result { - let runtime = Builder::new_current_thread() - .enable_all() - .build() - .expect("Failed building the Runtime"); - let sandbox = runtime.block_on(fut::Sandbox::new())?; - - Ok(Self { runtime, sandbox }) - } - - pub fn compile(&self, req: &CompileRequest) -> Result { - self.runtime.block_on(self.sandbox.compile(req)) - } - - pub fn execute(&self, req: &ExecuteRequest) -> Result { - self.runtime.block_on(self.sandbox.execute(req)) - } - - pub fn format(&self, req: &FormatRequest) -> Result { - self.runtime.block_on(self.sandbox.format(req)) - } - - pub fn clippy(&self, req: &ClippyRequest) -> Result { - self.runtime.block_on(self.sandbox.clippy(req)) - } - - pub fn miri(&self, req: &MiriRequest) -> Result { - self.runtime.block_on(self.sandbox.miri(req)) - } - - pub fn macro_expansion(&self, req: &MacroExpansionRequest) -> Result { - self.runtime.block_on(self.sandbox.macro_expansion(req)) - } - - pub fn crates(&self) -> Result> { - self.runtime.block_on(self.sandbox.crates()) - } - - pub fn version(&self, channel: Channel) -> Result { - self.runtime.block_on(self.sandbox.version(channel)) - } - - pub fn version_rustfmt(&self) -> Result { - self.runtime.block_on(self.sandbox.version_rustfmt()) - } - - pub fn version_clippy(&self) -> Result { - self.runtime.block_on(self.sandbox.version_clippy()) - } - - pub fn version_miri(&self) -> Result { - self.runtime.block_on(self.sandbox.version_miri()) - } -} - macro_rules! docker_command { ($($arg:expr),* $(,)?) => ({ let mut cmd = Command::new("docker"); @@ -288,7 +224,7 @@ pub mod fut { io::ErrorKind, path::{Path, PathBuf}, }; - use tempdir::TempDir; + use tempfile::TempDir; use tokio::{fs, process::Command, time}; use super::{ @@ -321,7 +257,10 @@ pub mod fut { // now and when it's dropped. We accept that under the // assumption that the specific operations will be quick // enough. - let scratch = TempDir::new("playground").context(UnableToCreateTempDirSnafu)?; + let scratch = tempfile::Builder::new() + .prefix("playground") + .tempdir() + .context(UnableToCreateTempDirSnafu)?; let input_file = scratch.path().join("input.rs"); let output_dir = scratch.path().join("output"); diff --git a/ui/src/server_axum.rs b/ui/src/server_axum.rs index afa7dc695..4e1dd4bf5 100644 --- a/ui/src/server_axum.rs +++ b/ui/src/server_axum.rs @@ -11,13 +11,13 @@ use crate::{ FormattingSnafu, GhToken, GistCreationSnafu, GistLoadingSnafu, InterpretingSnafu, LintingSnafu, MacroExpansionRequest, MacroExpansionResponse, MetaCratesResponse, MetaGistCreateRequest, MetaGistResponse, MetaVersionResponse, MetricsToken, MiriRequest, MiriResponse, Result, - SandboxCreationSnafu, ONE_HOUR, SANDBOX_CACHE_TIME_TO_LIVE, + SandboxCreationSnafu, }; use async_trait::async_trait; use axum::{ extract::{self, Extension, Path, TypedHeader}, handler::Handler, - headers::{authorization::Bearer, Authorization}, + headers::{authorization::Bearer, Authorization, CacheControl, ETag, IfNoneMatch}, http::{header, uri::PathAndQuery, HeaderValue, Method, Request, StatusCode, Uri}, middleware, response::IntoResponse, @@ -30,8 +30,9 @@ use std::{ convert::{TryFrom, TryInto}, future::Future, mem, path, + str::FromStr, sync::Arc, - time::Instant, + time::{Duration, Instant, SystemTime, UNIX_EPOCH}, }; use tokio::sync::Mutex; use tower_http::{ @@ -41,6 +42,12 @@ use tower_http::{ trace::TraceLayer, }; +const ONE_HOUR: Duration = Duration::from_secs(60 * 60); +const CORS_CACHE_TIME_TO_LIVE: Duration = ONE_HOUR; + +const TEN_MINUTES: Duration = Duration::from_secs(10 * 60); +const SANDBOX_CACHE_TIME_TO_LIVE: Duration = TEN_MINUTES; + const MAX_AGE_ONE_DAY: HeaderValue = HeaderValue::from_static("public, max-age=86400"); const MAX_AGE_ONE_YEAR: HeaderValue = HeaderValue::from_static("public, max-age=31536000"); @@ -85,7 +92,7 @@ pub(crate) async fn serve(config: Config) { .allow_headers([header::CONTENT_TYPE]) .allow_methods([Method::GET, Method::POST]) .allow_credentials(false) - .max_age(ONE_HOUR) + .max_age(CORS_CACHE_TIME_TO_LIVE) }); } @@ -243,58 +250,103 @@ where async fn meta_crates( Extension(cache): Extension>, -) -> Result> { - track_metric_no_request_async(Endpoint::MetaCrates, || cache.crates()) - .await - .map(Json) + if_none_match: Option>, +) -> Result { + // Json>, -) -> Result> { - track_metric_no_request_async(Endpoint::MetaVersionStable, || cache.version_stable()) - .await - .map(Json) + if_none_match: Option>, +) -> Result { + let value = + track_metric_no_request_async(Endpoint::MetaVersionStable, || cache.version_stable()) + .await?; + apply_timestamped_caching(value, if_none_match) } async fn meta_version_beta( Extension(cache): Extension>, -) -> Result> { - track_metric_no_request_async(Endpoint::MetaVersionBeta, || cache.version_beta()) - .await - .map(Json) + if_none_match: Option>, +) -> Result { + let value = + track_metric_no_request_async(Endpoint::MetaVersionBeta, || cache.version_beta()).await?; + apply_timestamped_caching(value, if_none_match) } async fn meta_version_nightly( Extension(cache): Extension>, -) -> Result> { - track_metric_no_request_async(Endpoint::MetaVersionNightly, || cache.version_nightly()) - .await - .map(Json) + if_none_match: Option>, +) -> Result { + let value = + track_metric_no_request_async(Endpoint::MetaVersionNightly, || cache.version_nightly()) + .await?; + apply_timestamped_caching(value, if_none_match) } async fn meta_version_rustfmt( Extension(cache): Extension>, -) -> Result> { - track_metric_no_request_async(Endpoint::MetaVersionRustfmt, || cache.version_rustfmt()) - .await - .map(Json) + if_none_match: Option>, +) -> Result { + let value = + track_metric_no_request_async(Endpoint::MetaVersionRustfmt, || cache.version_rustfmt()) + .await?; + apply_timestamped_caching(value, if_none_match) } async fn meta_version_clippy( Extension(cache): Extension>, -) -> Result> { - track_metric_no_request_async(Endpoint::MetaVersionClippy, || cache.version_clippy()) - .await - .map(Json) + if_none_match: Option>, +) -> Result { + let value = + track_metric_no_request_async(Endpoint::MetaVersionClippy, || cache.version_clippy()) + .await?; + apply_timestamped_caching(value, if_none_match) } async fn meta_version_miri( Extension(cache): Extension>, -) -> Result> { - track_metric_no_request_async(Endpoint::MetaVersionMiri, || cache.version_miri()) - .await - .map(Json) + if_none_match: Option>, +) -> Result { + let value = + track_metric_no_request_async(Endpoint::MetaVersionMiri, || cache.version_miri()).await?; + apply_timestamped_caching(value, if_none_match) +} + +fn apply_timestamped_caching( + value: Stamped, + if_none_match: Option>, +) -> Result +where + Json: IntoResponse, +{ + let (value, timestamp) = value; + + let timestamp = timestamp.duration_since(UNIX_EPOCH).unwrap(); + let etag = format!(r#""pg-ts-{}""#, timestamp.as_secs()); + let etag = ETag::from_str(&etag).unwrap(); + + let cache_control = CacheControl::new() + .with_max_age(SANDBOX_CACHE_TIME_TO_LIVE) + .with_public(); + + let use_fresh = if_none_match.map_or(true, |if_none_match| { + if_none_match.0.precondition_passes(&etag) + }); + + let etag = TypedHeader(etag); + let cache_control = TypedHeader(cache_control); + + let response = if use_fresh { + (StatusCode::OK, Json(value)).into_response() + } else { + StatusCode::NOT_MODIFIED.into_response() + }; + + Ok((etag, cache_control, response)) } async fn meta_gist_create( @@ -355,7 +407,7 @@ where Ok(Extension(expected)) => { match TypedHeader::>::from_request(req).await { Ok(TypedHeader(Authorization(actual))) => { - if actual.token() == &*expected.0 { + if actual.token() == *expected.0 { Ok(Self) } else { Err(Self::FAILURE) @@ -370,11 +422,10 @@ where } } +type Stamped = (T, SystemTime); + #[derive(Debug, Default)] struct SandboxCache { - // PERF: Since we clone these a lot, it could be more efficient to - // change them to contain `Arc`s. e.g., `Vec` could become - // `Arc<[Foo]>`. crates: CacheOne, version_stable: CacheOne, version_beta: CacheOne, @@ -385,7 +436,7 @@ struct SandboxCache { } impl SandboxCache { - async fn crates(&self) -> Result { + async fn crates(&self) -> Result> { self.crates .fetch( |sandbox| async move { Ok(sandbox.crates().await.context(CachingSnafu)?.into()) }, @@ -393,7 +444,7 @@ impl SandboxCache { .await } - async fn version_stable(&self) -> Result { + async fn version_stable(&self) -> Result> { self.version_stable .fetch(|sandbox| async move { let version = sandbox @@ -405,7 +456,7 @@ impl SandboxCache { .await } - async fn version_beta(&self) -> Result { + async fn version_beta(&self) -> Result> { self.version_beta .fetch(|sandbox| async move { let version = sandbox.version(Channel::Beta).await.context(CachingSnafu)?; @@ -414,7 +465,7 @@ impl SandboxCache { .await } - async fn version_nightly(&self) -> Result { + async fn version_nightly(&self) -> Result> { self.version_nightly .fetch(|sandbox| async move { let version = sandbox @@ -426,7 +477,7 @@ impl SandboxCache { .await } - async fn version_rustfmt(&self) -> Result { + async fn version_rustfmt(&self) -> Result> { self.version_rustfmt .fetch(|sandbox| async move { Ok(sandbox @@ -438,7 +489,7 @@ impl SandboxCache { .await } - async fn version_clippy(&self) -> Result { + async fn version_clippy(&self) -> Result> { self.version_clippy .fetch(|sandbox| async move { Ok(sandbox.version_clippy().await.context(CachingSnafu)?.into()) @@ -446,7 +497,7 @@ impl SandboxCache { .await } - async fn version_miri(&self) -> Result { + async fn version_miri(&self) -> Result> { self.version_miri .fetch(|sandbox| async move { Ok(sandbox.version_miri().await.context(CachingSnafu)?.into()) @@ -466,9 +517,9 @@ impl Default for CacheOne { impl CacheOne where - T: Clone, + T: Clone + PartialEq, { - async fn fetch(&self, generator: F) -> Result + async fn fetch(&self, generator: F) -> Result> where F: FnOnce(Sandbox) -> FFut, FFut: Future>, @@ -476,8 +527,8 @@ where let data = &mut *self.0.lock().await; match data { Some(info) => { - if info.creation_time.elapsed() <= SANDBOX_CACHE_TIME_TO_LIVE { - Ok(info.value.clone()) + if info.validation_time.elapsed() <= SANDBOX_CACHE_TIME_TO_LIVE { + Ok(info.stamped_value()) } else { Self::set_value(data, generator).await } @@ -486,7 +537,7 @@ where } } - async fn set_value(data: &mut Option>, generator: F) -> Result + async fn set_value(data: &mut Option>, generator: F) -> Result> where F: FnOnce(Sandbox) -> FFut, FFut: Future>, @@ -494,7 +545,27 @@ where let sandbox = Sandbox::new().await.context(SandboxCreationSnafu)?; let value = generator(sandbox).await?; - *data = Some(CacheInfo::build(&value)); + let old_info = data.take(); + let new_info = CacheInfo::build(value); + + let info = match old_info { + Some(mut old_value) => { + if old_value.value == new_info.value { + // The value hasn't changed; record that we have + // checked recently, but keep the creation time to + // preserve caching. + old_value.validation_time = new_info.validation_time; + old_value + } else { + new_info + } + } + None => new_info, + }; + + let value = info.stamped_value(); + + *data = Some(info); Ok(value) } @@ -503,22 +574,28 @@ where #[derive(Debug)] struct CacheInfo { value: T, - creation_time: Instant, + creation_time: SystemTime, + validation_time: Instant, } impl CacheInfo { - fn build(value: &T) -> Self - where - T: Clone, - { - let value = value.clone(); - let creation_time = Instant::now(); + fn build(value: T) -> Self { + let creation_time = SystemTime::now(); + let validation_time = Instant::now(); Self { value, creation_time, + validation_time, } } + + fn stamped_value(&self) -> Stamped + where + T: Clone, + { + (self.value.clone(), self.creation_time) + } } impl IntoResponse for Error { diff --git a/ui/src/server_iron.rs b/ui/src/server_iron.rs deleted file mode 100644 index 31f45a1d5..000000000 --- a/ui/src/server_iron.rs +++ /dev/null @@ -1,524 +0,0 @@ -use crate::{ - gist, - metrics::{self, track_metric, track_metric_force_endpoint, track_metric_no_request}, - sandbox::{self, Sandbox}, - CachingSnafu, ClippyRequest, ClippyResponse, CompilationSnafu, CompileRequest, CompileResponse, - Config, DeserializationSnafu, Error, ErrorJson, EvaluateRequest, EvaluateResponse, - EvaluationSnafu, ExecuteRequest, ExecuteResponse, ExecutionSnafu, ExpansionSnafu, - FormatRequest, FormatResponse, FormattingSnafu, GhToken, InterpretingSnafu, LintingSnafu, - MacroExpansionRequest, MacroExpansionResponse, MetaCratesResponse, MetaGistCreateRequest, - MetaGistResponse, MetaVersionResponse, MetricsToken, MiriRequest, MiriResponse, Result, - SandboxCreationSnafu, SerializationSnafu, FATAL_ERROR_JSON, ONE_DAY, ONE_HOUR_IN_SECONDS, - ONE_YEAR, SANDBOX_CACHE_TIME_TO_LIVE, -}; -use corsware::{AllowedOrigins, CorsMiddleware, UniCase}; -use iron::{ - headers::ContentType, - method::Method::{Get, Post}, - modifiers::Header, - prelude::*, - status, -}; -use lazy_static::lazy_static; -use mount::Mount; -use playground_middleware::{ - Cache, FileLogger, GuessContentType, ModifyWith, Prefix, Rewrite, Staticfile, StatisticLogger, -}; -use prometheus::{Encoder, TextEncoder}; -use router::Router; -use serde::{de::DeserializeOwned, Serialize}; -use snafu::ResultExt; -use std::{any::Any, convert::TryInto, sync::Mutex, time::Instant}; - -pub(crate) fn serve(config: Config) { - let Config { - root, - gh_token, - address, - port, - logfile, - cors_enabled, - metrics_token, - axum_enabled: _, - } = config; - - let files = Staticfile::new(&root).expect("Unable to open root directory"); - let mut files = Chain::new(files); - - files.link_after(ModifyWith::new(Cache::new(ONE_DAY))); - files.link_after(Prefix::new(&["assets"], Cache::new(ONE_YEAR))); - files.link_after(GuessContentType::new(ContentType::html().0)); - - let mut gist_router = Router::new(); - gist_router.post("/", meta_gist_create, "gist_create"); - gist_router.get("/:id", meta_gist_get, "gist_get"); - - let mut mount = Mount::new(); - mount.mount("/", files); - mount.mount("/compile", compile); - mount.mount("/execute", execute); - mount.mount("/format", format); - mount.mount("/clippy", clippy); - mount.mount("/miri", miri); - mount.mount("/macro-expansion", macro_expansion); - mount.mount("/meta/crates", meta_crates); - mount.mount("/meta/version/stable", meta_version_stable); - mount.mount("/meta/version/beta", meta_version_beta); - mount.mount("/meta/version/nightly", meta_version_nightly); - mount.mount("/meta/version/rustfmt", meta_version_rustfmt); - mount.mount("/meta/version/clippy", meta_version_clippy); - mount.mount("/meta/version/miri", meta_version_miri); - mount.mount("/meta/gist", gist_router); - mount.mount("/evaluate.json", evaluate); - - mount.mount("/metrics", metrics); - - let mut chain = Chain::new(mount); - let file_logger = FileLogger::new(logfile).expect("Unable to create file logger"); - let logger = StatisticLogger::new(file_logger); - let rewrite = Rewrite::new(vec![vec!["help".into()]], "/index.html".into()); - let gh_token = GhToken::new(gh_token); - - chain.link_around(logger); - chain.link_before(rewrite); - chain.link_before(gh_token); - - if let Some(metrics_token) = metrics_token { - let metrics_token = MetricsToken::new(metrics_token); - chain.link_before(metrics_token); - } - - if cors_enabled { - chain.link_around(CorsMiddleware { - // A null origin occurs when you make a request from a - // page hosted on a filesystem, such as when you read the - // Rust book locally - allowed_origins: AllowedOrigins::Any { allow_null: true }, - allowed_headers: vec![UniCase("Content-Type".to_owned())], - allowed_methods: vec![Get, Post], - exposed_headers: vec![], - allow_credentials: false, - max_age_seconds: ONE_HOUR_IN_SECONDS, - prefer_wildcard: true, - }); - } - - log::info!("Starting the server on http://{}:{}", address, port); - Iron::new(chain) - .http((&*address, port)) - .expect("Unable to start server"); -} - -impl iron::BeforeMiddleware for GhToken { - fn before(&self, req: &mut Request<'_, '_>) -> IronResult<()> { - req.extensions.insert::(self.clone()); - Ok(()) - } -} - -impl iron::typemap::Key for GhToken { - type Value = Self; -} - -impl iron::BeforeMiddleware for MetricsToken { - fn before(&self, req: &mut Request<'_, '_>) -> IronResult<()> { - req.extensions.insert::(self.clone()); - Ok(()) - } -} - -impl iron::typemap::Key for MetricsToken { - type Value = Self; -} - -fn compile(req: &mut Request<'_, '_>) -> IronResult { - with_sandbox(req, |sandbox, req: CompileRequest| { - let req = req.try_into()?; - track_metric(req, |req| sandbox.compile(&req)) - .map(CompileResponse::from) - .context(CompilationSnafu) - }) -} - -fn execute(req: &mut Request<'_, '_>) -> IronResult { - with_sandbox(req, |sandbox, req: ExecuteRequest| { - let req = req.try_into()?; - track_metric(req, |req| sandbox.execute(&req)) - .map(ExecuteResponse::from) - .context(ExecutionSnafu) - }) -} - -fn format(req: &mut Request<'_, '_>) -> IronResult { - with_sandbox(req, |sandbox, req: FormatRequest| { - let req = req.try_into()?; - track_metric(req, |req| sandbox.format(&req)) - .map(FormatResponse::from) - .context(FormattingSnafu) - }) -} - -fn clippy(req: &mut Request<'_, '_>) -> IronResult { - with_sandbox(req, |sandbox, req: ClippyRequest| { - let req = req.try_into()?; - track_metric(req, |req| sandbox.clippy(&req)) - .map(ClippyResponse::from) - .context(LintingSnafu) - }) -} - -fn miri(req: &mut Request<'_, '_>) -> IronResult { - with_sandbox(req, |sandbox, req: MiriRequest| { - let req = req.try_into()?; - track_metric(req, |req| sandbox.miri(&req)) - .map(MiriResponse::from) - .context(InterpretingSnafu) - }) -} - -fn macro_expansion(req: &mut Request<'_, '_>) -> IronResult { - with_sandbox(req, |sandbox, req: MacroExpansionRequest| { - let req = req.try_into()?; - track_metric(req, |req| sandbox.macro_expansion(&req)) - .map(MacroExpansionResponse::from) - .context(ExpansionSnafu) - }) -} - -fn meta_crates(_req: &mut Request<'_, '_>) -> IronResult { - with_sandbox_no_request(|sandbox| { - track_metric_no_request(metrics::Endpoint::MetaCrates, || cached(sandbox).crates()) - .map(MetaCratesResponse::from) - }) -} - -fn meta_version_stable(_req: &mut Request<'_, '_>) -> IronResult { - with_sandbox_no_request(|sandbox| { - track_metric_no_request(metrics::Endpoint::MetaVersionStable, || { - cached(sandbox).version_stable() - }) - .map(MetaVersionResponse::from) - }) -} - -fn meta_version_beta(_req: &mut Request<'_, '_>) -> IronResult { - with_sandbox_no_request(|sandbox| { - track_metric_no_request(metrics::Endpoint::MetaVersionBeta, || { - cached(sandbox).version_beta() - }) - .map(MetaVersionResponse::from) - }) -} - -fn meta_version_nightly(_req: &mut Request<'_, '_>) -> IronResult { - with_sandbox_no_request(|sandbox| { - track_metric_no_request(metrics::Endpoint::MetaVersionNightly, || { - cached(sandbox).version_nightly() - }) - .map(MetaVersionResponse::from) - }) -} - -fn meta_version_rustfmt(_req: &mut Request<'_, '_>) -> IronResult { - with_sandbox_no_request(|sandbox| { - track_metric_no_request(metrics::Endpoint::MetaVersionRustfmt, || { - cached(sandbox).version_rustfmt() - }) - .map(MetaVersionResponse::from) - }) -} - -fn meta_version_clippy(_req: &mut Request<'_, '_>) -> IronResult { - with_sandbox_no_request(|sandbox| { - track_metric_no_request(metrics::Endpoint::MetaVersionClippy, || { - cached(sandbox).version_clippy() - }) - .map(MetaVersionResponse::from) - }) -} - -fn meta_version_miri(_req: &mut Request<'_, '_>) -> IronResult { - with_sandbox_no_request(|sandbox| { - track_metric_no_request(metrics::Endpoint::MetaVersionMiri, || { - cached(sandbox).version_miri() - }) - .map(MetaVersionResponse::from) - }) -} - -fn meta_gist_create(req: &mut Request<'_, '_>) -> IronResult { - let token = req.extensions.get::().unwrap().0.as_ref().clone(); - serialize_to_response(deserialize_from_request(req, |r: MetaGistCreateRequest| { - let gist = gist::create(token, r.code); - Ok(MetaGistResponse::from(gist)) - })) -} - -fn meta_gist_get(req: &mut Request<'_, '_>) -> IronResult { - match req.extensions.get::().unwrap().find("id") { - Some(id) => { - let token = req.extensions.get::().unwrap().0.as_ref().clone(); - let gist = gist::load(token, id); - serialize_to_response(Ok(MetaGistResponse::from(gist))) - } - None => Ok(Response::with(status::UnprocessableEntity)), - } -} - -// This is a backwards compatibilty shim. The Rust homepage and the -// documentation use this to run code in place. -fn evaluate(req: &mut Request<'_, '_>) -> IronResult { - with_sandbox(req, |sandbox, req: EvaluateRequest| { - let req = req.try_into()?; - track_metric_force_endpoint(req, metrics::Endpoint::Evaluate, |req| { - sandbox.execute(&req) - }) - .map(EvaluateResponse::from) - .context(EvaluationSnafu) - }) -} - -fn with_sandbox(req: &mut Request<'_, '_>, f: F) -> IronResult -where - F: FnOnce(Sandbox, Req) -> Result, - Req: DeserializeOwned + Clone + Any + 'static, - Resp: Serialize, -{ - serialize_to_response(run_handler(req, f)) -} - -fn with_sandbox_no_request(f: F) -> IronResult -where - F: FnOnce(Sandbox) -> Result, - Resp: Serialize, -{ - serialize_to_response(run_handler_no_request(f)) -} - -fn run_handler(req: &mut Request<'_, '_>, f: F) -> Result -where - F: FnOnce(Sandbox, Req) -> Result, - Req: DeserializeOwned + Clone + Any + 'static, -{ - deserialize_from_request(req, |req| { - let sandbox = Sandbox::new().context(SandboxCreationSnafu)?; - f(sandbox, req) - }) -} - -fn deserialize_from_request(req: &mut Request<'_, '_>, f: F) -> Result -where - F: FnOnce(Req) -> Result, - Req: DeserializeOwned + Clone + Any + 'static, -{ - let body = req - .get::>() - .context(DeserializationSnafu)?; - - let req = body.ok_or(Error::RequestMissing)?; - - let resp = f(req)?; - - Ok(resp) -} - -fn run_handler_no_request(f: F) -> Result -where - F: FnOnce(Sandbox) -> Result, -{ - let sandbox = Sandbox::new().context(SandboxCreationSnafu)?; - let resp = f(sandbox)?; - Ok(resp) -} - -fn serialize_to_response(response: Result) -> IronResult -where - Resp: Serialize, -{ - let response = response.and_then(|resp| { - let resp = serde_json::ser::to_string(&resp).context(SerializationSnafu)?; - Ok(resp) - }); - - match response { - Ok(body) => Ok(Response::with(( - status::Ok, - Header(ContentType::json()), - body, - ))), - Err(err) => { - let err = ErrorJson { - error: err.to_string(), - }; - match serde_json::ser::to_string(&err) { - Ok(error_str) => Ok(Response::with(( - status::InternalServerError, - Header(ContentType::json()), - error_str, - ))), - Err(_) => Ok(Response::with(( - status::InternalServerError, - Header(ContentType::json()), - FATAL_ERROR_JSON, - ))), - } - } - } -} - -#[derive(Debug, Clone)] -struct SandboxCacheInfo { - value: T, - time: Instant, -} - -/// Caches the success value of a single operation -#[derive(Debug)] -struct SandboxCacheOne(Mutex>>); - -impl Default for SandboxCacheOne { - fn default() -> Self { - SandboxCacheOne(Mutex::default()) - } -} - -impl SandboxCacheOne -where - T: Clone, -{ - fn clone_or_populate(&self, populator: F) -> Result - where - F: FnOnce() -> sandbox::Result, - { - let mut cache = self.0.lock().map_err(|_| Error::CachePoisoned)?; - - match cache.clone() { - Some(cached) => { - if cached.time.elapsed() > SANDBOX_CACHE_TIME_TO_LIVE { - SandboxCacheOne::populate(&mut *cache, populator) - } else { - Ok(cached.value) - } - } - None => SandboxCacheOne::populate(&mut *cache, populator), - } - } - - fn populate(cache: &mut Option>, populator: F) -> Result - where - F: FnOnce() -> sandbox::Result, - { - let value = populator().context(CachingSnafu)?; - *cache = Some(SandboxCacheInfo { - value: value.clone(), - time: Instant::now(), - }); - Ok(value) - } -} - -/// Caches the successful results of all sandbox operations that make -/// sense to cache. -#[derive(Debug, Default)] -struct SandboxCache { - crates: SandboxCacheOne>, - version_stable: SandboxCacheOne, - version_beta: SandboxCacheOne, - version_nightly: SandboxCacheOne, - version_clippy: SandboxCacheOne, - version_rustfmt: SandboxCacheOne, - version_miri: SandboxCacheOne, -} - -/// Provides a similar API to the Sandbox that caches the successful results. -struct CachedSandbox<'a> { - sandbox: Sandbox, - cache: &'a SandboxCache, -} - -impl<'a> CachedSandbox<'a> { - fn crates(&self) -> Result> { - self.cache - .crates - .clone_or_populate(|| self.sandbox.crates()) - } - - fn version_stable(&self) -> Result { - self.cache - .version_stable - .clone_or_populate(|| self.sandbox.version(sandbox::Channel::Stable)) - } - - fn version_beta(&self) -> Result { - self.cache - .version_beta - .clone_or_populate(|| self.sandbox.version(sandbox::Channel::Beta)) - } - - fn version_nightly(&self) -> Result { - self.cache - .version_nightly - .clone_or_populate(|| self.sandbox.version(sandbox::Channel::Nightly)) - } - - fn version_clippy(&self) -> Result { - self.cache - .version_clippy - .clone_or_populate(|| self.sandbox.version_clippy()) - } - - fn version_rustfmt(&self) -> Result { - self.cache - .version_rustfmt - .clone_or_populate(|| self.sandbox.version_rustfmt()) - } - - fn version_miri(&self) -> Result { - self.cache - .version_miri - .clone_or_populate(|| self.sandbox.version_miri()) - } -} - -/// A convenience constructor -fn cached(sandbox: Sandbox) -> CachedSandbox<'static> { - lazy_static! { - static ref SANDBOX_CACHE: SandboxCache = Default::default(); - } - - CachedSandbox { - sandbox, - cache: &SANDBOX_CACHE, - } -} - -fn authorized_for_metrics(req: &mut Request<'_, '_>) -> bool { - use iron::headers::{Authorization, Bearer}; - - // If not configured, allow it to be public - let token = match req.extensions.get::() { - Some(token) => token, - None => return true, - }; - - let authorization = match req.headers.get::>() { - Some(a) => a, - None => return false, - }; - - authorization.0.token.as_str() == token.0.as_str() -} - -fn metrics(req: &mut Request<'_, '_>) -> IronResult { - if !authorized_for_metrics(req) { - return Ok(Response::with((status::Unauthorized, "Unauthorized"))); - } - - let metric_families = prometheus::gather(); - let encoder = TextEncoder::new(); - let mut buffer = Vec::new(); - - encoder.encode(&metric_families, &mut buffer).unwrap(); - - Ok(Response::with((status::Ok, buffer))) -}