mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
refactor public/private gateways
This commit is contained in:
251
core/Cargo.lock
generated
251
core/Cargo.lock
generated
@@ -116,6 +116,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi-width"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "219e3ce6f2611d83b51ec2098a12702112c29e57203a6b0a0929b2cddb486608"
|
||||
dependencies = [
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.19"
|
||||
@@ -181,6 +190,12 @@ dependencies = [
|
||||
"derive_arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "archery"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eae2ed21cd55021f05707a807a5fc85695dafb98832921f6cfa06db67ca5b869"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.9"
|
||||
@@ -306,9 +321,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-compression"
|
||||
version = "0.4.25"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40f6024f3f856663b45fd0c9b6f2024034a702f453549449e0d84a305900dad4"
|
||||
checksum = "ddb939d66e4ae03cee6091612804ba446b12878410cfa17f785f4dd67d4014e8"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"flate2",
|
||||
@@ -334,9 +349,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "2.4.1"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1237c0ae75a0f3765f58910ff9cdd0a12eeb39ab2f4c7de23262f337f0aacbb3"
|
||||
checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca"
|
||||
dependencies = [
|
||||
"async-lock",
|
||||
"cfg-if",
|
||||
@@ -345,10 +360,9 @@ dependencies = [
|
||||
"futures-lite",
|
||||
"parking",
|
||||
"polling",
|
||||
"rustix 1.0.7",
|
||||
"rustix 1.0.8",
|
||||
"slab",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -364,9 +378,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-process"
|
||||
version = "2.3.1"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cde3f4e40e6021d7acffc90095cbd6dc54cb593903d1de5832f435eb274b85dc"
|
||||
checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00"
|
||||
dependencies = [
|
||||
"async-channel 2.5.0",
|
||||
"async-io",
|
||||
@@ -377,8 +391,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"event-listener 5.4.0",
|
||||
"futures-lite",
|
||||
"rustix 1.0.7",
|
||||
"tracing",
|
||||
"rustix 1.0.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -394,9 +407,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-signal"
|
||||
version = "0.2.11"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7605a4e50d4b06df3898d5a70bf5fde51ed9059b0434b73105193bc27acce0d"
|
||||
checksum = "f567af260ef69e1d52c2b560ce0ea230763e6fbb9214a85d768760a920e3e3c1"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"async-lock",
|
||||
@@ -404,10 +417,10 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"rustix 1.0.7",
|
||||
"rustix 1.0.8",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -472,9 +485,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-rs"
|
||||
version = "1.13.2"
|
||||
version = "1.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08b5d4e069cbc868041a64bd68dc8cb39a0d79585cd6c5a24caa8c2d622121be"
|
||||
checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba"
|
||||
dependencies = [
|
||||
"aws-lc-sys",
|
||||
"zeroize",
|
||||
@@ -950,9 +963,9 @@ checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.29"
|
||||
version = "1.2.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362"
|
||||
checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
@@ -1340,9 +1353,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.2"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
@@ -1403,7 +1416,7 @@ dependencies = [
|
||||
"futures-core",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"rustix 1.0.7",
|
||||
"rustix 1.0.8",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
@@ -1491,9 +1504,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek"
|
||||
version = "4.2.0"
|
||||
version = "4.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "373b7c5dbd637569a2cca66e8d66b8c446a1e7bf064ea321d265d7b3dfe7c97e"
|
||||
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
@@ -1829,7 +1842,7 @@ version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
|
||||
dependencies = [
|
||||
"curve25519-dalek 4.2.0",
|
||||
"curve25519-dalek 4.1.3",
|
||||
"ed25519 2.2.3",
|
||||
"rand_core 0.6.4",
|
||||
"serde",
|
||||
@@ -2073,9 +2086,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fiat-crypto"
|
||||
version = "0.3.0"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24"
|
||||
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
@@ -2602,9 +2615,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hifijson"
|
||||
version = "0.2.2"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9958ab3ce3170c061a27679916bd9b969eceeb5e8b120438e6751d0987655c42"
|
||||
checksum = "0a7763b98ba8a24f59e698bf9ab197e7676c640d6455d1580b4ce7dc560f0f0d"
|
||||
|
||||
[[package]]
|
||||
name = "hkdf"
|
||||
@@ -2753,9 +2766,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.15"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f66d5bd4c6f02bf0542fad85d626775bab9258cf795a4256dcaf3161114d1df"
|
||||
checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
@@ -2769,7 +2782,7 @@ dependencies = [
|
||||
"libc",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"socket2 0.6.0",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
@@ -2946,13 +2959,28 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "imbl"
|
||||
version = "4.0.1"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ae128b3bc67ed43ec0a7bb1c337a9f026717628b3c4033f07ded1da3e854951"
|
||||
checksum = "33afdc5d333c1a43f1f640bfc6ad3788729e5b2f18472e5d33a9187315257f8e"
|
||||
dependencies = [
|
||||
"archery",
|
||||
"bitmaps",
|
||||
"imbl-sized-chunks",
|
||||
"rand_core 0.6.4",
|
||||
"rand_core 0.9.3",
|
||||
"rand_xoshiro",
|
||||
"serde",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imbl"
|
||||
version = "6.0.0"
|
||||
source = "git+https://github.com/dr-bonez/imbl.git?branch=bugfix%2Fordmap-lifetimes#897cf45b8c32bbee760d1348872724d4d9987ffe"
|
||||
dependencies = [
|
||||
"archery",
|
||||
"bitmaps",
|
||||
"imbl-sized-chunks",
|
||||
"rand_core 0.9.3",
|
||||
"rand_xoshiro",
|
||||
"serde",
|
||||
"version_check",
|
||||
@@ -2969,10 +2997,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "imbl-value"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/Start9Labs/imbl-value.git#229506ca83ae26bd78968719e5a78631deb39250"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80b000e99a562d9598ae56029f675dbf1104e8aed5a9b074824a752de0a61f39"
|
||||
dependencies = [
|
||||
"imbl",
|
||||
"imbl 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"yasi",
|
||||
@@ -2980,11 +3009,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "imbl-value"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c04359f6198e92e1986d221cfa7de62cd4c9c27880dffb2f98b6eaaec40cde4f"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/Start9Labs/imbl-value.git#82b91f973d67139ce5b3f662407f436bc64d2fe9"
|
||||
dependencies = [
|
||||
"imbl",
|
||||
"imbl 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"yasi",
|
||||
@@ -3072,9 +3100,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "io-uring"
|
||||
version = "0.7.8"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013"
|
||||
checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"cfg-if",
|
||||
@@ -3087,7 +3115,7 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
|
||||
dependencies = [
|
||||
"socket2",
|
||||
"socket2 0.5.10",
|
||||
"widestring",
|
||||
"windows-sys 0.48.0",
|
||||
"winreg",
|
||||
@@ -3288,7 +3316,7 @@ dependencies = [
|
||||
name = "json-patch"
|
||||
version = "0.2.7-alpha.0"
|
||||
dependencies = [
|
||||
"imbl-value 0.3.2",
|
||||
"imbl-value 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"json-ptr",
|
||||
"serde",
|
||||
]
|
||||
@@ -3297,8 +3325,8 @@ dependencies = [
|
||||
name = "json-ptr"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"imbl",
|
||||
"imbl-value 0.3.2",
|
||||
"imbl 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"imbl-value 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
@@ -3308,7 +3336,7 @@ name = "jsonpath_lib"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/Start9Labs/jsonpath.git#1cacbd64afa2e1941a21fef06bad14317ba92f30"
|
||||
dependencies = [
|
||||
"imbl-value 0.3.0",
|
||||
"imbl-value 0.4.0 (git+https://github.com/Start9Labs/imbl-value.git)",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -3422,13 +3450,13 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638"
|
||||
checksum = "4488594b9328dee448adb906d8b126d9b7deb7cf5c22161ee591610bb1be83c0"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"libc",
|
||||
"redox_syscall 0.5.13",
|
||||
"redox_syscall 0.5.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3486,9 +3514,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
|
||||
|
||||
[[package]]
|
||||
name = "litrs"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
|
||||
checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@@ -3658,9 +3686,9 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.9.5"
|
||||
version = "0.9.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
|
||||
checksum = "483758ad303d734cec05e5c12b41d7e93e6a6390c5e9dae6bdeb7c1259012d28"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -3732,7 +3760,7 @@ dependencies = [
|
||||
"num_enum",
|
||||
"openssl",
|
||||
"patch-db",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"rpc-toolkit",
|
||||
@@ -4187,7 +4215,7 @@ checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.5.13",
|
||||
"redox_syscall 0.5.15",
|
||||
"smallvec",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
@@ -4199,8 +4227,8 @@ dependencies = [
|
||||
"async-trait",
|
||||
"fd-lock-rs",
|
||||
"futures",
|
||||
"imbl",
|
||||
"imbl-value 0.3.2",
|
||||
"imbl 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"imbl-value 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"json-patch",
|
||||
"json-ptr",
|
||||
"lazy_static",
|
||||
@@ -4409,17 +4437,16 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "3.8.0"
|
||||
version = "3.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b53a684391ad002dd6a596ceb6c74fd004fdce75f4be2e3f615068abbea5fd50"
|
||||
checksum = "8ee9b2fa7a4517d2c91ff5bc6c297a427a96749d15f98fcdbb22c05571a4d4b7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"concurrent-queue 2.5.0",
|
||||
"hermit-abi",
|
||||
"pin-project-lite",
|
||||
"rustix 1.0.7",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
"rustix 1.0.8",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4460,9 +4487,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.35"
|
||||
version = "0.2.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a"
|
||||
checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 2.0.104",
|
||||
@@ -4545,7 +4572,7 @@ dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"lazy_static",
|
||||
"num-traits",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_xorshift",
|
||||
"regex-syntax 0.8.5",
|
||||
@@ -4605,11 +4632,11 @@ checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac"
|
||||
|
||||
[[package]]
|
||||
name = "pty-process"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a480f2bcfed0fee5dd30e529d985c2ff4457dc7468b3c0dcb92b9fd2b14c6b9"
|
||||
checksum = "71cec9e2670207c5ebb9e477763c74436af3b9091dd550b9fb3c1bec7f3ea266"
|
||||
dependencies = [
|
||||
"rustix 1.0.7",
|
||||
"rustix 1.0.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4699,9 +4726,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.1"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
@@ -4784,11 +4811,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rand_xoshiro"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa"
|
||||
checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41"
|
||||
dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4830,9 +4857,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.13"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
|
||||
checksum = "7e8af0dde094006011e6a740d4879319439489813bd0bcdc7d821beaeeff48ec"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
]
|
||||
@@ -4965,9 +4992,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reqwest_cookie_store"
|
||||
version = "0.8.0"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0b36498c7452f11b1833900f31fbb01fc46be20992a50269c88cf59d79f54e9"
|
||||
checksum = "2314c325724fea278d44c13a525ebf60074e33c05f13b4345c076eb65b2446b3"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"cookie_store",
|
||||
@@ -5019,7 +5046,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rpc-toolkit"
|
||||
version = "0.3.1"
|
||||
source = "git+https://github.com/Start9Labs/rpc-toolkit.git?branch=master#f83d9d9934036c1bc929073cad537774ecdbb5f2"
|
||||
source = "git+https://github.com/Start9Labs/rpc-toolkit.git?branch=master#b73d3375b5fec21df6221e644ae0a7c623e81a62"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
@@ -5028,7 +5055,7 @@ dependencies = [
|
||||
"futures",
|
||||
"http",
|
||||
"http-body-util",
|
||||
"imbl-value 0.3.2",
|
||||
"imbl-value 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.14.0",
|
||||
"lazy_format",
|
||||
"lazy_static",
|
||||
@@ -5131,15 +5158,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.7"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
||||
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"errno 0.3.13",
|
||||
"libc",
|
||||
"linux-raw-sys 0.9.4",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5264,17 +5291,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustyline-async"
|
||||
version = "0.4.6"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "055f3061e6c11d3c981f55b9c60da44d0413344ceeaf2fb479450f18dc9c2675"
|
||||
checksum = "6e07ddce8399c61495b405dc94d4f30d01fc1c5e1238f10b9c09940678bc81ab"
|
||||
dependencies = [
|
||||
"ansi-width",
|
||||
"crossterm",
|
||||
"futures-util",
|
||||
"pin-project",
|
||||
"thingbuf",
|
||||
"thiserror 2.0.12",
|
||||
"unicode-segmentation",
|
||||
"unicode-width 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5426,9 +5453,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.140"
|
||||
version = "1.0.141"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||
checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
|
||||
dependencies = [
|
||||
"indexmap 2.10.0",
|
||||
"itoa",
|
||||
@@ -5727,6 +5754,16 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-nohash-hasher"
|
||||
version = "0.2.1"
|
||||
@@ -6067,8 +6104,8 @@ dependencies = [
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"id-pool",
|
||||
"imbl",
|
||||
"imbl-value 0.3.2",
|
||||
"imbl 6.0.0 (git+https://github.com/dr-bonez/imbl.git?branch=bugfix%2Fordmap-lifetimes)",
|
||||
"imbl-value 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"include_dir",
|
||||
"indexmap 2.10.0",
|
||||
"indicatif",
|
||||
@@ -6110,7 +6147,7 @@ dependencies = [
|
||||
"proptest-derive",
|
||||
"pty-process",
|
||||
"qrcode",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"reqwest_cookie_store",
|
||||
@@ -6131,7 +6168,7 @@ dependencies = [
|
||||
"shell-words",
|
||||
"signal-hook",
|
||||
"simple-logging",
|
||||
"socket2",
|
||||
"socket2 0.5.10",
|
||||
"sqlx",
|
||||
"sscanf",
|
||||
"ssh-key",
|
||||
@@ -6301,7 +6338,7 @@ dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.3",
|
||||
"once_cell",
|
||||
"rustix 1.0.7",
|
||||
"rustix 1.0.8",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@@ -6498,7 +6535,7 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"socket2",
|
||||
"socket2 0.5.10",
|
||||
"tokio-macros",
|
||||
"tracing",
|
||||
"windows-sys 0.52.0",
|
||||
@@ -6708,7 +6745,7 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"prost",
|
||||
"socket2",
|
||||
"socket2 0.5.10",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tower 0.4.13",
|
||||
@@ -6981,7 +7018,7 @@ dependencies = [
|
||||
"httparse",
|
||||
"log",
|
||||
"native-tls",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"sha1",
|
||||
"thiserror 2.0.12",
|
||||
"url",
|
||||
@@ -7358,14 +7395,14 @@ version = "0.26.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
|
||||
dependencies = [
|
||||
"webpki-roots 1.0.1",
|
||||
"webpki-roots 1.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502"
|
||||
checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
@@ -7388,7 +7425,7 @@ version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7"
|
||||
dependencies = [
|
||||
"redox_syscall 0.5.13",
|
||||
"redox_syscall 0.5.15",
|
||||
"wasite",
|
||||
]
|
||||
|
||||
@@ -7811,7 +7848,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rustix 1.0.7",
|
||||
"rustix 1.0.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7888,9 +7925,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zbus"
|
||||
version = "5.8.0"
|
||||
version = "5.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597f45e98bc7e6f0988276012797855613cd8269e23b5be62cc4e5d28b7e515d"
|
||||
checksum = "4bb4f9a464286d42851d18a605f7193b8febaf5b0919d71c6399b7b26e5b0aad"
|
||||
dependencies = [
|
||||
"async-broadcast",
|
||||
"async-executor",
|
||||
@@ -7921,9 +7958,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zbus_macros"
|
||||
version = "5.8.0"
|
||||
version = "5.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5c8e4e14dcdd9d97a98b189cd1220f30e8394ad271e8c987da84f73693862c2"
|
||||
checksum = "ef9859f68ee0c4ee2e8cde84737c78e3f4c54f946f2a38645d0d4c7a95327659"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
|
||||
58
core/models/src/id/gateway.rs
Normal file
58
core/models/src/id/gateway.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use std::convert::Infallible;
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
use yasi::InternedString;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, TS)]
|
||||
#[ts(type = "string")]
|
||||
pub struct GatewayId(InternedString);
|
||||
impl GatewayId {
|
||||
pub fn as_str(&self) -> &str {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
impl<T> From<T> for GatewayId
|
||||
where
|
||||
T: Into<InternedString>,
|
||||
{
|
||||
fn from(value: T) -> Self {
|
||||
Self(value.into())
|
||||
}
|
||||
}
|
||||
impl FromStr for GatewayId {
|
||||
type Err = Infallible;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(GatewayId(InternedString::intern(s)))
|
||||
}
|
||||
}
|
||||
impl AsRef<GatewayId> for GatewayId {
|
||||
fn as_ref(&self) -> &GatewayId {
|
||||
self
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for GatewayId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", &self.0)
|
||||
}
|
||||
}
|
||||
impl AsRef<str> for GatewayId {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
impl AsRef<Path> for GatewayId {
|
||||
fn as_ref(&self) -> &Path {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
impl<'de> Deserialize<'de> for GatewayId {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::de::Deserializer<'de>,
|
||||
{
|
||||
Ok(GatewayId(serde::Deserialize::deserialize(deserializer)?))
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use yasi::InternedString;
|
||||
|
||||
mod action;
|
||||
mod gateway;
|
||||
mod health_check;
|
||||
mod host;
|
||||
mod image;
|
||||
@@ -16,6 +17,7 @@ mod service_interface;
|
||||
mod volume;
|
||||
|
||||
pub use action::ActionId;
|
||||
pub use gateway::GatewayId;
|
||||
pub use health_check::HealthCheckId;
|
||||
pub use host::HostId;
|
||||
pub use image::ImageId;
|
||||
|
||||
@@ -124,8 +124,11 @@ id-pool = { version = "0.2.2", default-features = false, features = [
|
||||
"serde",
|
||||
"u16",
|
||||
] }
|
||||
imbl = "4.0.1"
|
||||
imbl-value = "0.3.2"
|
||||
imbl = { version = "6", git = "https://github.com/dr-bonez/imbl.git", branch = "bugfix/ordmap-lifetimes", features = [
|
||||
"serde",
|
||||
"small-chunks",
|
||||
] }
|
||||
imbl-value = "0.4.0"
|
||||
include_dir = { version = "0.7.3", features = ["metadata"] }
|
||||
indexmap = { version = "2.0.2", features = ["serde"] }
|
||||
indicatif = { version = "0.17.7", features = ["tokio"] }
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use tokio::process::Command;
|
||||
@@ -48,7 +47,7 @@ async fn setup_or_init(
|
||||
update_phase.complete();
|
||||
reboot_phase.start();
|
||||
return Ok(Err(Shutdown {
|
||||
export_args: None,
|
||||
disk_guid: None,
|
||||
restart: true,
|
||||
}));
|
||||
}
|
||||
@@ -103,7 +102,7 @@ async fn setup_or_init(
|
||||
.expect("context dropped");
|
||||
|
||||
return Ok(Err(Shutdown {
|
||||
export_args: None,
|
||||
disk_guid: None,
|
||||
restart: true,
|
||||
}));
|
||||
}
|
||||
@@ -117,7 +116,9 @@ async fn setup_or_init(
|
||||
server.serve_setup(ctx.clone());
|
||||
|
||||
let mut shutdown = ctx.shutdown.subscribe();
|
||||
shutdown.recv().await.expect("context dropped");
|
||||
if let Some(shutdown) = shutdown.recv().await.expect("context dropped") {
|
||||
return Ok(Err(shutdown));
|
||||
}
|
||||
|
||||
tokio::task::yield_now().await;
|
||||
if let Err(e) = Command::new("killall")
|
||||
@@ -183,7 +184,7 @@ async fn setup_or_init(
|
||||
let mut reboot_phase = handle.add_phase("Rebooting".into(), Some(1));
|
||||
reboot_phase.start();
|
||||
return Ok(Err(Shutdown {
|
||||
export_args: Some((disk_guid, Path::new(DATA_DIR).to_owned())),
|
||||
disk_guid: Some(disk_guid),
|
||||
restart: true,
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
use cookie::{Cookie, Expiration, SameSite};
|
||||
use cookie_store::{CookieStore, RawCookie};
|
||||
use cookie_store::CookieStore;
|
||||
use imbl_value::InternedString;
|
||||
use josekit::jwk::Jwk;
|
||||
use once_cell::sync::OnceCell;
|
||||
@@ -13,7 +13,7 @@ use reqwest::Proxy;
|
||||
use reqwest_cookie_store::CookieStoreMutex;
|
||||
use rpc_toolkit::reqwest::{Client, Url};
|
||||
use rpc_toolkit::yajrc::RpcError;
|
||||
use rpc_toolkit::{call_remote_http, CallRemote, Context, Empty};
|
||||
use rpc_toolkit::{CallRemote, Context, Empty};
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio_tungstenite::{MaybeTlsStream, WebSocketStream};
|
||||
@@ -27,7 +27,6 @@ use crate::middleware::auth::AuthContext;
|
||||
use crate::prelude::*;
|
||||
use crate::rpc_continuations::Guid;
|
||||
use crate::tunnel::context::TunnelContext;
|
||||
use crate::tunnel::TUNNEL_DEFAULT_PORT;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CliContextSeed {
|
||||
|
||||
@@ -174,7 +174,7 @@ impl RpcContext {
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
webserver.try_upgrade(|a| net_ctrl.net_iface.upgrade_listener(a))?;
|
||||
webserver.try_upgrade(|a| net_ctrl.net_iface.watcher.upgrade_listener(a))?;
|
||||
let os_net_service = net_ctrl.os_bindings().await?;
|
||||
(net_ctrl, os_net_service)
|
||||
};
|
||||
|
||||
@@ -25,6 +25,7 @@ use crate::prelude::*;
|
||||
use crate::progress::FullProgressTracker;
|
||||
use crate::rpc_continuations::{Guid, RpcContinuation, RpcContinuations};
|
||||
use crate::setup::SetupProgress;
|
||||
use crate::shutdown::Shutdown;
|
||||
use crate::util::net::WebSocketExt;
|
||||
use crate::MAIN_DATA;
|
||||
|
||||
@@ -71,7 +72,8 @@ pub struct SetupContextSeed {
|
||||
pub progress: FullProgressTracker,
|
||||
pub task: OnceCell<NonDetachingJoinHandle<()>>,
|
||||
pub result: OnceCell<Result<(SetupResult, RpcContext), Error>>,
|
||||
pub shutdown: Sender<()>,
|
||||
pub disk_guid: OnceCell<Arc<String>>,
|
||||
pub shutdown: Sender<Option<Shutdown>>,
|
||||
pub rpc_continuations: RpcContinuations,
|
||||
}
|
||||
|
||||
@@ -97,6 +99,7 @@ impl SetupContext {
|
||||
progress: FullProgressTracker::new(),
|
||||
task: OnceCell::new(),
|
||||
result: OnceCell::new(),
|
||||
disk_guid: OnceCell::new(),
|
||||
shutdown,
|
||||
rpc_continuations: RpcContinuations::new(),
|
||||
})))
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use exver::{Version, VersionRange};
|
||||
use imbl::{OrdMap, OrdSet};
|
||||
use imbl_value::InternedString;
|
||||
use ipnet::IpNet;
|
||||
use isocountry::CountryCode;
|
||||
use itertools::Itertools;
|
||||
use models::PackageId;
|
||||
use lazy_static::lazy_static;
|
||||
use models::{GatewayId, PackageId};
|
||||
use openssl::hash::MessageDigest;
|
||||
use patch_db::{HasModel, Value};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -71,7 +73,8 @@ impl Public {
|
||||
net: NetInfo {
|
||||
assigned_port: None,
|
||||
assigned_ssl_port: Some(443),
|
||||
public: false,
|
||||
private_disabled: OrdSet::new(),
|
||||
public_enabled: OrdSet::new(),
|
||||
},
|
||||
},
|
||||
)]
|
||||
@@ -89,7 +92,7 @@ impl Public {
|
||||
enabled: true,
|
||||
..Default::default()
|
||||
},
|
||||
network_interfaces: BTreeMap::new(),
|
||||
network_interfaces: OrdMap::new(),
|
||||
acme: BTreeMap::new(),
|
||||
},
|
||||
status_info: ServerStatus {
|
||||
@@ -186,9 +189,9 @@ pub struct ServerInfo {
|
||||
pub struct NetworkInfo {
|
||||
pub wifi: WifiInfo,
|
||||
pub host: Host,
|
||||
#[ts(as = "BTreeMap::<String, NetworkInterfaceInfo>")]
|
||||
#[ts(as = "BTreeMap::<GatewayId, NetworkInterfaceInfo>")]
|
||||
#[serde(default)]
|
||||
pub network_interfaces: BTreeMap<InternedString, NetworkInterfaceInfo>,
|
||||
pub network_interfaces: OrdMap<GatewayId, NetworkInterfaceInfo>,
|
||||
#[serde(default)]
|
||||
pub acme: BTreeMap<AcmeProvider, AcmeSettings>,
|
||||
}
|
||||
@@ -199,9 +202,33 @@ pub struct NetworkInfo {
|
||||
#[ts(export)]
|
||||
pub struct NetworkInterfaceInfo {
|
||||
pub public: Option<bool>,
|
||||
pub secure: Option<bool>,
|
||||
pub ip_info: Option<IpInfo>,
|
||||
}
|
||||
impl NetworkInterfaceInfo {
|
||||
pub fn loopback() -> (&'static GatewayId, &'static Self) {
|
||||
lazy_static! {
|
||||
static ref LO: GatewayId = GatewayId::from("lo");
|
||||
static ref LOOPBACK: NetworkInterfaceInfo = NetworkInterfaceInfo {
|
||||
public: Some(false),
|
||||
secure: Some(true),
|
||||
ip_info: Some(IpInfo {
|
||||
name: "lo".into(),
|
||||
scope_id: 1,
|
||||
device_type: None,
|
||||
subnets: [
|
||||
IpNet::new(Ipv4Addr::LOCALHOST.into(), 8).unwrap(),
|
||||
IpNet::new(Ipv6Addr::LOCALHOST.into(), 128).unwrap(),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
wan_ip: None,
|
||||
ntp_servers: Default::default(),
|
||||
}),
|
||||
};
|
||||
}
|
||||
(&*LO, &*LOOPBACK)
|
||||
}
|
||||
pub fn public(&self) -> bool {
|
||||
self.public.unwrap_or_else(|| {
|
||||
!self.ip_info.as_ref().map_or(true, |ip_info| {
|
||||
@@ -233,6 +260,14 @@ impl NetworkInterfaceInfo {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn secure(&self) -> bool {
|
||||
self.secure.unwrap_or_else(|| {
|
||||
self.ip_info.as_ref().map_or(false, |ip_info| {
|
||||
ip_info.device_type == Some(NetworkInterfaceType::Wireguard)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize, TS, HasModel)]
|
||||
@@ -245,10 +280,10 @@ pub struct IpInfo {
|
||||
pub scope_id: u32,
|
||||
pub device_type: Option<NetworkInterfaceType>,
|
||||
#[ts(type = "string[]")]
|
||||
pub subnets: BTreeSet<IpNet>,
|
||||
pub subnets: OrdSet<IpNet>,
|
||||
pub wan_ip: Option<Ipv4Addr>,
|
||||
#[ts(type = "string[]")]
|
||||
pub ntp_servers: BTreeSet<InternedString>,
|
||||
pub ntp_servers: OrdSet<InternedString>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize, TS)]
|
||||
|
||||
@@ -3,6 +3,7 @@ use std::marker::PhantomData;
|
||||
use std::str::FromStr;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use imbl::OrdMap;
|
||||
pub use imbl_value::Value;
|
||||
use patch_db::value::InternedString;
|
||||
pub use patch_db::{HasModel, MutateResult, PatchDb};
|
||||
@@ -199,6 +200,18 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> Map for OrdMap<A, B>
|
||||
where
|
||||
A: serde::Serialize + serde::de::DeserializeOwned + Clone + Ord + AsRef<str>,
|
||||
B: serde::Serialize + serde::de::DeserializeOwned + Clone,
|
||||
{
|
||||
type Key = A;
|
||||
type Value = B;
|
||||
fn key_str(key: &Self::Key) -> Result<impl AsRef<str>, Error> {
|
||||
Ok(key.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Map> Model<T>
|
||||
where
|
||||
T::Value: Serialize,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rpc_toolkit::yajrc::RpcError;
|
||||
@@ -12,7 +11,6 @@ use crate::init::SYSTEM_REBUILD_PATH;
|
||||
use crate::prelude::*;
|
||||
use crate::shutdown::Shutdown;
|
||||
use crate::util::io::delete_file;
|
||||
use crate::DATA_DIR;
|
||||
|
||||
pub fn diagnostic<C: Context>() -> ParentHandler<C> {
|
||||
ParentHandler::new()
|
||||
@@ -70,10 +68,7 @@ pub fn error(ctx: DiagnosticContext) -> Result<Arc<RpcError>, Error> {
|
||||
pub fn restart(ctx: DiagnosticContext) -> Result<(), Error> {
|
||||
ctx.shutdown
|
||||
.send(Shutdown {
|
||||
export_args: ctx
|
||||
.disk_guid
|
||||
.clone()
|
||||
.map(|guid| (guid, Path::new(DATA_DIR).to_owned())),
|
||||
disk_guid: ctx.disk_guid.clone(),
|
||||
restart: true,
|
||||
})
|
||||
.map_err(|_| eyre!("receiver dropped"))
|
||||
|
||||
@@ -35,8 +35,8 @@ impl Hostname {
|
||||
|
||||
pub fn generate_hostname() -> Hostname {
|
||||
let mut rng = rng();
|
||||
let adjective = &ADJECTIVES[rng.gen_range(0..ADJECTIVES.len())];
|
||||
let noun = &NOUNS[rng.gen_range(0..NOUNS.len())];
|
||||
let adjective = &ADJECTIVES[rng.random_range(0..ADJECTIVES.len())];
|
||||
let noun = &NOUNS[rng.random_range(0..NOUNS.len())];
|
||||
Hostname(InternedString::from_display(&lazy_format!(
|
||||
"{adjective}-{noun}"
|
||||
)))
|
||||
|
||||
@@ -216,7 +216,7 @@ pub async fn init(
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
webserver.try_upgrade(|a| net_ctrl.net_iface.upgrade_listener(a))?;
|
||||
webserver.try_upgrade(|a| net_ctrl.net_iface.watcher.upgrade_listener(a))?;
|
||||
let os_net_service = net_ctrl.os_bindings().await?;
|
||||
start_net.complete();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::future::Future;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::time::Duration;
|
||||
@@ -18,7 +19,6 @@ use trust_dns_server::server::{Request, RequestHandler, ResponseHandler, Respons
|
||||
use trust_dns_server::ServerFuture;
|
||||
|
||||
use crate::net::forward::START9_BRIDGE_IFACE;
|
||||
use crate::util::sync::Watch;
|
||||
use crate::util::Invoke;
|
||||
use crate::{Error, ErrorKind, ResultExt};
|
||||
|
||||
@@ -140,7 +140,9 @@ impl RequestHandler for Resolver {
|
||||
|
||||
impl DnsController {
|
||||
#[instrument(skip_all)]
|
||||
pub async fn init(mut lxcbr_status: Watch<bool>) -> Result<Self, Error> {
|
||||
pub async fn init(
|
||||
bridge_activated: impl Future<Output = ()> + Send + Sync + 'static,
|
||||
) -> Result<Self, Error> {
|
||||
let services = Arc::new(RwLock::new(BTreeMap::new()));
|
||||
|
||||
let mut server = ServerFuture::new(Resolver {
|
||||
@@ -160,7 +162,7 @@ impl DnsController {
|
||||
.with_kind(ErrorKind::Network)?,
|
||||
);
|
||||
|
||||
lxcbr_status.wait_for(|a| *a).await;
|
||||
bridge_activated.await;
|
||||
|
||||
Command::new("resolvectl")
|
||||
.arg("dns")
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::net::{IpAddr, SocketAddr, SocketAddrV6};
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use futures::channel::oneshot;
|
||||
use helpers::NonDetachingJoinHandle;
|
||||
use id_pool::IdPool;
|
||||
use imbl_value::InternedString;
|
||||
use imbl::OrdMap;
|
||||
use models::GatewayId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::process::Command;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::db::model::public::NetworkInterfaceInfo;
|
||||
use crate::net::network_interface::{DynInterfaceFilter, InterfaceFilter};
|
||||
use crate::net::utils::ipv6_is_link_local;
|
||||
use crate::prelude::*;
|
||||
use crate::util::sync::Watch;
|
||||
use crate::util::Invoke;
|
||||
@@ -39,106 +42,162 @@ impl AvailablePorts {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ForwardRequest {
|
||||
public: bool,
|
||||
external: u16,
|
||||
target: SocketAddr,
|
||||
filter: DynInterfaceFilter,
|
||||
rc: Weak<()>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct ForwardState {
|
||||
requested: BTreeMap<u16, ForwardRequest>,
|
||||
current: BTreeMap<u16, BTreeMap<InternedString, SocketAddr>>,
|
||||
struct ForwardEntry {
|
||||
external: u16,
|
||||
target: SocketAddr,
|
||||
prev_filter: DynInterfaceFilter,
|
||||
forwards: BTreeMap<SocketAddr, GatewayId>,
|
||||
rc: Weak<()>,
|
||||
}
|
||||
impl ForwardState {
|
||||
async fn sync(
|
||||
impl ForwardEntry {
|
||||
fn new(external: u16, target: SocketAddr, rc: Weak<()>) -> Self {
|
||||
Self {
|
||||
external,
|
||||
target,
|
||||
prev_filter: false.into_dyn(),
|
||||
forwards: BTreeMap::new(),
|
||||
rc,
|
||||
}
|
||||
}
|
||||
|
||||
fn take(&mut self) -> Self {
|
||||
Self {
|
||||
external: self.external,
|
||||
target: self.target,
|
||||
prev_filter: std::mem::replace(&mut self.prev_filter, false.into_dyn()),
|
||||
forwards: std::mem::take(&mut self.forwards),
|
||||
rc: self.rc.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn destroy(mut self) -> Result<(), Error> {
|
||||
while let Some((source, interface)) = self.forwards.pop_first() {
|
||||
unforward(interface.as_str(), source, self.target).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update(
|
||||
&mut self,
|
||||
interfaces: &BTreeMap<InternedString, (bool, Vec<Ipv4Addr>)>,
|
||||
ip_info: &OrdMap<GatewayId, NetworkInterfaceInfo>,
|
||||
filter: Option<DynInterfaceFilter>,
|
||||
) -> Result<(), Error> {
|
||||
let private_interfaces = interfaces
|
||||
if self.rc.strong_count() == 0 {
|
||||
return self.take().destroy().await;
|
||||
}
|
||||
let filter_ref = filter.as_ref().unwrap_or(&self.prev_filter);
|
||||
let mut keep = BTreeSet::<SocketAddr>::new();
|
||||
for (iface, info) in ip_info
|
||||
.iter()
|
||||
.filter(|(_, (public, _))| !*public)
|
||||
.map(|(i, _)| i)
|
||||
.collect::<BTreeSet<_>>();
|
||||
let all_interfaces = interfaces.keys().collect::<BTreeSet<_>>();
|
||||
self.requested.retain(|_, req| req.rc.strong_count() > 0);
|
||||
for external in self
|
||||
.requested
|
||||
.keys()
|
||||
.chain(self.current.keys())
|
||||
.copied()
|
||||
.collect::<BTreeSet<_>>()
|
||||
.chain([NetworkInterfaceInfo::loopback()])
|
||||
.filter(|(id, info)| filter_ref.filter(*id, *info))
|
||||
{
|
||||
match (
|
||||
self.requested.get(&external),
|
||||
self.current.get_mut(&external),
|
||||
) {
|
||||
(Some(req), Some(cur)) => {
|
||||
let expected = if req.public {
|
||||
&all_interfaces
|
||||
} else {
|
||||
&private_interfaces
|
||||
if let Some(ip_info) = &info.ip_info {
|
||||
for ipnet in &ip_info.subnets {
|
||||
let addr = match ipnet.addr() {
|
||||
IpAddr::V6(ip6) => SocketAddrV6::new(
|
||||
ip6,
|
||||
self.external,
|
||||
0,
|
||||
if ipv6_is_link_local(ip6) {
|
||||
ip_info.scope_id
|
||||
} else {
|
||||
0
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
ip => SocketAddr::new(ip, self.external),
|
||||
};
|
||||
let actual = cur.keys().collect::<BTreeSet<_>>();
|
||||
let mut to_rm = actual
|
||||
.difference(expected)
|
||||
.copied()
|
||||
.map(|i| (i.clone(), &interfaces[i].1))
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
let mut to_add = expected
|
||||
.difference(&actual)
|
||||
.copied()
|
||||
.map(|i| (i.clone(), &interfaces[i].1))
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
for interface in actual.intersection(expected).copied() {
|
||||
if cur[interface] != req.target {
|
||||
to_rm.insert(interface.clone(), &interfaces[interface].1);
|
||||
to_add.insert(interface.clone(), &interfaces[interface].1);
|
||||
}
|
||||
}
|
||||
for (interface, ips) in to_rm {
|
||||
for ip in ips {
|
||||
unforward(&*interface, (*ip, external).into(), cur[&interface]).await?;
|
||||
}
|
||||
cur.remove(&interface);
|
||||
}
|
||||
for (interface, ips) in to_add {
|
||||
cur.insert(interface.clone(), req.target);
|
||||
for ip in ips {
|
||||
forward(&*interface, (*ip, external).into(), cur[&interface]).await?;
|
||||
}
|
||||
keep.insert(addr);
|
||||
if !self.forwards.contains_key(&addr) {
|
||||
forward(iface.as_str(), addr, self.target).await?;
|
||||
self.forwards.insert(addr, iface.clone());
|
||||
}
|
||||
}
|
||||
(Some(req), None) => {
|
||||
let cur = self.current.entry(external).or_default();
|
||||
for interface in if req.public {
|
||||
&all_interfaces
|
||||
} else {
|
||||
&private_interfaces
|
||||
}
|
||||
.into_iter()
|
||||
.copied()
|
||||
{
|
||||
cur.insert(interface.clone(), req.target);
|
||||
for ip in &interfaces[interface].1 {
|
||||
forward(&**interface, (*ip, external).into(), req.target).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
(None, Some(cur)) => {
|
||||
let to_rm = cur.keys().cloned().collect::<BTreeSet<_>>();
|
||||
for interface in to_rm {
|
||||
for ip in &interfaces[&interface].1 {
|
||||
unforward(&*interface, (*ip, external).into(), cur[&interface]).await?;
|
||||
}
|
||||
cur.remove(&interface);
|
||||
}
|
||||
self.current.remove(&external);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
let rm = self
|
||||
.forwards
|
||||
.keys()
|
||||
.copied()
|
||||
.filter(|a| !keep.contains(a))
|
||||
.collect::<Vec<_>>();
|
||||
for rm in rm {
|
||||
if let Some((source, interface)) = self.forwards.remove_entry(&rm) {
|
||||
unforward(interface.as_str(), source, self.target).await?;
|
||||
}
|
||||
}
|
||||
if let Some(filter) = filter {
|
||||
self.prev_filter = filter;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_request(
|
||||
&mut self,
|
||||
ForwardRequest {
|
||||
external,
|
||||
target,
|
||||
filter,
|
||||
rc,
|
||||
}: ForwardRequest,
|
||||
ip_info: &OrdMap<GatewayId, NetworkInterfaceInfo>,
|
||||
) -> Result<(), Error> {
|
||||
if external != self.external || target != self.target {
|
||||
self.take().destroy().await?;
|
||||
*self = Self::new(external, target, rc);
|
||||
self.update(ip_info, Some(filter)).await?;
|
||||
} else {
|
||||
if self.prev_filter != filter {
|
||||
self.update(ip_info, Some(filter)).await?;
|
||||
}
|
||||
self.rc = rc;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Drop for ForwardEntry {
|
||||
fn drop(&mut self) {
|
||||
if !self.forwards.is_empty() {
|
||||
let take = self.take();
|
||||
tokio::spawn(async move {
|
||||
take.destroy().await.log_err();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ForwardState {
|
||||
state: BTreeMap<u16, ForwardEntry>,
|
||||
}
|
||||
impl ForwardState {
|
||||
async fn handle_request(
|
||||
&mut self,
|
||||
request: ForwardRequest,
|
||||
ip_info: &OrdMap<GatewayId, NetworkInterfaceInfo>,
|
||||
) -> Result<(), Error> {
|
||||
self.state
|
||||
.entry(request.external)
|
||||
.or_insert_with(|| ForwardEntry::new(request.external, request.target, Weak::new()))
|
||||
.update_request(request, ip_info)
|
||||
.await
|
||||
}
|
||||
async fn sync(
|
||||
&mut self,
|
||||
ip_info: &OrdMap<GatewayId, NetworkInterfaceInfo>,
|
||||
) -> Result<(), Error> {
|
||||
for entry in self.state.values_mut() {
|
||||
entry.update(ip_info, None).await?;
|
||||
}
|
||||
self.state.retain(|_, fwd| !fwd.forwards.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -150,87 +209,37 @@ fn err_has_exited<T>(_: T) -> Error {
|
||||
)
|
||||
}
|
||||
|
||||
pub struct LanPortForwardController {
|
||||
req: mpsc::UnboundedSender<(
|
||||
Option<(u16, ForwardRequest)>,
|
||||
oneshot::Sender<Result<(), Error>>,
|
||||
)>,
|
||||
pub struct PortForwardController {
|
||||
req: mpsc::UnboundedSender<(Option<ForwardRequest>, oneshot::Sender<Result<(), Error>>)>,
|
||||
_thread: NonDetachingJoinHandle<()>,
|
||||
}
|
||||
impl LanPortForwardController {
|
||||
pub fn new(mut ip_info: Watch<BTreeMap<InternedString, NetworkInterfaceInfo>>) -> Self {
|
||||
let (req_send, mut req_recv) = mpsc::unbounded_channel();
|
||||
impl PortForwardController {
|
||||
pub fn new(mut ip_info: Watch<OrdMap<GatewayId, NetworkInterfaceInfo>>) -> Self {
|
||||
let (req_send, mut req_recv) = mpsc::unbounded_channel::<(
|
||||
Option<ForwardRequest>,
|
||||
oneshot::Sender<Result<(), Error>>,
|
||||
)>();
|
||||
let thread = NonDetachingJoinHandle::from(tokio::spawn(async move {
|
||||
let mut state = ForwardState::default();
|
||||
let mut interfaces = ip_info.peek_and_mark_seen(|ip_info| {
|
||||
ip_info
|
||||
.iter()
|
||||
.map(|(iface, info)| {
|
||||
(
|
||||
iface.clone(),
|
||||
(
|
||||
info.public(),
|
||||
info.ip_info.as_ref().map_or(Vec::new(), |i| {
|
||||
i.subnets
|
||||
.iter()
|
||||
.filter_map(|s| {
|
||||
if let IpAddr::V4(ip) = s.addr() {
|
||||
Some(ip)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}),
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
let mut reply: Option<oneshot::Sender<Result<(), Error>>> = None;
|
||||
let mut interfaces = ip_info.read_and_mark_seen();
|
||||
loop {
|
||||
tokio::select! {
|
||||
msg = req_recv.recv() => {
|
||||
if let Some((msg, re)) = msg {
|
||||
if let Some((external, req)) = msg {
|
||||
state.requested.insert(external, req);
|
||||
if let Some(req) = msg {
|
||||
re.send(state.handle_request(req, &interfaces).await).ok();
|
||||
} else {
|
||||
re.send(state.sync(&interfaces).await).ok();
|
||||
}
|
||||
reply = Some(re);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ = ip_info.changed() => {
|
||||
interfaces = ip_info.peek(|ip_info| {
|
||||
ip_info
|
||||
.iter()
|
||||
.map(|(iface, info)| (iface.clone(), (
|
||||
info.public(),
|
||||
info.ip_info.as_ref().map_or(Vec::new(), |i| {
|
||||
i.subnets
|
||||
.iter()
|
||||
.filter_map(|s| {
|
||||
if let IpAddr::V4(ip) = s.addr() {
|
||||
Some(ip)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}),
|
||||
)))
|
||||
.collect()
|
||||
});
|
||||
interfaces = ip_info.read();
|
||||
state.sync(&interfaces).await.log_err();
|
||||
}
|
||||
}
|
||||
let res = state.sync(&interfaces).await;
|
||||
if let Err(e) = &res {
|
||||
tracing::error!("Error in PortForwardController: {e}");
|
||||
tracing::debug!("{e:?}");
|
||||
}
|
||||
if let Some(re) = reply.take() {
|
||||
let _ = re.send(res);
|
||||
}
|
||||
}
|
||||
}));
|
||||
Self {
|
||||
@@ -238,19 +247,22 @@ impl LanPortForwardController {
|
||||
_thread: thread,
|
||||
}
|
||||
}
|
||||
pub async fn add(&self, port: u16, public: bool, target: SocketAddr) -> Result<Arc<()>, Error> {
|
||||
pub async fn add(
|
||||
&self,
|
||||
external: u16,
|
||||
filter: impl InterfaceFilter,
|
||||
target: SocketAddr,
|
||||
) -> Result<Arc<()>, Error> {
|
||||
let rc = Arc::new(());
|
||||
let (send, recv) = oneshot::channel();
|
||||
self.req
|
||||
.send((
|
||||
Some((
|
||||
port,
|
||||
ForwardRequest {
|
||||
public,
|
||||
target,
|
||||
rc: Arc::downgrade(&rc),
|
||||
},
|
||||
)),
|
||||
Some(ForwardRequest {
|
||||
external,
|
||||
target,
|
||||
filter: filter.into_dyn(),
|
||||
rc: Arc::downgrade(&rc),
|
||||
}),
|
||||
send,
|
||||
))
|
||||
.map_err(err_has_exited)?;
|
||||
|
||||
@@ -131,7 +131,7 @@ pub fn address_api<C: Context, Kind: HostApiKind>(
|
||||
use prettytable::*;
|
||||
|
||||
if let Some(format) = params.format {
|
||||
display_serializable(format, res);
|
||||
display_serializable(format, res)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::str::FromStr;
|
||||
|
||||
use clap::builder::ValueParserFactory;
|
||||
use clap::Parser;
|
||||
use models::{FromStrParser, HostId};
|
||||
use imbl::OrdSet;
|
||||
use models::{FromStrParser, GatewayId, HostId};
|
||||
use rpc_toolkit::{from_fn_async, Context, Empty, HandlerArgs, HandlerExt, ParentHandler};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::context::{CliContext, RpcContext};
|
||||
use crate::db::model::public::NetworkInterfaceInfo;
|
||||
use crate::net::forward::AvailablePorts;
|
||||
use crate::net::host::HostApiKind;
|
||||
use crate::net::network_interface::InterfaceFilter;
|
||||
use crate::net::vhost::AlpnInfo;
|
||||
use crate::prelude::*;
|
||||
use crate::util::serde::{display_serializable, HandlerExtSerde};
|
||||
@@ -50,11 +53,14 @@ pub struct BindInfo {
|
||||
pub net: NetInfo,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize, TS, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct NetInfo {
|
||||
pub public: bool,
|
||||
#[ts(as = "BTreeSet::<GatewayId>")]
|
||||
pub private_disabled: OrdSet<GatewayId>,
|
||||
#[ts(as = "BTreeSet::<GatewayId>")]
|
||||
pub public_enabled: OrdSet<GatewayId>,
|
||||
pub assigned_port: Option<u16>,
|
||||
pub assigned_ssl_port: Option<u16>,
|
||||
}
|
||||
@@ -65,16 +71,19 @@ impl BindInfo {
|
||||
if options.add_ssl.is_some() {
|
||||
assigned_ssl_port = Some(available_ports.alloc()?);
|
||||
}
|
||||
if let Some(secure) = options.secure {
|
||||
if !secure.ssl || !options.add_ssl.is_some() {
|
||||
assigned_port = Some(available_ports.alloc()?);
|
||||
}
|
||||
if options
|
||||
.secure
|
||||
.map_or(true, |s| !(s.ssl && options.add_ssl.is_some()))
|
||||
{
|
||||
assigned_port = Some(available_ports.alloc()?);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
enabled: true,
|
||||
options,
|
||||
net: NetInfo {
|
||||
public: false,
|
||||
private_disabled: OrdSet::new(),
|
||||
public_enabled: OrdSet::new(),
|
||||
assigned_port,
|
||||
assigned_ssl_port,
|
||||
},
|
||||
@@ -88,7 +97,7 @@ impl BindInfo {
|
||||
let Self { net: mut lan, .. } = self;
|
||||
if options
|
||||
.secure
|
||||
.map_or(false, |s| !(s.ssl && options.add_ssl.is_some()))
|
||||
.map_or(true, |s| !(s.ssl && options.add_ssl.is_some()))
|
||||
// doesn't make sense to have 2 listening ports, both with ssl
|
||||
{
|
||||
lan.assigned_port = if let Some(port) = lan.assigned_port.take() {
|
||||
@@ -122,6 +131,15 @@ impl BindInfo {
|
||||
self.enabled = false;
|
||||
}
|
||||
}
|
||||
impl InterfaceFilter for NetInfo {
|
||||
fn filter(&self, id: &GatewayId, info: &NetworkInterfaceInfo) -> bool {
|
||||
if info.public() {
|
||||
self.public_enabled.contains(id)
|
||||
} else {
|
||||
!self.private_disabled.contains(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, TS)]
|
||||
#[ts(export)]
|
||||
@@ -165,12 +183,11 @@ pub fn binding<C: Context, Kind: HostApiKind>(
|
||||
}
|
||||
|
||||
let mut table = Table::new();
|
||||
table.add_row(row![bc => "INTERNAL PORT", "ENABLED", "PUBLIC", "EXTERNAL PORT", "EXTERNAL SSL PORT"]);
|
||||
table.add_row(row![bc => "INTERNAL PORT", "ENABLED", "EXTERNAL PORT", "EXTERNAL SSL PORT"]);
|
||||
for (internal, info) in res {
|
||||
table.add_row(row![
|
||||
internal,
|
||||
info.enabled,
|
||||
info.net.public,
|
||||
if let Some(port) = info.net.assigned_port {
|
||||
port.to_string()
|
||||
} else {
|
||||
@@ -192,12 +209,12 @@ pub fn binding<C: Context, Kind: HostApiKind>(
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
"set-public",
|
||||
from_fn_async(set_public::<Kind>)
|
||||
"set-gateway-enabled",
|
||||
from_fn_async(set_gateway_enabled::<Kind>)
|
||||
.with_metadata("sync_db", Value::Bool(true))
|
||||
.with_inherited(Kind::inheritance)
|
||||
.no_display()
|
||||
.with_about("Add an binding to this host")
|
||||
.with_about("Set whether this gateway should be enabled for this binding")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
}
|
||||
@@ -215,29 +232,50 @@ pub async fn list_bindings<Kind: HostApiKind>(
|
||||
#[derive(Deserialize, Serialize, Parser, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct BindingSetPublicParams {
|
||||
pub struct BindingGatewaySetEnabledParams {
|
||||
internal_port: u16,
|
||||
gateway: GatewayId,
|
||||
#[arg(long)]
|
||||
public: Option<bool>,
|
||||
enabled: Option<bool>,
|
||||
}
|
||||
|
||||
pub async fn set_public<Kind: HostApiKind>(
|
||||
pub async fn set_gateway_enabled<Kind: HostApiKind>(
|
||||
ctx: RpcContext,
|
||||
BindingSetPublicParams {
|
||||
BindingGatewaySetEnabledParams {
|
||||
internal_port,
|
||||
public,
|
||||
}: BindingSetPublicParams,
|
||||
gateway,
|
||||
enabled,
|
||||
}: BindingGatewaySetEnabledParams,
|
||||
inheritance: Kind::Inheritance,
|
||||
) -> Result<(), Error> {
|
||||
let enabled = enabled.unwrap_or(true);
|
||||
let gateway_public = ctx
|
||||
.net_controller
|
||||
.net_iface
|
||||
.watcher
|
||||
.ip_info()
|
||||
.get(&gateway)
|
||||
.or_not_found(&gateway)?
|
||||
.public();
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
Kind::host_for(&inheritance, db)?
|
||||
.as_bindings_mut()
|
||||
.mutate(|b| {
|
||||
b.get_mut(&internal_port)
|
||||
.or_not_found(internal_port)?
|
||||
.net
|
||||
.public = public.unwrap_or(true);
|
||||
let net = &mut b.get_mut(&internal_port).or_not_found(internal_port)?.net;
|
||||
if gateway_public {
|
||||
if enabled {
|
||||
net.public_enabled.insert(gateway);
|
||||
} else {
|
||||
net.public_enabled.remove(&gateway);
|
||||
}
|
||||
} else {
|
||||
if enabled {
|
||||
net.private_disabled.remove(&gateway);
|
||||
} else {
|
||||
net.private_disabled.insert(gateway);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
|
||||
@@ -16,11 +16,14 @@ use crate::db::model::Database;
|
||||
use crate::error::ErrorCollection;
|
||||
use crate::hostname::Hostname;
|
||||
use crate::net::dns::DnsController;
|
||||
use crate::net::forward::LanPortForwardController;
|
||||
use crate::net::forward::{PortForwardController, START9_BRIDGE_IFACE};
|
||||
use crate::net::host::address::HostAddress;
|
||||
use crate::net::host::binding::{AddSslOptions, BindId, BindOptions};
|
||||
use crate::net::host::{host_for, Host, Hosts};
|
||||
use crate::net::network_interface::NetworkInterfaceController;
|
||||
use crate::net::network_interface::{
|
||||
AndFilter, DynInterfaceFilter, InterfaceFilter, LoopbackFilter, NetworkInterfaceController,
|
||||
SecureFilter,
|
||||
};
|
||||
use crate::net::service_interface::{HostnameInfo, IpHostname, OnionHostname};
|
||||
use crate::net::tor::TorController;
|
||||
use crate::net::utils::ipv6_is_local;
|
||||
@@ -36,7 +39,7 @@ pub struct NetController {
|
||||
pub(super) vhost: VHostController,
|
||||
pub(crate) net_iface: Arc<NetworkInterfaceController>,
|
||||
pub(super) dns: DnsController,
|
||||
pub(super) forward: LanPortForwardController,
|
||||
pub(super) forward: PortForwardController,
|
||||
pub(super) server_hostnames: Vec<Option<InternedString>>,
|
||||
pub(crate) callbacks: Arc<ServiceCallbacks>,
|
||||
}
|
||||
@@ -53,8 +56,13 @@ impl NetController {
|
||||
db: db.clone(),
|
||||
tor: TorController::new(tor_control, tor_socks),
|
||||
vhost: VHostController::new(db, net_iface.clone()),
|
||||
dns: DnsController::init(net_iface.lxcbr_status()).await?,
|
||||
forward: LanPortForwardController::new(net_iface.subscribe()),
|
||||
dns: DnsController::init(
|
||||
net_iface
|
||||
.watcher
|
||||
.wait_for_activated(START9_BRIDGE_IFACE.into()),
|
||||
)
|
||||
.await?,
|
||||
forward: PortForwardController::new(net_iface.watcher.subscribe()),
|
||||
net_iface,
|
||||
server_hostnames: vec![
|
||||
// LAN IP
|
||||
@@ -126,7 +134,7 @@ impl NetController {
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct HostBinds {
|
||||
forwards: BTreeMap<u16, (SocketAddr, bool, Arc<()>)>,
|
||||
forwards: BTreeMap<u16, (SocketAddr, DynInterfaceFilter, Arc<()>)>,
|
||||
vhosts: BTreeMap<(Option<InternedString>, u16), (TargetInfo, Arc<()>)>,
|
||||
tor: BTreeMap<OnionAddressV3, (OrdMap<u16, SocketAddr>, Vec<Arc<()>>)>,
|
||||
}
|
||||
@@ -217,7 +225,7 @@ impl NetServiceData {
|
||||
}
|
||||
|
||||
async fn update(&mut self, ctrl: &NetController, id: HostId, host: Host) -> Result<(), Error> {
|
||||
let mut forwards: BTreeMap<u16, (SocketAddr, bool)> = BTreeMap::new();
|
||||
let mut forwards: BTreeMap<u16, (SocketAddr, DynInterfaceFilter)> = BTreeMap::new();
|
||||
let mut vhosts: BTreeMap<(Option<InternedString>, u16), TargetInfo> = BTreeMap::new();
|
||||
let mut tor: BTreeMap<OnionAddressV3, (TorSecretKeyV3, OrdMap<u16, SocketAddr>)> =
|
||||
BTreeMap::new();
|
||||
@@ -228,7 +236,7 @@ impl NetServiceData {
|
||||
|
||||
// LAN
|
||||
let server_info = peek.as_public().as_server_info();
|
||||
let net_ifaces = ctrl.net_iface.ip_info();
|
||||
let net_ifaces = ctrl.net_iface.watcher.ip_info();
|
||||
let hostname = server_info.as_hostname().de()?;
|
||||
for (port, bind) in &host.bindings {
|
||||
if !bind.enabled {
|
||||
@@ -255,7 +263,7 @@ impl NetServiceData {
|
||||
vhosts.insert(
|
||||
(hostname, external),
|
||||
TargetInfo {
|
||||
public: bind.net.public,
|
||||
filter: bind.net.clone().into_dyn(),
|
||||
acme: None,
|
||||
addr,
|
||||
connect_ssl: connect_ssl.clone(),
|
||||
@@ -270,7 +278,7 @@ impl NetServiceData {
|
||||
vhosts.insert(
|
||||
(Some(hostname), external),
|
||||
TargetInfo {
|
||||
public: false,
|
||||
filter: LoopbackFilter.into_dyn(),
|
||||
acme: None,
|
||||
addr,
|
||||
connect_ssl: connect_ssl.clone(),
|
||||
@@ -286,11 +294,11 @@ impl NetServiceData {
|
||||
if hostnames.insert(address.clone()) {
|
||||
let address = Some(address.clone());
|
||||
if ssl.preferred_external_port == 443 {
|
||||
if public && bind.net.public {
|
||||
if public {
|
||||
vhosts.insert(
|
||||
(address.clone(), 5443),
|
||||
TargetInfo {
|
||||
public: false,
|
||||
filter: bind.net.clone().into_dyn(),
|
||||
acme: acme.clone(),
|
||||
addr,
|
||||
connect_ssl: connect_ssl.clone(),
|
||||
@@ -300,7 +308,7 @@ impl NetServiceData {
|
||||
vhosts.insert(
|
||||
(address.clone(), 443),
|
||||
TargetInfo {
|
||||
public: public && bind.net.public,
|
||||
filter: bind.net.clone().into_dyn(),
|
||||
acme,
|
||||
addr,
|
||||
connect_ssl: connect_ssl.clone(),
|
||||
@@ -310,7 +318,7 @@ impl NetServiceData {
|
||||
vhosts.insert(
|
||||
(address.clone(), external),
|
||||
TargetInfo {
|
||||
public: public && bind.net.public,
|
||||
filter: bind.net.clone().into_dyn(),
|
||||
acme,
|
||||
addr,
|
||||
connect_ssl: connect_ssl.clone(),
|
||||
@@ -322,28 +330,35 @@ impl NetServiceData {
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(security) = bind.options.secure {
|
||||
if bind.options.add_ssl.is_some() && security.ssl {
|
||||
// doesn't make sense to have 2 listening ports, both with ssl
|
||||
} else {
|
||||
let external = bind.net.assigned_port.or_not_found("assigned lan port")?;
|
||||
forwards.insert(external, ((self.ip, *port).into(), bind.net.public));
|
||||
}
|
||||
if bind
|
||||
.options
|
||||
.secure
|
||||
.map_or(true, |s| !(s.ssl && bind.options.add_ssl.is_some()))
|
||||
{
|
||||
let external = bind.net.assigned_port.or_not_found("assigned lan port")?;
|
||||
forwards.insert(
|
||||
external,
|
||||
(
|
||||
(self.ip, *port).into(),
|
||||
AndFilter(
|
||||
SecureFilter {
|
||||
secure: bind.options.secure.is_some(),
|
||||
},
|
||||
bind.net.clone(),
|
||||
)
|
||||
.into_dyn(),
|
||||
),
|
||||
);
|
||||
}
|
||||
let mut bind_hostname_info: Vec<HostnameInfo> =
|
||||
hostname_info.remove(port).unwrap_or_default();
|
||||
for (interface, public, ip_info) in
|
||||
net_ifaces.iter().filter_map(|(interface, info)| {
|
||||
if let Some(ip_info) = &info.ip_info {
|
||||
Some((interface, info.public(), ip_info))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
for (interface, info) in net_ifaces
|
||||
.iter()
|
||||
.filter(|(id, info)| bind.net.filter(id, info))
|
||||
{
|
||||
if !public {
|
||||
if !info.public() {
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
network_interface_id: interface.clone(),
|
||||
gateway_id: interface.clone(),
|
||||
public: false,
|
||||
hostname: IpHostname::Local {
|
||||
value: InternedString::from_display(&{
|
||||
@@ -357,47 +372,44 @@ impl NetServiceData {
|
||||
}
|
||||
for address in host.addresses() {
|
||||
if let HostAddress::Domain {
|
||||
address,
|
||||
public: domain_public,
|
||||
..
|
||||
address, public, ..
|
||||
} = address
|
||||
{
|
||||
if !public || (domain_public && bind.net.public) {
|
||||
if bind
|
||||
.options
|
||||
.add_ssl
|
||||
.as_ref()
|
||||
.map_or(false, |ssl| ssl.preferred_external_port == 443)
|
||||
{
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
network_interface_id: interface.clone(),
|
||||
public: public && domain_public && bind.net.public, // TODO: check if port forward is active
|
||||
hostname: IpHostname::Domain {
|
||||
domain: address.clone(),
|
||||
subdomain: None,
|
||||
port: None,
|
||||
ssl_port: Some(443),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
network_interface_id: interface.clone(),
|
||||
public,
|
||||
hostname: IpHostname::Domain {
|
||||
domain: address.clone(),
|
||||
subdomain: None,
|
||||
port: bind.net.assigned_port,
|
||||
ssl_port: bind.net.assigned_ssl_port,
|
||||
},
|
||||
});
|
||||
}
|
||||
if bind
|
||||
.options
|
||||
.add_ssl
|
||||
.as_ref()
|
||||
.map_or(false, |ssl| ssl.preferred_external_port == 443)
|
||||
{
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
gateway_id: interface.clone(),
|
||||
public, // TODO: check if port forward is active
|
||||
hostname: IpHostname::Domain {
|
||||
domain: address.clone(),
|
||||
subdomain: None,
|
||||
port: None,
|
||||
ssl_port: Some(443),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
gateway_id: interface.clone(),
|
||||
public,
|
||||
hostname: IpHostname::Domain {
|
||||
domain: address.clone(),
|
||||
subdomain: None,
|
||||
port: bind.net.assigned_port,
|
||||
ssl_port: bind.net.assigned_ssl_port,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if !public || bind.net.public {
|
||||
if let Some(ip_info) = &info.ip_info {
|
||||
let public = info.public();
|
||||
if let Some(wan_ip) = ip_info.wan_ip.filter(|_| public) {
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
network_interface_id: interface.clone(),
|
||||
gateway_id: interface.clone(),
|
||||
public,
|
||||
hostname: IpHostname::Ipv4 {
|
||||
value: wan_ip,
|
||||
@@ -411,7 +423,7 @@ impl NetServiceData {
|
||||
IpNet::V4(net) => {
|
||||
if !public {
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
network_interface_id: interface.clone(),
|
||||
gateway_id: interface.clone(),
|
||||
public,
|
||||
hostname: IpHostname::Ipv4 {
|
||||
value: net.addr(),
|
||||
@@ -423,7 +435,7 @@ impl NetServiceData {
|
||||
}
|
||||
IpNet::V6(net) => {
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
network_interface_id: interface.clone(),
|
||||
gateway_id: interface.clone(),
|
||||
public: public && !ipv6_is_local(net.addr()),
|
||||
hostname: IpHostname::Ipv6 {
|
||||
value: net.addr(),
|
||||
@@ -509,8 +521,8 @@ impl NetServiceData {
|
||||
.collect::<BTreeSet<_>>();
|
||||
for external in all {
|
||||
let mut prev = binds.forwards.remove(&external);
|
||||
if let Some((internal, public)) = forwards.remove(&external) {
|
||||
prev = prev.filter(|(i, p, _)| i == &internal && *p == public);
|
||||
if let Some((internal, filter)) = forwards.remove(&external) {
|
||||
prev = prev.filter(|(i, f, _)| i == &internal && *f == filter);
|
||||
binds.forwards.insert(
|
||||
external,
|
||||
if let Some(prev) = prev {
|
||||
@@ -518,8 +530,8 @@ impl NetServiceData {
|
||||
} else {
|
||||
(
|
||||
internal,
|
||||
public,
|
||||
ctrl.forward.add(external, public, internal).await?,
|
||||
filter.clone(),
|
||||
ctrl.forward.add(external, filter, internal).await?,
|
||||
)
|
||||
},
|
||||
);
|
||||
@@ -662,7 +674,7 @@ impl NetService {
|
||||
}
|
||||
|
||||
fn new(data: NetServiceData) -> Result<Self, Error> {
|
||||
let mut ip_info = data.net_controller()?.net_iface.subscribe();
|
||||
let mut ip_info = data.net_controller()?.net_iface.watcher.subscribe();
|
||||
let data = Arc::new(Mutex::new(data));
|
||||
let thread_data = data.clone();
|
||||
let sync_task = tokio::spawn(async move {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@ use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
|
||||
use imbl_value::InternedString;
|
||||
use lazy_format::lazy_format;
|
||||
use models::{HostId, ServiceInterfaceId};
|
||||
use models::{GatewayId, HostId, ServiceInterfaceId};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
@@ -14,7 +14,7 @@ use ts_rs::TS;
|
||||
pub enum HostnameInfo {
|
||||
Ip {
|
||||
#[ts(type = "string")]
|
||||
network_interface_id: InternedString,
|
||||
gateway_id: GatewayId,
|
||||
public: bool,
|
||||
hostname: IpHostname,
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use clap::Parser;
|
||||
use imbl_value::InternedString;
|
||||
use models::GatewayId;
|
||||
use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::process::Command;
|
||||
@@ -44,7 +45,7 @@ pub async fn add_tunnel(
|
||||
config,
|
||||
public,
|
||||
}: AddTunnelParams,
|
||||
) -> Result<InternedString, Error> {
|
||||
) -> Result<GatewayId, Error> {
|
||||
let existing = ctx
|
||||
.db
|
||||
.peek()
|
||||
@@ -54,17 +55,17 @@ pub async fn add_tunnel(
|
||||
.into_network()
|
||||
.into_network_interfaces()
|
||||
.keys()?;
|
||||
let mut iface = InternedString::intern("wg0");
|
||||
let mut iface = GatewayId::from("wg0");
|
||||
for id in 1.. {
|
||||
if !existing.contains(&iface) {
|
||||
break;
|
||||
}
|
||||
iface = InternedString::from_display(&lazy_format!("wg{id}"));
|
||||
iface = InternedString::from_display(&lazy_format!("wg{id}")).into();
|
||||
}
|
||||
let tmpdir = TmpDir::new().await?;
|
||||
let conf = tmpdir.join(&*iface).with_extension("conf");
|
||||
let conf = tmpdir.join(&iface).with_extension("conf");
|
||||
write_file_atomic(&conf, &config).await?;
|
||||
let mut ifaces = ctx.net_controller.net_iface.subscribe();
|
||||
let mut ifaces = ctx.net_controller.net_iface.watcher.subscribe();
|
||||
Command::new("nmcli")
|
||||
.arg("connection")
|
||||
.arg("import")
|
||||
@@ -91,8 +92,7 @@ pub async fn add_tunnel(
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, Parser, TS)]
|
||||
#[ts(export)]
|
||||
pub struct RemoveTunnelParams {
|
||||
#[ts(type = "string")]
|
||||
id: InternedString,
|
||||
id: GatewayId,
|
||||
}
|
||||
pub async fn remove_tunnel(
|
||||
ctx: RpcContext,
|
||||
|
||||
@@ -10,8 +10,10 @@ use color_eyre::eyre::eyre;
|
||||
use futures::FutureExt;
|
||||
use helpers::NonDetachingJoinHandle;
|
||||
use http::Uri;
|
||||
use imbl::OrdMap;
|
||||
use imbl_value::InternedString;
|
||||
use models::ResultExt;
|
||||
use itertools::Itertools;
|
||||
use models::{GatewayId, ResultExt};
|
||||
use rpc_toolkit::{from_fn, Context, HandlerArgs, HandlerExt, ParentHandler};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
@@ -31,13 +33,16 @@ use tracing::instrument;
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::context::{CliContext, RpcContext};
|
||||
use crate::db::model::public::NetworkInterfaceInfo;
|
||||
use crate::db::model::Database;
|
||||
use crate::net::acme::{AcmeCertCache, AcmeProvider};
|
||||
use crate::net::network_interface::{
|
||||
Accepted, NetworkInterfaceController, NetworkInterfaceListener,
|
||||
Accepted, AnyFilter, DynInterfaceFilter, InterfaceFilter, NetworkInterfaceController,
|
||||
NetworkInterfaceListener,
|
||||
};
|
||||
use crate::net::static_server::server_error;
|
||||
use crate::prelude::*;
|
||||
use crate::util::collections::EqSet;
|
||||
use crate::util::io::BackTrackingIO;
|
||||
use crate::util::serde::{display_serializable, HandlerExtSerde, MaybeUtf8String};
|
||||
use crate::util::sync::SyncMutex;
|
||||
@@ -51,12 +56,13 @@ pub fn vhost_api<C: Context>() -> ParentHandler<C> {
|
||||
use prettytable::*;
|
||||
|
||||
if let Some(format) = params.format {
|
||||
display_serializable(format, res);
|
||||
display_serializable(format, res)?;
|
||||
return Ok::<_, Error>(());
|
||||
}
|
||||
|
||||
let mut table = Table::new();
|
||||
table.add_row(row![bc => "FROM", "TO", "PUBLIC", "ACME", "CONNECT SSL", "ACTIVE"]);
|
||||
table
|
||||
.add_row(row![bc => "FROM", "TO", "GATEWAYS", "ACME", "CONNECT SSL", "ACTIVE"]);
|
||||
|
||||
for (external, targets) in res {
|
||||
for (host, targets) in targets {
|
||||
@@ -68,7 +74,7 @@ pub fn vhost_api<C: Context>() -> ParentHandler<C> {
|
||||
external.0
|
||||
),
|
||||
target.addr,
|
||||
target.public,
|
||||
target.gateways.iter().join(", "),
|
||||
target.acme.as_ref().map(|a| a.0.as_str()).unwrap_or("NONE"),
|
||||
target.connect_ssl.is_ok(),
|
||||
idx == 0
|
||||
@@ -117,12 +123,7 @@ impl VHostController {
|
||||
&self,
|
||||
hostname: Option<InternedString>,
|
||||
external: u16,
|
||||
TargetInfo {
|
||||
public,
|
||||
acme,
|
||||
addr,
|
||||
connect_ssl,
|
||||
}: TargetInfo,
|
||||
target: TargetInfo,
|
||||
) -> Result<Arc<()>, Error> {
|
||||
self.servers.mutate(|writable| {
|
||||
let server = if let Some(server) = writable.remove(&external) {
|
||||
@@ -136,15 +137,7 @@ impl VHostController {
|
||||
self.acme_tls_alpn_cache.clone(),
|
||||
)?
|
||||
};
|
||||
let rc = server.add(
|
||||
hostname,
|
||||
TargetInfo {
|
||||
public,
|
||||
acme,
|
||||
addr,
|
||||
connect_ssl,
|
||||
},
|
||||
);
|
||||
let rc = server.add(hostname, target);
|
||||
writable.insert(external, server);
|
||||
Ok(rc?)
|
||||
})
|
||||
@@ -152,8 +145,9 @@ impl VHostController {
|
||||
|
||||
pub fn dump_table(
|
||||
&self,
|
||||
) -> BTreeMap<JsonKey<u16>, BTreeMap<JsonKey<Option<InternedString>>, BTreeSet<TargetInfo>>>
|
||||
) -> BTreeMap<JsonKey<u16>, BTreeMap<JsonKey<Option<InternedString>>, EqSet<ShowTargetInfo>>>
|
||||
{
|
||||
let ip_info = self.interfaces.watcher.ip_info();
|
||||
self.servers.peek(|s| {
|
||||
s.iter()
|
||||
.map(|(k, v)| {
|
||||
@@ -167,8 +161,7 @@ impl VHostController {
|
||||
JsonKey::new(k.clone()),
|
||||
v.iter()
|
||||
.filter(|(_, v)| v.strong_count() > 0)
|
||||
.map(|(k, _)| k)
|
||||
.cloned()
|
||||
.map(|(k, _)| ShowTargetInfo::new(k.clone(), &ip_info))
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
@@ -192,14 +185,45 @@ impl VHostController {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct TargetInfo {
|
||||
pub public: bool,
|
||||
pub filter: DynInterfaceFilter,
|
||||
pub acme: Option<AcmeProvider>,
|
||||
pub addr: SocketAddr,
|
||||
pub connect_ssl: Result<(), AlpnInfo>, // Ok: yes, connect using ssl, pass through alpn; Err: connect tcp, use provided strategy for alpn
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct ShowTargetInfo {
|
||||
pub gateways: BTreeSet<GatewayId>,
|
||||
pub acme: Option<AcmeProvider>,
|
||||
pub addr: SocketAddr,
|
||||
pub connect_ssl: Result<(), AlpnInfo>, // Ok: yes, connect using ssl, pass through alpn; Err: connect tcp, use provided strategy for alpn
|
||||
}
|
||||
impl ShowTargetInfo {
|
||||
pub fn new(
|
||||
TargetInfo {
|
||||
filter,
|
||||
acme,
|
||||
addr,
|
||||
connect_ssl,
|
||||
}: TargetInfo,
|
||||
ip_info: &OrdMap<GatewayId, NetworkInterfaceInfo>,
|
||||
) -> Self {
|
||||
ShowTargetInfo {
|
||||
gateways: ip_info
|
||||
.iter()
|
||||
.filter(|(id, info)| filter.filter(*id, *info))
|
||||
.map(|(k, _)| k)
|
||||
.cloned()
|
||||
.collect(),
|
||||
acme,
|
||||
addr,
|
||||
connect_ssl,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
@@ -222,6 +246,21 @@ struct VHostServer {
|
||||
_thread: NonDetachingJoinHandle<()>,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a BTreeMap<Option<InternedString>, BTreeMap<TargetInfo, Weak<()>>>> for AnyFilter {
|
||||
fn from(value: &'a BTreeMap<Option<InternedString>, BTreeMap<TargetInfo, Weak<()>>>) -> Self {
|
||||
Self(
|
||||
value
|
||||
.iter()
|
||||
.flat_map(|(_, v)| {
|
||||
v.iter()
|
||||
.filter(|(_, r)| r.strong_count() > 0)
|
||||
.map(|(t, _)| t.filter.clone())
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl VHostServer {
|
||||
async fn accept(
|
||||
listener: &mut NetworkInterfaceListener,
|
||||
@@ -233,35 +272,35 @@ impl VHostServer {
|
||||
let accepted;
|
||||
|
||||
loop {
|
||||
let any_public = mapping
|
||||
.borrow()
|
||||
.iter()
|
||||
.any(|(_, targets)| targets.iter().any(|(target, _)| target.public));
|
||||
let any_filter = AnyFilter::from(&*mapping.borrow());
|
||||
|
||||
let changed_public = mapping
|
||||
.wait_for(|m| {
|
||||
m.iter()
|
||||
.any(|(_, targets)| targets.iter().any(|(target, _)| target.public))
|
||||
!= any_public
|
||||
})
|
||||
let changed_filter = mapping
|
||||
.wait_for(|m| any_filter != AnyFilter::from(m))
|
||||
.boxed();
|
||||
|
||||
tokio::select! {
|
||||
a = listener.accept(any_public) => {
|
||||
a = listener.accept(&any_filter) => {
|
||||
accepted = a?;
|
||||
break;
|
||||
}
|
||||
_ = changed_public => {
|
||||
tracing::debug!("port {} {} public bindings", listener.port(), if any_public { "no longer has" } else { "now has" });
|
||||
_ = changed_filter => {
|
||||
tracing::debug!("port {} filter changed", listener.port());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let check = listener.check_filter();
|
||||
tokio::spawn(async move {
|
||||
let bind = accepted.bind;
|
||||
if let Err(e) =
|
||||
Self::handle_stream(accepted, mapping, db, acme_tls_alpn_cache, crypto_provider)
|
||||
.await
|
||||
if let Err(e) = Self::handle_stream(
|
||||
accepted,
|
||||
check,
|
||||
mapping,
|
||||
db,
|
||||
acme_tls_alpn_cache,
|
||||
crypto_provider,
|
||||
)
|
||||
.await
|
||||
{
|
||||
tracing::error!("Error in VHostController on {bind}: {e}");
|
||||
tracing::debug!("{e:?}")
|
||||
@@ -273,11 +312,11 @@ impl VHostServer {
|
||||
async fn handle_stream(
|
||||
Accepted {
|
||||
stream,
|
||||
is_public,
|
||||
wan_ip,
|
||||
bind,
|
||||
..
|
||||
}: Accepted,
|
||||
check_filter: impl FnOnce(SocketAddr, &DynInterfaceFilter) -> bool,
|
||||
mapping: watch::Receiver<Mapping>,
|
||||
db: TypedPatchDb<Database>,
|
||||
acme_tls_alpn_cache: AcmeTlsAlpnCache,
|
||||
@@ -431,10 +470,8 @@ impl VHostServer {
|
||||
.map(|(target, _)| target.clone())
|
||||
};
|
||||
if let Some(target) = target {
|
||||
if is_public && !target.public {
|
||||
log::warn!(
|
||||
"Rejecting connection from public interface to private bind: {bind} -> {target:?}"
|
||||
);
|
||||
if !check_filter(bind, &target.filter) {
|
||||
log::warn!("Connection from {bind} to {target:?} rejected by filter");
|
||||
return Ok(());
|
||||
}
|
||||
let peek = db.peek().await;
|
||||
@@ -660,7 +697,10 @@ impl VHostServer {
|
||||
crypto_provider: Arc<CryptoProvider>,
|
||||
acme_tls_alpn_cache: AcmeTlsAlpnCache,
|
||||
) -> Result<Self, Error> {
|
||||
let mut listener = iface_ctrl.bind(port).with_kind(crate::ErrorKind::Network)?;
|
||||
let mut listener = iface_ctrl
|
||||
.watcher
|
||||
.bind(port)
|
||||
.with_kind(crate::ErrorKind::Network)?;
|
||||
let (map_send, map_recv) = watch::channel(BTreeMap::new());
|
||||
Ok(Self {
|
||||
mapping: map_send,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use std::future::Future;
|
||||
use std::net::SocketAddr;
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use std::task::Poll;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -16,7 +15,7 @@ use tokio::sync::oneshot;
|
||||
|
||||
use crate::context::{DiagnosticContext, InitContext, InstallContext, RpcContext, SetupContext};
|
||||
use crate::net::network_interface::{
|
||||
NetworkInterfaceListener, SelfContainedNetworkInterfaceListener,
|
||||
lookup_info_by_addr, NetworkInterfaceListener, SelfContainedNetworkInterfaceListener,
|
||||
};
|
||||
use crate::net::static_server::{
|
||||
diagnostic_ui_router, init_ui_router, install_ui_router, main_ui_router, redirecter, refresher,
|
||||
@@ -50,10 +49,15 @@ impl Accept for Vec<TcpListener> {
|
||||
}
|
||||
impl Accept for NetworkInterfaceListener {
|
||||
fn poll_accept(&mut self, cx: &mut std::task::Context<'_>) -> Poll<Result<Accepted, Error>> {
|
||||
NetworkInterfaceListener::poll_accept(self, cx, true).map(|res| {
|
||||
res.map(|a| Accepted {
|
||||
https_redirect: a.is_public,
|
||||
stream: a.stream,
|
||||
NetworkInterfaceListener::poll_accept(self, cx, &true).map(|res| {
|
||||
res.map(|a| {
|
||||
let public = self
|
||||
.ip_info
|
||||
.peek(|i| lookup_info_by_addr(i, a.bind).map_or(true, |(_, i)| i.public()));
|
||||
Accepted {
|
||||
https_redirect: public,
|
||||
stream: a.stream,
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -89,5 +89,6 @@ pub async fn get_service_port_forward(
|
||||
.de()?
|
||||
.get(&internal_port)
|
||||
.or_not_found(lazy_format!("binding for port {internal_port}"))?
|
||||
.net)
|
||||
.net
|
||||
.clone())
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ use crate::net::ssl::root_ca_start_time;
|
||||
use crate::prelude::*;
|
||||
use crate::progress::{FullProgress, PhaseProgressTrackerHandle, ProgressUnits};
|
||||
use crate::rpc_continuations::Guid;
|
||||
use crate::shutdown::Shutdown;
|
||||
use crate::system::sync_kiosk;
|
||||
use crate::util::crypto::EncryptedWire;
|
||||
use crate::util::io::{create_file, dir_copy, dir_size, Counter};
|
||||
@@ -67,6 +68,7 @@ pub fn setup<C: Context>() -> ParentHandler<C> {
|
||||
"logs",
|
||||
from_fn_async(crate::logs::cli_logs::<SetupContext, Empty>).no_display(),
|
||||
)
|
||||
.subcommand("restart", from_fn_async(restart).no_cli())
|
||||
}
|
||||
|
||||
pub fn disk<C: Context>() -> ParentHandler<C> {
|
||||
@@ -172,6 +174,7 @@ pub async fn attach(
|
||||
if disk_guid.ends_with("_UNENC") { None } else { Some(DEFAULT_PASSWORD) },
|
||||
)
|
||||
.await?;
|
||||
let _ = setup_ctx.disk_guid.set(disk_guid.clone());
|
||||
if tokio::fs::metadata(REPAIR_DISK_PATH).await.is_ok() {
|
||||
tokio::fs::remove_file(REPAIR_DISK_PATH)
|
||||
.await
|
||||
@@ -390,9 +393,19 @@ pub async fn complete(ctx: SetupContext) -> Result<SetupResult, Error> {
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
// #[command(rpc_only)]
|
||||
pub async fn exit(ctx: SetupContext) -> Result<(), Error> {
|
||||
ctx.shutdown.send(()).expect("failed to shutdown");
|
||||
ctx.shutdown.send(None).expect("failed to shutdown");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn restart(ctx: SetupContext) -> Result<(), Error> {
|
||||
ctx.shutdown
|
||||
.send(Some(Shutdown {
|
||||
disk_guid: ctx.disk_guid.get().cloned(),
|
||||
restart: true,
|
||||
}))
|
||||
.expect("failed to shutdown");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -435,6 +448,7 @@ pub async fn execute_inner(
|
||||
);
|
||||
let _ = crate::disk::main::import(&*guid, DATA_DIR, RepairStrategy::Preen, encryption_password)
|
||||
.await?;
|
||||
let _ = ctx.disk_guid.set(guid.clone());
|
||||
disk_phase.complete();
|
||||
|
||||
let progress = SetupExecuteProgress {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::context::RpcContext;
|
||||
@@ -7,11 +6,11 @@ use crate::init::{STANDBY_MODE_PATH, SYSTEM_REBUILD_PATH};
|
||||
use crate::prelude::*;
|
||||
use crate::sound::SHUTDOWN;
|
||||
use crate::util::Invoke;
|
||||
use crate::{DATA_DIR, PLATFORM};
|
||||
use crate::PLATFORM;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Shutdown {
|
||||
pub export_args: Option<(Arc<String>, PathBuf)>,
|
||||
pub disk_guid: Option<Arc<String>>,
|
||||
pub restart: bool,
|
||||
}
|
||||
impl Shutdown {
|
||||
@@ -41,8 +40,8 @@ impl Shutdown {
|
||||
tracing::error!("Error Stopping Journald: {}", e);
|
||||
tracing::debug!("{:?}", e);
|
||||
}
|
||||
if let Some((guid, datadir)) = &self.export_args {
|
||||
if let Err(e) = export(guid, datadir).await {
|
||||
if let Some(guid) = &self.disk_guid {
|
||||
if let Err(e) = export(guid, crate::DATA_DIR).await {
|
||||
tracing::error!("Error Exporting Volume Group: {}", e);
|
||||
tracing::debug!("{:?}", e);
|
||||
}
|
||||
@@ -87,7 +86,7 @@ pub async fn shutdown(ctx: RpcContext) -> Result<(), Error> {
|
||||
.result?;
|
||||
ctx.shutdown
|
||||
.send(Some(Shutdown {
|
||||
export_args: Some((ctx.disk_guid.clone(), Path::new(DATA_DIR).to_owned())),
|
||||
disk_guid: Some(ctx.disk_guid.clone()),
|
||||
restart: false,
|
||||
}))
|
||||
.map_err(|_| eyre!("receiver dropped"))
|
||||
@@ -108,7 +107,7 @@ pub async fn restart(ctx: RpcContext) -> Result<(), Error> {
|
||||
.result?;
|
||||
ctx.shutdown
|
||||
.send(Some(Shutdown {
|
||||
export_args: Some((ctx.disk_guid.clone(), Path::new(DATA_DIR).to_owned())),
|
||||
disk_guid: Some(ctx.disk_guid.clone()),
|
||||
restart: true,
|
||||
}))
|
||||
.map_err(|_| eyre!("receiver dropped"))
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
use std::net::{IpAddr, Ipv6Addr, SocketAddr};
|
||||
use std::ops::Deref;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
use clap::Parser;
|
||||
use imbl::OrdMap;
|
||||
use imbl_value::InternedString;
|
||||
use patch_db::PatchDb;
|
||||
use rpc_toolkit::yajrc::RpcError;
|
||||
@@ -15,13 +16,15 @@ use tracing::instrument;
|
||||
|
||||
use crate::auth::{check_password, Sessions};
|
||||
use crate::context::config::ContextConfig;
|
||||
use crate::context::{CliContext, RpcContext};
|
||||
use crate::context::CliContext;
|
||||
use crate::middleware::auth::AuthContext;
|
||||
use crate::middleware::signature::SignatureAuthContext;
|
||||
use crate::net::forward::PortForwardController;
|
||||
use crate::net::network_interface::NetworkInterfaceWatcher;
|
||||
use crate::prelude::*;
|
||||
use crate::rpc_continuations::{OpenAuthedContinuations, RpcContinuations};
|
||||
use crate::tunnel::{TunnelDatabase, TUNNEL_DEFAULT_PORT};
|
||||
use crate::util::iter::TransposeResultIterExt;
|
||||
use crate::tunnel::db::TunnelDatabase;
|
||||
use crate::tunnel::TUNNEL_DEFAULT_PORT;
|
||||
use crate::util::sync::SyncMutex;
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize, Parser)]
|
||||
@@ -62,6 +65,8 @@ pub struct TunnelContextSeed {
|
||||
pub rpc_continuations: RpcContinuations,
|
||||
pub open_authed_continuations: OpenAuthedContinuations<Option<InternedString>>,
|
||||
pub ephemeral_sessions: SyncMutex<Sessions>,
|
||||
pub net_iface: NetworkInterfaceWatcher,
|
||||
pub forward: PortForwardController,
|
||||
pub shutdown: Sender<()>,
|
||||
}
|
||||
|
||||
@@ -89,6 +94,8 @@ impl TunnelContext {
|
||||
Ipv6Addr::UNSPECIFIED.into(),
|
||||
TUNNEL_DEFAULT_PORT,
|
||||
));
|
||||
let net_iface = NetworkInterfaceWatcher::new(async { OrdMap::new() }, []);
|
||||
let forward = PortForwardController::new(net_iface.subscribe());
|
||||
Ok(Self(Arc::new(TunnelContextSeed {
|
||||
listen,
|
||||
addrs: crate::net::utils::all_socket_addrs_for(listen.port())
|
||||
@@ -101,6 +108,8 @@ impl TunnelContext {
|
||||
rpc_continuations: RpcContinuations::new(),
|
||||
open_authed_continuations: OpenAuthedContinuations::new(),
|
||||
ephemeral_sessions: SyncMutex::new(Sessions::new()),
|
||||
net_iface,
|
||||
forward,
|
||||
shutdown,
|
||||
})))
|
||||
}
|
||||
@@ -213,14 +222,3 @@ impl CallRemote<TunnelContext> for CliContext {
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl CallRemote<TunnelContext, TunnelAddrParams> for RpcContext {
|
||||
async fn call_remote(
|
||||
&self,
|
||||
mut method: &str,
|
||||
params: Value,
|
||||
TunnelAddrParams { tunnel }: TunnelAddrParams,
|
||||
) -> Result<Value, RpcError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::Parser;
|
||||
@@ -10,12 +12,31 @@ use serde::{Deserialize, Serialize};
|
||||
use tracing::instrument;
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::auth::Sessions;
|
||||
use crate::context::CliContext;
|
||||
use crate::prelude::*;
|
||||
use crate::sign::AnyVerifyingKey;
|
||||
use crate::tunnel::context::TunnelContext;
|
||||
use crate::tunnel::TunnelDatabase;
|
||||
use crate::util::serde::{apply_expr, HandlerExtSerde};
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, HasModel)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[model = "Model<Self>"]
|
||||
pub struct TunnelDatabase {
|
||||
pub sessions: Sessions,
|
||||
pub password: String,
|
||||
pub auth_pubkeys: HashSet<AnyVerifyingKey>,
|
||||
pub clients: BTreeMap<Ipv4Addr, ClientInfo>,
|
||||
pub port_forwards: BTreeMap<SocketAddr, SocketAddr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, HasModel)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[model = "Model<Self>"]
|
||||
pub struct ClientInfo {
|
||||
pub server: bool,
|
||||
}
|
||||
|
||||
pub fn db_api<C: Context>() -> ParentHandler<C> {
|
||||
ParentHandler::new()
|
||||
.subcommand(
|
||||
|
||||
0
core/startos/src/tunnel/init.rs
Normal file
0
core/startos/src/tunnel/init.rs
Normal file
@@ -1,4 +1,5 @@
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
|
||||
use axum::Router;
|
||||
use futures::future::ready;
|
||||
@@ -17,18 +18,10 @@ use crate::tunnel::context::TunnelContext;
|
||||
|
||||
pub mod context;
|
||||
pub mod db;
|
||||
pub mod init;
|
||||
|
||||
pub const TUNNEL_DEFAULT_PORT: u16 = 5960;
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, HasModel)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[model = "Model<Self>"]
|
||||
pub struct TunnelDatabase {
|
||||
pub sessions: Sessions,
|
||||
pub password: String,
|
||||
pub auth_pubkeys: HashSet<AnyVerifyingKey>,
|
||||
}
|
||||
|
||||
pub fn tunnel_api<C: Context>() -> ParentHandler<C> {
|
||||
ParentHandler::new().subcommand(
|
||||
"db",
|
||||
|
||||
@@ -359,7 +359,7 @@ impl UploadHandle {
|
||||
});
|
||||
}
|
||||
}
|
||||
async fn process_body<E: Into<Box<(dyn std::error::Error + Send + Sync + 'static)>>>(
|
||||
async fn process_body<E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>>(
|
||||
&mut self,
|
||||
mut body: impl Stream<Item = Result<Bytes, E>> + Unpin,
|
||||
) {
|
||||
|
||||
@@ -666,13 +666,27 @@ impl<K: Eq, V> IntoIterator for EqMap<K, V> {
|
||||
|
||||
impl<K: Eq, V> Extend<(K, V)> for EqMap<K, V> {
|
||||
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
|
||||
self.0.extend(iter)
|
||||
let iter = iter.into_iter();
|
||||
if let (_, Some(len)) = iter.size_hint() {
|
||||
self.0.reserve(len)
|
||||
}
|
||||
for (k, v) in iter {
|
||||
self.insert(k, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Eq, V> FromIterator<(K, V)> for EqMap<K, V> {
|
||||
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
|
||||
Self(Vec::from_iter(iter))
|
||||
let mut res = Self(Vec::new());
|
||||
let iter = iter.into_iter();
|
||||
if let (_, Some(len)) = iter.size_hint() {
|
||||
res.0.reserve(len)
|
||||
}
|
||||
for (k, v) in iter {
|
||||
res.insert(k, v);
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
@@ -687,7 +701,7 @@ impl<K: Eq, V, const N: usize> From<[(K, V); N]> for EqMap<K, V> {
|
||||
/// assert_eq!(map1, map2);
|
||||
/// ```
|
||||
fn from(arr: [(K, V); N]) -> Self {
|
||||
EqMap(Vec::from(arr))
|
||||
Self::from_iter(arr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
425
core/startos/src/util/collections/eq_set.rs
Normal file
425
core/startos/src/util/collections/eq_set.rs
Normal file
@@ -0,0 +1,425 @@
|
||||
use std::borrow::Borrow;
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
pub struct EqSet<T: Eq>(Vec<T>);
|
||||
impl<T: Eq> Default for EqSet<T> {
|
||||
fn default() -> Self {
|
||||
Self(Default::default())
|
||||
}
|
||||
}
|
||||
impl<T: Eq> EqSet<T> {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.0.clear()
|
||||
}
|
||||
|
||||
/// Returns a reference to the element in the set, if any, that is equal to
|
||||
/// the value.
|
||||
///
|
||||
/// The value may be any borrowed form of the set's element type,
|
||||
/// but the ordering on the borrowed form *must* match the
|
||||
/// ordering on the element type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use startos::util::collections::EqSet;
|
||||
///
|
||||
/// let set = EqSet::from([1, 2, 3]);
|
||||
/// assert_eq!(set.get(&2), Some(&2));
|
||||
/// assert_eq!(set.get(&4), None);
|
||||
/// ```
|
||||
pub fn get<Q: ?Sized>(&self, value: &Q) -> Option<&T>
|
||||
where
|
||||
T: Borrow<Q>,
|
||||
Q: Eq,
|
||||
{
|
||||
self.0.iter().find(|k| (*k).borrow() == value)
|
||||
}
|
||||
|
||||
/// Removes and returns an element in the set.
|
||||
/// There is no guarantee about which element this might be
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use startos::util::collections::EqSet;
|
||||
///
|
||||
/// let mut set = EqSet::new();
|
||||
/// set.insert("a");
|
||||
/// set.insert("b");
|
||||
/// while let Some(_val) = set.pop() { }
|
||||
/// assert!(set.is_empty());
|
||||
/// ```
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
self.0.pop()
|
||||
}
|
||||
|
||||
/// Returns `true` if the set contains a value for the specified value.
|
||||
///
|
||||
/// The value may be any borrowed form of the set's value type, but the equality
|
||||
/// on the borrowed form *must* match the equality on the value type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use startos::util::collections::EqSet;
|
||||
///
|
||||
/// let mut set = EqSet::new();
|
||||
/// set.insert("a");
|
||||
/// assert_eq!(set.contains("a"), true);
|
||||
/// assert_eq!(set.contains("b"), false);
|
||||
/// ```
|
||||
pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool
|
||||
where
|
||||
T: Borrow<Q>,
|
||||
Q: Eq,
|
||||
{
|
||||
self.get(value).is_some()
|
||||
}
|
||||
|
||||
/// Inserts a value into the set.
|
||||
///
|
||||
/// If the set did not have this value present, `None` is returned.
|
||||
///
|
||||
/// If the set did have this value present, the value is updated, and the old
|
||||
/// value is returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use startos::util::collections::EqSet;
|
||||
///
|
||||
/// let mut set = EqSet::new();
|
||||
/// assert_eq!(set.insert("a"), None);
|
||||
/// assert_eq!(set.is_empty(), false);
|
||||
///
|
||||
/// set.insert("b");
|
||||
/// assert_eq!(set.insert("b"), Some("b"));
|
||||
/// assert!(set.contains("a"));
|
||||
/// ```
|
||||
pub fn insert(&mut self, value: T) -> Option<T> {
|
||||
if let Some(entry) = self.0.iter_mut().find(|a| *a == &value) {
|
||||
Some(std::mem::replace(entry, value))
|
||||
} else {
|
||||
self.0.push(value);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to insert a value into the set.
|
||||
///
|
||||
/// If the set already had this value present, nothing is updated.
|
||||
///
|
||||
/// Returns whether the value was inserted.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use startos::util::collections::EqSet;
|
||||
///
|
||||
/// let mut set = EqSet::new();
|
||||
/// assert!(set.try_insert("a"));
|
||||
/// assert!(!set.try_insert("a"));
|
||||
/// ```
|
||||
pub fn try_insert(&mut self, value: T) -> bool {
|
||||
if self.0.iter().find(|a| *a == &value).is_some() {
|
||||
false
|
||||
} else {
|
||||
self.0.push(value);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes a value from the set, returning the value if it
|
||||
/// was previously in the set.
|
||||
///
|
||||
/// The value may be any borrowed form of the set's value type, but the equality
|
||||
/// on the borrowed form *must* match the equality on the value type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use startos::util::collections::EqSet;
|
||||
///
|
||||
/// let mut set = EqSet::new();
|
||||
/// set.insert("a");
|
||||
/// assert_eq!(set.remove("a"), Some("a"));
|
||||
/// assert_eq!(set.remove("a"), None);
|
||||
/// ```
|
||||
pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> Option<T>
|
||||
where
|
||||
T: Borrow<Q>,
|
||||
Q: Eq,
|
||||
{
|
||||
if let Some((idx, _)) = self
|
||||
.0
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, v)| (*v).borrow() == value)
|
||||
{
|
||||
Some(self.0.swap_remove(idx))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Retains only the elements specified by the predicate.
|
||||
///
|
||||
/// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`.
|
||||
/// The elements are visited in ascending value order.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use startos::util::collections::EqSet;
|
||||
///
|
||||
/// let mut set: EqSet<i32, i32> = (0..8).set(|x| (x, x*10)).collect();
|
||||
/// // Keep only the elements with even-numbered values.
|
||||
/// set.retain(|&k, _| k % 2 == 0);
|
||||
/// assert!(set.into_iter().eq(vec![(0, 0), (2, 20), (4, 40), (6, 60)]));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn retain<F>(&mut self, f: F)
|
||||
where
|
||||
F: FnMut(&T) -> bool,
|
||||
{
|
||||
self.0.retain(f)
|
||||
}
|
||||
|
||||
/// Moves all elements from `other` into `self`, leaving `other` empty.
|
||||
///
|
||||
/// If a value from `other` is already present in `self`, the respective
|
||||
/// value from `self` will be overwritten with the respective value from `other`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use startos::util::collections::EqSet;
|
||||
///
|
||||
/// let mut a = EqSet::new();
|
||||
/// a.insert("a");
|
||||
/// a.insert("b");
|
||||
/// a.insert("c"); // Note: "c" also present in b.
|
||||
///
|
||||
/// let mut b = EqSet::new();
|
||||
/// b.insert(3, "c"); // Note: "c" also present in a.
|
||||
/// b.insert(4, "d");
|
||||
/// b.insert(5, "e");
|
||||
///
|
||||
/// a.append(&mut b);
|
||||
///
|
||||
/// assert_eq!(a.len(), 5);
|
||||
/// assert_eq!(b.len(), 0);
|
||||
/// ```
|
||||
pub fn append(&mut self, other: &mut Self) {
|
||||
other.retain(|v| !self.contains(v));
|
||||
self.0.append(&mut other.0)
|
||||
}
|
||||
|
||||
// /// Creates an iterator that visits all elements (values) and
|
||||
// /// uses a closure to determine if an element should be removed. If the
|
||||
// /// closure returns `true`, the element is removed from the set and yielded.
|
||||
// /// If the closure returns `false`, or panics, the element remains in the set
|
||||
// /// and will not be yielded.
|
||||
// ///
|
||||
// /// The iterator also lets you mutate the value of each element in the
|
||||
// /// closure, regardless of whether you choose to keep or remove it.
|
||||
// ///
|
||||
// /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
|
||||
// /// or the iteration short-circuits, then the remaining elements will be retained.
|
||||
// /// Use [`retain`] with a negated predicate if you do not need the returned iterator.
|
||||
// ///
|
||||
// /// [`retain`]: EqSet::retain
|
||||
// ///
|
||||
// /// # Examples
|
||||
// ///
|
||||
// /// Splitting a set into even and odd values, reusing the original set:
|
||||
// ///
|
||||
// /// ```
|
||||
// /// use startos::util::collections::EqSet;
|
||||
// ///
|
||||
// /// let mut set: EqSet<i32, i32> = (0..8).set(|x| (x, x)).collect();
|
||||
// /// let evens: EqSet<_, _> = set.extract_if(|k, _v| k % 2 == 0).collect();
|
||||
// /// let odds = set;
|
||||
// /// assert_eq!(evens.values().copied().collect::<Vec<_>>(), [0, 2, 4, 6]);
|
||||
// /// assert_eq!(odds.values().copied().collect::<Vec<_>>(), [1, 3, 5, 7]);
|
||||
// /// ```
|
||||
// pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, T, F>
|
||||
// where
|
||||
// K: Eq,
|
||||
// F: FnMut(&K, &mut V) -> bool,
|
||||
// {
|
||||
// let (inner, alloc) = self.extract_if_inner();
|
||||
// ExtractIf { pred, inner, alloc }
|
||||
// }
|
||||
|
||||
/// Gets an iterator over the entries of the set, in no particular order.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use startos::util::collections::EqSet;
|
||||
///
|
||||
/// let mut set = EqSet::new();
|
||||
/// set.insert("c");
|
||||
/// set.insert("b");
|
||||
/// set.insert("a");
|
||||
///
|
||||
/// for value in set.iter() {
|
||||
/// println!("{value}");
|
||||
/// }
|
||||
///
|
||||
/// let first_value = set.iter().next().unwrap();
|
||||
/// assert_eq!(*first_value, "c");
|
||||
/// ```
|
||||
pub fn iter(&self) -> std::slice::Iter<'_, T> {
|
||||
self.0.iter()
|
||||
}
|
||||
|
||||
/// Returns the number of elements in the set.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use startos::util::collections::EqSet;
|
||||
///
|
||||
/// let mut a = EqSet::new();
|
||||
/// assert_eq!(a.len(), 0);
|
||||
/// a.insert("a");
|
||||
/// assert_eq!(a.len(), 1);
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
/// Returns `true` if the set contains no elements.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use startos::util::collections::EqSet;
|
||||
///
|
||||
/// let mut a = EqSet::new();
|
||||
/// assert!(a.is_empty());
|
||||
/// a.insert("a");
|
||||
/// assert!(!a.is_empty());
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug + Eq> fmt::Debug for EqSet<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_set().entries(self.iter()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq> IntoIterator for EqSet<T> {
|
||||
type IntoIter = std::vec::IntoIter<T>;
|
||||
type Item = T;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq> Extend<T> for EqSet<T> {
|
||||
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
|
||||
let iter = iter.into_iter();
|
||||
if let (_, Some(len)) = iter.size_hint() {
|
||||
self.0.reserve(len)
|
||||
}
|
||||
for v in iter {
|
||||
self.insert(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq> FromIterator<T> for EqSet<T> {
|
||||
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
||||
let mut res = Self(Vec::new());
|
||||
let iter = iter.into_iter();
|
||||
if let (_, Some(len)) = iter.size_hint() {
|
||||
res.0.reserve(len)
|
||||
}
|
||||
for v in iter {
|
||||
res.insert(v);
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq, const N: usize> From<[T; N]> for EqSet<T> {
|
||||
/// Converts a `[T; N]` into a `EqSet<T>`.
|
||||
///
|
||||
/// ```
|
||||
/// use startos::util::collections::EqSet;
|
||||
///
|
||||
/// let set1 = EqSet::from([(1, 2), (3, 4)]);
|
||||
/// let set2: EqSet<_, _> = [(1, 2), (3, 4)].into();
|
||||
/// assert_eq!(set1, set2);
|
||||
/// ```
|
||||
fn from(arr: [T; N]) -> Self {
|
||||
EqSet::from_iter(arr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq> PartialEq for EqSet<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.len() == other.len() && self.iter().all(|v| other.get(v) == Some(v))
|
||||
}
|
||||
}
|
||||
impl<T: Eq> Eq for EqSet<T> {}
|
||||
|
||||
impl<'de, T> Deserialize<'de> for EqSet<T>
|
||||
where
|
||||
T: Deserialize<'de> + Eq,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
struct Visitor<T> {
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'de, T> serde::de::Visitor<'de> for Visitor<T>
|
||||
where
|
||||
T: Deserialize<'de> + Eq,
|
||||
{
|
||||
type Value = EqSet<T>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a sequence")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: serde::de::SeqAccess<'de>,
|
||||
{
|
||||
let mut values = EqSet(Vec::new());
|
||||
|
||||
while let Some(value) = seq.next_element()? {
|
||||
values.insert(value);
|
||||
}
|
||||
|
||||
Ok(values)
|
||||
}
|
||||
}
|
||||
|
||||
let visitor = Visitor {
|
||||
marker: PhantomData,
|
||||
};
|
||||
deserializer.deserialize_seq(visitor)
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,44 @@
|
||||
pub mod eq_map;
|
||||
pub mod eq_set;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub use eq_map::EqMap;
|
||||
pub use eq_set::EqSet;
|
||||
use imbl::OrdMap;
|
||||
|
||||
pub struct OrdMapIterMut<'a, K: 'a, V: 'a> {
|
||||
map: *mut OrdMap<K, V>,
|
||||
prev: Option<&'a K>,
|
||||
_marker: PhantomData<&'a mut (K, V)>,
|
||||
}
|
||||
impl<'a, K, V> From<&'a mut OrdMap<K, V>> for OrdMapIterMut<'a, K, V> {
|
||||
fn from(value: &'a mut OrdMap<K, V>) -> Self {
|
||||
Self {
|
||||
map: value,
|
||||
prev: None,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a, K: Ord + Clone, V: Clone> Iterator for OrdMapIterMut<'a, K, V> {
|
||||
type Item = (&'a K, &'a mut V);
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
unsafe {
|
||||
let map: &'a mut OrdMap<K, V> = self.map.as_mut().unwrap();
|
||||
let res = if let Some(k) = self.prev.take() {
|
||||
map.get_next_mut(k)
|
||||
} else {
|
||||
let Some((k, _)) = map.get_min() else {
|
||||
return None;
|
||||
};
|
||||
let k = k.clone(); // hate that I have to do this but whatev
|
||||
map.get_key_value_mut(&k)
|
||||
};
|
||||
if let Some((k, _)) = &res {
|
||||
self.prev = Some(*k);
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use base64::Engine;
|
||||
use clap::builder::ValueParserFactory;
|
||||
use clap::{ArgMatches, CommandFactory, FromArgMatches};
|
||||
use color_eyre::eyre::eyre;
|
||||
use imbl::OrdMap;
|
||||
use imbl_value::imbl::OrdMap;
|
||||
use models::FromStrParser;
|
||||
use openssl::pkey::{PKey, Private};
|
||||
use openssl::x509::X509;
|
||||
|
||||
@@ -140,6 +140,9 @@ impl<T: Clone> Watch<T> {
|
||||
pub fn read(&self) -> T {
|
||||
self.peek(|a| a.clone())
|
||||
}
|
||||
pub fn read_and_mark_seen(&mut self) -> T {
|
||||
self.peek_and_mark_seen(|a| a.clone())
|
||||
}
|
||||
}
|
||||
impl<T: Clone> futures::Stream for Watch<T> {
|
||||
type Item = T;
|
||||
|
||||
2
patch-db
2
patch-db
Submodule patch-db updated: f43ee19587...de9a2a6787
@@ -0,0 +1,8 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { GatewayId } from "./GatewayId"
|
||||
|
||||
export type BindingGatewaySetEnabledParams = {
|
||||
internalPort: number
|
||||
gateway: GatewayId
|
||||
enabled: boolean | null
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { GatewayId } from "./GatewayId"
|
||||
|
||||
export type ForgetInterfaceParams = { interface: string }
|
||||
export type ForgetInterfaceParams = { interface: GatewayId }
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type BindingSetPublicParams = {
|
||||
internalPort: number
|
||||
public: boolean | null
|
||||
}
|
||||
export type GatewayId = string
|
||||
@@ -3,10 +3,5 @@ import type { IpHostname } from "./IpHostname"
|
||||
import type { OnionHostname } from "./OnionHostname"
|
||||
|
||||
export type HostnameInfo =
|
||||
| {
|
||||
kind: "ip"
|
||||
networkInterfaceId: string
|
||||
public: boolean
|
||||
hostname: IpHostname
|
||||
}
|
||||
| { kind: "ip"; gatewayId: string; public: boolean; hostname: IpHostname }
|
||||
| { kind: "onion"; hostname: OnionHostname }
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { PasswordType } from "./PasswordType"
|
||||
|
||||
export type LoginParams = { password: PasswordType | null; ephemeral: boolean }
|
||||
export type LoginParams = { password: string; ephemeral: boolean }
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { GatewayId } from "./GatewayId"
|
||||
|
||||
export type NetInfo = {
|
||||
public: boolean
|
||||
privateDisabled: Array<GatewayId>
|
||||
publicEnabled: Array<GatewayId>
|
||||
assignedPort: number | null
|
||||
assignedSslPort: number | null
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { AcmeProvider } from "./AcmeProvider"
|
||||
import type { AcmeSettings } from "./AcmeSettings"
|
||||
import type { GatewayId } from "./GatewayId"
|
||||
import type { Host } from "./Host"
|
||||
import type { NetworkInterfaceInfo } from "./NetworkInterfaceInfo"
|
||||
import type { WifiInfo } from "./WifiInfo"
|
||||
@@ -8,6 +9,6 @@ import type { WifiInfo } from "./WifiInfo"
|
||||
export type NetworkInfo = {
|
||||
wifi: WifiInfo
|
||||
host: Host
|
||||
networkInterfaces: { [key: string]: NetworkInterfaceInfo }
|
||||
networkInterfaces: { [key: GatewayId]: NetworkInterfaceInfo }
|
||||
acme: { [key: AcmeProvider]: AcmeSettings }
|
||||
}
|
||||
|
||||
@@ -3,5 +3,6 @@ import type { IpInfo } from "./IpInfo"
|
||||
|
||||
export type NetworkInterfaceInfo = {
|
||||
public: boolean | null
|
||||
secure: boolean | null
|
||||
ipInfo: IpInfo | null
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { GatewayId } from "./GatewayId"
|
||||
|
||||
export type NetworkInterfaceSetPublicParams = {
|
||||
interface: string
|
||||
interface: GatewayId
|
||||
public: boolean | null
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { GatewayId } from "./GatewayId"
|
||||
|
||||
export type RemoveTunnelParams = { id: string }
|
||||
export type RemoveTunnelParams = { id: GatewayId }
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { GatewayId } from "./GatewayId"
|
||||
|
||||
export type RenameInterfaceParams = { interface: string; name: string }
|
||||
export type RenameInterfaceParams = { interface: GatewayId; name: string }
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { GatewayId } from "./GatewayId"
|
||||
|
||||
export type UnsetInboundParams = { interface: string }
|
||||
export type UnsetInboundParams = { interface: GatewayId }
|
||||
|
||||
@@ -34,7 +34,7 @@ export { BackupTargetFS } from "./BackupTargetFS"
|
||||
export { Base64 } from "./Base64"
|
||||
export { BindId } from "./BindId"
|
||||
export { BindInfo } from "./BindInfo"
|
||||
export { BindingSetPublicParams } from "./BindingSetPublicParams"
|
||||
export { BindingGatewaySetEnabledParams } from "./BindingGatewaySetEnabledParams"
|
||||
export { BindOptions } from "./BindOptions"
|
||||
export { BindParams } from "./BindParams"
|
||||
export { Blake3Commitment } from "./Blake3Commitment"
|
||||
@@ -78,6 +78,7 @@ export { FileType } from "./FileType"
|
||||
export { ForgetInterfaceParams } from "./ForgetInterfaceParams"
|
||||
export { FullIndex } from "./FullIndex"
|
||||
export { FullProgress } from "./FullProgress"
|
||||
export { GatewayId } from "./GatewayId"
|
||||
export { GetActionInputParams } from "./GetActionInputParams"
|
||||
export { GetContainerIpParams } from "./GetContainerIpParams"
|
||||
export { GetHostInfoParams } from "./GetHostInfoParams"
|
||||
|
||||
Reference in New Issue
Block a user