diff --git a/.dockerignore b/.dockerignore
index c269c7eaf..37c369561 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,4 +1,8 @@
/target
-/config_example
-config.*
-.env
\ No newline at end of file
+readme.md
+typeshare.toml
+LICENSE
+*.code-workspace
+
+*/node_modules
+*/dist
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 48190eb74..6421117ee 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,9 @@
-target
-/frontend/build
-node_modules
-dist
-.env
-.env.development
-
-repos
-config.json
-config.toml
-secrets.json
-secrets.toml
\ No newline at end of file
+target
+/frontend/build
+node_modules
+/lib/ts_client/build
+dist
+.env
+.env.development
+creds.toml
+core.config.toml
\ No newline at end of file
diff --git a/.vscode/resolver.code-snippets b/.vscode/resolver.code-snippets
new file mode 100644
index 000000000..724485fbe
--- /dev/null
+++ b/.vscode/resolver.code-snippets
@@ -0,0 +1,26 @@
+{
+ "resolve": {
+ "scope": "rust",
+ "prefix": "resolve",
+ "body": [
+ "#[async_trait]",
+ "impl Resolve<${1}, User> for State {",
+ "\tasync fn resolve(&self, ${1} { ${0} }: ${1}, _: User) -> anyhow::Result<${2}> {",
+ "\t\ttodo!()",
+ "\t}",
+ "}"
+ ]
+ },
+ "static": {
+ "scope": "rust",
+ "prefix": "static",
+ "body": [
+ "fn ${1}() -> &'static ${2} {",
+ "\tstatic ${3}: OnceLock<${2}> = OnceLock::new();",
+ "\t${3}.get_or_init(|| {",
+ "\t\t${0}",
+ "\t})",
+ "}"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/.vscode/solid.code-snippets b/.vscode/solid.code-snippets
deleted file mode 100644
index 2ded946e2..000000000
--- a/.vscode/solid.code-snippets
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "component": {
- "scope": "typescriptreact,javascriptreact",
- "prefix": "comp",
- "body": [
- "import { Component } from \"solid-js\";",
- "",
- "const ${1:$TM_FILENAME_BASE}: Component<{}> = (p) => {",
- "\treturn (",
- "\t\t
",
- "\t\t\t${0}",
- "\t\t
",
- "\t);",
- "}",
- "",
- "export default ${1:$TM_FILENAME_BASE};"
- ]
- },
- "component-with-css": {
- "scope": "typescriptreact,javascriptreact",
- "prefix": "css-comp",
- "body": [
- "import { Component } from \"solid-js\";",
- "import s from \"./${1:$TM_FILENAME_BASE}.module.scss\";",
- "",
- "const ${2:$TM_FILENAME_BASE}: Component<{}> = (p) => {",
- "\treturn (",
- "\t\t",
- "\t\t\t${0}",
- "\t\t
",
- "\t);",
- "}",
- "",
- "export default ${2:$TM_FILENAME_BASE};"
- ]
- },
- "context": {
- "scope": "typescriptreact,javascriptreact",
- "prefix": "provider",
- "body": [
- "import { ParentComponent, createContext, useContext } from \"solid-js\";",
- "",
- "const value = () => {",
- "\treturn {};",
- "}",
- "",
- "export type Value = ReturnType;",
- "",
- "const context = createContext();",
- "",
- "export const Provider: ParentComponent<{}> = (p) => {",
- "\treturn (",
- "\t\t",
- "\t\t\t{p.children}",
- "\t\t",
- "\t);",
- "}",
- "",
- "export function useValue() {",
- "\treturn useContext(context) as Value;",
- "}"
- ]
- }
-}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 26ac37fc9..758c060b3 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -24,14 +24,14 @@
"label": "start dev",
"dependsOn": [
"run core",
- "yarn: start frontend"
+ "start frontend"
],
"problemMatcher": []
},
{
"type": "shell",
"command": "yarn start",
- "label": "yarn: start frontend",
+ "label": "start frontend",
"options": {
"cwd": "${workspaceFolder}/frontend"
},
@@ -44,7 +44,7 @@
"command": "run",
"label": "run core",
"options": {
- "cwd": "${workspaceFolder}/core"
+ "cwd": "${workspaceFolder}/bin/core"
},
"presentation": {
"group": "start"
@@ -55,24 +55,7 @@
"command": "run",
"label": "run periphery",
"options": {
- "cwd": "${workspaceFolder}/periphery"
- }
- },
- {
- "type": "shell",
- "command": "cargo install --path . && if pgrep periphery; then pkill periphery; fi && periphery --daemon --config-path ~/.monitor/local.periphery.config.toml",
- "label": "run periphery daemon",
- "options": {
- "cwd": "${workspaceFolder}/periphery"
- },
- "problemMatcher": []
- },
- {
- "type": "cargo",
- "command": "run",
- "label": "run cli",
- "options": {
- "cwd": "${workspaceFolder}/cli"
+ "cwd": "${workspaceFolder}/bin/periphery"
}
},
{
@@ -80,14 +63,14 @@
"command": "run",
"label": "run tests",
"options": {
- "cwd": "${workspaceFolder}/tests"
+ "cwd": "${workspaceFolder}/bin/tests"
}
},
{
"type": "cargo",
"command": "publish",
"args": ["--allow-dirty"],
- "label": "publish monitor types",
+ "label": "publish types",
"options": {
"cwd": "${workspaceFolder}/lib/types"
}
@@ -95,68 +78,14 @@
{
"type": "cargo",
"command": "publish",
- "label": "publish monitor client",
+ "label": "publish rs client",
"options": {
- "cwd": "${workspaceFolder}/lib/monitor_client"
+ "cwd": "${workspaceFolder}/lib/rs_client"
}
},
{
"type": "shell",
- "command": "docker compose up -d",
- "label": "docker compose up",
- "options": {
- "cwd": "${workspaceFolder}/tests"
- },
- "problemMatcher": []
- },
- {
- "type": "shell",
- "command": "docker compose down",
- "label": "docker compose down",
- "options": {
- "cwd": "${workspaceFolder}/tests"
- },
- "problemMatcher": []
- },
- {
- "type": "shell",
- "command": "docker compose build",
- "label": "docker compose build",
- "options": {
- "cwd": "${workspaceFolder}/tests"
- },
- "problemMatcher": []
- },
- {
- "type": "shell",
- "command": "docker compose down && docker compose up -d",
- "label": "docker compose restart",
- "options": {
- "cwd": "${workspaceFolder}/tests"
- },
- "problemMatcher": []
- },
- {
- "type": "shell",
- "command": "docker compose build && docker compose down && docker compose up -d",
- "label": "docker compose build and restart",
- "options": {
- "cwd": "${workspaceFolder}/tests"
- },
- "problemMatcher": []
- },
- {
- "type": "shell",
- "command": "docker compose build periphery",
- "label": "docker compose build periphery",
- "options": {
- "cwd": "${workspaceFolder}/tests"
- },
- "problemMatcher": []
- },
- {
- "type": "shell",
- "command": "typeshare ./lib/types --lang=typescript --output-file=./frontend/src/types.ts && typeshare ./core --lang=typescript --output-file=./frontend/src/util/client_types.ts",
+ "command": "node ./client/ts/generate_types.mjs",
"label": "generate typescript types",
"problemMatcher": []
}
diff --git a/Cargo.lock b/Cargo.lock
index 7620883fa..dddd154ae 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 3
+[[package]]
+name = "addr2line"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
+dependencies = [
+ "gimli",
+]
+
[[package]]
name = "adler"
version = "1.0.2"
@@ -10,24 +19,39 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
-version = "0.7.6"
+version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
+checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
dependencies = [
+ "cfg-if",
"getrandom",
"once_cell",
"version_check",
+ "zerocopy",
]
[[package]]
-name = "aho-corasick"
-version = "0.7.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
+name = "alert_logger"
+version = "1.1.0"
dependencies = [
- "memchr",
+ "anyhow",
+ "axum 0.7.5",
+ "dotenv",
+ "envy",
+ "logger",
+ "monitor_client",
+ "serde",
+ "termination_signal",
+ "tokio",
+ "tracing",
]
+[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
[[package]]
name = "android_system_properties"
version = "0.1.5"
@@ -39,59 +63,100 @@ dependencies = [
[[package]]
name = "anstream"
-version = "0.2.6"
+version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f"
+checksum = "4cd2405b3ac1faab2990b74d728624cd9fd115651fcecc7c2d8daf01376275ba"
dependencies = [
"anstyle",
"anstyle-parse",
+ "anstyle-query",
"anstyle-wincon",
- "concolor-override",
- "concolor-query",
- "is-terminal",
+ "colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
-version = "0.3.5"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2"
+checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
[[package]]
name = "anstyle-parse"
-version = "0.1.1"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116"
+checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
dependencies = [
"utf8parse",
]
[[package]]
-name = "anstyle-wincon"
-version = "0.2.0"
+name = "anstyle-query"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa"
+checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
+dependencies = [
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
dependencies = [
"anstyle",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
]
[[package]]
name = "anyhow"
-version = "1.0.69"
+version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
+checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
[[package]]
-name = "async-trait"
-version = "0.1.64"
+name = "async-recursion"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2"
+checksum = "30c5ef0ede93efbf733c1a727f3b6b5a1060bbedd5600183e66f6e4be4af0ec5"
dependencies = [
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.53",
+]
+
+[[package]]
+name = "async-stream"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51"
+dependencies = [
+ "async-stream-impl",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-stream-impl"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.53",
+]
+
+[[package]]
+name = "async-trait"
+version = "0.1.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.53",
]
[[package]]
@@ -102,22 +167,11 @@ checksum = "9de37a9f9ebc2a377f452555a2278e89548c7746c9a47cf3047b30366af7168e"
dependencies = [
"serde",
"serde_derive",
- "strum",
- "strum_macros",
+ "strum 0.24.1",
+ "strum_macros 0.24.3",
"tokio",
]
-[[package]]
-name = "atty"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
-dependencies = [
- "hermit-abi 0.1.19",
- "libc",
- "winapi",
-]
-
[[package]]
name = "autocfg"
version = "1.1.0"
@@ -126,339 +180,372 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "aws-config"
-version = "0.55.2"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc00553f5f3c06ffd4510a9d576f92143618706c45ea6ff81e84ad9be9588abd"
+checksum = "e2a89e0000cde82447155d64eeb71720b933b4396a6fbbebad3f8b4f88ca7b54"
dependencies = [
"aws-credential-types",
- "aws-http",
+ "aws-runtime",
"aws-sdk-sso",
+ "aws-sdk-ssooidc",
"aws-sdk-sts",
"aws-smithy-async",
- "aws-smithy-client",
"aws-smithy-http",
- "aws-smithy-http-tower",
"aws-smithy-json",
+ "aws-smithy-runtime",
+ "aws-smithy-runtime-api",
"aws-smithy-types",
"aws-types",
"bytes",
- "fastrand",
+ "fastrand 2.0.0",
"hex",
- "http",
- "hyper",
- "ring",
- "time 0.3.20",
+ "http 0.2.9",
+ "hyper 0.14.26",
+ "ring 0.17.7",
+ "time 0.3.21",
"tokio",
- "tower",
"tracing",
+ "url",
"zeroize",
]
[[package]]
name = "aws-credential-types"
-version = "0.55.2"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cb57ac6088805821f78d282c0ba8aec809f11cbee10dda19a97b03ab040ccc2"
+checksum = "e16838e6c9e12125face1c1eff1343c75e3ff540de98ff7ebd61874a89bcfeb9"
dependencies = [
"aws-smithy-async",
+ "aws-smithy-runtime-api",
"aws-smithy-types",
- "fastrand",
- "tokio",
- "tracing",
"zeroize",
]
[[package]]
-name = "aws-endpoint"
-version = "0.55.2"
+name = "aws-runtime"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c5f6f84a4f46f95a9bb71d9300b73cd67eb868bc43ae84f66ad34752299f4ac"
-dependencies = [
- "aws-smithy-http",
- "aws-smithy-types",
- "aws-types",
- "http",
- "regex",
- "tracing",
-]
-
-[[package]]
-name = "aws-http"
-version = "0.55.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a754683c322f7dc5167484266489fdebdcd04d26e53c162cad1f3f949f2c5671"
+checksum = "f4963ac9ff2d33a4231b3806c1c69f578f221a9cabb89ad2bde62ce2b442c8a7"
dependencies = [
"aws-credential-types",
+ "aws-sigv4",
+ "aws-smithy-async",
"aws-smithy-http",
+ "aws-smithy-runtime-api",
"aws-smithy-types",
"aws-types",
"bytes",
- "http",
- "http-body",
- "lazy_static",
+ "fastrand 2.0.0",
+ "http 0.2.9",
+ "http-body 0.4.5",
"percent-encoding",
"pin-project-lite",
"tracing",
+ "uuid",
]
[[package]]
name = "aws-sdk-ec2"
-version = "0.27.0"
+version = "1.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ab77050ecd90bf116dcbff6a7b8b2fb294b1399900a97e870c4879fe2010827"
+checksum = "4b58453a3033a5c2e1631abec61b6915c507a726d628a0c2d7b81578d81be1b3"
dependencies = [
"aws-credential-types",
- "aws-endpoint",
- "aws-http",
- "aws-sig-auth",
+ "aws-runtime",
"aws-smithy-async",
- "aws-smithy-client",
"aws-smithy-http",
- "aws-smithy-http-tower",
"aws-smithy-json",
"aws-smithy-query",
+ "aws-smithy-runtime",
+ "aws-smithy-runtime-api",
"aws-smithy-types",
"aws-smithy-xml",
"aws-types",
- "bytes",
- "fastrand",
- "http",
- "regex",
- "tokio-stream",
- "tower",
+ "fastrand 2.0.0",
+ "http 0.2.9",
+ "once_cell",
+ "regex-lite",
"tracing",
]
[[package]]
name = "aws-sdk-sso"
-version = "0.27.0"
+version = "1.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "babfd626348836a31785775e3c08a4c345a5ab4c6e06dfd9167f2bee0e6295d6"
+checksum = "32fcc572fd5c58489ec205ec3e4e5f7d63018898a485cbf922a462af496bc300"
dependencies = [
"aws-credential-types",
- "aws-endpoint",
- "aws-http",
- "aws-sig-auth",
+ "aws-runtime",
"aws-smithy-async",
- "aws-smithy-client",
"aws-smithy-http",
- "aws-smithy-http-tower",
"aws-smithy-json",
+ "aws-smithy-runtime",
+ "aws-smithy-runtime-api",
"aws-smithy-types",
"aws-types",
"bytes",
- "http",
- "regex",
- "tokio-stream",
- "tower",
+ "http 0.2.9",
+ "once_cell",
+ "regex-lite",
+ "tracing",
+]
+
+[[package]]
+name = "aws-sdk-ssooidc"
+version = "1.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b6275fa8684a1192754221173b1f7a7c1260d6b0571cc2b8af09468eb0cffe5"
+dependencies = [
+ "aws-credential-types",
+ "aws-runtime",
+ "aws-smithy-async",
+ "aws-smithy-http",
+ "aws-smithy-json",
+ "aws-smithy-runtime",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "aws-types",
+ "bytes",
+ "http 0.2.9",
+ "once_cell",
+ "regex-lite",
"tracing",
]
[[package]]
name = "aws-sdk-sts"
-version = "0.27.0"
+version = "1.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d0fbe3c2c342bc8dfea4bb43937405a8ec06f99140a0dcb9c7b59e54dfa93a1"
+checksum = "30acd58272fd567e4853c5075d838be1626b59057e0249c9be5a1a7eb13bf70f"
dependencies = [
"aws-credential-types",
- "aws-endpoint",
- "aws-http",
- "aws-sig-auth",
+ "aws-runtime",
"aws-smithy-async",
- "aws-smithy-client",
"aws-smithy-http",
- "aws-smithy-http-tower",
"aws-smithy-json",
"aws-smithy-query",
+ "aws-smithy-runtime",
+ "aws-smithy-runtime-api",
"aws-smithy-types",
"aws-smithy-xml",
"aws-types",
- "bytes",
- "http",
- "regex",
- "tower",
- "tracing",
-]
-
-[[package]]
-name = "aws-sig-auth"
-version = "0.55.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84dc92a63ede3c2cbe43529cb87ffa58763520c96c6a46ca1ced80417afba845"
-dependencies = [
- "aws-credential-types",
- "aws-sigv4",
- "aws-smithy-http",
- "aws-types",
- "http",
+ "http 0.2.9",
+ "once_cell",
+ "regex-lite",
"tracing",
]
[[package]]
name = "aws-sigv4"
-version = "0.55.2"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "392fefab9d6fcbd76d518eb3b1c040b84728ab50f58df0c3c53ada4bea9d327e"
+checksum = "11d6f29688a4be9895c0ba8bef861ad0c0dac5c15e9618b9b7a6c233990fc263"
dependencies = [
+ "aws-credential-types",
"aws-smithy-http",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "bytes",
"form_urlencoded",
"hex",
"hmac",
- "http",
+ "http 0.2.9",
+ "http 1.0.0",
"once_cell",
"percent-encoding",
- "regex",
"sha2",
- "time 0.3.20",
+ "time 0.3.21",
"tracing",
]
[[package]]
name = "aws-smithy-async"
-version = "0.55.2"
+version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae23b9fe7a07d0919000116c4c5c0578303fbce6fc8d32efca1f7759d4c20faf"
+checksum = "62220bc6e97f946ddd51b5f1361f78996e704677afc518a4ff66b7a72ea1378c"
dependencies = [
"futures-util",
"pin-project-lite",
"tokio",
- "tokio-stream",
-]
-
-[[package]]
-name = "aws-smithy-client"
-version = "0.55.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5230d25d244a51339273b8870f0f77874cd4449fb4f8f629b21188ae10cfc0ba"
-dependencies = [
- "aws-smithy-async",
- "aws-smithy-http",
- "aws-smithy-http-tower",
- "aws-smithy-types",
- "bytes",
- "fastrand",
- "http",
- "http-body",
- "hyper",
- "hyper-rustls",
- "lazy_static",
- "pin-project-lite",
- "rustls",
- "tokio",
- "tower",
- "tracing",
]
[[package]]
name = "aws-smithy-http"
-version = "0.55.2"
+version = "0.60.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b60e2133beb9fe6ffe0b70deca57aaeff0a35ad24a9c6fab2fd3b4f45b99fdb5"
+checksum = "3f10fa66956f01540051b0aa7ad54574640f748f9839e843442d99b970d3aff9"
dependencies = [
+ "aws-smithy-runtime-api",
"aws-smithy-types",
"bytes",
"bytes-utils",
"futures-core",
- "http",
- "http-body",
- "hyper",
+ "http 0.2.9",
+ "http-body 0.4.5",
"once_cell",
"percent-encoding",
"pin-project-lite",
"pin-utils",
- "tokio",
- "tokio-util",
- "tracing",
-]
-
-[[package]]
-name = "aws-smithy-http-tower"
-version = "0.55.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a4d94f556c86a0dd916a5d7c39747157ea8cb909ca469703e20fee33e448b67"
-dependencies = [
- "aws-smithy-http",
- "aws-smithy-types",
- "bytes",
- "http",
- "http-body",
- "pin-project-lite",
- "tower",
"tracing",
]
[[package]]
name = "aws-smithy-json"
-version = "0.55.2"
+version = "0.60.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ce3d6e6ebb00b2cce379f079ad5ec508f9bcc3a9510d9b9c1840ed1d6f8af39"
+checksum = "4683df9469ef09468dad3473d129960119a0d3593617542b7d52086c8486f2d6"
dependencies = [
"aws-smithy-types",
]
[[package]]
name = "aws-smithy-query"
-version = "0.55.2"
+version = "0.60.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d58edfca32ef9bfbc1ca394599e17ea329cb52d6a07359827be74235b64b3298"
+checksum = "f2fbd61ceb3fe8a1cb7352e42689cec5335833cd9f94103a61e98f9bb61c64bb"
dependencies = [
"aws-smithy-types",
"urlencoding",
]
[[package]]
-name = "aws-smithy-types"
-version = "0.55.2"
+name = "aws-smithy-runtime"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58db46fc1f4f26be01ebdb821751b4e2482cd43aa2b64a0348fb89762defaffa"
+checksum = "de34bcfa1fb3c82a80e252a753db34a6658e07f23d3a5b3fc96919518fa7a3f5"
+dependencies = [
+ "aws-smithy-async",
+ "aws-smithy-http",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "bytes",
+ "fastrand 2.0.0",
+ "h2 0.3.26",
+ "http 0.2.9",
+ "http-body 0.4.5",
+ "http-body 1.0.0",
+ "hyper 0.14.26",
+ "hyper-rustls",
+ "once_cell",
+ "pin-project-lite",
+ "pin-utils",
+ "rustls",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "aws-smithy-runtime-api"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cc56a5c96ec741de6c5e6bf1ce6948be969d6506dfa9c39cffc284e31e4979b"
+dependencies = [
+ "aws-smithy-async",
+ "aws-smithy-types",
+ "bytes",
+ "http 0.2.9",
+ "http 1.0.0",
+ "pin-project-lite",
+ "tokio",
+ "tracing",
+ "zeroize",
+]
+
+[[package]]
+name = "aws-smithy-types"
+version = "1.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abe14dceea1e70101d38fbf2a99e6a34159477c0fb95e68e05c66bd7ae4c3729"
dependencies = [
"base64-simd",
+ "bytes",
+ "bytes-utils",
+ "futures-core",
+ "http 0.2.9",
+ "http 1.0.0",
+ "http-body 0.4.5",
+ "http-body 1.0.0",
+ "http-body-util",
"itoa",
"num-integer",
+ "pin-project-lite",
+ "pin-utils",
"ryu",
- "time 0.3.20",
+ "serde",
+ "time 0.3.21",
+ "tokio",
+ "tokio-util",
]
[[package]]
name = "aws-smithy-xml"
-version = "0.55.2"
+version = "0.60.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb557fe4995bd9ec87fb244bbb254666a971dc902a783e9da8b7711610e9664c"
+checksum = "872c68cf019c0e4afc5de7753c4f7288ce4b71663212771bf5e4542eb9346ca9"
dependencies = [
"xmlparser",
]
[[package]]
name = "aws-types"
-version = "0.55.2"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de0869598bfe46ec44ffe17e063ed33336e59df90356ca8ff0e8da6f7c1d994b"
+checksum = "5a43b56df2c529fe44cb4d92bd64d0479883fb9608ff62daede4df5405381814"
dependencies = [
"aws-credential-types",
"aws-smithy-async",
- "aws-smithy-client",
- "aws-smithy-http",
+ "aws-smithy-runtime-api",
"aws-smithy-types",
- "http",
+ "http 0.2.9",
"rustc_version 0.4.0",
"tracing",
]
[[package]]
name = "axum"
-version = "0.6.9"
+version = "0.6.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6137c6234afb339e75e764c866e3594900f0211e1315d33779f269bbe2ec6967"
+checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
dependencies = [
"async-trait",
- "axum-core",
- "base64 0.21.0",
- "bitflags",
+ "axum-core 0.3.4",
+ "bitflags 1.3.2",
"bytes",
"futures-util",
- "http",
- "http-body",
- "hyper",
+ "http 0.2.9",
+ "http-body 0.4.5",
+ "hyper 0.14.26",
+ "itoa",
+ "matchit",
+ "memchr",
+ "mime",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustversion",
+ "serde",
+ "sync_wrapper 0.1.2",
+ "tower",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "axum"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf"
+dependencies = [
+ "async-trait",
+ "axum-core 0.4.3",
+ "axum-macros",
+ "base64 0.21.5",
+ "bytes",
+ "futures-util",
+ "http 1.0.0",
+ "http-body 1.0.0",
+ "http-body-util",
+ "hyper 1.2.0",
+ "hyper-util",
"itoa",
"matchit",
"memchr",
@@ -471,26 +558,26 @@ dependencies = [
"serde_path_to_error",
"serde_urlencoded",
"sha1",
- "sync_wrapper",
+ "sync_wrapper 1.0.1",
"tokio",
- "tokio-tungstenite 0.18.0",
+ "tokio-tungstenite",
"tower",
- "tower-http",
"tower-layer",
"tower-service",
+ "tracing",
]
[[package]]
name = "axum-core"
-version = "0.3.2"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cae3e661676ffbacb30f1a824089a8c9150e71017f7e1e38f2aa32009188d34"
+checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c"
dependencies = [
"async-trait",
"bytes",
"futures-util",
- "http",
- "http-body",
+ "http 0.2.9",
+ "http-body 0.4.5",
"mime",
"rustversion",
"tower-layer",
@@ -498,18 +585,74 @@ dependencies = [
]
[[package]]
-name = "axum_oauth2"
-version = "0.1.0"
+name = "axum-core"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3"
dependencies = [
- "anyhow",
- "axum",
- "jwt",
- "rand",
- "reqwest",
+ "async-trait",
+ "bytes",
+ "futures-util",
+ "http 1.0.0",
+ "http-body 1.0.0",
+ "http-body-util",
+ "mime",
+ "pin-project-lite",
+ "rustversion",
+ "sync_wrapper 0.1.2",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "axum-extra"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0be6ea09c9b96cb5076af0de2e383bd2bc0c18f827cf1967bdd353e0b910d733"
+dependencies = [
+ "axum 0.7.5",
+ "axum-core 0.4.3",
+ "bytes",
+ "futures-util",
+ "headers",
+ "http 1.0.0",
+ "http-body 1.0.0",
+ "http-body-util",
+ "mime",
+ "pin-project-lite",
"serde",
- "serde_derive",
- "serde_json",
- "urlencoding",
+ "tower",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "axum-macros"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa"
+dependencies = [
+ "heck 0.4.1",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.53",
+]
+
+[[package]]
+name = "backtrace"
+version = "0.3.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12"
+dependencies = [
+ "addr2line",
+ "cc",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
]
[[package]]
@@ -520,9 +663,15 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
-version = "0.21.0"
+version = "0.21.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
+checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
+
+[[package]]
+name = "base64"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51"
[[package]]
name = "base64-simd"
@@ -536,11 +685,11 @@ dependencies = [
[[package]]
name = "bcrypt"
-version = "0.14.0"
+version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9df288bec72232f78c1ec5fe4e8f1d108aa0265476e93097593c803c8c02062a"
+checksum = "e65938ed058ef47d92cf8b346cc76ef48984572ade631927e9937b5ffc7662c7"
dependencies = [
- "base64 0.21.0",
+ "base64 0.22.0",
"blowfish",
"getrandom",
"subtle",
@@ -553,6 +702,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+[[package]]
+name = "bitflags"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
+
[[package]]
name = "bitvec"
version = "1.0.1"
@@ -567,9 +722,9 @@ dependencies = [
[[package]]
name = "block-buffer"
-version = "0.10.3"
+version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
@@ -586,19 +741,22 @@ dependencies = [
[[package]]
name = "bollard"
-version = "0.14.0"
+version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af254ed2da4936ef73309e9597180558821cb16ae9bba4cb24ce6b612d8d80ed"
+checksum = "0aed08d3adb6ebe0eff737115056652670ae290f177759aac19c30456135f94c"
dependencies = [
- "base64 0.21.0",
+ "base64 0.22.0",
"bollard-stubs",
"bytes",
"futures-core",
"futures-util",
"hex",
- "http",
- "hyper",
- "hyperlocal",
+ "http 1.0.0",
+ "http-body-util",
+ "hyper 1.2.0",
+ "hyper-named-pipe",
+ "hyper-util",
+ "hyperlocal-next",
"log",
"pin-project-lite",
"serde",
@@ -609,46 +767,48 @@ dependencies = [
"thiserror",
"tokio",
"tokio-util",
+ "tower-service",
"url",
"winapi",
]
[[package]]
name = "bollard-stubs"
-version = "1.42.0-rc.7"
+version = "1.44.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "602bda35f33aeb571cef387dcd4042c643a8bf689d8aaac2cc47ea24cb7bc7e0"
+checksum = "709d9aa1c37abb89d40f19f5d0ad6f0d88cb1581264e571c9350fc5bb89cf1c5"
dependencies = [
"serde",
- "serde_with 2.2.0",
+ "serde_repr",
+ "serde_with 3.3.0",
]
[[package]]
name = "bson"
-version = "2.6.1"
+version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9aeb8bae494e49dbc330dd23cf78f6f7accee22f640ce3ab17841badaa4ce232"
+checksum = "88c18b51216e1f74b9d769cead6ace2f82b965b807e3d73330aabe9faec31c84"
dependencies = [
"ahash",
"base64 0.13.1",
"bitvec",
"hex",
- "indexmap",
+ "indexmap 1.9.3",
"js-sys",
- "lazy_static",
+ "once_cell",
"rand",
"serde",
"serde_bytes",
"serde_json",
- "time 0.3.20",
+ "time 0.3.21",
"uuid",
]
[[package]]
name = "bumpalo"
-version = "3.12.0"
+version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
+checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "byteorder"
@@ -674,11 +834,12 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.0.79"
+version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"jobserver",
+ "libc",
]
[[package]]
@@ -689,13 +850,13 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
-version = "0.4.23"
+version = "0.4.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
+checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
dependencies = [
+ "android-tzdata",
"iana-time-zone",
"js-sys",
- "num-integer",
"num-traits",
"serde",
"time 0.1.45",
@@ -705,9 +866,9 @@ dependencies = [
[[package]]
name = "cipher"
-version = "0.4.3"
+version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
@@ -715,81 +876,49 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.2.1"
+version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3"
+checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
dependencies = [
"clap_builder",
"clap_derive",
- "once_cell",
]
[[package]]
name = "clap_builder"
-version = "4.2.1"
+version = "4.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f"
+checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
dependencies = [
"anstream",
"anstyle",
- "bitflags",
"clap_lex",
- "strsim",
+ "strsim 0.11.0",
]
[[package]]
name = "clap_derive"
-version = "4.2.0"
+version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4"
+checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
dependencies = [
- "heck",
+ "heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.12",
+ "syn 2.0.53",
]
[[package]]
name = "clap_lex"
-version = "0.4.1"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
+checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
[[package]]
-name = "codespan-reporting"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
-dependencies = [
- "termcolor",
- "unicode-width",
-]
-
-[[package]]
-name = "colored"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
-dependencies = [
- "atty",
- "lazy_static",
- "winapi",
-]
-
-[[package]]
-name = "concolor-override"
+name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f"
-
-[[package]]
-name = "concolor-query"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf"
-dependencies = [
- "windows-sys 0.45.0",
-]
+checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "convert_case"
@@ -797,43 +926,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
-[[package]]
-name = "core"
-version = "0.3.4"
-dependencies = [
- "anyhow",
- "async_timing_util",
- "aws-config",
- "aws-sdk-ec2",
- "axum",
- "axum_oauth2",
- "bcrypt",
- "db_client",
- "diff-struct",
- "dotenv",
- "envy",
- "futures-util",
- "hex",
- "hmac",
- "jwt",
- "merge_config_files",
- "monitor_helpers",
- "monitor_types 0.3.4",
- "mungos",
- "periphery_client",
- "serde",
- "serde_json",
- "sha2",
- "slack_client_rs",
- "termination_signal",
- "tokio",
- "tokio-tungstenite 0.19.0",
- "tokio-util",
- "tower",
- "tower-http",
- "typeshare",
-]
-
[[package]]
name = "core-foundation"
version = "0.9.3"
@@ -846,15 +938,15 @@ dependencies = [
[[package]]
name = "core-foundation-sys"
-version = "0.8.3"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
+checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
[[package]]
name = "cpufeatures"
-version = "0.2.5"
+version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
+checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58"
dependencies = [
"libc",
]
@@ -870,19 +962,18 @@ dependencies = [
[[package]]
name = "crossbeam-channel"
-version = "0.5.6"
+version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
+checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95"
dependencies = [
- "cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
-version = "0.8.2"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
+checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [
"cfg-if",
"crossbeam-epoch",
@@ -891,9 +982,9 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
-version = "0.9.13"
+version = "0.9.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
+checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
dependencies = [
"autocfg",
"cfg-if",
@@ -904,12 +995,9 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
-version = "0.8.14"
+version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
-dependencies = [
- "cfg-if",
-]
+checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
[[package]]
name = "crypto-common"
@@ -921,50 +1009,6 @@ dependencies = [
"typenum",
]
-[[package]]
-name = "cxx"
-version = "1.0.91"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62"
-dependencies = [
- "cc",
- "cxxbridge-flags",
- "cxxbridge-macro",
- "link-cplusplus",
-]
-
-[[package]]
-name = "cxx-build"
-version = "1.0.91"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690"
-dependencies = [
- "cc",
- "codespan-reporting",
- "once_cell",
- "proc-macro2",
- "quote",
- "scratch",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "cxxbridge-flags"
-version = "1.0.91"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf"
-
-[[package]]
-name = "cxxbridge-macro"
-version = "1.0.91"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
[[package]]
name = "darling"
version = "0.13.4"
@@ -977,12 +1021,12 @@ dependencies = [
[[package]]
name = "darling"
-version = "0.14.3"
+version = "0.20.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8"
+checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391"
dependencies = [
- "darling_core 0.14.3",
- "darling_macro 0.14.3",
+ "darling_core 0.20.8",
+ "darling_macro 0.20.8",
]
[[package]]
@@ -995,22 +1039,22 @@ dependencies = [
"ident_case",
"proc-macro2",
"quote",
- "strsim",
+ "strsim 0.10.0",
"syn 1.0.109",
]
[[package]]
name = "darling_core"
-version = "0.14.3"
+version = "0.20.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb"
+checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
- "strsim",
- "syn 1.0.109",
+ "strsim 0.10.0",
+ "syn 2.0.53",
]
[[package]]
@@ -1026,29 +1070,20 @@ dependencies = [
[[package]]
name = "darling_macro"
-version = "0.14.3"
+version = "0.20.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685"
+checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
dependencies = [
- "darling_core 0.14.3",
+ "darling_core 0.20.8",
"quote",
- "syn 1.0.109",
+ "syn 2.0.53",
]
[[package]]
name = "data-encoding"
-version = "2.3.3"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
-
-[[package]]
-name = "db_client"
-version = "0.3.4"
-dependencies = [
- "anyhow",
- "monitor_types 0.3.4",
- "mungos",
-]
+checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "derivative"
@@ -1063,33 +1098,64 @@ dependencies = [
[[package]]
name = "derive_builder"
-version = "0.12.0"
+version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8"
+checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7"
dependencies = [
"derive_builder_macro",
]
[[package]]
name = "derive_builder_core"
-version = "0.12.0"
+version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f"
+checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d"
dependencies = [
- "darling 0.14.3",
+ "darling 0.20.8",
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.53",
]
[[package]]
name = "derive_builder_macro"
-version = "0.12.0"
+version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e"
+checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b"
dependencies = [
"derive_builder_core",
- "syn 1.0.109",
+ "syn 2.0.53",
+]
+
+[[package]]
+name = "derive_default_builder"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4bbfc9b0318750f07951ba6fdd6c886eaa0c68e1164cd2a7a8a540d21262aab"
+dependencies = [
+ "derive_default_builder_derive",
+]
+
+[[package]]
+name = "derive_default_builder_derive"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e520b61247a9470ec86a98baf2aebae5c6dd0f25f02b1c87cafe45b06c160e7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.53",
+]
+
+[[package]]
+name = "derive_empty_traits"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12c90da6aa09bad94e4411461560183be70bb33bc30efb2ce941492f22ed6850"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.53",
]
[[package]]
@@ -1106,32 +1172,21 @@ dependencies = [
]
[[package]]
-name = "diff-struct"
-version = "0.5.1"
+name = "derive_variants"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a699d33d273c6226fd3e8f310a9c90ca94f72be84f7aed95b22bb676f34fc90"
-dependencies = [
- "diff_derive",
- "num",
- "serde",
-]
-
-[[package]]
-name = "diff_derive"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe165e7ead196bbbf44c7ce11a7a21157b5c002ce46d7098ff9c556784a4912d"
+checksum = "4140db2d06b71f45b6c3ab1a30db4c024a930b5b87c207ff8e8c8bfc2f13e461"
dependencies = [
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.53",
]
[[package]]
name = "digest"
-version = "0.10.6"
+version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
@@ -1165,7 +1220,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73"
dependencies = [
- "heck",
+ "heck 0.4.1",
"proc-macro2",
"quote",
"syn 1.0.109",
@@ -1181,14 +1236,20 @@ dependencies = [
]
[[package]]
-name = "errno"
-version = "0.2.8"
+name = "equivalent"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "errno"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
dependencies = [
"errno-dragonfly",
"libc",
- "winapi",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -1211,10 +1272,16 @@ dependencies = [
]
[[package]]
-name = "flate2"
-version = "1.0.25"
+name = "fastrand"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
+checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
+
+[[package]]
+name = "flate2"
+version = "1.0.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743"
dependencies = [
"crc32fast",
"miniz_oxide",
@@ -1243,9 +1310,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "form_urlencoded"
-version = "1.1.0"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
+checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
dependencies = [
"percent-encoding",
]
@@ -1258,9 +1325,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "futures"
-version = "0.3.26"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84"
+checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
dependencies = [
"futures-channel",
"futures-core",
@@ -1273,9 +1340,9 @@ dependencies = [
[[package]]
name = "futures-channel"
-version = "0.3.28"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
dependencies = [
"futures-core",
"futures-sink",
@@ -1283,15 +1350,15 @@ dependencies = [
[[package]]
name = "futures-core"
-version = "0.3.28"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
[[package]]
name = "futures-executor"
-version = "0.3.26"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e"
+checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
dependencies = [
"futures-core",
"futures-task",
@@ -1300,38 +1367,38 @@ dependencies = [
[[package]]
name = "futures-io"
-version = "0.3.28"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
[[package]]
name = "futures-macro"
-version = "0.3.28"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
+checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.12",
+ "syn 2.0.53",
]
[[package]]
name = "futures-sink"
-version = "0.3.28"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
[[package]]
name = "futures-task"
-version = "0.3.28"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
[[package]]
name = "futures-util"
-version = "0.3.28"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
"futures-channel",
"futures-core",
@@ -1347,9 +1414,9 @@ dependencies = [
[[package]]
name = "generic-array"
-version = "0.14.6"
+version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
@@ -1357,9 +1424,9 @@ dependencies = [
[[package]]
name = "getrandom"
-version = "0.2.8"
+version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
"libc",
@@ -1367,18 +1434,49 @@ dependencies = [
]
[[package]]
-name = "h2"
-version = "0.3.15"
+name = "gimli"
+version = "0.27.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4"
+checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
+
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
+[[package]]
+name = "h2"
+version = "0.3.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
dependencies = [
"bytes",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
- "http",
- "indexmap",
+ "http 0.2.9",
+ "indexmap 2.2.5",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "h2"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51ee2dd2e4f378392eeff5d51618cd9a63166a2513846bbc55f21cfacd9199d4"
+dependencies = [
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http 1.0.0",
+ "indexmap 2.2.5",
"slab",
"tokio",
"tokio-util",
@@ -1392,13 +1490,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
-name = "hdrhistogram"
-version = "7.5.2"
+name = "hashbrown"
+version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f19b9f54f7c7f55e31401bb647626ce0cf0f67b0004982ce815b3ee72a02aa8"
+checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+
+[[package]]
+name = "headers"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9"
dependencies = [
- "byteorder",
- "num-traits",
+ "base64 0.21.5",
+ "bytes",
+ "headers-core",
+ "http 1.0.0",
+ "httpdate",
+ "mime",
+ "sha1",
+]
+
+[[package]]
+name = "headers-core"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
+dependencies = [
+ "http 1.0.0",
]
[[package]]
@@ -1408,13 +1526,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
-name = "hermit-abi"
-version = "0.1.19"
+name = "heck"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
-dependencies = [
- "libc",
-]
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
@@ -1468,6 +1583,17 @@ dependencies = [
"itoa",
]
+[[package]]
+name = "http"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
[[package]]
name = "http-body"
version = "0.4.5"
@@ -1475,15 +1601,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
dependencies = [
"bytes",
- "http",
+ "http 0.2.9",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
+dependencies = [
+ "bytes",
+ "http 1.0.0",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840"
+dependencies = [
+ "bytes",
+ "futures-util",
+ "http 1.0.0",
+ "http-body 1.0.0",
"pin-project-lite",
]
[[package]]
name = "http-range-header"
-version = "0.3.0"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29"
+checksum = "3ce4ef31cda248bbdb6e6820603b82dfcd9e833db65a43e997a0ccec777d11fe"
[[package]]
name = "httparse"
@@ -1499,22 +1648,22 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "hyper"
-version = "0.14.25"
+version = "0.14.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899"
+checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
- "h2",
- "http",
- "http-body",
+ "h2 0.3.26",
+ "http 0.2.9",
+ "http-body 0.4.5",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
- "socket2",
+ "socket2 0.4.9",
"tokio",
"tower-service",
"tracing",
@@ -1522,13 +1671,50 @@ dependencies = [
]
[[package]]
-name = "hyper-rustls"
-version = "0.23.2"
+name = "hyper"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c"
+checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a"
dependencies = [
- "http",
- "hyper",
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "h2 0.4.3",
+ "http 1.0.0",
+ "http-body 1.0.0",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-named-pipe"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278"
+dependencies = [
+ "hex",
+ "hyper 1.2.0",
+ "hyper-util",
+ "pin-project-lite",
+ "tokio",
+ "tower-service",
+ "winapi",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97"
+dependencies = [
+ "futures-util",
+ "http 0.2.9",
+ "hyper 0.14.26",
"log",
"rustls",
"rustls-native-certs",
@@ -1536,6 +1722,18 @@ dependencies = [
"tokio-rustls",
]
+[[package]]
+name = "hyper-timeout"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1"
+dependencies = [
+ "hyper 0.14.26",
+ "pin-project-lite",
+ "tokio",
+ "tokio-io-timeout",
+]
+
[[package]]
name = "hyper-tls"
version = "0.5.0"
@@ -1543,47 +1741,84 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
- "hyper",
+ "hyper 0.14.26",
"native-tls",
"tokio",
"tokio-native-tls",
]
[[package]]
-name = "hyperlocal"
-version = "0.8.0"
+name = "hyper-tls"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fafdf7b2b2de7c9784f76e02c0935e65a8117ec3b768644379983ab333ac98c"
+checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
dependencies = [
- "futures-util",
- "hex",
- "hyper",
- "pin-project",
+ "bytes",
+ "http-body-util",
+ "hyper 1.2.0",
+ "hyper-util",
+ "native-tls",
"tokio",
+ "tokio-native-tls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http 1.0.0",
+ "http-body 1.0.0",
+ "hyper 1.2.0",
+ "pin-project-lite",
+ "socket2 0.5.5",
+ "tokio",
+ "tower",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "hyperlocal-next"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acf569d43fa9848e510358c07b80f4adf34084ddc28c6a4a651ee8474c070dcc"
+dependencies = [
+ "hex",
+ "http-body-util",
+ "hyper 1.2.0",
+ "hyper-util",
+ "pin-project-lite",
+ "tokio",
+ "tower-service",
]
[[package]]
name = "iana-time-zone"
-version = "0.1.53"
+version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
+checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
- "winapi",
+ "windows 0.48.0",
]
[[package]]
name = "iana-time-zone-haiku"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
- "cxx",
- "cxx-build",
+ "cc",
]
[[package]]
@@ -1605,9 +1840,9 @@ dependencies = [
[[package]]
name = "idna"
-version = "0.3.0"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
+checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
dependencies = [
"unicode-bidi",
"unicode-normalization",
@@ -1615,12 +1850,23 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "1.9.2"
+version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
- "hashbrown",
+ "hashbrown 0.12.3",
+ "serde",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.14.3",
"serde",
]
@@ -1644,64 +1890,62 @@ dependencies = [
[[package]]
name = "io-lifetimes"
-version = "1.0.5"
+version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3"
+checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
+ "hermit-abi 0.3.1",
"libc",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
]
[[package]]
name = "ipconfig"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be"
+checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
dependencies = [
- "socket2",
+ "socket2 0.5.5",
"widestring",
- "winapi",
- "winreg",
+ "windows-sys 0.48.0",
+ "winreg 0.50.0",
]
[[package]]
name = "ipnet"
-version = "2.7.1"
+version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146"
+checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
[[package]]
-name = "is-terminal"
-version = "0.4.4"
+name = "itertools"
+version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857"
+checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
- "hermit-abi 0.3.1",
- "io-lifetimes",
- "rustix",
- "windows-sys 0.45.0",
+ "either",
]
[[package]]
name = "itoa"
-version = "1.0.5"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
+checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "jobserver"
-version = "0.1.25"
+version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
+checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
dependencies = [
"libc",
]
[[package]]
name = "js-sys"
-version = "0.3.61"
+version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
+checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
dependencies = [
"wasm-bindgen",
]
@@ -1729,18 +1973,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
-version = "0.2.139"
+version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
-
-[[package]]
-name = "link-cplusplus"
-version = "1.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
-dependencies = [
- "cc",
-]
+checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "linked-hash-map"
@@ -1750,15 +1985,15 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "linux-raw-sys"
-version = "0.1.4"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
+checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "lock_api"
-version = "0.4.9"
+version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
+checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
dependencies = [
"autocfg",
"scopeguard",
@@ -1766,11 +2001,22 @@ dependencies = [
[[package]]
name = "log"
-version = "0.4.17"
+version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+
+[[package]]
+name = "logger"
+version = "1.1.0"
dependencies = [
- "cfg-if",
+ "anyhow",
+ "monitor_client",
+ "opentelemetry",
+ "opentelemetry-otlp",
+ "opentelemetry_sdk",
+ "tracing",
+ "tracing-opentelemetry",
+ "tracing-subscriber",
]
[[package]]
@@ -1817,18 +2063,18 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memoffset"
-version = "0.7.1"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
+checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
dependencies = [
"autocfg",
]
[[package]]
name = "merge_config_files"
-version = "0.1.3"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48ed7c516ae04f732a7651e6bbbbdfd7762170fca6b6d263c14a105c41cab9a5"
+checksum = "268a14a3b7df38fd426624ed6398cc3358ceb0717761c308a095545afd9dda80"
dependencies = [
"serde",
"serde_json",
@@ -1836,11 +2082,29 @@ dependencies = [
"toml",
]
+[[package]]
+name = "migrator"
+version = "1.1.0"
+dependencies = [
+ "anyhow",
+ "chrono",
+ "dotenv",
+ "envy",
+ "logger",
+ "mongo_indexed",
+ "monitor_client",
+ "mungos",
+ "serde",
+ "termination_signal",
+ "tokio",
+ "tracing",
+]
+
[[package]]
name = "mime"
-version = "0.3.16"
+version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mime_guess"
@@ -1854,34 +2118,57 @@ dependencies = [
[[package]]
name = "miniz_oxide"
-version = "0.6.2"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
+checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
]
[[package]]
name = "mio"
-version = "0.8.6"
+version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
+checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
dependencies = [
"libc",
- "log",
"wasi 0.11.0+wasi-snapshot-preview1",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "mongo_indexed"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0cd571ac04a8ac4751e6899f404e5d1370ec79f17609ea5a3caa823619b7513"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "mongo_indexed_derive",
+ "mongodb",
+ "serde",
+]
+
+[[package]]
+name = "mongo_indexed_derive"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da28743409e01e8a63877563786b227285423a0f36c3c16e83f6b8226de9990e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.53",
]
[[package]]
name = "mongodb"
-version = "2.5.0"
+version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebe15399de63ad4294c80069967736cbb87ebe467a8cd0629df9cab88a6fbde6"
+checksum = "46c30763a5c6c52079602be44fa360ca3bfacee55fca73f4734aecd23706a7f2"
dependencies = [
"async-trait",
"base64 0.13.1",
- "bitflags",
+ "bitflags 1.3.2",
"bson",
"chrono",
"derivative",
@@ -1900,16 +2187,16 @@ dependencies = [
"rand",
"rustc_version_runtime",
"rustls",
- "rustls-pemfile",
+ "rustls-pemfile 1.0.2",
"serde",
"serde_bytes",
"serde_with 1.14.0",
"sha-1",
"sha2",
"snap",
- "socket2",
+ "socket2 0.4.9",
"stringprep",
- "strsim",
+ "strsim 0.10.0",
"take_mut",
"thiserror",
"tokio",
@@ -1923,122 +2210,157 @@ dependencies = [
"zstd",
]
-[[package]]
-name = "monitor_cli"
-version = "0.3.4"
-dependencies = [
- "async_timing_util",
- "clap",
- "colored",
- "monitor_types 0.3.4",
- "rand",
- "run_command 0.0.5",
- "serde",
- "serde_derive",
- "strum",
- "strum_macros",
- "toml",
-]
-
[[package]]
name = "monitor_client"
-version = "0.3.4"
+version = "1.1.0"
dependencies = [
"anyhow",
+ "async_timing_util",
+ "bollard",
+ "clap",
+ "derive_builder",
+ "derive_default_builder",
+ "derive_empty_traits",
+ "derive_variants",
"envy",
- "futures-util",
- "monitor_types 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "reqwest",
+ "futures",
+ "mongo_indexed",
+ "mungos",
+ "partial_derive2",
+ "reqwest 0.12.3",
+ "resolver_api",
"serde",
- "serde_derive",
"serde_json",
+ "serror",
+ "strum 0.26.2",
+ "thiserror",
"tokio",
- "tokio-tungstenite 0.19.0",
+ "tokio-tungstenite",
"tokio-util",
+ "tracing",
+ "typeshare",
+ "uuid",
]
[[package]]
-name = "monitor_helpers"
-version = "0.3.4"
+name = "monitor_core"
+version = "1.1.0"
dependencies = [
"anyhow",
- "axum",
- "monitor_types 0.3.4",
+ "async-recursion",
+ "async-trait",
+ "async_timing_util",
+ "aws-config",
+ "aws-sdk-ec2",
+ "axum 0.7.5",
+ "axum-extra",
+ "bcrypt",
+ "dotenv",
+ "envy",
+ "futures",
+ "hex",
+ "hmac",
+ "jwt",
+ "logger",
+ "merge_config_files",
+ "mongo_indexed",
+ "monitor_client",
+ "mungos",
+ "parse_csl",
+ "periphery_client",
"rand",
+ "reqwest 0.12.3",
+ "resolver_api",
+ "serde",
+ "serde_json",
+ "serror",
+ "sha2",
+ "slack_client_rs",
+ "termination_signal",
+ "tokio",
+ "tokio-util",
+ "toml",
+ "tower",
+ "tower-http",
+ "tracing",
+ "typeshare",
+ "urlencoding",
+ "uuid",
]
[[package]]
name = "monitor_periphery"
-version = "0.3.4"
+version = "1.1.0"
dependencies = [
"anyhow",
+ "async-trait",
"async_timing_util",
- "axum",
+ "axum 0.7.5",
+ "axum-extra",
"bollard",
"clap",
"dotenv",
"envy",
- "futures",
+ "logger",
"merge_config_files",
- "monitor_helpers",
- "monitor_types 0.3.4",
+ "monitor_client",
"parse_csl",
- "run_command 0.0.6",
+ "periphery_client",
+ "resolver_api",
+ "run_command",
"serde",
"serde_json",
+ "serror",
"svi",
"sysinfo",
+ "termination_signal",
"tokio",
- "tower",
+ "tracing",
+ "uuid",
]
[[package]]
-name = "monitor_types"
-version = "0.3.4"
+name = "monitor_sync"
+version = "1.1.0"
dependencies = [
"anyhow",
- "bollard",
- "bson",
- "chrono",
- "derive_builder",
- "diff-struct",
+ "clap",
+ "dotenv",
+ "merge_config_files",
+ "monitor_client",
"serde",
- "strum",
- "strum_macros",
- "typeshare",
+ "tokio",
]
[[package]]
-name = "monitor_types"
-version = "0.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24ce7541ee0fad1452ae11d0db73285cfbb9df79ad3e49c0680d0bc27c64db24"
+name = "monrun"
+version = "1.1.0"
dependencies = [
"anyhow",
- "bollard",
- "bson",
- "chrono",
- "derive_builder",
- "diff-struct",
+ "clap",
+ "futures",
+ "monitor_client",
+ "partial_derive2",
"serde",
- "serde_derive",
- "strum",
- "strum_macros",
- "typeshare",
+ "strum 0.26.2",
+ "tokio",
+ "toml",
+ "tracing",
+ "tracing-subscriber",
]
[[package]]
name = "mungos"
-version = "0.3.19"
+version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb7d2b7c11b7b18b1436117633a8ec1d7d037530456c6603d5296499f0e38185"
+checksum = "ecb32eadede40c482d0220c7949fcd5f1620185aa6317a1fc19b3b42ea0615b1"
dependencies = [
"anyhow",
+ "async-trait",
"envy",
"futures",
"mongodb",
"serde",
- "tokio",
]
[[package]]
@@ -2061,45 +2383,21 @@ dependencies = [
[[package]]
name = "ntapi"
-version = "0.4.0"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc51db7b362b205941f71232e56c625156eb9a929f8cf74a428fd5bc094a4afc"
+checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
dependencies = [
"winapi",
]
[[package]]
-name = "num"
-version = "0.4.0"
+name = "nu-ansi-term"
+version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
+checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [
- "num-bigint",
- "num-complex",
- "num-integer",
- "num-iter",
- "num-rational",
- "num-traits",
-]
-
-[[package]]
-name = "num-bigint"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
-dependencies = [
- "autocfg",
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "num-complex"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
-dependencies = [
- "num-traits",
+ "overload",
+ "winapi",
]
[[package]]
@@ -2112,29 +2410,6 @@ dependencies = [
"num-traits",
]
-[[package]]
-name = "num-iter"
-version = "0.1.43"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
-dependencies = [
- "autocfg",
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "num-rational"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
-dependencies = [
- "autocfg",
- "num-bigint",
- "num-integer",
- "num-traits",
-]
-
[[package]]
name = "num-traits"
version = "0.2.15"
@@ -2155,18 +2430,27 @@ dependencies = [
]
[[package]]
-name = "once_cell"
-version = "1.17.1"
+name = "object"
+version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
+checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "openssl"
-version = "0.10.45"
+version = "0.10.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1"
+checksum = "69b3f656a17a6cbc115b5c7a40c616947d213ba182135b014d6051b73ab6f019"
dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
"cfg-if",
"foreign-types",
"libc",
@@ -2177,13 +2461,13 @@ dependencies = [
[[package]]
name = "openssl-macros"
-version = "0.1.0"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.53",
]
[[package]]
@@ -2194,23 +2478,111 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
-version = "0.9.80"
+version = "0.9.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7"
+checksum = "c2ce0f250f34a308dcfdbb351f511359857d4ed2134ba715a4eadd46e1ffd617"
dependencies = [
- "autocfg",
"cc",
"libc",
"pkg-config",
"vcpkg",
]
+[[package]]
+name = "opentelemetry"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "900d57987be3f2aeb70d385fff9b27fb74c5723cc9a52d904d4f9c807a0667bf"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+ "js-sys",
+ "once_cell",
+ "pin-project-lite",
+ "thiserror",
+ "urlencoding",
+]
+
+[[package]]
+name = "opentelemetry-otlp"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a016b8d9495c639af2145ac22387dcb88e44118e45320d9238fbf4e7889abcb"
+dependencies = [
+ "async-trait",
+ "futures-core",
+ "http 0.2.9",
+ "opentelemetry",
+ "opentelemetry-proto",
+ "opentelemetry-semantic-conventions",
+ "opentelemetry_sdk",
+ "prost",
+ "thiserror",
+ "tokio",
+ "tonic",
+]
+
+[[package]]
+name = "opentelemetry-proto"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a8fddc9b68f5b80dae9d6f510b88e02396f006ad48cac349411fbecc80caae4"
+dependencies = [
+ "opentelemetry",
+ "opentelemetry_sdk",
+ "prost",
+ "tonic",
+]
+
+[[package]]
+name = "opentelemetry-semantic-conventions"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9ab5bd6c42fb9349dcf28af2ba9a0667f697f9bdcca045d39f2cec5543e2910"
+
+[[package]]
+name = "opentelemetry_sdk"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e90c7113be649e31e9a0f8b5ee24ed7a16923b322c3c5ab6367469c049d6b7e"
+dependencies = [
+ "async-trait",
+ "crossbeam-channel",
+ "futures-channel",
+ "futures-executor",
+ "futures-util",
+ "glob",
+ "once_cell",
+ "opentelemetry",
+ "ordered-float",
+ "percent-encoding",
+ "rand",
+ "thiserror",
+ "tokio",
+ "tokio-stream",
+]
+
+[[package]]
+name = "ordered-float"
+version = "4.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a76df7075c7d4d01fdcb46c912dd17fba5b60c78ea480b475f2b6ab6f666584e"
+dependencies = [
+ "num-traits",
+]
+
[[package]]
name = "outref"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a"
+[[package]]
+name = "overload"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
+
[[package]]
name = "parking_lot"
version = "0.12.1"
@@ -2223,15 +2595,15 @@ dependencies = [
[[package]]
name = "parking_lot_core"
-version = "0.9.7"
+version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
+checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
- "windows-sys 0.45.0",
+ "windows-targets 0.48.0",
]
[[package]]
@@ -2240,6 +2612,26 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffa94c2e5674923c67d7f3dfce1279507b191e10eb064881b46ed3e1256e5ca6"
+[[package]]
+name = "partial_derive2"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "258bf4a15b30c642aa810f6a33cc8c0dfddd2fa46918ca068fde958882d6b18b"
+dependencies = [
+ "partial_derive2_derive",
+]
+
+[[package]]
+name = "partial_derive2_derive"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e49f7410574cdfb56362c529cb2893a246e147072d5e993c46341f02891f9cd1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.53",
+]
+
[[package]]
name = "pbkdf2"
version = "0.11.0"
@@ -2251,49 +2643,49 @@ dependencies = [
[[package]]
name = "percent-encoding"
-version = "2.2.0"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
+checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
[[package]]
name = "periphery_client"
-version = "0.3.4"
+version = "1.1.0"
dependencies = [
"anyhow",
- "futures-util",
- "monitor_types 0.3.4",
- "reqwest",
+ "monitor_client",
+ "reqwest 0.12.3",
+ "resolver_api",
"serde",
"serde_json",
- "tokio",
- "tokio-tungstenite 0.19.0",
+ "serror",
+ "tracing",
]
[[package]]
name = "pin-project"
-version = "1.0.12"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc"
+checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
-version = "1.0.12"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
+checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07"
dependencies = [
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.53",
]
[[package]]
name = "pin-project-lite"
-version = "0.2.9"
+version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
+checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05"
[[package]]
name = "pin-utils"
@@ -2303,9 +2695,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
-version = "0.3.26"
+version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
+checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "ppv-lite86"
@@ -2315,13 +2707,36 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
-version = "1.0.54"
+version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534"
+checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
dependencies = [
"unicode-ident",
]
+[[package]]
+name = "prost"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922"
+dependencies = [
+ "bytes",
+ "prost-derive",
+]
+
+[[package]]
+name = "prost-derive"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48"
+dependencies = [
+ "anyhow",
+ "itertools",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.53",
+]
+
[[package]]
name = "quick-error"
version = "1.2.3"
@@ -2330,9 +2745,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
-version = "1.0.26"
+version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
+checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
@@ -2375,9 +2790,9 @@ dependencies = [
[[package]]
name = "rayon"
-version = "1.6.1"
+version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7"
+checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
dependencies = [
"either",
"rayon-core",
@@ -2385,58 +2800,45 @@ dependencies = [
[[package]]
name = "rayon-core"
-version = "1.10.2"
+version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b"
+checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
dependencies = [
- "crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
- "num_cpus",
]
[[package]]
name = "redox_syscall"
-version = "0.2.16"
+version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
]
[[package]]
-name = "regex"
-version = "1.7.1"
+name = "regex-lite"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.6.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
+checksum = "30b661b2f27137bdbc16f00eda72866a92bb28af1753ffbd56744fb6e2e9cd8e"
[[package]]
name = "reqwest"
-version = "0.11.14"
+version = "0.11.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9"
+checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
dependencies = [
- "base64 0.21.0",
+ "base64 0.21.5",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
- "h2",
- "http",
- "http-body",
- "hyper",
- "hyper-tls",
+ "h2 0.3.26",
+ "http 0.2.9",
+ "http-body 0.4.5",
+ "hyper 0.14.26",
+ "hyper-tls 0.5.0",
"ipnet",
"js-sys",
"log",
@@ -2445,9 +2847,12 @@ dependencies = [
"once_cell",
"percent-encoding",
"pin-project-lite",
+ "rustls-pemfile 1.0.2",
"serde",
"serde_json",
"serde_urlencoded",
+ "sync_wrapper 0.1.2",
+ "system-configuration",
"tokio",
"tokio-native-tls",
"tower-service",
@@ -2455,7 +2860,49 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
- "winreg",
+ "winreg 0.50.0",
+]
+
+[[package]]
+name = "reqwest"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e6cc1e89e689536eb5aeede61520e874df5a4707df811cd5da4aa5fbb2aae19"
+dependencies = [
+ "base64 0.22.0",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "h2 0.4.3",
+ "http 1.0.0",
+ "http-body 1.0.0",
+ "http-body-util",
+ "hyper 1.2.0",
+ "hyper-tls 0.6.0",
+ "hyper-util",
+ "ipnet",
+ "js-sys",
+ "log",
+ "mime",
+ "native-tls",
+ "once_cell",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustls-pemfile 2.1.2",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper 0.1.2",
+ "system-configuration",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "winreg 0.52.0",
]
[[package]]
@@ -2468,6 +2915,31 @@ dependencies = [
"quick-error",
]
+[[package]]
+name = "resolver_api"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43981e6bc9a85f1072ffd38bcaca5823e3cd7f24bb675fa5e79736a318f1f998"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "resolver_api_derive",
+ "serde",
+ "serde_json",
+ "thiserror",
+]
+
+[[package]]
+name = "resolver_api_derive"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e0af2b29987c0bff183294b58b5b084f16c8f1b77951c7c72b7c70d66cf91ac"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.53",
+]
+
[[package]]
name = "ring"
version = "0.16.20"
@@ -2477,17 +2949,25 @@ dependencies = [
"cc",
"libc",
"once_cell",
- "spin",
- "untrusted",
+ "spin 0.5.2",
+ "untrusted 0.7.1",
"web-sys",
"winapi",
]
[[package]]
-name = "run_command"
-version = "0.0.5"
+name = "ring"
+version = "0.17.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb00d9c9c67906454ba83e62aaa52368814512ac1c5b65b8791bb313a9257b0e"
+checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74"
+dependencies = [
+ "cc",
+ "getrandom",
+ "libc",
+ "spin 0.9.8",
+ "untrusted 0.9.0",
+ "windows-sys 0.48.0",
+]
[[package]]
name = "run_command"
@@ -2498,6 +2978,12 @@ dependencies = [
"tokio",
]
+[[package]]
+name = "rustc-demangle"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+
[[package]]
name = "rustc_version"
version = "0.2.3"
@@ -2513,7 +2999,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
- "semver 1.0.16",
+ "semver 1.0.17",
]
[[package]]
@@ -2528,38 +3014,38 @@ dependencies = [
[[package]]
name = "rustix"
-version = "0.36.8"
+version = "0.37.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644"
+checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
]
[[package]]
name = "rustls"
-version = "0.20.8"
+version = "0.21.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f"
+checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
dependencies = [
"log",
- "ring",
+ "ring 0.17.7",
+ "rustls-webpki",
"sct",
- "webpki",
]
[[package]]
name = "rustls-native-certs"
-version = "0.6.2"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50"
+checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
dependencies = [
"openssl-probe",
- "rustls-pemfile",
+ "rustls-pemfile 1.0.2",
"schannel",
"security-framework",
]
@@ -2570,20 +3056,46 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
dependencies = [
- "base64 0.21.0",
+ "base64 0.21.5",
+]
+
+[[package]]
+name = "rustls-pemfile"
+version = "2.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d"
+dependencies = [
+ "base64 0.22.0",
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247"
+
+[[package]]
+name = "rustls-webpki"
+version = "0.101.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
+dependencies = [
+ "ring 0.17.7",
+ "untrusted 0.9.0",
]
[[package]]
name = "rustversion"
-version = "1.0.11"
+version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70"
+checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
[[package]]
name = "ryu"
-version = "1.0.12"
+version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
+checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
[[package]]
name = "schannel"
@@ -2600,29 +3112,23 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
-[[package]]
-name = "scratch"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2"
-
[[package]]
name = "sct"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
dependencies = [
- "ring",
- "untrusted",
+ "ring 0.16.20",
+ "untrusted 0.7.1",
]
[[package]]
name = "security-framework"
-version = "2.8.2"
+version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254"
+checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8"
dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
"core-foundation",
"core-foundation-sys",
"libc",
@@ -2631,9 +3137,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
-version = "2.8.0"
+version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4"
+checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7"
dependencies = [
"core-foundation-sys",
"libc",
@@ -2650,9 +3156,9 @@ dependencies = [
[[package]]
name = "semver"
-version = "1.0.16"
+version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
+checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
[[package]]
name = "semver-parser"
@@ -2662,9 +3168,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
-version = "1.0.152"
+version = "1.0.198"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
+checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc"
dependencies = [
"serde_derive",
]
@@ -2680,22 +3186,22 @@ dependencies = [
[[package]]
name = "serde_derive"
-version = "1.0.152"
+version = "1.0.198"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
+checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9"
dependencies = [
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.53",
]
[[package]]
name = "serde_json"
-version = "1.0.93"
+version = "1.0.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
+checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
dependencies = [
- "indexmap",
+ "indexmap 2.2.5",
"itoa",
"ryu",
"serde",
@@ -2703,29 +3209,29 @@ dependencies = [
[[package]]
name = "serde_path_to_error"
-version = "0.1.9"
+version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26b04f22b563c91331a10074bda3dd5492e3cc39d56bd557e91c0af42b6c7341"
+checksum = "f7f05c1d5476066defcdfacce1f52fc3cae3af1d3089727100c02ae92e5abbe0"
dependencies = [
"serde",
]
[[package]]
name = "serde_repr"
-version = "0.1.10"
+version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a5ec9fa74a20ebbe5d9ac23dac1fc96ba0ecfe9f50f2843b52e537b10fbcb4e"
+checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab"
dependencies = [
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.53",
]
[[package]]
name = "serde_spanned"
-version = "0.6.1"
+version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4"
+checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
dependencies = [
"serde",
]
@@ -2754,17 +3260,18 @@ dependencies = [
[[package]]
name = "serde_with"
-version = "2.2.0"
+version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30d904179146de381af4c93d3af6ca4984b3152db687dacb9c3c35e86f39809c"
+checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237"
dependencies = [
- "base64 0.13.1",
+ "base64 0.21.5",
"chrono",
"hex",
- "indexmap",
+ "indexmap 1.9.3",
+ "indexmap 2.2.5",
"serde",
"serde_json",
- "time 0.3.20",
+ "time 0.3.21",
]
[[package]]
@@ -2779,6 +3286,19 @@ dependencies = [
"syn 1.0.109",
]
+[[package]]
+name = "serror"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6c430d274ef4964c27e7b338fdfed6d400b18ceac80cba827ddd84055f9eca8"
+dependencies = [
+ "anyhow",
+ "axum 0.7.5",
+ "axum-extra",
+ "serde",
+ "serde_json",
+]
+
[[package]]
name = "sha-1"
version = "0.10.1"
@@ -2803,15 +3323,24 @@ dependencies = [
[[package]]
name = "sha2"
-version = "0.10.6"
+version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
+[[package]]
+name = "sharded-slab"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
+dependencies = [
+ "lazy_static",
+]
+
[[package]]
name = "signal-hook"
version = "0.3.15"
@@ -2854,24 +3383,24 @@ dependencies = [
[[package]]
name = "slack_client_rs"
-version = "0.0.8"
+version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9c9597f2b960b592f97701c89c9ceb2658c8f804f39f876e1ab25379080fe2e"
+checksum = "4c78a07312af77255ee84e41fe32546f97ffc06c4166e753f005888dd12d967f"
dependencies = [
"anyhow",
- "reqwest",
+ "reqwest 0.11.27",
"serde",
"serde_derive",
"serde_json",
- "strum",
- "strum_macros",
+ "strum 0.25.0",
+ "strum_macros 0.25.3",
]
[[package]]
name = "smallvec"
-version = "1.10.0"
+version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "snap"
@@ -2889,12 +3418,28 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "socket2"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
+dependencies = [
+ "libc",
+ "windows-sys 0.48.0",
+]
+
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
+[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+
[[package]]
name = "stringprep"
version = "0.1.2"
@@ -2911,19 +3456,40 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+[[package]]
+name = "strsim"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
+
[[package]]
name = "strum"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
+[[package]]
+name = "strum"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
+
+[[package]]
+name = "strum"
+version = "0.26.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29"
+dependencies = [
+ "strum_macros 0.26.2",
+]
+
[[package]]
name = "strum_macros"
version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
dependencies = [
- "heck",
+ "heck 0.4.1",
"proc-macro2",
"quote",
"rustversion",
@@ -2931,10 +3497,36 @@ dependencies = [
]
[[package]]
-name = "subtle"
-version = "2.4.1"
+name = "strum_macros"
+version = "0.25.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
+checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0"
+dependencies = [
+ "heck 0.4.1",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn 2.0.53",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.26.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946"
+dependencies = [
+ "heck 0.4.1",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn 2.0.53",
+]
+
+[[package]]
+name = "subtle"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "svi"
@@ -2958,9 +3550,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.12"
+version = "2.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927"
+checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
dependencies = [
"proc-macro2",
"quote",
@@ -2974,10 +3566,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
-name = "sysinfo"
-version = "0.29.0"
+name = "sync_wrapper"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02f1dc6930a439cc5d154221b5387d153f8183529b07c19aca24ea31e0a167e1"
+checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
+
+[[package]]
+name = "sysinfo"
+version = "0.30.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87341a165d73787554941cd5ef55ad728011566fe714e987d1b976c15dbc3a83"
dependencies = [
"cfg-if",
"core-foundation-sys",
@@ -2985,7 +3583,28 @@ dependencies = [
"ntapi",
"once_cell",
"rayon",
- "winapi",
+ "windows 0.52.0",
+]
+
+[[package]]
+name = "system-configuration"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "system-configuration-sys",
+]
+
+[[package]]
+name = "system-configuration-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
]
[[package]]
@@ -3002,31 +3621,23 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "tempfile"
-version = "3.4.0"
+version = "3.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95"
+checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6"
dependencies = [
+ "autocfg",
"cfg-if",
- "fastrand",
+ "fastrand 1.9.0",
"redox_syscall",
"rustix",
- "windows-sys 0.42.0",
-]
-
-[[package]]
-name = "termcolor"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
-dependencies = [
- "winapi-util",
+ "windows-sys 0.48.0",
]
[[package]]
name = "termination_signal"
-version = "0.1.2"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c8af403325efec5c1f2ab0f69732a47680c40c5379b088958d053cf946b6bfa"
+checksum = "16e2993a3469a2732b1c07df31a0227f2354500779c175f42af4c21693f1ad8f"
dependencies = [
"anyhow",
"futures",
@@ -3037,37 +3648,50 @@ dependencies = [
[[package]]
name = "tests"
-version = "0.1.0"
+version = "1.1.0"
dependencies = [
"anyhow",
- "async_timing_util",
"dotenv",
"envy",
+ "logger",
"monitor_client",
+ "mungos",
+ "partial_derive2",
+ "rand",
"serde",
- "serde_derive",
"serde_json",
"tokio",
+ "tracing",
]
[[package]]
name = "thiserror"
-version = "1.0.38"
+version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
+checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.38"
+version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
+checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.53",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
+dependencies = [
+ "cfg-if",
+ "once_cell",
]
[[package]]
@@ -3083,9 +3707,9 @@ dependencies = [
[[package]]
name = "time"
-version = "0.3.20"
+version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
+checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc"
dependencies = [
"itoa",
"serde",
@@ -3095,15 +3719,15 @@ dependencies = [
[[package]]
name = "time-core"
-version = "0.1.0"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
+checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
[[package]]
name = "time-macros"
-version = "0.2.8"
+version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36"
+checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b"
dependencies = [
"time-core",
]
@@ -3125,11 +3749,11 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
-version = "1.28.0"
+version = "1.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f"
+checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
dependencies = [
- "autocfg",
+ "backtrace",
"bytes",
"libc",
"mio",
@@ -3137,20 +3761,30 @@ dependencies = [
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
- "socket2",
+ "socket2 0.5.5",
"tokio-macros",
"windows-sys 0.48.0",
]
[[package]]
-name = "tokio-macros"
-version = "2.1.0"
+name = "tokio-io-timeout"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
+checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf"
+dependencies = [
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.12",
+ "syn 2.0.53",
]
[[package]]
@@ -3165,20 +3799,19 @@ dependencies = [
[[package]]
name = "tokio-rustls"
-version = "0.23.4"
+version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
+checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
dependencies = [
"rustls",
"tokio",
- "webpki",
]
[[package]]
name = "tokio-stream"
-version = "0.1.12"
+version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313"
+checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af"
dependencies = [
"futures-core",
"pin-project-lite",
@@ -3187,35 +3820,21 @@ dependencies = [
[[package]]
name = "tokio-tungstenite"
-version = "0.18.0"
+version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd"
+checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38"
dependencies = [
"futures-util",
"log",
"tokio",
- "tungstenite 0.18.0",
-]
-
-[[package]]
-name = "tokio-tungstenite"
-version = "0.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec509ac96e9a0c43427c74f003127d953a265737636129424288d27cb5c4b12c"
-dependencies = [
- "futures-util",
- "log",
- "native-tls",
- "tokio",
- "tokio-native-tls",
- "tungstenite 0.19.0",
+ "tungstenite",
]
[[package]]
name = "tokio-util"
-version = "0.7.7"
+version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2"
+checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
dependencies = [
"bytes",
"futures-core",
@@ -3228,9 +3847,9 @@ dependencies = [
[[package]]
name = "toml"
-version = "0.7.2"
+version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6"
+checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
dependencies = [
"serde",
"serde_spanned",
@@ -3240,26 +3859,53 @@ dependencies = [
[[package]]
name = "toml_datetime"
-version = "0.6.1"
+version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
+checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
-version = "0.19.4"
+version = "0.22.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825"
+checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4"
dependencies = [
- "indexmap",
+ "indexmap 2.2.5",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
+[[package]]
+name = "tonic"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13"
+dependencies = [
+ "async-stream",
+ "async-trait",
+ "axum 0.6.20",
+ "base64 0.21.5",
+ "bytes",
+ "h2 0.3.26",
+ "http 0.2.9",
+ "http-body 0.4.5",
+ "hyper 0.14.26",
+ "hyper-timeout",
+ "percent-encoding",
+ "pin-project",
+ "prost",
+ "tokio",
+ "tokio-stream",
+ "tower",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
[[package]]
name = "tower"
version = "0.4.13"
@@ -3268,8 +3914,7 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
dependencies = [
"futures-core",
"futures-util",
- "hdrhistogram",
- "indexmap",
+ "indexmap 1.9.3",
"pin-project",
"pin-project-lite",
"rand",
@@ -3283,16 +3928,16 @@ dependencies = [
[[package]]
name = "tower-http"
-version = "0.4.0"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d1d42a9b3f3ec46ba828e8d376aec14592ea199f70a06a548587ecd1c4ab658"
+checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
dependencies = [
- "bitflags",
+ "bitflags 2.4.1",
"bytes",
- "futures-core",
"futures-util",
- "http",
- "http-body",
+ "http 1.0.0",
+ "http-body 1.0.0",
+ "http-body-util",
"http-range-header",
"httpdate",
"mime",
@@ -3301,7 +3946,6 @@ dependencies = [
"pin-project-lite",
"tokio",
"tokio-util",
- "tower",
"tower-layer",
"tower-service",
"tracing",
@@ -3321,11 +3965,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
[[package]]
name = "tracing"
-version = "0.1.37"
+version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
+checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
- "cfg-if",
"log",
"pin-project-lite",
"tracing-attributes",
@@ -3334,22 +3977,79 @@ dependencies = [
[[package]]
name = "tracing-attributes"
-version = "0.1.23"
+version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
+checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.53",
]
[[package]]
name = "tracing-core"
-version = "0.1.30"
+version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
+checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
dependencies = [
"once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
+dependencies = [
+ "log",
+ "once_cell",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-opentelemetry"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9be14ba1bbe4ab79e9229f7f89fab8d120b865859f10527f31c033e599d2284"
+dependencies = [
+ "js-sys",
+ "once_cell",
+ "opentelemetry",
+ "opentelemetry_sdk",
+ "smallvec",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+ "tracing-subscriber",
+ "web-time",
+]
+
+[[package]]
+name = "tracing-serde"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1"
+dependencies = [
+ "serde",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
+dependencies = [
+ "nu-ansi-term",
+ "serde",
+ "serde_json",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing-core",
+ "tracing-log",
+ "tracing-serde",
]
[[package]]
@@ -3405,36 +4105,16 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
name = "tungstenite"
-version = "0.18.0"
+version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788"
-dependencies = [
- "base64 0.13.1",
- "byteorder",
- "bytes",
- "http",
- "httparse",
- "log",
- "rand",
- "sha1",
- "thiserror",
- "url",
- "utf-8",
-]
-
-[[package]]
-name = "tungstenite"
-version = "0.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15fba1a6d6bb030745759a9a2a588bfe8490fc8b4751a277db3a0be1c9ebbf67"
+checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1"
dependencies = [
"byteorder",
"bytes",
"data-encoding",
- "http",
+ "http 1.0.0",
"httparse",
"log",
- "native-tls",
"rand",
"sha1",
"thiserror",
@@ -3461,9 +4141,9 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "typeshare"
-version = "1.0.1"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f44d1a2f454cb35fbe05b218c410792697e76bd868f48d3a418f2cd1a7d527d6"
+checksum = "99877a66770b25072a67101e80790fd7fe9ed9eff8c69ffb81e9bf5cbea7733f"
dependencies = [
"chrono",
"serde",
@@ -3473,34 +4153,34 @@ dependencies = [
[[package]]
name = "typeshare-annotation"
-version = "1.0.2"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc670d0e358428857cc3b4bf504c691e572fccaec9542ff09212d3f13d74b7a9"
+checksum = "ecce25dea8aeaadc44909f4c1226d22d84512fccd07d22447ecbad176bc09545"
dependencies = [
"quote",
- "syn 1.0.109",
+ "syn 2.0.53",
]
[[package]]
name = "unicase"
-version = "2.6.0"
+version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
+checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
dependencies = [
"version_check",
]
[[package]]
name = "unicode-bidi"
-version = "0.3.10"
+version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58"
+checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
[[package]]
name = "unicode-ident"
-version = "1.0.6"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
+checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
[[package]]
name = "unicode-normalization"
@@ -3511,12 +4191,6 @@ dependencies = [
"tinyvec",
]
-[[package]]
-name = "unicode-width"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
-
[[package]]
name = "untrusted"
version = "0.7.1"
@@ -3524,21 +4198,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
-name = "url"
-version = "2.3.1"
+name = "untrusted"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
+[[package]]
+name = "update_logger"
+version = "1.1.0"
+dependencies = [
+ "anyhow",
+ "logger",
+ "monitor_client",
+ "termination_signal",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "url"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
dependencies = [
"form_urlencoded",
- "idna 0.3.0",
+ "idna 0.4.0",
"percent-encoding",
]
[[package]]
name = "urlencoding"
-version = "2.1.2"
+version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9"
+checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]]
name = "utf-8"
@@ -3554,14 +4246,21 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "uuid"
-version = "1.3.0"
+version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
+checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
dependencies = [
"getrandom",
+ "rand",
"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"
@@ -3604,9 +4303,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
-version = "0.2.84"
+version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
+checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@@ -3614,24 +4313,24 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.84"
+version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
+checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.53",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.34"
+version = "0.4.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
+checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e"
dependencies = [
"cfg-if",
"js-sys",
@@ -3641,9 +4340,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.84"
+version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
+checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -3651,57 +4350,54 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.84"
+version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
+checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.53",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.84"
+version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
+checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
[[package]]
name = "web-sys"
-version = "0.3.61"
+version = "0.3.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
+checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
-name = "webpki"
-version = "0.22.0"
+name = "web-time"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
dependencies = [
- "ring",
- "untrusted",
+ "js-sys",
+ "wasm-bindgen",
]
[[package]]
name = "webpki-roots"
-version = "0.22.6"
+version = "0.25.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
-dependencies = [
- "webpki",
-]
+checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10"
[[package]]
name = "widestring"
-version = "0.5.1"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983"
+checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
[[package]]
name = "winapi"
@@ -3719,43 +4415,53 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-[[package]]
-name = "winapi-util"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
-dependencies = [
- "winapi",
-]
-
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+[[package]]
+name = "windows"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
+dependencies = [
+ "windows-targets 0.48.0",
+]
+
+[[package]]
+name = "windows"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
+dependencies = [
+ "windows-core",
+ "windows-targets 0.52.0",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+dependencies = [
+ "windows-targets 0.52.0",
+]
+
[[package]]
name = "windows-sys"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
- "windows_aarch64_gnullvm 0.42.1",
- "windows_aarch64_msvc 0.42.1",
- "windows_i686_gnu 0.42.1",
- "windows_i686_msvc 0.42.1",
- "windows_x86_64_gnu 0.42.1",
- "windows_x86_64_gnullvm 0.42.1",
- "windows_x86_64_msvc 0.42.1",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.45.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
-dependencies = [
- "windows-targets 0.42.1",
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
]
[[package]]
@@ -3767,21 +4473,6 @@ dependencies = [
"windows-targets 0.48.0",
]
-[[package]]
-name = "windows-targets"
-version = "0.42.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
-dependencies = [
- "windows_aarch64_gnullvm 0.42.1",
- "windows_aarch64_msvc 0.42.1",
- "windows_i686_gnu 0.42.1",
- "windows_i686_msvc 0.42.1",
- "windows_x86_64_gnu 0.42.1",
- "windows_x86_64_gnullvm 0.42.1",
- "windows_x86_64_msvc 0.42.1",
-]
-
[[package]]
name = "windows-targets"
version = "0.48.0"
@@ -3798,10 +4489,25 @@ dependencies = [
]
[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.42.1"
+name = "windows-targets"
+version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
+checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.0",
+ "windows_aarch64_msvc 0.52.0",
+ "windows_i686_gnu 0.52.0",
+ "windows_i686_msvc 0.52.0",
+ "windows_x86_64_gnu 0.52.0",
+ "windows_x86_64_gnullvm 0.52.0",
+ "windows_x86_64_msvc 0.52.0",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
@@ -3810,10 +4516,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
-name = "windows_aarch64_msvc"
-version = "0.42.1"
+name = "windows_aarch64_gnullvm"
+version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
+checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
@@ -3822,10 +4534,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
-name = "windows_i686_gnu"
-version = "0.42.1"
+name = "windows_aarch64_msvc"
+version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
+checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
@@ -3834,10 +4552,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
-name = "windows_i686_msvc"
-version = "0.42.1"
+name = "windows_i686_gnu"
+version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
+checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
@@ -3846,10 +4570,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
-name = "windows_x86_64_gnu"
-version = "0.42.1"
+name = "windows_i686_msvc"
+version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
+checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
@@ -3858,10 +4588,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.42.1"
+name = "windows_x86_64_gnu"
+version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
+checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
@@ -3870,10 +4606,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
-name = "windows_x86_64_msvc"
-version = "0.42.1"
+name = "windows_x86_64_gnullvm"
+version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
+checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
@@ -3882,21 +4624,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
-name = "winnow"
-version = "0.3.3"
+name = "windows_x86_64_msvc"
+version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "faf09497b8f8b5ac5d3bb4d05c0a99be20f26fd3d5f2db7b0716e946d5103658"
+checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+
+[[package]]
+name = "winnow"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8"
dependencies = [
"memchr",
]
[[package]]
name = "winreg"
-version = "0.10.1"
+version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
+checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
- "winapi",
+ "cfg-if",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "winreg"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
+dependencies = [
+ "cfg-if",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -3915,10 +4674,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd"
[[package]]
-name = "zeroize"
-version = "1.5.7"
+name = "zerocopy"
+version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
+checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.53",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
[[package]]
name = "zstd"
@@ -3941,9 +4720,9 @@ dependencies = [
[[package]]
name = "zstd-sys"
-version = "2.0.7+zstd.1.5.4"
+version = "2.0.8+zstd.1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5"
+checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c"
dependencies = [
"cc",
"libc",
diff --git a/Cargo.toml b/Cargo.toml
index bd8bc329d..52b4b7819 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,14 +1,94 @@
-[workspace]
-
-members = [
- "cli",
- "core",
- "periphery",
- "tests",
- "lib/axum_oauth2",
- "lib/db_client",
- "lib/helpers",
- "lib/periphery_client",
- "lib/types",
- "lib/monitor_client"
-]
\ No newline at end of file
+[workspace]
+resolver = "2"
+members = ["bin/*", "lib/*", "client/core/rs", "client/periphery/rs"]
+
+[workspace.package]
+version = "1.1.0"
+edition = "2021"
+authors = ["mbecker20 "]
+license = "GPL-3.0-or-later"
+
+[workspace.dependencies]
+# LOCAL
+monitor_macros = { path = "lib/macros" }
+monitor_client = { path = "client/core/rs" }
+periphery_client = { path = "client/periphery/rs" }
+logger = { path = "lib/logger" }
+
+# MOGH
+run_command = { version = "0.0.6", features = ["async_tokio"] }
+serror = { version = "0.3.4", features = ["axum"] }
+slack = { version = "0.1.0", package = "slack_client_rs" }
+derive_default_builder = "0.1.8"
+derive_empty_traits = "0.1.0"
+merge_config_files = "0.1.5"
+termination_signal = "0.1.3"
+async_timing_util = "0.1.14"
+partial_derive2 = "0.3.2"
+derive_variants = "0.1.3"
+mongo_indexed = "0.2.2"
+resolver_api = "0.1.9"
+parse_csl = "0.1.0"
+mungos = "0.5.4"
+svi = "0.1.4"
+
+# ASYNC
+tokio = { version = "1.37.0", features = ["full"] }
+reqwest = { version = "0.12.3", features = ["json"] }
+tokio-util = "0.7.10"
+futures = "0.3.30"
+futures-util = "0.3.30"
+async-trait = "0.1.80"
+async-recursion = "1.1.0"
+
+# SERVER
+axum = { version = "0.7.5", features = ["ws", "json"] }
+axum-extra = { version = "0.9.3", features = ["typed-header"] }
+tower = { version = "0.4.13", features = ["timeout"] }
+tower-http = { version = "0.5.2", features = ["fs", "cors"] }
+tokio-tungstenite = "0.21.0"
+
+# SER/DE
+serde = { version = "1.0.198", features = ["derive"] }
+strum = { version = "0.26.2", features = ["derive"] }
+serde_json = "1.0.116"
+toml = "0.8.12"
+
+# ERROR
+anyhow = "1.0.82"
+thiserror = "1.0.58"
+
+# LOGGING
+opentelemetry_sdk = { version = "0.22.1", features = ["rt-tokio"] }
+tracing-subscriber = { version = "0.3.18", features = ["json"] }
+tracing-opentelemetry = "0.23.0"
+opentelemetry-otlp = "0.15.0"
+opentelemetry = "0.22.0"
+tracing = "0.1.40"
+
+# CONFIG
+clap = { version = "4.5.4", features = ["derive"] }
+dotenv = "0.15.0"
+envy = "0.4.2"
+
+# CRYPTO
+uuid = { version = "1.8.0", features = ["v4", "fast-rng", "serde"] }
+urlencoding = "2.1.3"
+rand = "0.8.5"
+jwt = "0.16.0"
+hmac = "0.12.1"
+sha2 = "0.10.8"
+bcrypt = "0.15.1"
+hex = "0.4.3"
+
+# SYSTEM
+bollard = "0.16.1"
+sysinfo = "0.30.11"
+
+# CLOUD
+aws-config = "1.2.0"
+aws-sdk-ec2 = "1.34.0"
+
+# MISC
+derive_builder = "0.20.0"
+typeshare = "1.0.2"
diff --git a/bin/alert_logger/Cargo.toml b/bin/alert_logger/Cargo.toml
new file mode 100644
index 000000000..2b4f68391
--- /dev/null
+++ b/bin/alert_logger/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "alert_logger"
+version.workspace = true
+edition.workspace = true
+authors.workspace = true
+license.workspace = true
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+# local
+monitor_client.workspace = true
+logger.workspace = true
+# mogh
+termination_signal.workspace = true
+# external
+tokio.workspace = true
+tracing.workspace = true
+axum.workspace = true
+anyhow.workspace = true
+serde.workspace = true
+dotenv.workspace = true
+envy.workspace = true
\ No newline at end of file
diff --git a/bin/alert_logger/Dockerfile b/bin/alert_logger/Dockerfile
new file mode 100644
index 000000000..14441ab07
--- /dev/null
+++ b/bin/alert_logger/Dockerfile
@@ -0,0 +1,14 @@
+FROM rust:1.71.1 as builder
+WORKDIR /builder
+
+COPY . .
+
+RUN cargo build -p alert_logger --release
+
+FROM gcr.io/distroless/cc
+
+COPY --from=builder /builder/target/release/alert_logger /
+
+EXPOSE 7000
+
+CMD ["./alert_logger"]
\ No newline at end of file
diff --git a/bin/alert_logger/src/main.rs b/bin/alert_logger/src/main.rs
new file mode 100644
index 000000000..2a70fd71e
--- /dev/null
+++ b/bin/alert_logger/src/main.rs
@@ -0,0 +1,70 @@
+#[macro_use]
+extern crate tracing;
+
+use std::{net::SocketAddr, str::FromStr};
+
+use anyhow::Context;
+use axum::{routing::post, Json, Router};
+use monitor_client::entities::{
+ alert::Alert, server::stats::SeverityLevel,
+};
+use serde::Deserialize;
+use termination_signal::tokio::immediate_term_handle;
+
+#[derive(Deserialize)]
+struct Env {
+ #[serde(default = "default_port")]
+ port: u16,
+}
+
+fn default_port() -> u16 {
+ 7000
+}
+
+async fn app() -> anyhow::Result<()> {
+ dotenv::dotenv().ok();
+ logger::init(&Default::default())?;
+
+ let Env { port } =
+ envy::from_env().context("failed to parse env")?;
+
+ let socket_addr = SocketAddr::from_str(&format!("0.0.0.0:{port}"))
+ .context("invalid socket addr")?;
+
+ info!("v {} | {socket_addr}", env!("CARGO_PKG_VERSION"));
+
+ let app = Router::new().route(
+ "/",
+ post(|Json(alert): Json| async move {
+ if alert.resolved {
+ info!("Alert Resolved!: {alert:?}");
+ return;
+ }
+ match alert.level {
+ SeverityLevel::Ok => info!("{alert:?}"),
+ SeverityLevel::Warning => warn!("{alert:?}"),
+ SeverityLevel::Critical => error!("{alert:?}"),
+ }
+ }),
+ );
+
+ let listener = tokio::net::TcpListener::bind(socket_addr)
+ .await
+ .context("failed to bind tcp listener")?;
+
+ axum::serve(listener, app).await.context("server crashed")
+}
+
+#[tokio::main]
+async fn main() -> anyhow::Result<()> {
+ let term_signal = immediate_term_handle()?;
+
+ let app = tokio::spawn(app());
+
+ tokio::select! {
+ res = app => return res?,
+ _ = term_signal => {},
+ }
+
+ Ok(())
+}
diff --git a/bin/core/Cargo.toml b/bin/core/Cargo.toml
new file mode 100644
index 000000000..57c03cf61
--- /dev/null
+++ b/bin/core/Cargo.toml
@@ -0,0 +1,57 @@
+[package]
+name = "monitor_core"
+version.workspace = true
+edition.workspace = true
+authors.workspace = true
+license.workspace = true
+
+[[bin]]
+name = "core"
+path = "src/main.rs"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+# local
+monitor_client.workspace = true
+periphery_client.workspace = true
+logger.workspace = true
+# mogh
+async_timing_util.workspace = true
+merge_config_files.workspace = true
+parse_csl.workspace = true
+termination_signal.workspace = true
+resolver_api.workspace = true
+mungos.workspace = true
+mongo_indexed.workspace = true
+slack.workspace = true
+serror.workspace = true
+# external
+tokio.workspace = true
+tokio-util.workspace = true
+axum.workspace = true
+axum-extra.workspace = true
+tower.workspace = true
+tower-http.workspace = true
+serde.workspace = true
+serde_json.workspace = true
+toml.workspace = true
+uuid.workspace = true
+anyhow.workspace = true
+tracing.workspace = true
+dotenv.workspace = true
+envy.workspace = true
+reqwest.workspace = true
+urlencoding.workspace = true
+rand.workspace = true
+jwt.workspace = true
+hmac.workspace = true
+sha2.workspace = true
+bcrypt.workspace = true
+hex.workspace = true
+async-trait.workspace = true
+async-recursion.workspace = true
+futures.workspace = true
+aws-config.workspace = true
+aws-sdk-ec2.workspace = true
+typeshare.workspace = true
diff --git a/bin/core/Dockerfile b/bin/core/Dockerfile
new file mode 100644
index 000000000..e91efd3f5
--- /dev/null
+++ b/bin/core/Dockerfile
@@ -0,0 +1,23 @@
+# Build Core
+FROM rust:1.77.2-bullseye as core-builder
+WORKDIR /builder
+COPY . .
+RUN cargo build -p monitor_core --release
+
+# Build Frontend
+FROM node:20.12-alpine as frontend-builder
+WORKDIR /builder
+COPY ./frontend ./frontend
+COPY ./client/core/ts ./client
+RUN cd client && yarn && yarn build && yarn link
+RUN cd frontend && yarn link @monitor/client && yarn && yarn build
+
+# Final Image
+# FROM gcr.io/distroless/cc
+FROM debian:bullseye-slim
+RUN apt update && apt install -y ca-certificates
+COPY ./config_example/core.config.example.toml /config/config.toml
+COPY --from=core-builder /builder/target/release/core /
+COPY --from=frontend-builder /builder/frontend/dist /frontend
+EXPOSE 9000
+CMD ["./core"]
\ No newline at end of file
diff --git a/bin/core/src/api/auth.rs b/bin/core/src/api/auth.rs
new file mode 100644
index 000000000..c691bed12
--- /dev/null
+++ b/bin/core/src/api/auth.rs
@@ -0,0 +1,132 @@
+use std::{sync::OnceLock, time::Instant};
+
+use anyhow::anyhow;
+use async_trait::async_trait;
+use axum::{http::HeaderMap, routing::post, Router};
+use axum_extra::{headers::ContentType, TypedHeader};
+use monitor_client::{api::auth::*, entities::user::User};
+use resolver_api::{derive::Resolver, Resolve, Resolver};
+use serde::{Deserialize, Serialize};
+use serror::Json;
+use typeshare::typeshare;
+use uuid::Uuid;
+
+use crate::{
+ auth::{
+ get_user_id_from_headers,
+ github::{self, client::github_oauth_client},
+ google::{self, client::google_oauth_client},
+ },
+ config::core_config,
+ helpers::query::get_user,
+ state::{jwt_client, State},
+};
+
+#[typeshare]
+#[derive(Serialize, Deserialize, Debug, Clone, Resolver)]
+#[resolver_target(State)]
+#[resolver_args(HeaderMap)]
+#[serde(tag = "type", content = "params")]
+#[allow(clippy::enum_variant_names, clippy::large_enum_variant)]
+pub enum AuthRequest {
+ GetLoginOptions(GetLoginOptions),
+ CreateLocalUser(CreateLocalUser),
+ LoginLocalUser(LoginLocalUser),
+ ExchangeForJwt(ExchangeForJwt),
+ GetUser(GetUser),
+}
+
+pub fn router() -> Router {
+ let mut router = Router::new().route("/", post(handler));
+
+ if github_oauth_client().is_some() {
+ router = router.nest("/github", github::router())
+ }
+
+ if google_oauth_client().is_some() {
+ router = router.nest("/google", google::router())
+ }
+
+ router
+}
+
+#[instrument(name = "AuthHandler", level = "debug", skip(headers))]
+async fn handler(
+ headers: HeaderMap,
+ Json(request): Json,
+) -> serror::Result<(TypedHeader, String)> {
+ let timer = Instant::now();
+ let req_id = Uuid::new_v4();
+ debug!("/auth request {req_id} | METHOD: {}", request.req_type());
+ let res = State.resolve_request(request, headers).await.map_err(
+ |e| match e {
+ resolver_api::Error::Serialization(e) => {
+ anyhow!("{e:?}").context("response serialization error")
+ }
+ resolver_api::Error::Inner(e) => e,
+ },
+ );
+ if let Err(e) = &res {
+ debug!("/auth request {req_id} | error: {e:#}");
+ }
+ let elapsed = timer.elapsed();
+ debug!("/auth request {req_id} | resolve time: {elapsed:?}");
+ Ok((TypedHeader(ContentType::json()), res?))
+}
+
+fn login_options_reponse() -> &'static GetLoginOptionsResponse {
+ static GET_LOGIN_OPTIONS_RESPONSE: OnceLock<
+ GetLoginOptionsResponse,
+ > = OnceLock::new();
+ GET_LOGIN_OPTIONS_RESPONSE.get_or_init(|| {
+ let config = core_config();
+ GetLoginOptionsResponse {
+ local: config.local_auth,
+ github: config.github_oauth.enabled
+ && !config.github_oauth.id.is_empty()
+ && !config.github_oauth.secret.is_empty(),
+ google: config.google_oauth.enabled
+ && !config.google_oauth.id.is_empty()
+ && !config.google_oauth.secret.is_empty(),
+ }
+ })
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "GetLoginOptions", level = "debug", skip(self))]
+ async fn resolve(
+ &self,
+ _: GetLoginOptions,
+ _: HeaderMap,
+ ) -> anyhow::Result {
+ Ok(*login_options_reponse())
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "ExchangeForJwt", level = "debug", skip(self))]
+ async fn resolve(
+ &self,
+ ExchangeForJwt { token }: ExchangeForJwt,
+ _: HeaderMap,
+ ) -> anyhow::Result {
+ let jwt = jwt_client().redeem_exchange_token(&token).await?;
+ let res = ExchangeForJwtResponse { jwt };
+ Ok(res)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "GetUser", level = "debug", skip(self))]
+ async fn resolve(
+ &self,
+ GetUser {}: GetUser,
+ headers: HeaderMap,
+ ) -> anyhow::Result {
+ let user_id = get_user_id_from_headers(&headers).await?;
+ get_user(&user_id).await
+ }
+}
diff --git a/bin/core/src/api/execute/build.rs b/bin/core/src/api/execute/build.rs
new file mode 100644
index 000000000..f018c141b
--- /dev/null
+++ b/bin/core/src/api/execute/build.rs
@@ -0,0 +1,534 @@
+use std::{str::FromStr, time::Duration};
+
+use anyhow::{anyhow, Context};
+use async_trait::async_trait;
+use futures::future::join_all;
+use monitor_client::{
+ api::execute::{
+ CancelBuild, CancelBuildResponse, Deploy, RunBuild,
+ },
+ entities::{
+ all_logs_success,
+ build::Build,
+ builder::{AwsBuilderConfig, Builder, BuilderConfig},
+ deployment::DockerContainerState,
+ monitor_timestamp,
+ permission::PermissionLevel,
+ server::Server,
+ server_template::AwsServerTemplateConfig,
+ update::{Log, Update},
+ user::{auto_redeploy_user, User},
+ Operation,
+ },
+};
+use mungos::{
+ find::find_collect,
+ mongodb::bson::{doc, oid::ObjectId, to_bson},
+};
+use periphery_client::{
+ api::{self, GetVersionResponse},
+ PeripheryClient,
+};
+use resolver_api::Resolve;
+use serror::{serialize_error, serialize_error_pretty};
+use tokio_util::sync::CancellationToken;
+
+use crate::{
+ cloud::{
+ aws::{
+ launch_ec2_instance, terminate_ec2_instance_with_retry,
+ Ec2Instance,
+ },
+ BuildCleanupData,
+ },
+ config::core_config,
+ helpers::{
+ channel::build_cancel_channel,
+ periphery_client,
+ query::get_deployment_state,
+ resource::StateResource,
+ update::{add_update, make_update, update_update},
+ },
+ state::{action_states, db_client, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "RunBuild", skip(self, user))]
+ async fn resolve(
+ &self,
+ RunBuild { build }: RunBuild,
+ user: User,
+ ) -> anyhow::Result {
+ let mut build = Build::get_resource_check_permissions(
+ &build,
+ &user,
+ PermissionLevel::Execute,
+ )
+ .await?;
+
+ // get the action state for the build (or insert default).
+ let action_state =
+ action_states().build.get_or_insert_default(&build.id).await;
+
+ // This will set action state back to default when dropped.
+ // Will also check to ensure build not already busy before updating.
+ let _action_guard =
+ action_state.update(|state| state.building = true)?;
+
+ build.config.version.increment();
+
+ let mut update = make_update(&build, Operation::RunBuild, &user);
+ update.in_progress();
+ update.version = build.config.version.clone();
+
+ let cancel = CancellationToken::new();
+ let cancel_clone = cancel.clone();
+ let mut cancel_recv =
+ build_cancel_channel().receiver.resubscribe();
+ let build_id = build.id.clone();
+
+ tokio::spawn(async move {
+ let poll = async {
+ loop {
+ let (incoming_build_id, mut update) = tokio::select! {
+ _ = cancel_clone.cancelled() => return Ok(()),
+ id = cancel_recv.recv() => id?
+ };
+ if incoming_build_id == build_id {
+ info!("build cancel acknowledged");
+ update.push_simple_log(
+ "cancel acknowledged",
+ "the build cancellation has been queud, it may still take some time",
+ );
+ update.finalize();
+ let id = update.id.clone();
+ if let Err(e) = update_update(update).await {
+ warn!("failed to update Update {id} | {e:#}");
+ }
+ cancel_clone.cancel();
+ return Ok(());
+ }
+ }
+ #[allow(unreachable_code)]
+ anyhow::Ok(())
+ };
+ tokio::select! {
+ _ = cancel_clone.cancelled() => {}
+ _ = poll => {}
+ }
+ });
+
+ update.id = add_update(update.clone()).await?;
+
+ // GET BUILDER PERIPHERY
+
+ let (periphery, cleanup_data) =
+ match get_build_builder(&build, &mut update).await {
+ Ok(builder) => {
+ info!("got builder for build");
+ builder
+ }
+ Err(e) => {
+ warn!("failed to get builder | {e:#}");
+ update.logs.push(Log::error(
+ "get builder",
+ serialize_error_pretty(&e),
+ ));
+ update.finalize();
+ update_update(update.clone()).await?;
+ return Ok(update);
+ }
+ };
+
+ let core_config = core_config();
+
+ // CLONE REPO
+
+ let github_token = core_config
+ .github_accounts
+ .get(&build.config.github_account)
+ .cloned();
+
+ let res = tokio::select! {
+ res = periphery
+ .request(api::git::CloneRepo {
+ args: (&build).into(),
+ github_token,
+ }) => res,
+ _ = cancel.cancelled() => {
+ info!("build cancelled during clone, cleaning up builder");
+ update.push_error_log("build cancelled", String::from("user cancelled build during repo clone"));
+ cleanup_builder_instance(periphery, cleanup_data, &mut update)
+ .await;
+ info!("builder cleaned up");
+ update.finalize();
+ update_update(update.clone()).await?;
+ return Ok(update)
+ },
+ };
+
+ match res {
+ Ok(clone_logs) => {
+ info!("finished repo clone");
+ update.logs.extend(clone_logs);
+ }
+ Err(e) => {
+ warn!("failed build at clone repo | {e:#}");
+ update.push_error_log("clone repo", serialize_error(&e));
+ }
+ }
+
+ update_update(update.clone()).await?;
+
+ if all_logs_success(&update.logs) {
+ let docker_token = core_config
+ .docker_accounts
+ .get(&build.config.docker_account)
+ .cloned();
+
+ let res = tokio::select! {
+ res = periphery
+ .request(api::build::Build {
+ build: build.clone(),
+ docker_token,
+ }) => res.context("failed at call to periphery to build"),
+ _ = cancel.cancelled() => {
+ info!("build cancelled during build, cleaning up builder");
+ update.push_error_log("build cancelled", String::from("user cancelled build during docker build"));
+ cleanup_builder_instance(periphery, cleanup_data, &mut update)
+ .await;
+ update.finalize();
+ update_update(update.clone()).await?;
+ return Ok(update)
+ },
+ };
+
+ match res {
+ Ok(logs) => {
+ info!("finished build");
+ update.logs.extend(logs);
+ }
+ Err(e) => {
+ warn!("error in build | {e:#}");
+ update.push_error_log("build", serialize_error(&e))
+ }
+ };
+ }
+
+ update.finalize();
+
+ if update.success {
+ let _ = db_client()
+ .await
+ .builds
+ .update_one(
+ doc! { "_id": ObjectId::from_str(&build.id)? },
+ doc! {
+ "$set": {
+ "config.version": to_bson(&build.config.version)
+ .context("failed at converting version to bson")?,
+ "info.last_built_at": monitor_timestamp(),
+ }
+ },
+ None,
+ )
+ .await;
+ }
+
+ cancel.cancel();
+
+ cleanup_builder_instance(periphery, cleanup_data, &mut update)
+ .await;
+
+ info!("builder instance cleaned up");
+
+ update_update(update.clone()).await?;
+
+ if update.success {
+ handle_post_build_redeploy(&build.id).await;
+ info!("post build redeploy handled");
+ }
+
+ Ok(update)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "CancelBuild", skip(self, user))]
+ async fn resolve(
+ &self,
+ CancelBuild { build }: CancelBuild,
+ user: User,
+ ) -> anyhow::Result {
+ let build = Build::get_resource_check_permissions(
+ &build,
+ &user,
+ PermissionLevel::Execute,
+ )
+ .await?;
+
+ // check if theres already an open cancel build update
+ if db_client()
+ .await
+ .updates
+ .find_one(
+ doc! {
+ "operation": "CancelBuild",
+ "status": "InProgress",
+ "target.id": &build.id,
+ },
+ None,
+ )
+ .await
+ .context("failed to query updates")?
+ .is_some()
+ {
+ return Err(anyhow!("Build cancel is already in progress"));
+ }
+
+ let mut update =
+ make_update(&build, Operation::CancelBuild, &user);
+
+ update.push_simple_log(
+ "cancel triggered",
+ "the build cancel has been triggered",
+ );
+ update.in_progress();
+
+ update.id =
+ add_update(make_update(&build, Operation::CancelBuild, &user))
+ .await?;
+
+ build_cancel_channel()
+ .sender
+ .lock()
+ .await
+ .send((build.id, update))?;
+
+ Ok(CancelBuildResponse {})
+ }
+}
+
+const BUILDER_POLL_RATE_SECS: u64 = 2;
+const BUILDER_POLL_MAX_TRIES: usize = 30;
+
+#[instrument]
+async fn get_build_builder(
+ build: &Build,
+ update: &mut Update,
+) -> anyhow::Result<(PeripheryClient, BuildCleanupData)> {
+ if build.config.builder_id.is_empty() {
+ return Err(anyhow!("build has not configured a builder"));
+ }
+ let builder =
+ Builder::get_resource(&build.config.builder_id).await?;
+ match builder.config {
+ BuilderConfig::Server(config) => {
+ if config.server_id.is_empty() {
+ return Err(anyhow!("builder has not configured a server"));
+ }
+ let server = Server::get_resource(&config.server_id).await?;
+ let periphery = periphery_client(&server)?;
+ Ok((
+ periphery,
+ BuildCleanupData::Server {
+ repo_name: build.name.clone(),
+ },
+ ))
+ }
+ BuilderConfig::Aws(config) => {
+ get_aws_builder(build, config, update).await
+ }
+ }
+}
+
+#[instrument]
+async fn get_aws_builder(
+ build: &Build,
+ config: AwsBuilderConfig,
+ update: &mut Update,
+) -> anyhow::Result<(PeripheryClient, BuildCleanupData)> {
+ let start_create_ts = monitor_timestamp();
+
+ let instance_name = format!(
+ "BUILDER-{}-v{}",
+ build.name,
+ build.config.version.to_string()
+ );
+ let Ec2Instance { instance_id, ip } = launch_ec2_instance(
+ &instance_name,
+ AwsServerTemplateConfig::from_builder_config(&config),
+ )
+ .await?;
+
+ info!("ec2 instance launched");
+
+ let log = Log {
+ stage: "start build instance".to_string(),
+ success: true,
+ stdout: start_aws_builder_log(&instance_id, &ip, &config),
+ start_ts: start_create_ts,
+ end_ts: monitor_timestamp(),
+ ..Default::default()
+ };
+
+ update.logs.push(log);
+
+ update_update(update.clone()).await?;
+
+ let periphery_address = format!("http://{ip}:{}", config.port);
+ let periphery =
+ PeripheryClient::new(&periphery_address, &core_config().passkey);
+
+ let start_connect_ts = monitor_timestamp();
+ let mut res = Ok(GetVersionResponse {
+ version: String::new(),
+ });
+ for _ in 0..BUILDER_POLL_MAX_TRIES {
+ let version = periphery
+ .request(api::GetVersion {})
+ .await
+ .context("failed to reach periphery client on builder");
+ if let Ok(GetVersionResponse { version }) = &version {
+ let connect_log = Log {
+ stage: "build instance connected".to_string(),
+ success: true,
+ stdout: format!(
+ "established contact with periphery on builder\nperiphery version: v{}",
+ version
+ ),
+ start_ts: start_connect_ts,
+ end_ts: monitor_timestamp(),
+ ..Default::default()
+ };
+ update.logs.push(connect_log);
+ update_update(update.clone()).await?;
+ return Ok((
+ periphery,
+ BuildCleanupData::Aws {
+ instance_id,
+ region: config.region,
+ },
+ ));
+ }
+ res = version;
+ tokio::time::sleep(Duration::from_secs(BUILDER_POLL_RATE_SECS))
+ .await;
+ }
+ tokio::spawn(async move {
+ let _ =
+ terminate_ec2_instance_with_retry(config.region, &instance_id)
+ .await;
+ });
+
+ // Unwrap is safe, only way to get here is after check Ok / early return, so it must be err
+ Err(res.err().unwrap())
+}
+
+#[instrument(skip(periphery))]
+async fn cleanup_builder_instance(
+ periphery: PeripheryClient,
+ cleanup_data: BuildCleanupData,
+ update: &mut Update,
+) {
+ match cleanup_data {
+ BuildCleanupData::Server { repo_name } => {
+ let _ = periphery
+ .request(api::git::DeleteRepo { name: repo_name })
+ .await;
+ }
+ BuildCleanupData::Aws {
+ instance_id,
+ region,
+ } => {
+ let _instance_id = instance_id.clone();
+ tokio::spawn(async move {
+ let _ =
+ terminate_ec2_instance_with_retry(region, &_instance_id)
+ .await;
+ });
+ update.push_simple_log(
+ "terminate instance",
+ format!("termination queued for instance id {instance_id}"),
+ );
+ }
+ }
+}
+
+#[instrument]
+async fn handle_post_build_redeploy(build_id: &str) {
+ let Ok(redeploy_deployments) = find_collect(
+ &db_client().await.deployments,
+ doc! {
+ "config.image.params.build_id": build_id,
+ "config.redeploy_on_build": true
+ },
+ None,
+ )
+ .await
+ else {
+ return;
+ };
+
+ let futures =
+ redeploy_deployments
+ .into_iter()
+ .map(|deployment| async move {
+ let state =
+ get_deployment_state(&deployment).await.unwrap_or_default();
+ if state == DockerContainerState::Running {
+ let res = State
+ .resolve(
+ Deploy {
+ deployment: deployment.id.clone(),
+ stop_signal: None,
+ stop_time: None,
+ },
+ auto_redeploy_user().to_owned(),
+ )
+ .await;
+ Some((deployment.id.clone(), res))
+ } else {
+ None
+ }
+ });
+
+ let redeploy_results = join_all(futures).await;
+
+ let mut redeploys = Vec::::new();
+ let mut redeploy_failures = Vec::::new();
+
+ for res in redeploy_results {
+ if res.is_none() {
+ continue;
+ }
+ let (id, res) = res.unwrap();
+ match res {
+ Ok(_) => redeploys.push(id),
+ Err(e) => redeploy_failures.push(format!("{id}: {e:#?}")),
+ }
+ }
+}
+
+fn start_aws_builder_log(
+ instance_id: &str,
+ ip: &str,
+ config: &AwsBuilderConfig,
+) -> String {
+ let AwsBuilderConfig {
+ ami_id,
+ instance_type,
+ volume_gb,
+ subnet_id,
+ assign_public_ip,
+ security_group_ids,
+ use_public_ip,
+ ..
+ } = config;
+
+ let readable_sec_group_ids = security_group_ids.join(", ");
+
+ format!("instance id: {instance_id}\nip: {ip}\nami id: {ami_id}\ninstance type: {instance_type}\nvolume size: {volume_gb} GB\nsubnet id: {subnet_id}\nsecurity groups: {readable_sec_group_ids}\nassign public ip: {assign_public_ip}\nuse public ip: {use_public_ip}")
+}
diff --git a/bin/core/src/api/execute/deployment.rs b/bin/core/src/api/execute/deployment.rs
new file mode 100644
index 000000000..d911fae6a
--- /dev/null
+++ b/bin/core/src/api/execute/deployment.rs
@@ -0,0 +1,455 @@
+use anyhow::{anyhow, Context};
+use async_trait::async_trait;
+use futures::future::join_all;
+use monitor_client::{
+ api::execute::*,
+ entities::{
+ build::Build,
+ deployment::{Deployment, DeploymentImage},
+ get_image_name, monitor_timestamp,
+ permission::PermissionLevel,
+ server::ServerStatus,
+ update::{Log, ResourceTarget, Update, UpdateStatus},
+ user::User,
+ Operation, Version,
+ },
+};
+use mungos::{find::find_collect, mongodb::bson::doc};
+use periphery_client::api;
+use resolver_api::Resolve;
+use serror::serialize_error_pretty;
+
+use crate::{
+ config::core_config,
+ helpers::{
+ periphery_client,
+ query::get_server_with_status,
+ resource::StateResource,
+ update::{add_update, make_update, update_update},
+ },
+ monitor::update_cache_for_server,
+ state::{action_states, db_client, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "Deploy", skip(self, user))]
+ async fn resolve(
+ &self,
+ Deploy {
+ deployment,
+ stop_signal,
+ stop_time,
+ }: Deploy,
+ user: User,
+ ) -> anyhow::Result {
+ let mut deployment = Deployment::get_resource_check_permissions(
+ &deployment,
+ &user,
+ PermissionLevel::Execute,
+ )
+ .await?;
+
+ // get the action state for the deployment (or insert default).
+ let action_state = action_states()
+ .deployment
+ .get_or_insert_default(&deployment.id)
+ .await;
+
+ // Will check to ensure deployment not already busy before updating, and return Err if so.
+ // The returned guard will set the action state back to default when dropped.
+ let _action_guard =
+ action_state.update(|state| state.deploying = true)?;
+
+ if deployment.config.server_id.is_empty() {
+ return Err(anyhow!("deployment has no server configured"));
+ }
+
+ let (server, status) =
+ get_server_with_status(&deployment.config.server_id).await?;
+ if status != ServerStatus::Ok {
+ return Err(anyhow!(
+ "cannot send action when server is unreachable or disabled"
+ ));
+ }
+
+ let periphery = periphery_client(&server)?;
+
+ let version = match deployment.config.image {
+ DeploymentImage::Build { build_id, version } => {
+ let build = Build::get_resource(&build_id).await?;
+ let image_name = get_image_name(&build);
+ let version = if version.is_none() {
+ build.config.version
+ } else {
+ version
+ };
+ deployment.config.image = DeploymentImage::Image {
+ image: format!("{image_name}:{}", version.to_string()),
+ };
+ if deployment.config.docker_account.is_empty() {
+ deployment.config.docker_account =
+ build.config.docker_account;
+ }
+ version
+ }
+ DeploymentImage::Image { .. } => Version::default(),
+ };
+
+ let mut update =
+ make_update(&deployment, Operation::DeployContainer, &user);
+ update.in_progress();
+ update.version = version;
+
+ update.id = add_update(update.clone()).await?;
+
+ let docker_token = core_config()
+ .docker_accounts
+ .get(&deployment.config.docker_account)
+ .cloned();
+
+ match periphery
+ .request(api::container::Deploy {
+ deployment,
+ stop_signal,
+ stop_time,
+ docker_token,
+ })
+ .await
+ {
+ Ok(log) => update.logs.push(log),
+ Err(e) => {
+ update.push_error_log(
+ "deploy container",
+ serialize_error_pretty(&e),
+ );
+ }
+ };
+
+ update_cache_for_server(&server).await;
+
+ update.finalize();
+ update_update(update.clone()).await?;
+
+ Ok(update)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "StartContainer", skip(self, user))]
+ async fn resolve(
+ &self,
+ StartContainer { deployment }: StartContainer,
+ user: User,
+ ) -> anyhow::Result {
+ let deployment = Deployment::get_resource_check_permissions(
+ &deployment,
+ &user,
+ PermissionLevel::Execute,
+ )
+ .await?;
+
+ // get the action state for the deployment (or insert default).
+ let action_state = action_states()
+ .deployment
+ .get_or_insert_default(&deployment.id)
+ .await;
+
+ // Will check to ensure deployment not already busy before updating, and return Err if so.
+ // The returned guard will set the action state back to default when dropped.
+ let _action_guard =
+ action_state.update(|state| state.starting = true)?;
+
+ if deployment.config.server_id.is_empty() {
+ return Err(anyhow!("deployment has no server configured"));
+ }
+
+ let (server, status) =
+ get_server_with_status(&deployment.config.server_id).await?;
+ if status != ServerStatus::Ok {
+ return Err(anyhow!(
+ "cannot send action when server is unreachable or disabled"
+ ));
+ }
+
+ let periphery = periphery_client(&server)?;
+
+ let start_ts = monitor_timestamp();
+
+ let mut update = Update {
+ target: ResourceTarget::Deployment(deployment.id.clone()),
+ operation: Operation::StartContainer,
+ start_ts,
+ status: UpdateStatus::InProgress,
+ success: true,
+ operator: user.id.clone(),
+ ..Default::default()
+ };
+
+ update.id = add_update(update.clone()).await?;
+
+ let log = match periphery
+ .request(api::container::StartContainer {
+ name: deployment.name.clone(),
+ })
+ .await
+ {
+ Ok(log) => log,
+ Err(e) => {
+ Log::error("start container", serialize_error_pretty(&e))
+ }
+ };
+
+ update.logs.push(log);
+ update.finalize();
+ update_cache_for_server(&server).await;
+ update_update(update.clone()).await?;
+
+ Ok(update)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "StopContainer", skip(self, user))]
+ async fn resolve(
+ &self,
+ StopContainer {
+ deployment,
+ signal,
+ time,
+ }: StopContainer,
+ user: User,
+ ) -> anyhow::Result {
+ let deployment = Deployment::get_resource_check_permissions(
+ &deployment,
+ &user,
+ PermissionLevel::Execute,
+ )
+ .await?;
+
+ // get the action state for the deployment (or insert default).
+ let action_state = action_states()
+ .deployment
+ .get_or_insert_default(&deployment.id)
+ .await;
+
+ // Will check to ensure deployment not already busy before updating, and return Err if so.
+ // The returned guard will set the action state back to default when dropped.
+ let _action_guard =
+ action_state.update(|state| state.stopping = true)?;
+
+ if deployment.config.server_id.is_empty() {
+ return Err(anyhow!("deployment has no server configured"));
+ }
+
+ let (server, status) =
+ get_server_with_status(&deployment.config.server_id).await?;
+ if status != ServerStatus::Ok {
+ return Err(anyhow!(
+ "cannot send action when server is unreachable or disabled"
+ ));
+ }
+
+ let periphery = periphery_client(&server)?;
+
+ let mut update =
+ make_update(&deployment, Operation::StopContainer, &user);
+
+ update.id = add_update(update.clone()).await?;
+
+ let log = match periphery
+ .request(api::container::StopContainer {
+ name: deployment.name.clone(),
+ signal: signal
+ .unwrap_or(deployment.config.termination_signal)
+ .into(),
+ time: time
+ .unwrap_or(deployment.config.termination_timeout)
+ .into(),
+ })
+ .await
+ {
+ Ok(log) => log,
+ Err(e) => {
+ Log::error("stop container", serialize_error_pretty(&e))
+ }
+ };
+
+ update.logs.push(log);
+ update.finalize();
+ update_cache_for_server(&server).await;
+ update_update(update.clone()).await?;
+
+ Ok(update)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "StopAllContainers", skip(self, user))]
+ async fn resolve(
+ &self,
+ StopAllContainers { server }: StopAllContainers,
+ user: User,
+ ) -> anyhow::Result {
+ let (server, status) = get_server_with_status(&server).await?;
+ if status != ServerStatus::Ok {
+ return Err(anyhow!(
+ "cannot send action when server is unreachable or disabled"
+ ));
+ }
+
+ // get the action state for the server (or insert default).
+ let action_state = action_states()
+ .server
+ .get_or_insert_default(&server.id)
+ .await;
+
+ // Will check to ensure server not already busy before updating, and return Err if so.
+ // The returned guard will set the action state back to default when dropped.
+ let _action_guard = action_state
+ .update(|state| state.stopping_containers = true)?;
+
+ let deployments = find_collect(
+ &db_client().await.deployments,
+ doc! {
+ "config.server_id": &server.id
+ },
+ None,
+ )
+ .await
+ .context("failed to find deployments on server")?;
+
+ let mut update =
+ make_update(&server, Operation::StopAllContainers, &user);
+ update.in_progress();
+ update.id = add_update(update.clone()).await?;
+
+ let futures = deployments.iter().map(|deployment| async {
+ (
+ self
+ .resolve(
+ StopContainer {
+ deployment: deployment.id.clone(),
+ signal: None,
+ time: None,
+ },
+ user.clone(),
+ )
+ .await,
+ deployment.name.clone(),
+ deployment.id.clone(),
+ )
+ });
+ let results = join_all(futures).await;
+ let deployment_names = deployments
+ .iter()
+ .map(|d| format!("{} ({})", d.name, d.id))
+ .collect::>()
+ .join("\n");
+ update.push_simple_log("stopping containers", deployment_names);
+ for (res, name, id) in results {
+ if let Err(e) = res {
+ update.push_error_log(
+ "stop container failure",
+ format!(
+ "failed to stop container {name} ({id})\n\n{}",
+ serialize_error_pretty(&e)
+ ),
+ );
+ }
+ }
+
+ update.finalize();
+ update_update(update.clone()).await?;
+
+ Ok(update)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "RemoveContainer", skip(self, user))]
+ async fn resolve(
+ &self,
+ RemoveContainer {
+ deployment,
+ signal,
+ time,
+ }: RemoveContainer,
+ user: User,
+ ) -> anyhow::Result {
+ let deployment = Deployment::get_resource_check_permissions(
+ &deployment,
+ &user,
+ PermissionLevel::Execute,
+ )
+ .await?;
+
+ // get the action state for the deployment (or insert default).
+ let action_state = action_states()
+ .deployment
+ .get_or_insert_default(&deployment.id)
+ .await;
+
+ // Will check to ensure deployment not already busy before updating, and return Err if so.
+ // The returned guard will set the action state back to default when dropped.
+ let _action_guard =
+ action_state.update(|state| state.removing = true)?;
+
+ if deployment.config.server_id.is_empty() {
+ return Err(anyhow!("deployment has no server configured"));
+ }
+
+ let (server, status) =
+ get_server_with_status(&deployment.config.server_id).await?;
+ if status != ServerStatus::Ok {
+ return Err(anyhow!(
+ "cannot send action when server is unreachable or disabled"
+ ));
+ }
+
+ let periphery = periphery_client(&server)?;
+
+ let start_ts = monitor_timestamp();
+
+ let mut update = Update {
+ target: ResourceTarget::Deployment(deployment.id.clone()),
+ operation: Operation::RemoveContainer,
+ start_ts,
+ status: UpdateStatus::InProgress,
+ success: true,
+ operator: user.id.clone(),
+ ..Default::default()
+ };
+
+ update.id = add_update(update.clone()).await?;
+
+ let log = match periphery
+ .request(api::container::RemoveContainer {
+ name: deployment.name.clone(),
+ signal: signal
+ .unwrap_or(deployment.config.termination_signal)
+ .into(),
+ time: time
+ .unwrap_or(deployment.config.termination_timeout)
+ .into(),
+ })
+ .await
+ {
+ Ok(log) => log,
+ Err(e) => {
+ Log::error("stop container", serialize_error_pretty(&e))
+ }
+ };
+
+ update.logs.push(log);
+ update.finalize();
+ update_cache_for_server(&server).await;
+ update_update(update.clone()).await?;
+
+ Ok(update)
+ }
+}
diff --git a/bin/core/src/api/execute/mod.rs b/bin/core/src/api/execute/mod.rs
new file mode 100644
index 000000000..9cdefadcf
--- /dev/null
+++ b/bin/core/src/api/execute/mod.rs
@@ -0,0 +1,109 @@
+use std::time::Instant;
+
+use anyhow::{anyhow, Context};
+use axum::{middleware, routing::post, Extension, Router};
+use axum_extra::{headers::ContentType, TypedHeader};
+use monitor_client::{api::execute::*, entities::user::User};
+use resolver_api::{derive::Resolver, Resolve, Resolver};
+use serde::{Deserialize, Serialize};
+use serror::Json;
+use typeshare::typeshare;
+use uuid::Uuid;
+
+use crate::{auth::auth_request, state::State};
+
+mod build;
+mod deployment;
+mod procedure;
+mod repo;
+mod server;
+mod server_template;
+
+#[typeshare]
+#[derive(Serialize, Deserialize, Debug, Clone, Resolver)]
+#[resolver_target(State)]
+#[resolver_args(User)]
+#[serde(tag = "type", content = "params")]
+enum ExecuteRequest {
+ // ==== SERVER ====
+ PruneContainers(PruneDockerContainers),
+ PruneImages(PruneDockerImages),
+ PruneNetworks(PruneDockerNetworks),
+
+ // ==== DEPLOYMENT ====
+ Deploy(Deploy),
+ StartContainer(StartContainer),
+ StopContainer(StopContainer),
+ StopAllContainers(StopAllContainers),
+ RemoveContainer(RemoveContainer),
+
+ // ==== BUILD ====
+ RunBuild(RunBuild),
+ CancelBuild(CancelBuild),
+
+ // ==== REPO ====
+ CloneRepo(CloneRepo),
+ PullRepo(PullRepo),
+
+ // ==== PROCEDURE ====
+ RunProcedure(RunProcedure),
+
+ // ==== SERVER TEMPLATE ====
+ LaunchServer(LaunchServer),
+}
+
+pub fn router() -> Router {
+ Router::new()
+ .route("/", post(handler))
+ .layer(middleware::from_fn(auth_request))
+}
+
+async fn handler(
+ Extension(user): Extension,
+ Json(request): Json,
+) -> serror::Result<(TypedHeader, String)> {
+ let req_id = Uuid::new_v4();
+
+ let res = tokio::spawn(task(req_id, request, user))
+ .await
+ .context("failure in spawned execute task");
+
+ if let Err(e) = &res {
+ warn!("/execute request {req_id} spawn error: {e:#}",);
+ }
+
+ Ok((TypedHeader(ContentType::json()), res??))
+}
+
+#[instrument(name = "ExecuteRequest", skip(user))]
+async fn task(
+ req_id: Uuid,
+ request: ExecuteRequest,
+ user: User,
+) -> anyhow::Result {
+ info!(
+ "/execute request {req_id} | user: {} ({})",
+ user.username, user.id
+ );
+ let timer = Instant::now();
+
+ let res =
+ State
+ .resolve_request(request, user)
+ .await
+ .map_err(|e| match e {
+ resolver_api::Error::Serialization(e) => {
+ anyhow!("{e:?}").context("response serialization error")
+ }
+ resolver_api::Error::Inner(e) => e,
+ });
+
+ if let Err(e) = &res {
+ warn!("/execute request {req_id} error: {e:#}");
+ }
+
+ let elapsed = timer.elapsed();
+ info!("/execute request {req_id} | resolve time: {elapsed:?}");
+
+ res
+}
diff --git a/bin/core/src/api/execute/procedure.rs b/bin/core/src/api/execute/procedure.rs
new file mode 100644
index 000000000..f81c7eec6
--- /dev/null
+++ b/bin/core/src/api/execute/procedure.rs
@@ -0,0 +1,83 @@
+use async_trait::async_trait;
+use monitor_client::{
+ api::execute::RunProcedure,
+ entities::{
+ permission::PermissionLevel, procedure::Procedure,
+ update::Update, user::User, Operation,
+ },
+};
+use resolver_api::Resolve;
+use serror::serialize_error_pretty;
+use tokio::sync::Mutex;
+
+use crate::{
+ helpers::{
+ procedure::execute_procedure,
+ resource::StateResource,
+ update::{add_update, make_update, update_update},
+ },
+ state::{action_states, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "RunProcedure", skip(self, user))]
+ async fn resolve(
+ &self,
+ RunProcedure { procedure }: RunProcedure,
+ user: User,
+ ) -> anyhow::Result {
+ let procedure = Procedure::get_resource_check_permissions(
+ &procedure,
+ &user,
+ PermissionLevel::Execute,
+ )
+ .await?;
+
+ // get the action state for the procedure (or insert default).
+ let action_state = action_states()
+ .procedure
+ .get_or_insert_default(&procedure.id)
+ .await;
+
+ // This will set action state back to default when dropped.
+ // Will also check to ensure procedure not already busy before updating.
+ let _action_guard =
+ action_state.update(|state| state.running = true)?;
+
+ let mut update =
+ make_update(&procedure, Operation::RunProcedure, &user);
+ update.in_progress();
+ update.push_simple_log(
+ "execute procedure",
+ format!("Executing procedure: {}", procedure.name),
+ );
+
+ update.id = add_update(update.clone()).await?;
+
+ let update = Mutex::new(update);
+
+ let res = execute_procedure(&procedure, &update).await;
+
+ let mut update = update.into_inner();
+
+ match res {
+ Ok(_) => {
+ update.push_simple_log(
+ "execution ok",
+ "the procedure has completed with no errors",
+ );
+ }
+ Err(e) => update.push_error_log(
+ "execution error",
+ serialize_error_pretty(&e),
+ ),
+ }
+
+ update.finalize();
+
+ update_update(update.clone()).await?;
+
+ Ok(update)
+ }
+}
diff --git a/bin/core/src/api/execute/repo.rs b/bin/core/src/api/execute/repo.rs
new file mode 100644
index 000000000..0f68258d0
--- /dev/null
+++ b/bin/core/src/api/execute/repo.rs
@@ -0,0 +1,205 @@
+use std::str::FromStr;
+
+use anyhow::anyhow;
+use async_trait::async_trait;
+use monitor_client::{
+ api::execute::*,
+ entities::{
+ monitor_timestamp, optional_string,
+ permission::PermissionLevel,
+ repo::Repo,
+ server::Server,
+ update::{Log, ResourceTarget, Update, UpdateStatus},
+ user::User,
+ Operation,
+ },
+};
+use mungos::mongodb::bson::{doc, oid::ObjectId};
+use periphery_client::api;
+use resolver_api::Resolve;
+use serror::serialize_error_pretty;
+
+use crate::{
+ config::core_config,
+ helpers::{
+ periphery_client,
+ resource::StateResource,
+ update::{add_update, update_update},
+ },
+ state::{action_states, db_client, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "CloneRepo", skip(self, user))]
+ async fn resolve(
+ &self,
+ CloneRepo { repo }: CloneRepo,
+ user: User,
+ ) -> anyhow::Result {
+ let repo = Repo::get_resource_check_permissions(
+ &repo,
+ &user,
+ PermissionLevel::Execute,
+ )
+ .await?;
+
+ // get the action state for the repo (or insert default).
+ let action_state =
+ action_states().repo.get_or_insert_default(&repo.id).await;
+
+ // This will set action state back to default when dropped.
+ // Will also check to ensure repo not already busy before updating.
+ let _action_guard =
+ action_state.update(|state| state.cloning = true)?;
+
+ if repo.config.server_id.is_empty() {
+ return Err(anyhow!("repo has no server attached"));
+ }
+
+ let server = Server::get_resource(&repo.config.server_id).await?;
+
+ let periphery = periphery_client(&server)?;
+
+ let start_ts = monitor_timestamp();
+
+ let mut update = Update {
+ operation: Operation::CloneRepo,
+ target: ResourceTarget::Repo(repo.id.clone()),
+ start_ts,
+ status: UpdateStatus::InProgress,
+ operator: user.id.clone(),
+ success: true,
+ ..Default::default()
+ };
+
+ update.id = add_update(update.clone()).await?;
+
+ let github_token = core_config()
+ .github_accounts
+ .get(&repo.config.github_account)
+ .cloned();
+
+ let logs = match periphery
+ .request(api::git::CloneRepo {
+ args: (&repo).into(),
+ github_token,
+ })
+ .await
+ {
+ Ok(logs) => logs,
+ Err(e) => {
+ vec![Log::error("clone repo", serialize_error_pretty(&e))]
+ }
+ };
+
+ update.logs.extend(logs);
+ update.finalize();
+
+ if update.success {
+ let res = db_client().await
+ .repos
+ .update_one(
+ doc! { "_id": ObjectId::from_str(&repo.id)? },
+ doc! { "$set": { "info.last_pulled_at": monitor_timestamp() } },
+ None,
+ )
+ .await;
+ if let Err(e) = res {
+ warn!(
+ "failed to update repo last_pulled_at | repo id: {} | {e:#}",
+ repo.id
+ );
+ }
+ }
+
+ update_update(update.clone()).await?;
+ Ok(update)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "PullRepo", skip(self, user))]
+ async fn resolve(
+ &self,
+ PullRepo { repo }: PullRepo,
+ user: User,
+ ) -> anyhow::Result {
+ let repo = Repo::get_resource_check_permissions(
+ &repo,
+ &user,
+ PermissionLevel::Write,
+ )
+ .await?;
+
+ // get the action state for the repo (or insert default).
+ let action_state =
+ action_states().repo.get_or_insert_default(&repo.id).await;
+
+ // This will set action state back to default when dropped.
+ // Will also check to ensure repo not already busy before updating.
+ let _action_guard =
+ action_state.update(|state| state.pulling = true)?;
+
+ if repo.config.server_id.is_empty() {
+ return Err(anyhow!("repo has no server attached"));
+ }
+
+ let server = Server::get_resource(&repo.config.server_id).await?;
+
+ let periphery = periphery_client(&server)?;
+
+ let start_ts = monitor_timestamp();
+
+ let mut update = Update {
+ operation: Operation::PullRepo,
+ target: ResourceTarget::Repo(repo.id.clone()),
+ start_ts,
+ status: UpdateStatus::InProgress,
+ operator: user.id.clone(),
+ success: true,
+ ..Default::default()
+ };
+
+ update.id = add_update(update.clone()).await?;
+
+ let logs = match periphery
+ .request(api::git::PullRepo {
+ name: repo.name,
+ branch: optional_string(&repo.config.branch),
+ on_pull: repo.config.on_pull.into_option(),
+ })
+ .await
+ {
+ Ok(logs) => logs,
+ Err(e) => {
+ vec![Log::error("pull repo", serialize_error_pretty(&e))]
+ }
+ };
+
+ update.logs.extend(logs);
+
+ update.finalize();
+
+ if update.success {
+ let res = db_client().await
+ .repos
+ .update_one(
+ doc! { "_id": ObjectId::from_str(&repo.id)? },
+ doc! { "$set": { "info.last_pulled_at": monitor_timestamp() } },
+ None,
+ )
+ .await;
+ if let Err(e) = res {
+ warn!(
+ "failed to update repo last_pulled_at | repo id: {} | {e:#}",
+ repo.id
+ );
+ }
+ }
+
+ update_update(update.clone()).await?;
+ Ok(update)
+ }
+}
diff --git a/bin/core/src/api/execute/server.rs b/bin/core/src/api/execute/server.rs
new file mode 100644
index 000000000..6f0f7c11c
--- /dev/null
+++ b/bin/core/src/api/execute/server.rs
@@ -0,0 +1,194 @@
+use anyhow::Context;
+use async_trait::async_trait;
+use monitor_client::{
+ api::execute::*,
+ entities::{
+ monitor_timestamp,
+ permission::PermissionLevel,
+ server::Server,
+ update::{Log, Update, UpdateStatus},
+ user::User,
+ Operation,
+ },
+};
+use periphery_client::api;
+use resolver_api::Resolve;
+use serror::serialize_error_pretty;
+
+use crate::{
+ helpers::{
+ periphery_client,
+ resource::StateResource,
+ update::{add_update, make_update, update_update},
+ },
+ state::{action_states, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "PruneDockerContainers", skip(self, user))]
+ async fn resolve(
+ &self,
+ PruneDockerContainers { server }: PruneDockerContainers,
+ user: User,
+ ) -> anyhow::Result {
+ let server = Server::get_resource_check_permissions(
+ &server,
+ &user,
+ PermissionLevel::Execute,
+ )
+ .await?;
+
+ // get the action state for the server (or insert default).
+ let action_state = action_states()
+ .server
+ .get_or_insert_default(&server.id)
+ .await;
+
+ // Will check to ensure server not already busy before updating, and return Err if so.
+ // The returned guard will set the action state back to default when dropped.
+ let _action_guard =
+ action_state.update(|state| state.pruning_containers = true)?;
+
+ let periphery = periphery_client(&server)?;
+
+ let mut update =
+ make_update(&server, Operation::PruneContainersServer, &user);
+ update.in_progress();
+ update.id = add_update(update.clone()).await?;
+
+ let log = match periphery
+ .request(api::container::PruneContainers {})
+ .await
+ .context(format!(
+ "failed to prune containers on server {}",
+ server.name
+ )) {
+ Ok(log) => log,
+ Err(e) => {
+ Log::error("prune containers", serialize_error_pretty(&e))
+ }
+ };
+
+ update.success = log.success;
+ update.status = UpdateStatus::Complete;
+ update.end_ts = Some(monitor_timestamp());
+ update.logs.push(log);
+
+ update_update(update.clone()).await?;
+
+ Ok(update)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "PruneDockerNetworks", skip(self, user))]
+ async fn resolve(
+ &self,
+ PruneDockerNetworks { server }: PruneDockerNetworks,
+ user: User,
+ ) -> anyhow::Result {
+ let server = Server::get_resource_check_permissions(
+ &server,
+ &user,
+ PermissionLevel::Execute,
+ )
+ .await?;
+
+ // get the action state for the server (or insert default).
+ let action_state = action_states()
+ .server
+ .get_or_insert_default(&server.id)
+ .await;
+
+ // Will check to ensure server not already busy before updating, and return Err if so.
+ // The returned guard will set the action state back to default when dropped.
+ let _action_guard =
+ action_state.update(|state| state.pruning_networks = true)?;
+
+ let periphery = periphery_client(&server)?;
+
+ let mut update =
+ make_update(&server, Operation::PruneNetworksServer, &user);
+ update.in_progress();
+ update.id = add_update(update.clone()).await?;
+
+ let log = match periphery
+ .request(api::network::PruneNetworks {})
+ .await
+ .context(format!(
+ "failed to prune networks on server {}",
+ server.name
+ )) {
+ Ok(log) => log,
+ Err(e) => {
+ Log::error("prune networks", serialize_error_pretty(&e))
+ }
+ };
+
+ update.success = log.success;
+ update.status = UpdateStatus::Complete;
+ update.end_ts = Some(monitor_timestamp());
+ update.logs.push(log);
+
+ update_update(update.clone()).await?;
+
+ Ok(update)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "PruneDockerImages", skip(self, user))]
+ async fn resolve(
+ &self,
+ PruneDockerImages { server }: PruneDockerImages,
+ user: User,
+ ) -> anyhow::Result {
+ let server = Server::get_resource_check_permissions(
+ &server,
+ &user,
+ PermissionLevel::Execute,
+ )
+ .await?;
+
+ // get the action state for the server (or insert default).
+ let action_state = action_states()
+ .server
+ .get_or_insert_default(&server.id)
+ .await;
+
+ // Will check to ensure server not already busy before updating, and return Err if so.
+ // The returned guard will set the action state back to default when dropped.
+ let _action_guard =
+ action_state.update(|state| state.pruning_images = true)?;
+
+ let periphery = periphery_client(&server)?;
+
+ let mut update =
+ make_update(&server, Operation::PruneImagesServer, &user);
+ update.in_progress();
+ update.id = add_update(update.clone()).await?;
+
+ let log =
+ match periphery.request(api::build::PruneImages {}).await {
+ Ok(log) => log,
+ Err(e) => Log::error(
+ "prune images",
+ format!(
+ "failed to prune images on server {} | {e:#?}",
+ server.name
+ ),
+ ),
+ };
+
+ update.logs.push(log);
+
+ update.finalize();
+
+ update_update(update.clone()).await?;
+
+ Ok(update)
+ }
+}
diff --git a/bin/core/src/api/execute/server_template.rs b/bin/core/src/api/execute/server_template.rs
new file mode 100644
index 000000000..21008775f
--- /dev/null
+++ b/bin/core/src/api/execute/server_template.rs
@@ -0,0 +1,89 @@
+use axum::async_trait;
+use monitor_client::{
+ api::{execute::LaunchServer, write::CreateServer},
+ entities::{
+ permission::PermissionLevel,
+ server::PartialServerConfig,
+ server_template::{ServerTemplate, ServerTemplateConfig},
+ update::Update,
+ user::User,
+ Operation,
+ },
+};
+use resolver_api::Resolve;
+
+use crate::{
+ cloud::aws::launch_ec2_instance,
+ helpers::{
+ resource::StateResource,
+ update::{add_update, make_update, update_update},
+ },
+ state::State,
+};
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "LaunchServer", skip(self, user))]
+ async fn resolve(
+ &self,
+ LaunchServer {
+ name,
+ server_template,
+ }: LaunchServer,
+ user: User,
+ ) -> anyhow::Result {
+ let template = ServerTemplate::get_resource_check_permissions(
+ &server_template,
+ &user,
+ PermissionLevel::Execute,
+ )
+ .await?;
+ let mut update =
+ make_update(&template, Operation::LaunchServer, &user);
+ update.push_simple_log(
+ "launching server",
+ format!("{:#?}", template.config),
+ );
+ update.id = add_update(update.clone()).await?;
+ match template.config {
+ ServerTemplateConfig::Aws(config) => {
+ let region = config.region.clone();
+ let instance = launch_ec2_instance(&name, config).await;
+ if let Err(e) = &instance {
+ update.push_error_log(
+ "launch server",
+ format!("failed to launch aws instance\n\n{e:#?}"),
+ );
+ update.finalize();
+ update_update(update.clone()).await?;
+ return Ok(update);
+ }
+ let instance = instance.unwrap();
+ update.push_simple_log(
+ "launch server",
+ format!(
+ "successfully launched server {name} on ip {}",
+ instance.ip
+ ),
+ );
+ let _ = self
+ .resolve(
+ CreateServer {
+ name,
+ config: PartialServerConfig {
+ address: format!("http://{}:8120", instance.ip)
+ .into(),
+ region: region.into(),
+ ..Default::default()
+ },
+ },
+ user,
+ )
+ .await;
+ }
+ }
+ update.finalize();
+ update_update(update.clone()).await?;
+ Ok(update)
+ }
+}
diff --git a/bin/core/src/api/mod.rs b/bin/core/src/api/mod.rs
new file mode 100644
index 000000000..55f891e40
--- /dev/null
+++ b/bin/core/src/api/mod.rs
@@ -0,0 +1,4 @@
+pub mod auth;
+pub mod execute;
+pub mod read;
+pub mod write;
diff --git a/bin/core/src/api/read/alert.rs b/bin/core/src/api/read/alert.rs
new file mode 100644
index 000000000..1ecf91039
--- /dev/null
+++ b/bin/core/src/api/read/alert.rs
@@ -0,0 +1,80 @@
+use anyhow::Context;
+use async_trait::async_trait;
+use monitor_client::{
+ api::read::{
+ GetAlert, GetAlertResponse, ListAlerts, ListAlertsResponse,
+ },
+ entities::{deployment::Deployment, server::Server, user::User},
+};
+use mungos::{
+ by_id::find_one_by_id,
+ find::find_collect,
+ mongodb::{bson::doc, options::FindOptions},
+};
+use resolver_api::Resolve;
+
+use crate::{
+ helpers::resource::StateResource,
+ state::{db_client, State},
+};
+
+const NUM_ALERTS_PER_PAGE: u64 = 20;
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListAlerts { query, page }: ListAlerts,
+ user: User,
+ ) -> anyhow::Result {
+ let mut query = query.unwrap_or_default();
+ if !user.admin {
+ let server_ids =
+ Server::get_resource_ids_for_non_admin(&user.id).await?;
+ let deployment_ids =
+ Deployment::get_resource_ids_for_non_admin(&user.id).await?;
+ query.extend(doc! {
+ "$or": [
+ { "target.type": "Server", "target.id": { "$in": &server_ids } },
+ { "target.type": "Deployment", "target.id": { "$in": &deployment_ids } },
+ ]
+ });
+ }
+
+ let alerts = find_collect(
+ &db_client().await.alerts,
+ query,
+ FindOptions::builder()
+ .sort(doc! { "ts": -1 })
+ .limit(NUM_ALERTS_PER_PAGE as i64)
+ .skip(page * NUM_ALERTS_PER_PAGE)
+ .build(),
+ )
+ .await
+ .context("failed to get alerts from db")?;
+
+ let next_page = if alerts.len() < NUM_ALERTS_PER_PAGE as usize {
+ None
+ } else {
+ Some((page + 1) as i64)
+ };
+
+ let res = ListAlertsResponse { next_page, alerts };
+
+ Ok(res)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetAlert { id }: GetAlert,
+ _: User,
+ ) -> anyhow::Result {
+ find_one_by_id(&db_client().await.alerts, &id)
+ .await
+ .context("failed to query db for alert")?
+ .context("no alert found with given id")
+ }
+}
diff --git a/bin/core/src/api/read/alerter.rs b/bin/core/src/api/read/alerter.rs
new file mode 100644
index 000000000..87fbe8599
--- /dev/null
+++ b/bin/core/src/api/read/alerter.rs
@@ -0,0 +1,85 @@
+use std::str::FromStr;
+
+use anyhow::Context;
+use async_trait::async_trait;
+use monitor_client::{
+ api::read::*,
+ entities::{
+ alerter::{Alerter, AlerterListItem},
+ permission::PermissionLevel,
+ update::ResourceTargetVariant,
+ user::User,
+ },
+};
+use mungos::mongodb::bson::{doc, oid::ObjectId};
+use resolver_api::Resolve;
+
+use crate::{
+ helpers::resource::{
+ get_resource_ids_for_non_admin, StateResource,
+ },
+ state::{db_client, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetAlerter { alerter }: GetAlerter,
+ user: User,
+ ) -> anyhow::Result {
+ Alerter::get_resource_check_permissions(
+ &alerter,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListAlerters { query }: ListAlerters,
+ user: User,
+ ) -> anyhow::Result> {
+ Alerter::list_resource_list_items_for_user(query, &user).await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetAlertersSummary {}: GetAlertersSummary,
+ user: User,
+ ) -> anyhow::Result {
+ let query = if user.admin {
+ None
+ } else {
+ let ids = get_resource_ids_for_non_admin(
+ &user.id,
+ ResourceTargetVariant::Alerter,
+ )
+ .await?
+ .into_iter()
+ .flat_map(|id| ObjectId::from_str(&id))
+ .collect::>();
+ let query = doc! {
+ "_id": { "$in": ids }
+ };
+ Some(query)
+ };
+ let total = db_client()
+ .await
+ .alerters
+ .count_documents(query, None)
+ .await
+ .context("failed to count all alerter documents")?;
+ let res = GetAlertersSummaryResponse {
+ total: total as u32,
+ };
+ Ok(res)
+ }
+}
diff --git a/bin/core/src/api/read/build.rs b/bin/core/src/api/read/build.rs
new file mode 100644
index 000000000..1d64a0f16
--- /dev/null
+++ b/bin/core/src/api/read/build.rs
@@ -0,0 +1,262 @@
+use std::{collections::HashMap, str::FromStr, sync::OnceLock};
+
+use anyhow::Context;
+use async_timing_util::unix_timestamp_ms;
+use async_trait::async_trait;
+use futures::TryStreamExt;
+use monitor_client::{
+ api::read::*,
+ entities::{
+ build::{Build, BuildActionState, BuildListItem},
+ permission::PermissionLevel,
+ update::{ResourceTargetVariant, UpdateStatus},
+ user::User,
+ Operation,
+ },
+};
+use mungos::{
+ find::find_collect,
+ mongodb::{
+ bson::{doc, oid::ObjectId},
+ options::FindOptions,
+ },
+};
+use resolver_api::{Resolve, ResolveToString};
+
+use crate::{
+ config::core_config,
+ helpers::resource::{
+ get_resource_ids_for_non_admin, StateResource,
+ },
+ state::{action_states, db_client, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetBuild { build }: GetBuild,
+ user: User,
+ ) -> anyhow::Result {
+ Build::get_resource_check_permissions(
+ &build,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListBuilds { query }: ListBuilds,
+ user: User,
+ ) -> anyhow::Result> {
+ Build::list_resource_list_items_for_user(query, &user).await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetBuildActionState { build }: GetBuildActionState,
+ user: User,
+ ) -> anyhow::Result {
+ let build = Build::get_resource_check_permissions(
+ &build,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ let action_state = action_states()
+ .build
+ .get(&build.id)
+ .await
+ .unwrap_or_default()
+ .get()?;
+ Ok(action_state)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetBuildsSummary {}: GetBuildsSummary,
+ user: User,
+ ) -> anyhow::Result {
+ let query = if user.admin {
+ None
+ } else {
+ let ids = get_resource_ids_for_non_admin(
+ &user.id,
+ ResourceTargetVariant::Build,
+ )
+ .await?
+ .into_iter()
+ .flat_map(|id| ObjectId::from_str(&id))
+ .collect::>();
+ let query = doc! {
+ "_id": { "$in": ids }
+ };
+ Some(query)
+ };
+ let total = db_client()
+ .await
+ .builds
+ .count_documents(query, None)
+ .await
+ .context("failed to count all build documents")?;
+ let res = GetBuildsSummaryResponse {
+ total: total as u32,
+ };
+ Ok(res)
+ }
+}
+
+const ONE_DAY_MS: i64 = 86400000;
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetBuildMonthlyStats { page }: GetBuildMonthlyStats,
+ _: User,
+ ) -> anyhow::Result {
+ let curr_ts = unix_timestamp_ms() as i64;
+ let next_day = curr_ts - curr_ts % ONE_DAY_MS + ONE_DAY_MS;
+
+ let close_ts = next_day - page as i64 * 30 * ONE_DAY_MS;
+ let open_ts = close_ts - 30 * ONE_DAY_MS;
+
+ let mut build_updates = db_client()
+ .await
+ .updates
+ .find(
+ doc! {
+ "start_ts": {
+ "$gte": open_ts,
+ "$lt": close_ts
+ },
+ "operation": Operation::RunBuild.to_string(),
+ },
+ None,
+ )
+ .await
+ .context("failed to get updates cursor")?;
+
+ let mut days = HashMap::::with_capacity(32);
+
+ let mut curr = open_ts;
+
+ while curr < close_ts {
+ let stats = BuildStatsDay {
+ ts: curr as f64,
+ ..Default::default()
+ };
+ days.insert(curr, stats);
+ curr += ONE_DAY_MS;
+ }
+
+ while let Some(update) = build_updates.try_next().await? {
+ if let Some(end_ts) = update.end_ts {
+ let day = update.start_ts - update.start_ts % ONE_DAY_MS;
+ let entry = days.entry(day).or_default();
+ entry.count += 1.0;
+ entry.time += ms_to_hour(end_ts - update.start_ts);
+ }
+ }
+
+ Ok(GetBuildMonthlyStatsResponse::new(
+ days.into_values().collect(),
+ ))
+ }
+}
+
+const MS_TO_HOUR_DIVISOR: f64 = 1000.0 * 60.0 * 60.0;
+fn ms_to_hour(duration: i64) -> f64 {
+ duration as f64 / MS_TO_HOUR_DIVISOR
+}
+
+const NUM_VERSIONS_PER_PAGE: u64 = 10;
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetBuildVersions {
+ build,
+ page,
+ major,
+ minor,
+ patch,
+ }: GetBuildVersions,
+ user: User,
+ ) -> anyhow::Result> {
+ let build = Build::get_resource_check_permissions(
+ &build,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+
+ let mut filter = doc! {
+ "target": {
+ "type": "Build",
+ "id": build.id
+ },
+ "operation": Operation::RunBuild.to_string(),
+ "status": UpdateStatus::Complete.to_string(),
+ "success": true
+ };
+ if let Some(major) = major {
+ filter.insert("version.major", major);
+ }
+ if let Some(minor) = minor {
+ filter.insert("version.minor", minor);
+ }
+ if let Some(patch) = patch {
+ filter.insert("version.patch", patch);
+ }
+
+ let versions = find_collect(
+ &db_client().await.updates,
+ filter,
+ FindOptions::builder()
+ .sort(doc! { "_id": -1 })
+ .limit(NUM_VERSIONS_PER_PAGE as i64)
+ .skip(page as u64 * NUM_VERSIONS_PER_PAGE)
+ .build(),
+ )
+ .await
+ .context("failed to pull versions from mongo")?
+ .into_iter()
+ .map(|u| (u.version, u.start_ts))
+ .filter(|(v, _)| !v.is_none())
+ .map(|(version, ts)| BuildVersionResponseItem { version, ts })
+ .collect();
+ Ok(versions)
+ }
+}
+
+fn docker_organizations() -> &'static String {
+ static DOCKER_ORGANIZATIONS: OnceLock = OnceLock::new();
+ DOCKER_ORGANIZATIONS.get_or_init(|| {
+ serde_json::to_string(&core_config().docker_organizations)
+ .expect("failed to serialize docker organizations")
+ })
+}
+
+#[async_trait]
+impl ResolveToString for State {
+ async fn resolve_to_string(
+ &self,
+ ListDockerOrganizations {}: ListDockerOrganizations,
+ _: User,
+ ) -> anyhow::Result {
+ Ok(docker_organizations().clone())
+ }
+}
diff --git a/bin/core/src/api/read/builder.rs b/bin/core/src/api/read/builder.rs
new file mode 100644
index 000000000..33e6faf64
--- /dev/null
+++ b/bin/core/src/api/read/builder.rs
@@ -0,0 +1,123 @@
+use std::str::FromStr;
+
+use anyhow::Context;
+use async_trait::async_trait;
+use monitor_client::{
+ api::read::{self, *},
+ entities::{
+ builder::{Builder, BuilderConfig, BuilderListItem},
+ permission::PermissionLevel,
+ update::ResourceTargetVariant,
+ user::User,
+ },
+};
+use mungos::mongodb::bson::{doc, oid::ObjectId};
+use resolver_api::Resolve;
+
+use crate::{
+ helpers::resource::{
+ get_resource_ids_for_non_admin, StateResource,
+ },
+ state::{db_client, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetBuilder { builder }: GetBuilder,
+ user: User,
+ ) -> anyhow::Result {
+ Builder::get_resource_check_permissions(
+ &builder,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListBuilders { query }: ListBuilders,
+ user: User,
+ ) -> anyhow::Result> {
+ Builder::list_resource_list_items_for_user(query, &user).await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetBuildersSummary {}: GetBuildersSummary,
+ user: User,
+ ) -> anyhow::Result {
+ let query = if user.admin {
+ None
+ } else {
+ let ids = get_resource_ids_for_non_admin(
+ &user.id,
+ ResourceTargetVariant::Builder,
+ )
+ .await?
+ .into_iter()
+ .flat_map(|id| ObjectId::from_str(&id))
+ .collect::>();
+ let query = doc! {
+ "_id": { "$in": ids }
+ };
+ Some(query)
+ };
+ let total = db_client()
+ .await
+ .builders
+ .count_documents(query, None)
+ .await
+ .context("failed to count all builder documents")?;
+ let res = GetBuildersSummaryResponse {
+ total: total as u32,
+ };
+ Ok(res)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetBuilderAvailableAccounts { builder }: GetBuilderAvailableAccounts,
+ user: User,
+ ) -> anyhow::Result {
+ let builder = Builder::get_resource_check_permissions(
+ &builder,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ match builder.config {
+ BuilderConfig::Aws(config) => {
+ Ok(GetBuilderAvailableAccountsResponse {
+ github: config.github_accounts,
+ docker: config.docker_accounts,
+ })
+ }
+ BuilderConfig::Server(config) => {
+ let res = self
+ .resolve(
+ read::GetAvailableAccounts {
+ server: config.server_id,
+ },
+ user,
+ )
+ .await?;
+ Ok(GetBuilderAvailableAccountsResponse {
+ github: res.github,
+ docker: res.docker,
+ })
+ }
+ }
+ }
+}
diff --git a/bin/core/src/api/read/deployment.rs b/bin/core/src/api/read/deployment.rs
new file mode 100644
index 000000000..7e67c5926
--- /dev/null
+++ b/bin/core/src/api/read/deployment.rs
@@ -0,0 +1,281 @@
+use std::{cmp, collections::HashSet, str::FromStr};
+
+use anyhow::{anyhow, Context};
+use async_trait::async_trait;
+use monitor_client::{
+ api::read::*,
+ entities::{
+ deployment::{
+ Deployment, DeploymentActionState, DeploymentConfig,
+ DeploymentListItem, DockerContainerState, DockerContainerStats,
+ },
+ permission::PermissionLevel,
+ server::Server,
+ update::{Log, ResourceTargetVariant},
+ user::User,
+ },
+};
+use mungos::{
+ find::find_collect,
+ mongodb::bson::{doc, oid::ObjectId},
+};
+use periphery_client::api;
+use resolver_api::Resolve;
+
+use crate::{
+ helpers::{
+ periphery_client,
+ resource::{get_resource_ids_for_non_admin, StateResource},
+ },
+ state::{action_states, db_client, deployment_status_cache, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetDeployment { deployment }: GetDeployment,
+ user: User,
+ ) -> anyhow::Result {
+ Deployment::get_resource_check_permissions(
+ &deployment,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListDeployments { query }: ListDeployments,
+ user: User,
+ ) -> anyhow::Result> {
+ Deployment::list_resource_list_items_for_user(query, &user).await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetDeploymentContainer { deployment }: GetDeploymentContainer,
+ user: User,
+ ) -> anyhow::Result {
+ let deployment = Deployment::get_resource_check_permissions(
+ &deployment,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ let status = deployment_status_cache()
+ .get(&deployment.id)
+ .await
+ .unwrap_or_default();
+ let response = GetDeploymentContainerResponse {
+ state: status.curr.state,
+ container: status.curr.container.clone(),
+ };
+ Ok(response)
+ }
+}
+
+const MAX_LOG_LENGTH: u64 = 5000;
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetLog { deployment, tail }: GetLog,
+ user: User,
+ ) -> anyhow::Result {
+ let Deployment {
+ name,
+ config: DeploymentConfig { server_id, .. },
+ ..
+ } = Deployment::get_resource_check_permissions(
+ &deployment,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ if server_id.is_empty() {
+ return Ok(Log::default());
+ }
+ let server = Server::get_resource(&server_id).await?;
+ periphery_client(&server)?
+ .request(api::container::GetContainerLog {
+ name,
+ tail: cmp::min(tail, MAX_LOG_LENGTH),
+ })
+ .await
+ .context("failed at call to periphery")
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ SearchLog {
+ deployment,
+ terms,
+ combinator,
+ }: SearchLog,
+ user: User,
+ ) -> anyhow::Result {
+ let Deployment {
+ name,
+ config: DeploymentConfig { server_id, .. },
+ ..
+ } = Deployment::get_resource_check_permissions(
+ &deployment,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ if server_id.is_empty() {
+ return Ok(Log::default());
+ }
+ let server = Server::get_resource(&server_id).await?;
+ periphery_client(&server)?
+ .request(api::container::GetContainerLogSearch {
+ name,
+ terms,
+ combinator,
+ })
+ .await
+ .context("failed at call to periphery")
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetDeploymentStats { deployment }: GetDeploymentStats,
+ user: User,
+ ) -> anyhow::Result {
+ let Deployment {
+ name,
+ config: DeploymentConfig { server_id, .. },
+ ..
+ } = Deployment::get_resource_check_permissions(
+ &deployment,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ if server_id.is_empty() {
+ return Err(anyhow!("deployment has no server attached"));
+ }
+ let server = Server::get_resource(&server_id).await?;
+ periphery_client(&server)?
+ .request(api::container::GetContainerStats { name })
+ .await
+ .context("failed to get stats from periphery")
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetDeploymentActionState { deployment }: GetDeploymentActionState,
+ user: User,
+ ) -> anyhow::Result {
+ let deployment = Deployment::get_resource_check_permissions(
+ &deployment,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ let action_state = action_states()
+ .deployment
+ .get(&deployment.id)
+ .await
+ .unwrap_or_default()
+ .get()?;
+ Ok(action_state)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetDeploymentsSummary {}: GetDeploymentsSummary,
+ user: User,
+ ) -> anyhow::Result {
+ let query = if user.admin {
+ None
+ } else {
+ let ids = get_resource_ids_for_non_admin(
+ &user.id,
+ ResourceTargetVariant::Deployment,
+ )
+ .await?
+ .into_iter()
+ .flat_map(|id| ObjectId::from_str(&id))
+ .collect::>();
+ let query = doc! {
+ "_id": { "$in": ids }
+ };
+ Some(query)
+ };
+
+ let deployments =
+ find_collect(&db_client().await.deployments, query, None)
+ .await
+ .context("failed to count all deployment documents")?;
+ let mut res = GetDeploymentsSummaryResponse::default();
+ let status_cache = deployment_status_cache();
+ for deployment in deployments {
+ res.total += 1;
+ let status =
+ status_cache.get(&deployment.id).await.unwrap_or_default();
+ match status.curr.state {
+ DockerContainerState::Running => {
+ res.running += 1;
+ }
+ DockerContainerState::Unknown => {
+ res.unknown += 1;
+ }
+ DockerContainerState::NotDeployed => {
+ res.not_deployed += 1;
+ }
+ _ => {
+ res.stopped += 1;
+ }
+ }
+ }
+ Ok(res)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListCommonExtraArgs { query }: ListCommonExtraArgs,
+ user: User,
+ ) -> anyhow::Result {
+ let deployments =
+ Deployment::list_resources_for_user(query, &user)
+ .await
+ .context("failed to get resources matching query")?;
+
+ // first collect with guaranteed uniqueness
+ let mut res = HashSet::::new();
+
+ for deployment in deployments {
+ for extra_arg in deployment.config.extra_args {
+ res.insert(extra_arg);
+ }
+ }
+
+ Ok(res.into_iter().collect())
+ }
+}
diff --git a/bin/core/src/api/read/mod.rs b/bin/core/src/api/read/mod.rs
new file mode 100644
index 000000000..7d31ba31f
--- /dev/null
+++ b/bin/core/src/api/read/mod.rs
@@ -0,0 +1,215 @@
+use std::time::Instant;
+
+use anyhow::anyhow;
+use async_trait::async_trait;
+use axum::{middleware, routing::post, Extension, Router};
+use axum_extra::{headers::ContentType, TypedHeader};
+use monitor_client::{api::read::*, entities::user::User};
+use resolver_api::{
+ derive::Resolver, Resolve, ResolveToString, Resolver,
+};
+use serde::{Deserialize, Serialize};
+use serror::Json;
+use typeshare::typeshare;
+use uuid::Uuid;
+
+use crate::{auth::auth_request, config::core_config, state::State};
+
+mod alert;
+mod alerter;
+mod build;
+mod builder;
+mod deployment;
+mod permission;
+mod procedure;
+mod repo;
+mod search;
+mod server;
+mod server_template;
+mod tag;
+mod toml;
+mod update;
+mod user;
+mod user_group;
+
+#[typeshare]
+#[derive(Serialize, Deserialize, Debug, Clone, Resolver)]
+#[resolver_target(State)]
+#[resolver_args(User)]
+#[serde(tag = "type", content = "params")]
+enum ReadRequest {
+ GetVersion(GetVersion),
+ GetCoreInfo(GetCoreInfo),
+
+ // ==== USER ====
+ ListUsers(ListUsers),
+ GetUsername(GetUsername),
+ ListApiKeys(ListApiKeys),
+ ListApiKeysForServiceUser(ListApiKeysForServiceUser),
+ ListPermissions(ListPermissions),
+ GetPermissionLevel(GetPermissionLevel),
+ ListUserTargetPermissions(ListUserTargetPermissions),
+
+ // ==== USER GROUP ====
+ GetUserGroup(GetUserGroup),
+ ListUserGroups(ListUserGroups),
+
+ // ==== SEARCH ====
+ FindResources(FindResources),
+
+ // ==== PROCEDURE ====
+ GetProceduresSummary(GetProceduresSummary),
+ GetProcedure(GetProcedure),
+ GetProcedureActionState(GetProcedureActionState),
+ ListProcedures(ListProcedures),
+
+ // ==== SERVER TEMPLATE ====
+ GetServerTemplate(GetServerTemplate),
+ ListServerTemplates(ListServerTemplates),
+ GetServerTemplateSummary(GetServerTemplatesSummary),
+
+ // ==== SERVER ====
+ GetServersSummary(GetServersSummary),
+ GetServer(GetServer),
+ ListServers(ListServers),
+ GetServerStatus(GetServerStatus),
+ GetPeripheryVersion(GetPeripheryVersion),
+ GetDockerContainers(GetDockerContainers),
+ GetDockerImages(GetDockerImages),
+ GetDockerNetworks(GetDockerNetworks),
+ GetServerActionState(GetServerActionState),
+ GetHistoricalServerStats(GetHistoricalServerStats),
+ GetAvailableAccounts(GetAvailableAccounts),
+ GetAvailableSecrets(GetAvailableSecrets),
+
+ // ==== DEPLOYMENT ====
+ GetDeploymentsSummary(GetDeploymentsSummary),
+ GetDeployment(GetDeployment),
+ ListDeployments(ListDeployments),
+ GetDeploymentContainer(GetDeploymentContainer),
+ GetDeploymentActionState(GetDeploymentActionState),
+ GetDeploymentStats(GetDeploymentStats),
+ GetLog(GetLog),
+ SearchLog(SearchLog),
+ ListCommonExtraArgs(ListCommonExtraArgs),
+
+ // ==== BUILD ====
+ GetBuildsSummary(GetBuildsSummary),
+ GetBuild(GetBuild),
+ ListBuilds(ListBuilds),
+ GetBuildActionState(GetBuildActionState),
+ GetBuildMonthlyStats(GetBuildMonthlyStats),
+ GetBuildVersions(GetBuildVersions),
+ #[to_string_resolver]
+ ListDockerOrganizations(ListDockerOrganizations),
+
+ // ==== REPO ====
+ GetReposSummary(GetReposSummary),
+ GetRepo(GetRepo),
+ ListRepos(ListRepos),
+ GetRepoActionState(GetRepoActionState),
+
+ // ==== BUILDER ====
+ GetBuildersSummary(GetBuildersSummary),
+ GetBuilder(GetBuilder),
+ ListBuilders(ListBuilders),
+ GetBuilderAvailableAccounts(GetBuilderAvailableAccounts),
+
+ // ==== ALERTER ====
+ GetAlertersSummary(GetAlertersSummary),
+ GetAlerter(GetAlerter),
+ ListAlerters(ListAlerters),
+
+ // ==== TOML ====
+ ExportAllResourcesToToml(ExportAllResourcesToToml),
+ ExportResourcesToToml(ExportResourcesToToml),
+
+ // ==== TAG ====
+ GetTag(GetTag),
+ ListTags(ListTags),
+
+ // ==== UPDATE ====
+ GetUpdate(GetUpdate),
+ ListUpdates(ListUpdates),
+
+ // ==== ALERT ====
+ ListAlerts(ListAlerts),
+ GetAlert(GetAlert),
+
+ // ==== SERVER STATS ====
+ #[to_string_resolver]
+ GetSystemInformation(GetSystemInformation),
+ #[to_string_resolver]
+ GetSystemStats(GetSystemStats),
+ #[to_string_resolver]
+ GetSystemProcesses(GetSystemProcesses),
+}
+
+pub fn router() -> Router {
+ Router::new()
+ .route("/", post(handler))
+ .layer(middleware::from_fn(auth_request))
+}
+
+#[instrument(name = "ReadHandler", level = "debug", skip(user))]
+async fn handler(
+ Extension(user): Extension,
+ Json(request): Json,
+) -> serror::Result<(TypedHeader, String)> {
+ let timer = Instant::now();
+ let req_id = Uuid::new_v4();
+ debug!(
+ "/read request {req_id} | user: {} ({})",
+ user.username, user.id
+ );
+ let res =
+ State
+ .resolve_request(request, user)
+ .await
+ .map_err(|e| match e {
+ resolver_api::Error::Serialization(e) => {
+ anyhow!("{e:?}").context("response serialization error")
+ }
+ resolver_api::Error::Inner(e) => e,
+ });
+ if let Err(e) = &res {
+ warn!("/read request {req_id} error: {e:#}");
+ }
+ let elapsed = timer.elapsed();
+ debug!("/read request {req_id} | resolve time: {elapsed:?}");
+ Ok((TypedHeader(ContentType::json()), res?))
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "GetVersion", level = "debug", skip(self))]
+ async fn resolve(
+ &self,
+ GetVersion {}: GetVersion,
+ _: User,
+ ) -> anyhow::Result {
+ Ok(GetVersionResponse {
+ version: env!("CARGO_PKG_VERSION").to_string(),
+ })
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "GetCoreInfo", level = "debug", skip(self))]
+ async fn resolve(
+ &self,
+ GetCoreInfo {}: GetCoreInfo,
+ _: User,
+ ) -> anyhow::Result {
+ let config = core_config();
+ Ok(GetCoreInfoResponse {
+ title: config.title.clone(),
+ monitoring_interval: config.monitoring_interval,
+ github_webhook_base_url: config
+ .github_webhook_base_url
+ .clone()
+ .unwrap_or_else(|| config.host.clone()),
+ })
+ }
+}
diff --git a/bin/core/src/api/read/permission.rs b/bin/core/src/api/read/permission.rs
new file mode 100644
index 000000000..74305213f
--- /dev/null
+++ b/bin/core/src/api/read/permission.rs
@@ -0,0 +1,76 @@
+use anyhow::{anyhow, Context};
+use axum::async_trait;
+use monitor_client::{
+ api::read::{
+ GetPermissionLevel, GetPermissionLevelResponse, ListPermissions,
+ ListPermissionsResponse, ListUserTargetPermissions,
+ ListUserTargetPermissionsResponse,
+ },
+ entities::{permission::PermissionLevel, user::User},
+};
+use mungos::{find::find_collect, mongodb::bson::doc};
+use resolver_api::Resolve;
+
+use crate::{
+ helpers::resource::get_user_permission_on_resource,
+ state::{db_client, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListPermissions {}: ListPermissions,
+ user: User,
+ ) -> anyhow::Result {
+ find_collect(
+ &db_client().await.permissions,
+ doc! {
+ "user_target.type": "User",
+ "user_target.id": &user.id
+ },
+ None,
+ )
+ .await
+ .context("failed to query db for permissions")
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetPermissionLevel { target }: GetPermissionLevel,
+ user: User,
+ ) -> anyhow::Result {
+ if user.admin {
+ return Ok(PermissionLevel::Write);
+ }
+ let (variant, id) = target.extract_variant_id();
+ get_user_permission_on_resource(&user.id, variant, id).await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListUserTargetPermissions { user_target }: ListUserTargetPermissions,
+ user: User,
+ ) -> anyhow::Result {
+ if !user.admin {
+ return Err(anyhow!("this method is admin only"));
+ }
+ let (variant, id) = user_target.extract_variant_id();
+ find_collect(
+ &db_client().await.permissions,
+ doc! {
+ "user_target.type": variant.as_ref(),
+ "user_target.id": id
+ },
+ None,
+ )
+ .await
+ .context("failed to query db for permissions")
+ }
+}
diff --git a/bin/core/src/api/read/procedure.rs b/bin/core/src/api/read/procedure.rs
new file mode 100644
index 000000000..2e690c039
--- /dev/null
+++ b/bin/core/src/api/read/procedure.rs
@@ -0,0 +1,111 @@
+use std::str::FromStr;
+
+use anyhow::Context;
+use async_trait::async_trait;
+use monitor_client::{
+ api::read::{
+ GetProcedure, GetProcedureActionState,
+ GetProcedureActionStateResponse, GetProcedureResponse,
+ GetProceduresSummary, GetProceduresSummaryResponse,
+ ListProcedures, ListProceduresResponse,
+ },
+ entities::{
+ permission::PermissionLevel, procedure::Procedure,
+ update::ResourceTargetVariant, user::User,
+ },
+};
+use mungos::mongodb::bson::{doc, oid::ObjectId};
+use resolver_api::Resolve;
+
+use crate::{
+ helpers::resource::{
+ get_resource_ids_for_non_admin, StateResource,
+ },
+ state::{action_states, db_client, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetProcedure { procedure }: GetProcedure,
+ user: User,
+ ) -> anyhow::Result {
+ Procedure::get_resource_check_permissions(
+ &procedure,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListProcedures { query }: ListProcedures,
+ user: User,
+ ) -> anyhow::Result {
+ Procedure::list_resource_list_items_for_user(query, &user).await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetProceduresSummary {}: GetProceduresSummary,
+ user: User,
+ ) -> anyhow::Result {
+ let query = if user.admin {
+ None
+ } else {
+ let ids = get_resource_ids_for_non_admin(
+ &user.id,
+ ResourceTargetVariant::Procedure,
+ )
+ .await?
+ .into_iter()
+ .flat_map(|id| ObjectId::from_str(&id))
+ .collect::>();
+ let query = doc! {
+ "_id": { "$in": ids }
+ };
+ Some(query)
+ };
+ let total = db_client()
+ .await
+ .procedures
+ .count_documents(query, None)
+ .await
+ .context("failed to count all procedure documents")?;
+ let res = GetProceduresSummaryResponse {
+ total: total as u32,
+ };
+ Ok(res)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetProcedureActionState { procedure }: GetProcedureActionState,
+ user: User,
+ ) -> anyhow::Result {
+ let procedure = Procedure::get_resource_check_permissions(
+ &procedure,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ let action_state = action_states()
+ .procedure
+ .get(&procedure.id)
+ .await
+ .unwrap_or_default()
+ .get()?;
+ Ok(action_state)
+ }
+}
diff --git a/bin/core/src/api/read/repo.rs b/bin/core/src/api/read/repo.rs
new file mode 100644
index 000000000..e2528963e
--- /dev/null
+++ b/bin/core/src/api/read/repo.rs
@@ -0,0 +1,108 @@
+use std::str::FromStr;
+
+use anyhow::Context;
+use async_trait::async_trait;
+use monitor_client::{
+ api::read::*,
+ entities::{
+ permission::PermissionLevel,
+ repo::{Repo, RepoActionState, RepoListItem},
+ update::ResourceTargetVariant,
+ user::User,
+ },
+};
+use mungos::mongodb::bson::{doc, oid::ObjectId};
+use resolver_api::Resolve;
+
+use crate::{
+ helpers::resource::{
+ get_resource_ids_for_non_admin, StateResource,
+ },
+ state::{action_states, db_client, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetRepo { repo }: GetRepo,
+ user: User,
+ ) -> anyhow::Result {
+ Repo::get_resource_check_permissions(
+ &repo,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListRepos { query }: ListRepos,
+ user: User,
+ ) -> anyhow::Result> {
+ Repo::list_resource_list_items_for_user(query, &user).await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetRepoActionState { repo }: GetRepoActionState,
+ user: User,
+ ) -> anyhow::Result {
+ let repo = Repo::get_resource_check_permissions(
+ &repo,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ let action_state = action_states()
+ .repo
+ .get(&repo.id)
+ .await
+ .unwrap_or_default()
+ .get()?;
+ Ok(action_state)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetReposSummary {}: GetReposSummary,
+ user: User,
+ ) -> anyhow::Result {
+ let query = if user.admin {
+ None
+ } else {
+ let ids = get_resource_ids_for_non_admin(
+ &user.id,
+ ResourceTargetVariant::Alerter,
+ )
+ .await?
+ .into_iter()
+ .flat_map(|id| ObjectId::from_str(&id))
+ .collect::>();
+ let query = doc! {
+ "_id": { "$in": ids }
+ };
+ Some(query)
+ };
+ let total = db_client()
+ .await
+ .repos
+ .count_documents(query, None)
+ .await
+ .context("failed to count all build documents")?;
+ let res = GetReposSummaryResponse {
+ total: total as u32,
+ };
+ Ok(res)
+ }
+}
diff --git a/bin/core/src/api/read/search.rs b/bin/core/src/api/read/search.rs
new file mode 100644
index 000000000..9c84a025f
--- /dev/null
+++ b/bin/core/src/api/read/search.rs
@@ -0,0 +1,79 @@
+use async_trait::async_trait;
+use monitor_client::{
+ api::read::{FindResources, FindResourcesResponse},
+ entities::{
+ build, deployment, procedure, repo, server,
+ update::ResourceTargetVariant::{self, *},
+ user::User,
+ },
+};
+use resolver_api::Resolve;
+
+use crate::{helpers::resource::StateResource, state::State};
+
+const FIND_RESOURCE_TYPES: [ResourceTargetVariant; 5] =
+ [Server, Build, Deployment, Repo, Procedure];
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ FindResources { query, resources }: FindResources,
+ user: User,
+ ) -> anyhow::Result {
+ let mut res = FindResourcesResponse::default();
+ let resource_types = if resources.is_empty() {
+ FIND_RESOURCE_TYPES.to_vec()
+ } else {
+ resources
+ .into_iter()
+ .filter(|r| !matches!(r, System | Builder | Alerter))
+ .collect()
+ };
+ for resource_type in resource_types {
+ match resource_type {
+ Server => {
+ res.servers =
+ server::Server::query_resource_list_items_for_user(
+ query.clone(),
+ &user,
+ )
+ .await?;
+ }
+ Deployment => {
+ res.deployments =
+ deployment::Deployment::query_resource_list_items_for_user(
+ query.clone(),
+ &user,
+ )
+ .await?;
+ }
+ Build => {
+ res.builds =
+ build::Build::query_resource_list_items_for_user(
+ query.clone(),
+ &user,
+ )
+ .await?;
+ }
+ Repo => {
+ res.repos = repo::Repo::query_resource_list_items_for_user(
+ query.clone(),
+ &user,
+ )
+ .await?;
+ }
+ Procedure => {
+ res.procedures =
+ procedure::Procedure::query_resource_list_items_for_user(
+ query.clone(),
+ &user,
+ )
+ .await?;
+ }
+ _ => {}
+ }
+ }
+ Ok(res)
+ }
+}
diff --git a/bin/core/src/api/read/server.rs b/bin/core/src/api/read/server.rs
new file mode 100644
index 000000000..93a69b32e
--- /dev/null
+++ b/bin/core/src/api/read/server.rs
@@ -0,0 +1,432 @@
+use std::{
+ collections::HashMap,
+ sync::{Arc, OnceLock},
+};
+
+use anyhow::{anyhow, Context};
+use async_timing_util::{
+ get_timelength_in_ms, unix_timestamp_ms, FIFTEEN_SECONDS_MS,
+};
+use async_trait::async_trait;
+use monitor_client::{
+ api::read::*,
+ entities::{
+ deployment::ContainerSummary,
+ permission::PermissionLevel,
+ server::{
+ docker_image::ImageSummary, docker_network::DockerNetwork,
+ Server, ServerActionState, ServerListItem, ServerStatus,
+ },
+ user::User,
+ },
+};
+use mungos::{
+ find::find_collect,
+ mongodb::{bson::doc, options::FindOptions},
+};
+use periphery_client::api::{self, GetAccountsResponse};
+use resolver_api::{Resolve, ResolveToString};
+use tokio::sync::Mutex;
+
+use crate::{
+ helpers::{periphery_client, resource::StateResource},
+ state::{action_states, db_client, server_status_cache, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetServersSummary {}: GetServersSummary,
+ user: User,
+ ) -> anyhow::Result {
+ let servers = Server::list_resource_list_items_for_user(
+ Default::default(),
+ &user,
+ )
+ .await?;
+ let mut res = GetServersSummaryResponse::default();
+ for server in servers {
+ res.total += 1;
+ match server.info.status {
+ ServerStatus::Ok => {
+ res.healthy += 1;
+ }
+ ServerStatus::NotOk => {
+ res.unhealthy += 1;
+ }
+ ServerStatus::Disabled => {
+ res.disabled += 1;
+ }
+ }
+ }
+ Ok(res)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ req: GetPeripheryVersion,
+ user: User,
+ ) -> anyhow::Result {
+ let server = Server::get_resource_check_permissions(
+ &req.server,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ let version = server_status_cache()
+ .get(&server.id)
+ .await
+ .map(|s| s.version.clone())
+ .unwrap_or(String::from("unknown"));
+ Ok(GetPeripheryVersionResponse { version })
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ req: GetServer,
+ user: User,
+ ) -> anyhow::Result {
+ Server::get_resource_check_permissions(
+ &req.server,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListServers { query }: ListServers,
+ user: User,
+ ) -> anyhow::Result> {
+ Server::list_resource_list_items_for_user(query, &user).await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetServerStatus { server }: GetServerStatus,
+ user: User,
+ ) -> anyhow::Result {
+ let server = Server::get_resource_check_permissions(
+ &server,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ let status = server_status_cache()
+ .get(&server.id)
+ .await
+ .ok_or(anyhow!("did not find cached status for server"))?;
+ let response = GetServerStatusResponse {
+ status: status.status,
+ };
+ Ok(response)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetServerActionState { server }: GetServerActionState,
+ user: User,
+ ) -> anyhow::Result {
+ let server = Server::get_resource_check_permissions(
+ &server,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ let action_state = action_states()
+ .server
+ .get(&server.id)
+ .await
+ .unwrap_or_default()
+ .get()?;
+ Ok(action_state)
+ }
+}
+
+// This protects the peripheries from spam requests
+const SYSTEM_INFO_EXPIRY: u128 = FIFTEEN_SECONDS_MS;
+type SystemInfoCache = Mutex>>;
+fn system_info_cache() -> &'static SystemInfoCache {
+ static SYSTEM_INFO_CACHE: OnceLock =
+ OnceLock::new();
+ SYSTEM_INFO_CACHE.get_or_init(Default::default)
+}
+
+#[async_trait]
+impl ResolveToString for State {
+ async fn resolve_to_string(
+ &self,
+ GetSystemInformation { server }: GetSystemInformation,
+ user: User,
+ ) -> anyhow::Result {
+ let server = Server::get_resource_check_permissions(
+ &server,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+
+ let mut lock = system_info_cache().lock().await;
+ let res = match lock.get(&server.id) {
+ Some(cached) if cached.1 > unix_timestamp_ms() => {
+ cached.0.clone()
+ }
+ _ => {
+ let stats = periphery_client(&server)?
+ .request(api::stats::GetSystemInformation {})
+ .await?;
+ let res = serde_json::to_string(&stats)?;
+ lock.insert(
+ server.id,
+ (res.clone(), unix_timestamp_ms() + SYSTEM_INFO_EXPIRY)
+ .into(),
+ );
+ res
+ }
+ };
+ Ok(res)
+ }
+}
+
+#[async_trait]
+impl ResolveToString for State {
+ async fn resolve_to_string(
+ &self,
+ GetSystemStats { server }: GetSystemStats,
+ user: User,
+ ) -> anyhow::Result {
+ let server = Server::get_resource_check_permissions(
+ &server,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ let status =
+ server_status_cache().get(&server.id).await.with_context(
+ || format!("did not find status for server at {}", server.id),
+ )?;
+ let stats = status
+ .stats
+ .as_ref()
+ .context("server stats not available")?;
+ let stats = serde_json::to_string(&stats)?;
+ Ok(stats)
+ }
+}
+
+// This protects the peripheries from spam requests
+const PROCESSES_EXPIRY: u128 = FIFTEEN_SECONDS_MS;
+type ProcessesCache = Mutex>>;
+fn processes_cache() -> &'static ProcessesCache {
+ static PROCESSES_CACHE: OnceLock = OnceLock::new();
+ PROCESSES_CACHE.get_or_init(Default::default)
+}
+
+#[async_trait]
+impl ResolveToString for State {
+ async fn resolve_to_string(
+ &self,
+ GetSystemProcesses { server }: GetSystemProcesses,
+ user: User,
+ ) -> anyhow::Result {
+ let server = Server::get_resource_check_permissions(
+ &server,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ let mut lock = processes_cache().lock().await;
+ let res = match lock.get(&server.id) {
+ Some(cached) if cached.1 > unix_timestamp_ms() => {
+ cached.0.clone()
+ }
+ _ => {
+ let stats = periphery_client(&server)?
+ .request(api::stats::GetSystemProcesses {})
+ .await?;
+ let res = serde_json::to_string(&stats)?;
+ lock.insert(
+ server.id,
+ (res.clone(), unix_timestamp_ms() + PROCESSES_EXPIRY)
+ .into(),
+ );
+ res
+ }
+ };
+ Ok(res)
+ }
+}
+
+const STATS_PER_PAGE: i64 = 500;
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetHistoricalServerStats {
+ server,
+ granularity,
+ page,
+ }: GetHistoricalServerStats,
+ user: User,
+ ) -> anyhow::Result {
+ let server = Server::get_resource_check_permissions(
+ &server,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ let granularity =
+ get_timelength_in_ms(granularity.to_string().parse().unwrap())
+ as i64;
+ let mut ts_vec = Vec::::new();
+ let curr_ts = unix_timestamp_ms() as i64;
+ let mut curr_ts = curr_ts
+ - curr_ts % granularity
+ - granularity * STATS_PER_PAGE * page as i64;
+ for _ in 0..STATS_PER_PAGE {
+ ts_vec.push(curr_ts);
+ curr_ts -= granularity;
+ }
+
+ let stats = find_collect(
+ &db_client().await.stats,
+ doc! {
+ "sid": server.id,
+ "ts": { "$in": ts_vec },
+ },
+ FindOptions::builder()
+ .sort(doc! { "ts": -1 })
+ .skip(page as u64 * STATS_PER_PAGE as u64)
+ .limit(STATS_PER_PAGE)
+ .build(),
+ )
+ .await
+ .context("failed to pull stats from db")?;
+ let next_page = if stats.len() == STATS_PER_PAGE as usize {
+ Some(page + 1)
+ } else {
+ None
+ };
+ let res = GetHistoricalServerStatsResponse { stats, next_page };
+ Ok(res)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetDockerImages { server }: GetDockerImages,
+ user: User,
+ ) -> anyhow::Result> {
+ let server = Server::get_resource_check_permissions(
+ &server,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ periphery_client(&server)?
+ .request(api::build::GetImageList {})
+ .await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetDockerNetworks { server }: GetDockerNetworks,
+ user: User,
+ ) -> anyhow::Result> {
+ let server = Server::get_resource_check_permissions(
+ &server,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ periphery_client(&server)?
+ .request(api::network::GetNetworkList {})
+ .await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetDockerContainers { server }: GetDockerContainers,
+ user: User,
+ ) -> anyhow::Result> {
+ let server = Server::get_resource_check_permissions(
+ &server,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ periphery_client(&server)?
+ .request(api::container::GetContainerList {})
+ .await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetAvailableAccounts { server }: GetAvailableAccounts,
+ user: User,
+ ) -> anyhow::Result {
+ let server = Server::get_resource_check_permissions(
+ &server,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ let GetAccountsResponse { github, docker } =
+ periphery_client(&server)?
+ .request(api::GetAccounts {})
+ .await
+ .context("failed to get accounts from periphery")?;
+ let res = GetAvailableAccountsResponse { github, docker };
+ Ok(res)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetAvailableSecrets { server }: GetAvailableSecrets,
+ user: User,
+ ) -> anyhow::Result {
+ let server = Server::get_resource_check_permissions(
+ &server,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ let secrets = periphery_client(&server)?
+ .request(api::GetSecrets {})
+ .await
+ .context("failed to get accounts from periphery")?;
+ Ok(secrets)
+ }
+}
diff --git a/bin/core/src/api/read/server_template.rs b/bin/core/src/api/read/server_template.rs
new file mode 100644
index 000000000..7d270838b
--- /dev/null
+++ b/bin/core/src/api/read/server_template.rs
@@ -0,0 +1,88 @@
+use std::str::FromStr;
+
+use anyhow::Context;
+use axum::async_trait;
+use monitor_client::{
+ api::read::{
+ GetServerTemplate, GetServerTemplateResponse,
+ GetServerTemplatesSummary, GetServerTemplatesSummaryResponse,
+ ListServerTemplates, ListServerTemplatesResponse,
+ },
+ entities::{
+ permission::PermissionLevel, server_template::ServerTemplate,
+ update::ResourceTargetVariant, user::User,
+ },
+};
+use mungos::mongodb::bson::{doc, oid::ObjectId};
+use resolver_api::Resolve;
+
+use crate::{
+ helpers::resource::{
+ get_resource_ids_for_non_admin, StateResource,
+ },
+ state::{db_client, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetServerTemplate { server_template }: GetServerTemplate,
+ user: User,
+ ) -> anyhow::Result {
+ ServerTemplate::get_resource_check_permissions(
+ &server_template,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListServerTemplates { query }: ListServerTemplates,
+ user: User,
+ ) -> anyhow::Result {
+ ServerTemplate::list_resource_list_items_for_user(query, &user)
+ .await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetServerTemplatesSummary {}: GetServerTemplatesSummary,
+ user: User,
+ ) -> anyhow::Result {
+ let query = if user.admin {
+ None
+ } else {
+ let ids = get_resource_ids_for_non_admin(
+ &user.id,
+ ResourceTargetVariant::ServerTemplate,
+ )
+ .await?
+ .into_iter()
+ .flat_map(|id| ObjectId::from_str(&id))
+ .collect::>();
+ let query = doc! {
+ "_id": { "$in": ids }
+ };
+ Some(query)
+ };
+ let total = db_client()
+ .await
+ .builders
+ .count_documents(query, None)
+ .await
+ .context("failed to count all builder documents")?;
+ let res = GetServerTemplatesSummaryResponse {
+ total: total as u32,
+ };
+ Ok(res)
+ }
+}
diff --git a/bin/core/src/api/read/tag.rs b/bin/core/src/api/read/tag.rs
new file mode 100644
index 000000000..293ee8224
--- /dev/null
+++ b/bin/core/src/api/read/tag.rs
@@ -0,0 +1,37 @@
+use anyhow::Context;
+use async_trait::async_trait;
+use monitor_client::{
+ api::read::{GetTag, ListTags},
+ entities::{tag::Tag, user::User},
+};
+use mungos::find::find_collect;
+use resolver_api::Resolve;
+
+use crate::{
+ helpers::query::get_tag,
+ state::{db_client, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetTag { tag }: GetTag,
+ _: User,
+ ) -> anyhow::Result {
+ get_tag(&tag).await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListTags { query }: ListTags,
+ _: User,
+ ) -> anyhow::Result> {
+ find_collect(&db_client().await.tags, query, None)
+ .await
+ .context("failed to get tags from db")
+ }
+}
diff --git a/bin/core/src/api/read/toml.rs b/bin/core/src/api/read/toml.rs
new file mode 100644
index 000000000..398824f0e
--- /dev/null
+++ b/bin/core/src/api/read/toml.rs
@@ -0,0 +1,481 @@
+use std::collections::HashMap;
+
+use anyhow::Context;
+use axum::async_trait;
+use monitor_client::{
+ api::{
+ execute::Execution,
+ read::{
+ ExportAllResourcesToToml, ExportAllResourcesToTomlResponse,
+ ExportResourcesToToml, ExportResourcesToTomlResponse,
+ GetUserGroup, ListUserTargetPermissions,
+ },
+ },
+ entities::{
+ alerter::Alerter,
+ build::Build,
+ builder::{Builder, BuilderConfig},
+ deployment::{Deployment, DeploymentImage},
+ permission::{PermissionLevel, UserTarget},
+ procedure::Procedure,
+ repo::Repo,
+ resource::Resource,
+ server::Server,
+ server_template::ServerTemplate,
+ toml::{
+ PermissionToml, ResourceToml, ResourcesToml, UserGroupToml,
+ },
+ update::ResourceTarget,
+ user::User,
+ },
+};
+use mungos::find::find_collect;
+use resolver_api::Resolve;
+
+use crate::{
+ helpers::{
+ query::get_user_user_group_ids, resource::StateResource,
+ },
+ state::{db_client, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ExportAllResourcesToToml {}: ExportAllResourcesToToml,
+ user: User,
+ ) -> anyhow::Result {
+ let mut targets = Vec::::new();
+
+ targets.extend(
+ Alerter::list_resource_list_items_for_user(
+ Default::default(),
+ &user,
+ )
+ .await?
+ .into_iter()
+ .map(|resource| ResourceTarget::Alerter(resource.id)),
+ );
+ targets.extend(
+ Builder::list_resource_list_items_for_user(
+ Default::default(),
+ &user,
+ )
+ .await?
+ .into_iter()
+ .map(|resource| ResourceTarget::Builder(resource.id)),
+ );
+ targets.extend(
+ Server::list_resource_list_items_for_user(
+ Default::default(),
+ &user,
+ )
+ .await?
+ .into_iter()
+ .map(|resource| ResourceTarget::Server(resource.id)),
+ );
+ targets.extend(
+ Deployment::list_resource_list_items_for_user(
+ Default::default(),
+ &user,
+ )
+ .await?
+ .into_iter()
+ .map(|resource| ResourceTarget::Deployment(resource.id)),
+ );
+ targets.extend(
+ Build::list_resource_list_items_for_user(
+ Default::default(),
+ &user,
+ )
+ .await?
+ .into_iter()
+ .map(|resource| ResourceTarget::Build(resource.id)),
+ );
+ targets.extend(
+ Repo::list_resource_list_items_for_user(
+ Default::default(),
+ &user,
+ )
+ .await?
+ .into_iter()
+ .map(|resource| ResourceTarget::Repo(resource.id)),
+ );
+ targets.extend(
+ Procedure::list_resource_list_items_for_user(
+ Default::default(),
+ &user,
+ )
+ .await?
+ .into_iter()
+ .map(|resource| ResourceTarget::Procedure(resource.id)),
+ );
+
+ let user_groups = if user.admin {
+ find_collect(&db_client().await.user_groups, None, None)
+ .await
+ .context("failed to query db for user groups")?
+ .into_iter()
+ .map(|user_group| user_group.id)
+ .collect()
+ } else {
+ get_user_user_group_ids(&user.id).await?
+ };
+
+ self
+ .resolve(
+ ExportResourcesToToml {
+ targets,
+ user_groups,
+ },
+ user,
+ )
+ .await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ExportResourcesToToml {
+ targets,
+ user_groups,
+ }: ExportResourcesToToml,
+ user: User,
+ ) -> anyhow::Result {
+ let mut res = ResourcesToml::default();
+ let names = ResourceNames::new()
+ .await
+ .context("failed to init resource name maps")?;
+ for target in targets {
+ match target {
+ ResourceTarget::Alerter(id) => {
+ let alerter = Alerter::get_resource_check_permissions(
+ &id,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ res.alerters.push(convert_resource(alerter, &names.tags))
+ }
+ ResourceTarget::ServerTemplate(id) => {
+ let template =
+ ServerTemplate::get_resource_check_permissions(
+ &id,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ res
+ .server_templates
+ .push(convert_resource(template, &names.tags))
+ }
+ ResourceTarget::Server(id) => {
+ let server = Server::get_resource_check_permissions(
+ &id,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ res.servers.push(convert_resource(server, &names.tags))
+ }
+ ResourceTarget::Builder(id) => {
+ let mut builder = Builder::get_resource_check_permissions(
+ &id,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ // replace server id of builder
+ if let BuilderConfig::Server(config) = &mut builder.config {
+ config.server_id.clone_from(
+ names.servers.get(&id).unwrap_or(&String::new()),
+ )
+ }
+ res.builders.push(convert_resource(builder, &names.tags))
+ }
+ ResourceTarget::Build(id) => {
+ let mut build = Build::get_resource_check_permissions(
+ &id,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ // replace builder id of build
+ build.config.builder_id.clone_from(
+ names
+ .builders
+ .get(&build.config.builder_id)
+ .unwrap_or(&String::new()),
+ );
+ res.builds.push(convert_resource(build, &names.tags))
+ }
+ ResourceTarget::Deployment(id) => {
+ let mut deployment =
+ Deployment::get_resource_check_permissions(
+ &id,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ // replace deployment server with name
+ deployment.config.server_id.clone_from(
+ names
+ .servers
+ .get(&deployment.config.server_id)
+ .unwrap_or(&String::new()),
+ );
+ // replace deployment build id with name
+ if let DeploymentImage::Build { build_id, .. } =
+ &mut deployment.config.image
+ {
+ build_id.clone_from(
+ names.builds.get(build_id).unwrap_or(&String::new()),
+ );
+ }
+ res
+ .deployments
+ .push(convert_resource(deployment, &names.tags))
+ }
+ ResourceTarget::Repo(id) => {
+ let mut repo = Repo::get_resource_check_permissions(
+ &id,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ // replace repo server with name
+ repo.config.server_id.clone_from(
+ names
+ .servers
+ .get(&repo.config.server_id)
+ .unwrap_or(&String::new()),
+ );
+ res.repos.push(convert_resource(repo, &names.tags))
+ }
+ ResourceTarget::Procedure(id) => {
+ add_procedure(&id, &mut res, &user, &names)
+ .await
+ .with_context(|| {
+ format!("failed to add procedure {id}")
+ })?;
+ }
+ ResourceTarget::System(_) => continue,
+ };
+ }
+
+ add_user_groups(user_groups, &mut res, &user)
+ .await
+ .context("failed to add user groups")?;
+
+ let toml = toml::to_string_pretty(&res)
+ .context("failed to serialize resources to toml")?;
+
+ Ok(ExportResourcesToTomlResponse { toml })
+ }
+}
+
+async fn add_procedure(
+ id: &str,
+ res: &mut ResourcesToml,
+ user: &User,
+ names: &ResourceNames,
+) -> anyhow::Result<()> {
+ let mut procedure = Procedure::get_resource_check_permissions(
+ id,
+ user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ for execution in &mut procedure.config.executions {
+ match &mut execution.execution {
+ Execution::RunProcedure(exec) => exec.procedure.clone_from(
+ names
+ .procedures
+ .get(&exec.procedure)
+ .unwrap_or(&String::new()),
+ ),
+ Execution::RunBuild(exec) => exec.build.clone_from(
+ names.builds.get(&exec.build).unwrap_or(&String::new()),
+ ),
+ Execution::Deploy(exec) => exec.deployment.clone_from(
+ names
+ .deployments
+ .get(&exec.deployment)
+ .unwrap_or(&String::new()),
+ ),
+ Execution::StartContainer(exec) => exec.deployment.clone_from(
+ names
+ .deployments
+ .get(&exec.deployment)
+ .unwrap_or(&String::new()),
+ ),
+ Execution::StopContainer(exec) => exec.deployment.clone_from(
+ names
+ .deployments
+ .get(&exec.deployment)
+ .unwrap_or(&String::new()),
+ ),
+ Execution::RemoveContainer(exec) => exec.deployment.clone_from(
+ names
+ .deployments
+ .get(&exec.deployment)
+ .unwrap_or(&String::new()),
+ ),
+ Execution::CloneRepo(exec) => exec.repo.clone_from(
+ names.repos.get(&exec.repo).unwrap_or(&String::new()),
+ ),
+ Execution::PullRepo(exec) => exec.repo.clone_from(
+ names.repos.get(&exec.repo).unwrap_or(&String::new()),
+ ),
+ Execution::StopAllContainers(exec) => exec.server.clone_from(
+ names.servers.get(&exec.server).unwrap_or(&String::new()),
+ ),
+ Execution::PruneDockerNetworks(exec) => exec.server.clone_from(
+ names.servers.get(&exec.server).unwrap_or(&String::new()),
+ ),
+ Execution::PruneDockerImages(exec) => exec.server.clone_from(
+ names.servers.get(&exec.server).unwrap_or(&String::new()),
+ ),
+ Execution::PruneDockerContainers(exec) => {
+ exec.server.clone_from(
+ names.servers.get(&exec.server).unwrap_or(&String::new()),
+ )
+ }
+ Execution::None(_) => continue,
+ }
+ }
+ res
+ .procedures
+ .push(convert_resource(procedure, &names.tags));
+ Ok(())
+}
+
+struct ResourceNames {
+ tags: HashMap,
+ servers: HashMap,
+ builders: HashMap,
+ builds: HashMap,
+ repos: HashMap,
+ deployments: HashMap,
+ procedures: HashMap,
+}
+
+impl ResourceNames {
+ async fn new() -> anyhow::Result {
+ let db = db_client().await;
+ Ok(ResourceNames {
+ tags: find_collect(&db.tags, None, None)
+ .await
+ .context("failed to get all tags")?
+ .into_iter()
+ .map(|t| (t.id, t.name))
+ .collect::>(),
+ servers: find_collect(&db.servers, None, None)
+ .await
+ .context("failed to get all servers")?
+ .into_iter()
+ .map(|t| (t.id, t.name))
+ .collect::>(),
+ builders: find_collect(&db.builders, None, None)
+ .await
+ .context("failed to get all builders")?
+ .into_iter()
+ .map(|t| (t.id, t.name))
+ .collect::>(),
+ builds: find_collect(&db.builds, None, None)
+ .await
+ .context("failed to get all builds")?
+ .into_iter()
+ .map(|t| (t.id, t.name))
+ .collect::>(),
+ repos: find_collect(&db.repos, None, None)
+ .await
+ .context("failed to get all repos")?
+ .into_iter()
+ .map(|t| (t.id, t.name))
+ .collect::>(),
+ deployments: find_collect(&db.deployments, None, None)
+ .await
+ .context("failed to get all deployments")?
+ .into_iter()
+ .map(|t| (t.id, t.name))
+ .collect::>(),
+ procedures: find_collect(&db.procedures, None, None)
+ .await
+ .context("failed to get all procedures")?
+ .into_iter()
+ .map(|t| (t.id, t.name))
+ .collect::>(),
+ })
+ }
+}
+
+async fn add_user_groups(
+ user_groups: Vec,
+ res: &mut ResourcesToml,
+ user: &User,
+) -> anyhow::Result<()> {
+ let db = db_client().await;
+
+ let usernames = find_collect(&db.users, None, None)
+ .await?
+ .into_iter()
+ .map(|user| (user.id, user.username))
+ .collect::>();
+
+ for user_group in user_groups {
+ let ug = State
+ .resolve(GetUserGroup { user_group }, user.clone())
+ .await?;
+ // this method is admin only, but we already know user can see user group if above does not return Err
+ let permissions = State
+ .resolve(
+ ListUserTargetPermissions {
+ user_target: UserTarget::UserGroup(ug.id),
+ },
+ User {
+ admin: true,
+ ..Default::default()
+ },
+ )
+ .await?
+ .into_iter()
+ .map(|permission| PermissionToml {
+ target: permission.resource_target,
+ level: permission.level,
+ })
+ .collect();
+ res.user_groups.push(UserGroupToml {
+ name: ug.name,
+ users: ug
+ .users
+ .into_iter()
+ .filter_map(|user_id| usernames.get(&user_id).cloned())
+ .collect(),
+ permissions,
+ });
+ }
+ Ok(())
+}
+
+fn convert_resource(
+ resource: Resource,
+ tag_names: &HashMap,
+) -> ResourceToml
+where
+ Config: Into,
+{
+ ResourceToml {
+ name: resource.name,
+ tags: resource
+ .tags
+ .iter()
+ .filter_map(|t| tag_names.get(t).cloned())
+ .collect(),
+ description: resource.description,
+ config: resource.config.into(),
+ }
+}
diff --git a/bin/core/src/api/read/update.rs b/bin/core/src/api/read/update.rs
new file mode 100644
index 000000000..8982c6e2d
--- /dev/null
+++ b/bin/core/src/api/read/update.rs
@@ -0,0 +1,214 @@
+use std::collections::HashMap;
+
+use anyhow::{anyhow, Context};
+use async_trait::async_trait;
+use monitor_client::{
+ api::read::{GetUpdate, ListUpdates, ListUpdatesResponse},
+ entities::{
+ alerter::Alerter,
+ build::Build,
+ builder::Builder,
+ deployment::Deployment,
+ permission::PermissionLevel,
+ procedure::Procedure,
+ repo::Repo,
+ server::Server,
+ server_template::ServerTemplate,
+ update::{ResourceTarget, Update, UpdateListItem},
+ user::User,
+ },
+};
+use mungos::{
+ by_id::find_one_by_id,
+ find::find_collect,
+ mongodb::{bson::doc, options::FindOptions},
+};
+use resolver_api::Resolve;
+
+use crate::{
+ helpers::resource::StateResource,
+ state::{db_client, State},
+};
+
+const UPDATES_PER_PAGE: i64 = 20;
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListUpdates { query, page }: ListUpdates,
+ user: User,
+ ) -> anyhow::Result {
+ let query = if user.admin {
+ query
+ } else {
+ let server_ids =
+ Server::get_resource_ids_for_non_admin(&user.id).await?;
+ let deployment_ids =
+ Deployment::get_resource_ids_for_non_admin(&user.id).await?;
+ let build_ids =
+ Build::get_resource_ids_for_non_admin(&user.id).await?;
+ let repo_ids =
+ Repo::get_resource_ids_for_non_admin(&user.id).await?;
+ let procedure_ids =
+ Procedure::get_resource_ids_for_non_admin(&user.id).await?;
+ let builder_ids =
+ Builder::get_resource_ids_for_non_admin(&user.id).await?;
+ let alerter_ids =
+ Alerter::get_resource_ids_for_non_admin(&user.id).await?;
+ let mut query = query.unwrap_or_default();
+ query.extend(doc! {
+ "$or": [
+ { "target.type": "Server", "target.id": { "$in": &server_ids } },
+ { "target.type": "Deployment", "target.id": { "$in": &deployment_ids } },
+ { "target.type": "Build", "target.id": { "$in": &build_ids } },
+ { "target.type": "Repo", "target.id": { "$in": &repo_ids } },
+ { "target.type": "Procedure", "target.id": { "$in": &procedure_ids } },
+ { "target.type": "Builder", "target.id": { "$in": &builder_ids } },
+ { "target.type": "Alerter", "target.id": { "$in": &alerter_ids } },
+ ]
+ });
+ query.into()
+ };
+
+ let usernames =
+ find_collect(&db_client().await.users, None, None)
+ .await
+ .context("failed to pull users from db")?
+ .into_iter()
+ .map(|u| (u.id, u.username))
+ .collect::>();
+
+ let updates = find_collect(
+ &db_client().await.updates,
+ query,
+ FindOptions::builder()
+ .sort(doc! { "start_ts": -1 })
+ .skip(page as u64 * UPDATES_PER_PAGE as u64)
+ .limit(UPDATES_PER_PAGE)
+ .build(),
+ )
+ .await
+ .context("failed to pull updates from db")?
+ .into_iter()
+ .map(|u| {
+ let username = if User::is_service_user(&u.operator) {
+ u.operator.clone()
+ } else {
+ usernames
+ .get(&u.operator)
+ .cloned()
+ .unwrap_or("unknown".to_string())
+ };
+ UpdateListItem {
+ username,
+ id: u.id,
+ operation: u.operation,
+ start_ts: u.start_ts,
+ success: u.success,
+ operator: u.operator,
+ target: u.target,
+ status: u.status,
+ version: u.version,
+ }
+ })
+ .collect::>();
+
+ let next_page = if updates.len() == UPDATES_PER_PAGE as usize {
+ Some(page + 1)
+ } else {
+ None
+ };
+
+ Ok(ListUpdatesResponse { updates, next_page })
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetUpdate { id }: GetUpdate,
+ user: User,
+ ) -> anyhow::Result {
+ let update = find_one_by_id(&db_client().await.updates, &id)
+ .await
+ .context("failed to query to db")?
+ .context("no update exists with given id")?;
+ if user.admin {
+ return Ok(update);
+ }
+ match &update.target {
+ ResourceTarget::System(_) => {
+ return Err(anyhow!(
+ "user must be admin to view system updates"
+ ))
+ }
+ ResourceTarget::Server(id) => {
+ Server::get_resource_check_permissions(
+ id,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ }
+ ResourceTarget::Deployment(id) => {
+ Deployment::get_resource_check_permissions(
+ id,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ }
+ ResourceTarget::Build(id) => {
+ Build::get_resource_check_permissions(
+ id,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ }
+ ResourceTarget::Repo(id) => {
+ Repo::get_resource_check_permissions(
+ id,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ }
+ ResourceTarget::Builder(id) => {
+ Builder::get_resource_check_permissions(
+ id,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ }
+ ResourceTarget::Alerter(id) => {
+ Alerter::get_resource_check_permissions(
+ id,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ }
+ ResourceTarget::Procedure(id) => {
+ Procedure::get_resource_check_permissions(
+ id,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ }
+ ResourceTarget::ServerTemplate(id) => {
+ ServerTemplate::get_resource_check_permissions(
+ id,
+ &user,
+ PermissionLevel::Read,
+ )
+ .await?;
+ }
+ }
+ Ok(update)
+ }
+}
diff --git a/bin/core/src/api/read/user.rs b/bin/core/src/api/read/user.rs
new file mode 100644
index 000000000..8c7886f11
--- /dev/null
+++ b/bin/core/src/api/read/user.rs
@@ -0,0 +1,111 @@
+use anyhow::{anyhow, Context};
+use async_trait::async_trait;
+use monitor_client::{
+ api::read::{
+ GetUsername, GetUsernameResponse, ListApiKeys,
+ ListApiKeysForServiceUser, ListApiKeysForServiceUserResponse,
+ ListApiKeysResponse, ListUsers, ListUsersResponse,
+ },
+ entities::user::{User, UserConfig},
+};
+use mungos::{
+ by_id::find_one_by_id, find::find_collect, mongodb::bson::doc,
+};
+use resolver_api::Resolve;
+
+use crate::state::{db_client, State};
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetUsername { user_id }: GetUsername,
+ _: User,
+ ) -> anyhow::Result {
+ let user = find_one_by_id(&db_client().await.users, &user_id)
+ .await
+ .context("failed at mongo query for user")?
+ .context("no user found with id")?;
+
+ Ok(GetUsernameResponse {
+ username: user.username,
+ })
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListUsers {}: ListUsers,
+ user: User,
+ ) -> anyhow::Result {
+ if !user.admin {
+ return Err(anyhow!("this route is only accessable by admins"));
+ }
+ let mut users =
+ find_collect(&db_client().await.users, None, None)
+ .await
+ .context("failed to pull users from db")?;
+ users.iter_mut().for_each(|user| user.sanitize());
+ Ok(users)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListApiKeys {}: ListApiKeys,
+ user: User,
+ ) -> anyhow::Result {
+ let api_keys = find_collect(
+ &db_client().await.api_keys,
+ doc! { "user_id": &user.id },
+ None,
+ )
+ .await
+ .context("failed to query db for api keys")?
+ .into_iter()
+ .map(|mut api_keys| {
+ api_keys.sanitize();
+ api_keys
+ })
+ .collect();
+ Ok(api_keys)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListApiKeysForServiceUser { user_id }: ListApiKeysForServiceUser,
+ admin: User,
+ ) -> anyhow::Result {
+ if !admin.admin {
+ return Err(anyhow!("This method is admin only."));
+ }
+ let user = find_one_by_id(&db_client().await.users, &user_id)
+ .await
+ .context("failed to query db for users")?
+ .context("user at id not found")?;
+ let UserConfig::Service { .. } = user.config else {
+ return Err(anyhow!("Given user is not service user"));
+ };
+ let api_keys = find_collect(
+ &db_client().await.api_keys,
+ doc! { "user_id": user_id },
+ None,
+ )
+ .await
+ .context("failed to query db for api keys")?
+ .into_iter()
+ .map(|mut api_keys| {
+ api_keys.sanitize();
+ api_keys
+ })
+ .collect();
+ Ok(api_keys)
+ }
+}
diff --git a/bin/core/src/api/read/user_group.rs b/bin/core/src/api/read/user_group.rs
new file mode 100644
index 000000000..b3103de3a
--- /dev/null
+++ b/bin/core/src/api/read/user_group.rs
@@ -0,0 +1,61 @@
+use std::str::FromStr;
+
+use anyhow::Context;
+use async_trait::async_trait;
+use monitor_client::{
+ api::read::{
+ GetUserGroup, GetUserGroupResponse, ListUserGroups,
+ ListUserGroupsResponse,
+ },
+ entities::user::User,
+};
+use mungos::{
+ find::find_collect,
+ mongodb::bson::{doc, oid::ObjectId, Document},
+};
+use resolver_api::Resolve;
+
+use crate::state::{db_client, State};
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ GetUserGroup { user_group }: GetUserGroup,
+ user: User,
+ ) -> anyhow::Result {
+ let mut filter = match ObjectId::from_str(&user_group) {
+ Ok(id) => doc! { "_id": id },
+ Err(_) => doc! { "name": &user_group },
+ };
+ // Don't allow non admin users to get UserGroups they aren't a part of.
+ if !user.admin {
+ // Filter for only UserGroups which contain the users id
+ filter.insert("users", &user.id);
+ }
+ db_client()
+ .await
+ .user_groups
+ .find_one(filter, None)
+ .await
+ .context("failed to query db for user groups")?
+ .context("no UserGroup found with given name or id")
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ async fn resolve(
+ &self,
+ ListUserGroups {}: ListUserGroups,
+ user: User,
+ ) -> anyhow::Result {
+ let mut filter = Document::new();
+ if !user.admin {
+ filter.insert("users", &user.id);
+ }
+ find_collect(&db_client().await.user_groups, filter, None)
+ .await
+ .context("failed to query db for UserGroups")
+ }
+}
diff --git a/bin/core/src/api/write/alerter.rs b/bin/core/src/api/write/alerter.rs
new file mode 100644
index 000000000..291bb7ebd
--- /dev/null
+++ b/bin/core/src/api/write/alerter.rs
@@ -0,0 +1,240 @@
+use std::str::FromStr;
+
+use anyhow::{anyhow, Context};
+use async_trait::async_trait;
+use monitor_client::{
+ api::write::{
+ CopyAlerter, CreateAlerter, DeleteAlerter, UpdateAlerter,
+ },
+ entities::{
+ alerter::{Alerter, AlerterInfo},
+ monitor_timestamp,
+ permission::PermissionLevel,
+ user::User,
+ Operation,
+ },
+};
+use mungos::{
+ by_id::{delete_one_by_id, update_one_by_id},
+ mongodb::bson::{doc, oid::ObjectId, to_bson},
+};
+use resolver_api::Resolve;
+
+use crate::{
+ helpers::{
+ create_permission, remove_from_recently_viewed,
+ resource::{delete_all_permissions_on_resource, StateResource},
+ update::{add_update, make_update},
+ },
+ state::{db_client, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "CreateAlerter", skip(self, user))]
+ async fn resolve(
+ &self,
+ CreateAlerter { name, config }: CreateAlerter,
+ user: User,
+ ) -> anyhow::Result {
+ if ObjectId::from_str(&name).is_ok() {
+ return Err(anyhow!("valid ObjectIds cannot be used as names"));
+ }
+ let start_ts = monitor_timestamp();
+ let is_default = db_client()
+ .await
+ .alerters
+ .find_one(None, None)
+ .await?
+ .is_none();
+ let alerter = Alerter {
+ id: Default::default(),
+ name,
+ updated_at: start_ts,
+ description: Default::default(),
+ tags: Default::default(),
+ config: config.into(),
+ info: AlerterInfo { is_default },
+ };
+ let alerter_id = db_client()
+ .await
+ .alerters
+ .insert_one(alerter, None)
+ .await
+ .context("failed to add alerter to db")?
+ .inserted_id
+ .as_object_id()
+ .context("inserted_id is not ObjectId")?
+ .to_string();
+ let alerter = Alerter::get_resource(&alerter_id).await?;
+
+ create_permission(&user, &alerter, PermissionLevel::Write).await;
+
+ let mut update =
+ make_update(&alerter, Operation::CreateAlerter, &user);
+
+ update.push_simple_log(
+ "create alerter",
+ format!(
+ "created alerter\nid: {}\nname: {}",
+ alerter.id, alerter.name
+ ),
+ );
+ update
+ .push_simple_log("config", format!("{:#?}", alerter.config));
+
+ update.finalize();
+
+ add_update(update).await?;
+
+ Ok(alerter)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "CopyAlerter", skip(self, user))]
+ async fn resolve(
+ &self,
+ CopyAlerter { name, id }: CopyAlerter,
+ user: User,
+ ) -> anyhow::Result {
+ let Alerter {
+ config,
+ description,
+ ..
+ } = Alerter::get_resource_check_permissions(
+ &id,
+ &user,
+ PermissionLevel::Write,
+ )
+ .await?;
+ let start_ts = monitor_timestamp();
+ let alerter = Alerter {
+ id: Default::default(),
+ name,
+ updated_at: start_ts,
+ description,
+ config,
+ tags: Default::default(),
+ info: Default::default(),
+ };
+ let alerter_id = db_client()
+ .await
+ .alerters
+ .insert_one(alerter, None)
+ .await
+ .context("failed to add alerter to db")?
+ .inserted_id
+ .as_object_id()
+ .context("inserted_id is not ObjectId")?
+ .to_string();
+ let alerter = Alerter::get_resource(&alerter_id).await?;
+
+ create_permission(&user, &alerter, PermissionLevel::Write).await;
+
+ let mut update =
+ make_update(&alerter, Operation::CreateAlerter, &user);
+
+ update.push_simple_log(
+ "create alerter",
+ format!(
+ "created alerter\nid: {}\nname: {}",
+ alerter.id, alerter.name
+ ),
+ );
+
+ update
+ .push_simple_log("config", format!("{:#?}", alerter.config));
+
+ update.finalize();
+
+ add_update(update).await?;
+
+ Ok(alerter)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "DeleteAlerter", skip(self, user))]
+ async fn resolve(
+ &self,
+ DeleteAlerter { id }: DeleteAlerter,
+ user: User,
+ ) -> anyhow::Result {
+ let alerter = Alerter::get_resource_check_permissions(
+ &id,
+ &user,
+ PermissionLevel::Write,
+ )
+ .await?;
+
+ let mut update =
+ make_update(&alerter, Operation::DeleteAlerter, &user);
+
+ delete_one_by_id(&db_client().await.alerters, &id, None)
+ .await
+ .context("failed to delete alerter from database")?;
+
+ delete_all_permissions_on_resource(&alerter).await;
+
+ update.push_simple_log(
+ "delete alerter",
+ format!("deleted alerter {}", alerter.name),
+ );
+
+ update.finalize();
+
+ add_update(update).await?;
+
+ remove_from_recently_viewed(&alerter).await?;
+
+ Ok(alerter)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "UpdateAlerter", skip(self, user))]
+ async fn resolve(
+ &self,
+ UpdateAlerter { id, config }: UpdateAlerter,
+ user: User,
+ ) -> anyhow::Result {
+ let alerter = Alerter::get_resource_check_permissions(
+ &id,
+ &user,
+ PermissionLevel::Write,
+ )
+ .await?;
+
+ let mut update =
+ make_update(&alerter, Operation::UpdateAlerter, &user);
+
+ update.push_simple_log(
+ "alerter update",
+ serde_json::to_string_pretty(&config)?,
+ );
+
+ let config = alerter.config.merge_partial(config);
+
+ update_one_by_id(
+ &db_client().await.alerters,
+ &id,
+ mungos::update::Update::FlattenSet(
+ doc! { "config": to_bson(&config)? },
+ ),
+ None,
+ )
+ .await
+ .with_context(|| format!("failed to update alerter {id}"))?;
+
+ let alerter = Alerter::get_resource(&id).await?;
+
+ update.finalize();
+ add_update(update).await?;
+
+ Ok(alerter)
+ }
+}
diff --git a/bin/core/src/api/write/api_key.rs b/bin/core/src/api/write/api_key.rs
new file mode 100644
index 000000000..bd9eb4420
--- /dev/null
+++ b/bin/core/src/api/write/api_key.rs
@@ -0,0 +1,152 @@
+use anyhow::{anyhow, Context};
+use async_trait::async_trait;
+use monitor_client::{
+ api::write::*,
+ entities::{
+ api_key::ApiKey,
+ monitor_timestamp,
+ user::{User, UserConfig},
+ },
+};
+use mungos::{by_id::find_one_by_id, mongodb::bson::doc};
+use resolver_api::Resolve;
+
+use crate::{
+ auth::random_string,
+ helpers::query::get_user,
+ state::{db_client, State},
+};
+
+const SECRET_LENGTH: usize = 40;
+const BCRYPT_COST: u32 = 10;
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(
+ name = "CreateApiKey",
+ level = "debug",
+ skip(self, user)
+ )]
+ async fn resolve(
+ &self,
+ CreateApiKey { name, expires }: CreateApiKey,
+ user: User,
+ ) -> anyhow::Result {
+ let user = get_user(&user.id).await?;
+
+ let key = format!("K-{}", random_string(SECRET_LENGTH));
+ let secret = format!("S-{}", random_string(SECRET_LENGTH));
+ let secret_hash = bcrypt::hash(&secret, BCRYPT_COST)
+ .context("failed at hashing secret string")?;
+
+ let api_key = ApiKey {
+ name,
+ key: key.clone(),
+ secret: secret_hash,
+ user_id: user.id.clone(),
+ created_at: monitor_timestamp(),
+ expires,
+ };
+ db_client()
+ .await
+ .api_keys
+ .insert_one(api_key, None)
+ .await
+ .context("failed to create api key on db")?;
+ Ok(CreateApiKeyResponse { key, secret })
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(
+ name = "DeleteApiKey",
+ level = "debug",
+ skip(self, user)
+ )]
+ async fn resolve(
+ &self,
+ DeleteApiKey { key }: DeleteApiKey,
+ user: User,
+ ) -> anyhow::Result {
+ let client = db_client().await;
+ let key = client
+ .api_keys
+ .find_one(doc! { "key": &key }, None)
+ .await
+ .context("failed at db query")?
+ .context("no api key with key found")?;
+ if user.id != key.user_id {
+ return Err(anyhow!("api key does not belong to user"));
+ }
+ client
+ .api_keys
+ .delete_one(doc! { "key": key.key }, None)
+ .await
+ .context("failed to delete api key from db")?;
+ Ok(DeleteApiKeyResponse {})
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "CreateApiKeyForServiceUser", skip(self, user))]
+ async fn resolve(
+ &self,
+ CreateApiKeyForServiceUser {
+ user_id,
+ name,
+ expires,
+ }: CreateApiKeyForServiceUser,
+ user: User,
+ ) -> anyhow::Result {
+ if !user.admin {
+ return Err(anyhow!("user not admin"));
+ }
+ let service_user =
+ find_one_by_id(&db_client().await.users, &user_id)
+ .await
+ .context("failed to query db for user")?
+ .context("no user found with id")?;
+ let UserConfig::Service { .. } = &service_user.config else {
+ return Err(anyhow!("user is not service user"));
+ };
+ self
+ .resolve(CreateApiKey { name, expires }, service_user)
+ .await
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "DeleteApiKeyForServiceUser", skip(self, user))]
+ async fn resolve(
+ &self,
+ DeleteApiKeyForServiceUser { key }: DeleteApiKeyForServiceUser,
+ user: User,
+ ) -> anyhow::Result {
+ if !user.admin {
+ return Err(anyhow!("user not admin"));
+ }
+ let db = db_client().await;
+ let api_key = db
+ .api_keys
+ .find_one(doc! { "key": &key }, None)
+ .await
+ .context("failed to query db for api key")?
+ .context("did not find matching api key")?;
+ let service_user =
+ find_one_by_id(&db_client().await.users, &api_key.user_id)
+ .await
+ .context("failed to query db for user")?
+ .context("no user found with id")?;
+ let UserConfig::Service { .. } = &service_user.config else {
+ return Err(anyhow!("user is not service user"));
+ };
+ db.api_keys
+ .delete_one(doc! { "key": key }, None)
+ .await
+ .context("failed to delete api key on db")?;
+ Ok(DeleteApiKeyForServiceUserResponse {})
+ }
+}
diff --git a/bin/core/src/api/write/build.rs b/bin/core/src/api/write/build.rs
new file mode 100644
index 000000000..25fb7059d
--- /dev/null
+++ b/bin/core/src/api/write/build.rs
@@ -0,0 +1,309 @@
+use std::str::FromStr;
+
+use anyhow::{anyhow, Context};
+use async_trait::async_trait;
+use monitor_client::{
+ api::write::*,
+ entities::{
+ build::Build,
+ builder::Builder,
+ monitor_timestamp,
+ permission::PermissionLevel,
+ to_monitor_name,
+ update::{Log, UpdateStatus},
+ user::User,
+ Operation,
+ },
+};
+use mungos::{
+ by_id::update_one_by_id,
+ mongodb::bson::{doc, oid::ObjectId, to_document},
+};
+use resolver_api::Resolve;
+
+use crate::{
+ helpers::{
+ create_permission, empty_or_only_spaces,
+ remove_from_recently_viewed,
+ resource::{delete_all_permissions_on_resource, StateResource},
+ update::{add_update, make_update, update_update},
+ },
+ state::{action_states, db_client, State},
+};
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "CreateBuild", skip(self, user))]
+ async fn resolve(
+ &self,
+ CreateBuild { name, mut config }: CreateBuild,
+ user: User,
+ ) -> anyhow::Result {
+ if !user.admin && !user.create_build_permissions {
+ return Err(anyhow!(
+ "User does not have create build permissions."
+ ));
+ }
+ let name = to_monitor_name(&name);
+ if ObjectId::from_str(&name).is_ok() {
+ return Err(anyhow!("valid ObjectIds cannot be used as names"));
+ }
+ if let Some(builder_id) = &config.builder_id {
+ let builder = Builder::get_resource_check_permissions(builder_id, &user, PermissionLevel::Read)
+ .await
+ .context("cannot create build using this builder. user must have at least read permissions on the builder.")?;
+ config.builder_id = Some(builder.id)
+ }
+ let start_ts = monitor_timestamp();
+ let build = Build {
+ id: Default::default(),
+ name,
+ updated_at: start_ts,
+ description: Default::default(),
+ tags: Default::default(),
+ config: config.into(),
+ info: Default::default(),
+ };
+ let build_id = db_client()
+ .await
+ .builds
+ .insert_one(build, None)
+ .await
+ .context("failed to add build to db")?
+ .inserted_id
+ .as_object_id()
+ .context("inserted_id is not ObjectId")?
+ .to_string();
+ let build = Build::get_resource(&build_id).await?;
+
+ create_permission(&user, &build, PermissionLevel::Write).await;
+
+ let mut update =
+ make_update(&build, Operation::CreateBuild, &user);
+
+ update.push_simple_log(
+ "create build",
+ format!(
+ "created build\nid: {}\nname: {}",
+ build.id, build.name
+ ),
+ );
+
+ update.push_simple_log("config", format!("{:#?}", build.config));
+
+ update.finalize();
+
+ add_update(update).await?;
+
+ Ok(build)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "CopyBuild", skip(self, user))]
+ async fn resolve(
+ &self,
+ CopyBuild { name, id }: CopyBuild,
+ user: User,
+ ) -> anyhow::Result {
+ if !user.admin && !user.create_build_permissions {
+ return Err(anyhow!(
+ "User does not have create build permissions."
+ ));
+ }
+ let name = to_monitor_name(&name);
+ let Build {
+ config,
+ description,
+ tags,
+ ..
+ } = Build::get_resource_check_permissions(
+ &id,
+ &user,
+ PermissionLevel::Write,
+ )
+ .await?;
+ Builder::get_resource_check_permissions(&config.builder_id, &user, PermissionLevel::Read)
+ .await
+ .context("cannot create build using this builder. user must have at least read permissions on the builder.")?;
+ let start_ts = monitor_timestamp();
+ let build = Build {
+ id: Default::default(),
+ name,
+ updated_at: start_ts,
+ description,
+ tags,
+ config,
+ info: Default::default(),
+ };
+ let build_id = db_client()
+ .await
+ .builds
+ .insert_one(build, None)
+ .await
+ .context("failed to add build to db")?
+ .inserted_id
+ .as_object_id()
+ .context("inserted_id is not ObjectId")?
+ .to_string();
+ let build = Build::get_resource(&build_id).await?;
+
+ create_permission(&user, &build, PermissionLevel::Write).await;
+
+ let mut update =
+ make_update(&build, Operation::CreateBuild, &user);
+
+ update.push_simple_log(
+ "create build",
+ format!(
+ "created build\nid: {}\nname: {}",
+ build.id, build.name
+ ),
+ );
+ update.push_simple_log(
+ "config",
+ serde_json::to_string_pretty(&build)?,
+ );
+
+ update.finalize();
+
+ add_update(update).await?;
+
+ Ok(build)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "DeleteBuild", skip(self, user))]
+ async fn resolve(
+ &self,
+ DeleteBuild { id }: DeleteBuild,
+ user: User,
+ ) -> anyhow::Result {
+ if action_states()
+ .build
+ .get(&id)
+ .await
+ .unwrap_or_default()
+ .busy()?
+ {
+ return Err(anyhow!("build busy"));
+ }
+
+ let build = Build::get_resource_check_permissions(
+ &id,
+ &user,
+ PermissionLevel::Write,
+ )
+ .await?;
+
+ let mut update =
+ make_update(&build, Operation::DeleteBuild, &user);
+ update.status = UpdateStatus::InProgress;
+ update.id = add_update(update.clone()).await?;
+
+ let res = db_client()
+ .await
+ .builds
+ .delete_one(doc! { "_id": ObjectId::from_str(&id)? }, None)
+ .await
+ .context("failed to delete build from database");
+
+ delete_all_permissions_on_resource(&build).await;
+
+ let log = match res {
+ Ok(_) => Log::simple(
+ "delete build",
+ format!("deleted build {}", build.name),
+ ),
+ Err(e) => Log::error(
+ "delete build",
+ format!("failed to delete build\n{e:#?}"),
+ ),
+ };
+
+ update.logs.push(log);
+ update.finalize();
+ update_update(update).await?;
+
+ remove_from_recently_viewed(&build).await?;
+
+ Ok(build)
+ }
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "UpdateBuild", skip(self, user))]
+ async fn resolve(
+ &self,
+ UpdateBuild { id, mut config }: UpdateBuild,
+ user: User,
+ ) -> anyhow::Result {
+ if action_states()
+ .build
+ .get(&id)
+ .await
+ .unwrap_or_default()
+ .busy()?
+ {
+ return Err(anyhow!("build busy"));
+ }
+
+ let build = Build::get_resource_check_permissions(
+ &id,
+ &user,
+ PermissionLevel::Write,
+ )
+ .await?;
+
+ if let Some(builder_id) = &config.builder_id {
+ let builder = Builder::get_resource_check_permissions(builder_id, &user, PermissionLevel::Read)
+ .await
+ .context("cannot create build using this builder. user must have at least read permissions on the builder.")?;
+ config.builder_id = Some(builder.id)
+ }
+
+ if let Some(build_args) = &mut config.build_args {
+ build_args.retain(|v| {
+ !empty_or_only_spaces(&v.variable)
+ && !empty_or_only_spaces(&v.value)
+ })
+ }
+ if let Some(extra_args) = &mut config.extra_args {
+ extra_args.retain(|v| !empty_or_only_spaces(v))
+ }
+
+ let config_doc = to_document(&config)
+ .context("failed to serialize config to bson document")?;
+
+ update_one_by_id(
+ &db_client().await.builds,
+ &build.id,
+ mungos::update::Update::FlattenSet(
+ doc! { "config": config_doc },
+ ),
+ None,
+ )
+ .await
+ .context("failed to update build on database")?;
+
+ let mut update =
+ make_update(&build, Operation::UpdateBuild, &user);
+
+ update.push_simple_log(
+ "build update",
+ serde_json::to_string_pretty(&config)
+ .context("failed to serialize config to json")?,
+ );
+
+ update.finalize();
+
+ add_update(update).await?;
+
+ let build = Build::get_resource(&build.id).await?;
+ Ok(build)
+ }
+}
diff --git a/bin/core/src/api/write/builder.rs b/bin/core/src/api/write/builder.rs
new file mode 100644
index 000000000..30604ad6c
--- /dev/null
+++ b/bin/core/src/api/write/builder.rs
@@ -0,0 +1,283 @@
+use std::str::FromStr;
+
+use anyhow::{anyhow, Context};
+use async_trait::async_trait;
+use monitor_client::{
+ api::write::*,
+ entities::{
+ builder::{
+ Builder, PartialBuilderConfig, PartialServerBuilderConfig,
+ },
+ monitor_timestamp,
+ permission::PermissionLevel,
+ server::Server,
+ update::{Log, ResourceTarget, Update},
+ user::User,
+ Operation,
+ },
+};
+use mungos::{
+ by_id::{delete_one_by_id, update_one_by_id},
+ mongodb::bson::{doc, oid::ObjectId, to_document},
+};
+use resolver_api::Resolve;
+
+use crate::{
+ helpers::{
+ create_permission, remove_from_recently_viewed,
+ resource::{delete_all_permissions_on_resource, StateResource},
+ update::{add_update, make_update},
+ },
+ state::{db_client, State},
+};
+
+#[instrument(skip(user))]
+async fn validate_config(
+ config: &mut PartialBuilderConfig,
+ user: &User,
+) -> anyhow::Result<()> {
+ match config {
+ PartialBuilderConfig::Server(PartialServerBuilderConfig {
+ server_id: Some(server_id),
+ }) if !server_id.is_empty() => {
+ let server = Server::get_resource_check_permissions(
+ server_id,
+ user,
+ PermissionLevel::Write,
+ )
+ .await?;
+ *server_id = server.id;
+ }
+ _ => {}
+ }
+ Ok(())
+}
+
+#[async_trait]
+impl Resolve for State {
+ #[instrument(name = "CreateBuilder", skip(self, user))]
+ async fn resolve(
+ &self,
+ CreateBuilder { name, mut config }: CreateBuilder,
+ user: User,
+ ) -> anyhow::Result