diff --git a/Cargo.lock b/Cargo.lock index 35198900..c6caf328 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,6 +95,9 @@ name = "anyhow" version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +dependencies = [ + "backtrace", +] [[package]] name = "arrayref" @@ -124,6 +127,19 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "async-posthog" +version = "0.2.3" +source = "git+https://github.com/rivet-gg/posthog-rs?rev=ef4e80e#ef4e80e57747ea7204794bce9a103bfeccefabf1" +dependencies = [ + "posthog-core", + "reqwest 0.11.27", + "serde", + "serde_json", + "thiserror", + "tokio", +] + [[package]] name = "async-stream" version = "0.3.5" @@ -333,6 +349,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.38" @@ -341,8 +363,10 @@ checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", "serde", + "wasm-bindgen", "windows-targets 0.52.6", ] @@ -545,6 +569,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctrlc" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix 0.29.0", + "windows-sys 0.59.0", +] + [[package]] name = "darling" version = "0.20.10" @@ -580,6 +614,16 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "serde", + "uuid", +] + [[package]] name = "deranged" version = "0.3.11" @@ -745,6 +789,18 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "findshlibs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" +dependencies = [ + "cc", + "lazy_static", + "libc", + "winapi", +] + [[package]] name = "flate2" version = "1.0.34" @@ -761,6 +817,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -783,6 +854,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -919,7 +991,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", "indexmap 2.5.0", "slab", "tokio", @@ -972,6 +1044,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "hostname" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba" +dependencies = [ + "cfg-if", + "libc", + "windows 0.52.0", +] + [[package]] name = "http" version = "0.2.12" @@ -983,6 +1066,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -990,7 +1084,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -1023,8 +1140,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -1036,6 +1153,25 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-rustls" version = "0.24.2" @@ -1043,13 +1179,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", - "hyper", + "http 0.2.12", + "hyper 0.14.30", "rustls", "tokio", "tokio-rustls", ] +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.5.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.5.1", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" version = "0.1.61" @@ -1061,7 +1232,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -1549,6 +1720,23 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "ndk-context" version = "0.1.1" @@ -1575,6 +1763,27 @@ dependencies = [ "libc", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -1654,12 +1863,67 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "openssl" +version = "0.10.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "os_info" +version = "3.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" +dependencies = [ + "log", + "serde", + "windows-sys 0.52.0", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -1732,12 +1996,32 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +[[package]] +name = "posthog-core" +version = "0.1.0" +source = "git+https://github.com/rivet-gg/posthog-rs?rev=ef4e80e#ef4e80e57747ea7204794bce9a103bfeccefabf1" +dependencies = [ + "chrono", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "powerfmt" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "predicates" version = "3.1.2" @@ -1789,6 +2073,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "rayon" version = "1.10.0" @@ -1870,9 +2184,9 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.30", "hyper-rustls", "ipnet", "js-sys", @@ -1883,11 +2197,11 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tokio-rustls", @@ -1902,6 +2216,46 @@ dependencies = [ "winreg", ] +[[package]] +name = "reqwest" +version = "0.12.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.5.1", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 2.2.0", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + [[package]] name = "ring" version = "0.17.8" @@ -1921,7 +2275,7 @@ dependencies = [ name = "rivet-api-ee" version = "0.0.1" dependencies = [ - "reqwest", + "reqwest 0.11.27", "serde", "serde_derive", "serde_json", @@ -1935,13 +2289,17 @@ name = "rivet-cli" version = "2.0.0-rc.4" dependencies = [ "anyhow", + "async-posthog", "base64 0.22.1", "clap", + "ctrlc", "inquire", "kv-str", "rivet-toolchain", + "sentry", "serde", "serde_json", + "sysinfo", "tokio", "url", "uuid", @@ -1955,7 +2313,7 @@ version = "0.1.0" dependencies = [ "anyhow", "dirs", - "reqwest", + "reqwest 0.11.27", "serde_json", "tempfile", "tokio", @@ -1996,10 +2354,10 @@ dependencies = [ "lazy_static", "lz4", "mime_guess", - "nix", + "nix 0.27.1", "pkg-version", "regex", - "reqwest", + "reqwest 0.11.27", "rivet-api-ee", "rivet-deno-embed", "rivet-js-utils-embed", @@ -2016,7 +2374,7 @@ dependencies = [ "uuid", "vergen-git2", "which", - "windows", + "windows 0.48.0", "zip", ] @@ -2069,6 +2427,21 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -2100,6 +2473,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -2116,6 +2498,29 @@ dependencies = [ "untrusted", ] +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.6.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "1.0.23" @@ -2125,6 +2530,126 @@ dependencies = [ "serde", ] +[[package]] +name = "sentry" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5484316556650182f03b43d4c746ce0e3e48074a21e2f51244b648b6542e1066" +dependencies = [ + "httpdate", + "native-tls", + "reqwest 0.12.9", + "sentry-anyhow", + "sentry-backtrace", + "sentry-contexts", + "sentry-core", + "sentry-debug-images", + "sentry-panic", + "sentry-tracing", + "tokio", + "ureq", +] + +[[package]] +name = "sentry-anyhow" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d672bfd1ed4e90978435f3c0704edb71a7a9d86403657839d518cd6aa278aff5" +dependencies = [ + "anyhow", + "sentry-backtrace", + "sentry-core", +] + +[[package]] +name = "sentry-backtrace" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40aa225bb41e2ec9d7c90886834367f560efc1af028f1c5478a6cce6a59c463a" +dependencies = [ + "backtrace", + "once_cell", + "regex", + "sentry-core", +] + +[[package]] +name = "sentry-contexts" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a8dd746da3d16cb8c39751619cefd4fcdbd6df9610f3310fd646b55f6e39910" +dependencies = [ + "hostname", + "libc", + "os_info", + "rustc_version", + "sentry-core", + "uname", +] + +[[package]] +name = "sentry-core" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161283cfe8e99c8f6f236a402b9ccf726b201f365988b5bb637ebca0abbd4a30" +dependencies = [ + "once_cell", + "rand", + "sentry-types", + "serde", + "serde_json", +] + +[[package]] +name = "sentry-debug-images" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc6b25e945fcaa5e97c43faee0267eebda9f18d4b09a251775d8fef1086238a" +dependencies = [ + "findshlibs", + "once_cell", + "sentry-core", +] + +[[package]] +name = "sentry-panic" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc74f229c7186dd971a9491ffcbe7883544aa064d1589bd30b83fb856cd22d63" +dependencies = [ + "sentry-backtrace", + "sentry-core", +] + +[[package]] +name = "sentry-tracing" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3c5faf2103cd01eeda779ea439b68c4ee15adcdb16600836e97feafab362ec" +dependencies = [ + "sentry-backtrace", + "sentry-core", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "sentry-types" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d68cdf6bc41b8ff3ae2a9c4671e97426dcdd154cc1d4b6b72813f285d6b163f" +dependencies = [ + "debugid", + "hex", + "rand", + "serde", + "serde_json", + "thiserror", + "time 0.3.36", + "url", + "uuid", +] + [[package]] name = "serde" version = "1.0.215" @@ -2348,6 +2873,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + [[package]] name = "synstructure" version = "0.13.1" @@ -2359,6 +2893,20 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "sysinfo" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ae3f4f7d64646c46c4cae4e3f01d1c5d255c7406fdd7c7f999a94e488791" +dependencies = [ + "core-foundation-sys", + "libc", + "memchr", + "ntapi", + "rayon", + "windows 0.57.0", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -2523,6 +3071,16 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.24.1" @@ -2569,6 +3127,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "tracing-core", ] [[package]] @@ -2589,6 +3157,15 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "uname" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8" +dependencies = [ + "libc", +] + [[package]] name = "unicase" version = "2.7.0" @@ -2628,6 +3205,19 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "ureq" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" +dependencies = [ + "base64 0.22.1", + "log", + "native-tls", + "once_cell", + "url", +] + [[package]] name = "url" version = "2.5.3" @@ -2668,6 +3258,12 @@ dependencies = [ "serde", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" @@ -2929,6 +3525,26 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core 0.52.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +dependencies = [ + "windows-core 0.57.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -2938,6 +3554,79 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result 0.1.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "windows-interface" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result 0.2.0", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -3209,6 +3898,27 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "zerofrom" version = "0.1.4" diff --git a/packages/cli/Cargo.toml b/packages/cli/Cargo.toml index 49ae6989..2d42b32a 100644 --- a/packages/cli/Cargo.toml +++ b/packages/cli/Cargo.toml @@ -10,6 +10,10 @@ repository = "https://github.com/rivet-gg/cli" name = "rivet" path = "src/main.rs" +[features] +default = ["sentry"] +sentry = [] + [dependencies] clap = { version = "4.5.9", features = ["derive"] } toolchain = { version = "0.1.0", path = "../toolchain", package = "rivet-toolchain" } @@ -23,6 +27,13 @@ base64 = "0.22.1" kv-str = { version = "0.1.0", path = "../kv-str" } inquire = "0.7.5" webbrowser = "1.0.2" +sentry = { version = "0.34.0", features = ["anyhow"] } +sysinfo = "0.32.0" +ctrlc = "3.4.5" + +[dependencies.async-posthog] +git = "https://github.com/rivet-gg/posthog-rs" +rev = "ef4e80e" [build-dependencies] anyhow = "1.0" diff --git a/packages/cli/src/commands/actor/create.rs b/packages/cli/src/commands/actor/create.rs index d819e652..a09d0f7c 100644 --- a/packages/cli/src/commands/actor/create.rs +++ b/packages/cli/src/commands/actor/create.rs @@ -8,7 +8,6 @@ use toolchain::{ }; use uuid::Uuid; - #[derive(ValueEnum, Clone)] enum NetworkMode { Bridge, diff --git a/packages/cli/src/commands/actor/destroy.rs b/packages/cli/src/commands/actor/destroy.rs index c7b96451..9f9a963e 100644 --- a/packages/cli/src/commands/actor/destroy.rs +++ b/packages/cli/src/commands/actor/destroy.rs @@ -1,6 +1,6 @@ use anyhow::*; use clap::Parser; -use toolchain::rivet_api::apis; +use toolchain::{errors, rivet_api::apis}; use uuid::Uuid; #[derive(Parser)] @@ -21,7 +21,8 @@ impl Opts { let env = crate::util::env::get_or_select(&ctx, self.environment.as_ref()).await?; - let actor_id = Uuid::parse_str(&self.id).context("invalid id uuid")?; + let actor_id = + Uuid::parse_str(&self.id).map_err(|_| errors::UserError::new("invalid id uuid"))?; apis::actor_api::actor_destroy( &ctx.openapi_config_cloud, diff --git a/packages/cli/src/commands/actor/logs.rs b/packages/cli/src/commands/actor/logs.rs index c1858319..35c76085 100644 --- a/packages/cli/src/commands/actor/logs.rs +++ b/packages/cli/src/commands/actor/logs.rs @@ -1,5 +1,6 @@ use anyhow::*; use clap::Parser; +use toolchain::errors; use uuid::Uuid; #[derive(Parser)] @@ -26,7 +27,8 @@ impl Opts { let env = crate::util::env::get_or_select(&ctx, self.environment.as_ref()).await?; - let actor_id = Uuid::parse_str(&self.id).context("invalid id uuid")?; + let actor_id = + Uuid::parse_str(&self.id).map_err(|_| errors::UserError::new("invalid id uuid"))?; crate::util::actor::logs::tail( &ctx, diff --git a/packages/cli/src/commands/build/get.rs b/packages/cli/src/commands/build/get.rs index ccd5b594..7f474b84 100644 --- a/packages/cli/src/commands/build/get.rs +++ b/packages/cli/src/commands/build/get.rs @@ -1,6 +1,6 @@ use anyhow::*; use clap::Parser; -use toolchain::rivet_api::apis; +use toolchain::{errors, rivet_api::apis}; use uuid::Uuid; #[derive(Parser)] @@ -18,7 +18,8 @@ impl Opts { let env = crate::util::env::get_or_select(&ctx, self.environment.as_ref()).await?; - let build_id = Uuid::parse_str(&self.id).context("invalid id uuid")?; + let build_id = + Uuid::parse_str(&self.id).map_err(|_| errors::UserError::new("invalid id uuid"))?; let res = apis::actor_builds_api::actor_builds_get( &ctx.openapi_config_cloud, diff --git a/packages/cli/src/commands/login.rs b/packages/cli/src/commands/login.rs index 7f7b13bf..8c897b70 100644 --- a/packages/cli/src/commands/login.rs +++ b/packages/cli/src/commands/login.rs @@ -5,7 +5,6 @@ use toolchain::tasks; use crate::util::{ os, task::{run_task, TaskOutputStyle}, - term, }; /// Login to a project @@ -37,10 +36,6 @@ impl Opts { ) .await?; - // Prompt user to press enter to open browser - println!("Press Enter to login in your browser"); - term::wait_for_enter().await?; - // Open link in browser // // Linux root users often cannot open the browser, so we fallback to printing the URL @@ -52,10 +47,13 @@ impl Opts { ) .is_ok() { - println!("Waiting for browser..."); + println!( + "Waiting for browser...\n\nIf browser did not open, open this URL to login:\n{}", + device_link_output.device_link_url + ); } else { println!( - "Failed to open browser.\n\nVisit this URL:\n{}", + "Open this URL to login:\n{}", device_link_output.device_link_url ); } diff --git a/packages/cli/src/main.rs b/packages/cli/src/main.rs index 6daba6dd..351c437d 100644 --- a/packages/cli/src/main.rs +++ b/packages/cli/src/main.rs @@ -3,8 +3,7 @@ pub mod util; use clap::{builder::styling, Parser}; use std::process::ExitCode; - -use crate::util::errors; +use toolchain::errors; const STYLES: styling::Styles = styling::Styles::styled() .header(styling::AnsiColor::Red.on_default().bold()) @@ -35,22 +34,68 @@ struct Cli { command: commands::SubCommand, } -#[tokio::main] -async fn main() -> ExitCode { +fn main() -> ExitCode { + // We use a sync main for Sentry. Read more: https://docs.sentry.io/platforms/rust/#async-main-function + + // This has a 2 second deadline to flush any remaining events which is sufficient for + // short-lived commands. + let _guard = sentry::init(("https://b329eb15c63e1002611fb3b7a58a1dfa@o4504307129188352.ingest.us.sentry.io/4508361147809792", sentry::ClientOptions { + release: sentry::release_name!(), + ..Default::default() +})); + + // Run main + let exit_code = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() + .block_on(async move { main_async().await }); + + exit_code +} + +async fn main_async() -> ExitCode { let cli = Cli::parse(); - match cli.command.execute().await { + let exit_code = match cli.command.execute().await { Ok(()) => ExitCode::SUCCESS, Err(err) => { - if err.is::() { + // TODO(TOOL-438): Catch 400 API errors as user errors + if err.is::() || err.is::() { // Don't print anything, already handled } else if let Some(err) = err.downcast_ref::() { + // Don't report error since this is a user error eprintln!("{err}"); } else { + // This is an internal error, report error eprintln!("{err}"); - // TODO: Report error + report_error(err).await; } ExitCode::FAILURE } + }; + + // Wait for telemetry to publish + util::telemetry::wait_all().await; + + exit_code +} + +async fn report_error(err: anyhow::Error) { + let event_id = sentry::integrations::anyhow::capture_anyhow(&err); + + // Capture event in PostHog + let capture_res = util::telemetry::capture_event( + "$exception", + Some(|event: &mut async_posthog::Event| { + event.insert_prop("errors", format!("{}", err))?; + event.insert_prop("$sentry_event_id", event_id.to_string())?; + event.insert_prop("$sentry_url", format!("https://sentry.io/organizations/rivet-gaming/issues/?project=4508361147809792&query={event_id}"))?; + Ok(()) + }), + ) + .await; + if let Err(err) = capture_res { + eprintln!("Failed to capture event in PostHog: {:?}", err); } } diff --git a/packages/cli/src/util/deploy.rs b/packages/cli/src/util/deploy.rs index 284b4c7e..48b0941c 100644 --- a/packages/cli/src/util/deploy.rs +++ b/packages/cli/src/util/deploy.rs @@ -1,12 +1,12 @@ use anyhow::*; use std::collections::HashMap; -use toolchain::tasks::{deploy, get_bootstrap_data}; -use uuid::Uuid; - -use crate::util::{ +use toolchain::{ errors, - task::{run_task, TaskOutputStyle}, + tasks::{deploy, get_bootstrap_data}, }; +use uuid::Uuid; + +use crate::util::task::{run_task, TaskOutputStyle}; pub struct DeployOpts<'a> { pub environment: &'a str, diff --git a/packages/cli/src/util/mod.rs b/packages/cli/src/util/mod.rs index 0940e3fd..5f601f16 100644 --- a/packages/cli/src/util/mod.rs +++ b/packages/cli/src/util/mod.rs @@ -1,8 +1,7 @@ pub mod actor; pub mod deploy; pub mod env; -pub mod errors; pub mod global_opts; pub mod os; pub mod task; -pub mod term; +pub mod telemetry; diff --git a/packages/cli/src/util/telemetry.rs b/packages/cli/src/util/telemetry.rs new file mode 100644 index 00000000..106cf91f --- /dev/null +++ b/packages/cli/src/util/telemetry.rs @@ -0,0 +1,137 @@ +use anyhow::*; +use serde_json::json; +use sysinfo::System; +use tokio::{ + sync::{Mutex, OnceCell}, + task::JoinSet, + time::Duration, +}; +use toolchain::{meta, paths}; + +pub static JOIN_SET: OnceCell>> = OnceCell::const_new(); + +/// Get the global join set for telemetry futures. +async fn join_set() -> &'static Mutex> { + JOIN_SET + .get_or_init(|| async { Mutex::new(JoinSet::new()) }) + .await +} + +/// Waits for all telemetry events to finish. +pub async fn wait_all() { + let mut join_set = join_set().await.lock().await; + match tokio::time::timeout(Duration::from_secs(5), async move { + while join_set.join_next().await.is_some() {} + }) + .await + { + Result::Ok(_) => {} + Err(_) => { + println!("Timed out waiting for request to finish") + } + } +} + +// This API key is safe to hardcode. It will not change and is intended to be public. +const POSTHOG_API_KEY: &str = "phc_6kfTNEAVw7rn1LA51cO3D69FefbKupSWFaM7OUgEpEo"; + +fn build_client() -> async_posthog::Client { + async_posthog::client(POSTHOG_API_KEY) +} + +/// Builds a new PostHog event with associated data. +/// +/// This is slightly expensive, so it should not be used frequently. +pub async fn capture_event Result<()>>( + name: &str, + mutate: Option, +) -> Result<()> { + // Check if telemetry disabled + let (toolchain_instance_id, telemetry_disabled, api_endpoint) = + meta::read_project(&paths::data_dir()?, |x| { + let api_endpoint = x.cloud.as_ref().map(|cloud| cloud.api_endpoint.clone()); + (x.toolchain_instance_id, x.telemetry_disabled, api_endpoint) + }) + .await?; + + if telemetry_disabled { + return Ok(()); + } + + // Read project ID. If not signed in or fails to reach server, then ignore. + let (project_id, project_name) = match toolchain::toolchain_ctx::try_load().await { + Result::Ok(Some(ctx)) => ( + Some(ctx.project.game_id), + Some(ctx.project.display_name.clone()), + ), + Result::Ok(None) => (None, None), + Err(_) => { + // Ignore error + (None, None) + } + }; + + let distinct_id = format!("toolchain:{toolchain_instance_id}"); + + let mut event = async_posthog::Event::new(name, &distinct_id); + + // Helps us understand what version of the CLI is being used. + let version = json!({ + "git_sha": env!("VERGEN_GIT_SHA"), + "git_branch": env!("VERGEN_GIT_BRANCH"), + "build_semver": env!("CARGO_PKG_VERSION"), + "build_timestamp": env!("VERGEN_BUILD_TIMESTAMP"), + "build_target": env!("VERGEN_CARGO_TARGET_TRIPLE"), + "build_debug": env!("VERGEN_CARGO_DEBUG"), + "rustc_version": env!("VERGEN_RUSTC_SEMVER"), + }); + + // Add properties + if let Some(project_id) = project_id { + event.insert_prop( + "$groups", + &json!({ + "project_id": project_id, + }), + )?; + } + + event.insert_prop( + "$set", + &json!({ + "name": project_name, + "toolchain_instance_id": toolchain_instance_id, + "api_endpoint": api_endpoint, + "version": version, + "project_id": project_id, + "project_root": paths::project_root()?, + "sys": { + "name": System::name(), + "kernel_version": System::kernel_version(), + "os_version": System::os_version(), + "host_name": System::host_name(), + "cpu_arch": System::cpu_arch(), + }, + }), + )?; + + event.insert_prop("api_endpoint", api_endpoint)?; + event.insert_prop("args", std::env::args().collect::>())?; + + // Customize the event properties + if let Some(mutate) = mutate { + mutate(&mut event)?; + } + + // Capture event + join_set().await.lock().await.spawn(async move { + match build_client().capture(event).await { + Result::Ok(_) => {} + Err(_) => { + // Fail silently + } + } + }); + + Ok(()) +} diff --git a/packages/cli/src/util/term.rs b/packages/cli/src/util/term.rs deleted file mode 100644 index abb4107d..00000000 --- a/packages/cli/src/util/term.rs +++ /dev/null @@ -1,8 +0,0 @@ -use tokio::io::{self, AsyncBufReadExt}; - -pub async fn wait_for_enter() -> io::Result<()> { - let mut stdin = io::BufReader::new(io::stdin()); - let mut line = String::new(); - stdin.read_line(&mut line).await?; - Ok(()) -} diff --git a/packages/cli/src/util/errors.rs b/packages/toolchain/src/errors.rs similarity index 73% rename from packages/cli/src/util/errors.rs rename to packages/toolchain/src/errors.rs index 92f020da..1de818c1 100644 --- a/packages/cli/src/util/errors.rs +++ b/packages/toolchain/src/errors.rs @@ -18,6 +18,25 @@ impl std::fmt::Display for GracefulExit { impl std::error::Error for GracefulExit {} +/// This error type will exit without printing anything. +/// +/// This indicates the program was exited with a Ctrl-C event. +pub struct CtrlC; + +impl std::fmt::Debug for CtrlC { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("CtrlC").finish() + } +} + +impl std::fmt::Display for CtrlC { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "CtrlC occurred") + } +} + +impl std::error::Error for CtrlC {} + /// This error type will exit with a message, but will not report the error to Rivet. /// /// This should be used for errors where the user input is incorrect. diff --git a/packages/toolchain/src/lib.rs b/packages/toolchain/src/lib.rs index 77effbc5..8a1d6d35 100644 --- a/packages/toolchain/src/lib.rs +++ b/packages/toolchain/src/lib.rs @@ -1,5 +1,6 @@ pub mod build; pub mod config; +pub mod errors; pub mod meta; pub mod paths; pub mod project; diff --git a/packages/toolchain/src/meta.rs b/packages/toolchain/src/meta.rs index 5e16e222..43cb6bdd 100644 --- a/packages/toolchain/src/meta.rs +++ b/packages/toolchain/src/meta.rs @@ -5,15 +5,32 @@ use std::{collections::HashMap, path::PathBuf}; use tokio::{fs, sync::Mutex}; use uuid::Uuid; -use crate::paths; +use crate::{errors, paths}; /// Config stored in {data_dir}/meta.json. Used to store persistent data, such as tokens & cache. -#[derive(Default, Serialize, Deserialize)] +#[derive(Serialize, Deserialize)] pub struct Meta { + /// Unique ID for this instance of the toolchain. + /// + /// This ID is unique to each project folder. + pub toolchain_instance_id: Uuid, + /// If logged in to Rivet, this will include relevant information. /// /// If not logged in, will be None. pub cloud: Option, + + pub telemetry_disabled: bool, +} + +impl Meta { + fn new() -> Self { + Self { + toolchain_instance_id: Uuid::new_v4(), + cloud: None, + telemetry_disabled: false, + } + } } impl Meta { @@ -21,14 +38,14 @@ impl Meta { Ok(self .cloud .as_ref() - .context("Not logged in. Please run `rivet login`.")?) + .ok_or_else(|| errors::UserError::new("Not logged in. Please run `rivet login`."))?) } pub fn cloud_mut(&mut self) -> Result<&mut Cloud> { Ok(self .cloud .as_mut() - .context("Not logged in. Please run `rivet login`.")?) + .ok_or_else(|| errors::UserError::new("Not logged in. Please run `rivet login`."))?) } } @@ -96,7 +113,7 @@ pub async fn try_read_project Result, T>( let mut meta = match fs::read_to_string(&meta_path).await { Result::Ok(config) => serde_json::from_str::(&config) .context(format!("deserialize meta ({})", meta_path.display()))?, - Err(err) if err.kind() == std::io::ErrorKind::NotFound => Meta::default(), + Err(err) if err.kind() == std::io::ErrorKind::NotFound => Meta::new(), Err(err) => return Err(err.into()), }; @@ -131,7 +148,7 @@ pub async fn try_mutate_project Result, T>( let mut meta = match fs::read_to_string(&meta_path).await { Result::Ok(config) => serde_json::from_str::(&config) .context(format!("deserialize meta ({})", meta_path.display()))?, - Err(err) if err.kind() == std::io::ErrorKind::NotFound => Meta::default(), + Err(err) if err.kind() == std::io::ErrorKind::NotFound => Meta::new(), Err(err) => return Err(err.into()), }; diff --git a/packages/toolchain/src/toolchain_ctx.rs b/packages/toolchain/src/toolchain_ctx.rs index 513c9394..1ef5fcd7 100644 --- a/packages/toolchain/src/toolchain_ctx.rs +++ b/packages/toolchain/src/toolchain_ctx.rs @@ -2,6 +2,7 @@ use anyhow::*; use pkg_version::{pkg_version_major, pkg_version_minor, pkg_version_patch}; use rivet_api::{apis, models}; use std::{env, sync::Arc}; +use tokio::sync::OnceCell; use crate::{meta, paths}; @@ -30,6 +31,8 @@ pub struct CtxInner { pub openapi_config_cloud: apis::configuration::Configuration, } +static TOOLCHAIN_CTX: OnceCell = OnceCell::const_new(); + pub async fn try_load() -> Result> { let data = meta::read_project(&paths::data_dir()?, |x| { x.cloud @@ -38,8 +41,10 @@ pub async fn try_load() -> Result> { }) .await?; if let Some((api_endpoint, token)) = data { - let ctx = init(api_endpoint, token).await?; - Ok(Some(ctx)) + let ctx = TOOLCHAIN_CTX + .get_or_try_init(|| async { init(api_endpoint, token).await }) + .await?; + Ok(Some(ctx.clone())) } else { Ok(None) } @@ -51,7 +56,10 @@ pub async fn load() -> Result { Ok((cloud.api_endpoint.clone(), cloud.cloud_token.clone())) }) .await?; - init(api_endpoint, token).await + let ctx = TOOLCHAIN_CTX + .get_or_try_init(|| async { init(api_endpoint, token).await }) + .await?; + Ok(ctx.clone()) } pub async fn init(api_endpoint: String, cloud_token: String) -> Result { diff --git a/packages/toolchain/src/util/task/run.rs b/packages/toolchain/src/util/task/run.rs index 46fe1cac..2f1f84cc 100644 --- a/packages/toolchain/src/util/task/run.rs +++ b/packages/toolchain/src/util/task/run.rs @@ -3,6 +3,8 @@ use tokio::sync::{broadcast, mpsc}; use super::{Task, TaskCtxInner, TaskEvent}; +use crate::errors; + /// Run config passed to the task. pub struct RunConfig { pub abort_rx: mpsc::Receiver<()>, @@ -71,7 +73,7 @@ where // Shutdown shutdown_tx.send(())?; - Err(anyhow!("task aborted")) + Err(errors::GracefulExit.into()) }, } }