From 3d13486a012021e0209e7aff6ad2612b10e574b6 Mon Sep 17 00:00:00 2001 From: Jacob Rothstein Date: Fri, 8 May 2026 11:15:48 -0700 Subject: [PATCH 1/4] [trillium] improve implementation and update for recent changes --- frameworks/trillium-tuned/Cargo.lock | 433 +++++++++--------- frameworks/trillium-tuned/Cargo.toml | 14 +- frameworks/trillium-tuned/Dockerfile | 2 + frameworks/trillium-tuned/askama.toml | 3 + frameworks/trillium-tuned/meta.json | 1 + frameworks/trillium-tuned/src/handlers.rs | 3 + .../trillium-tuned/src/handlers/fortunes.rs | 86 ++++ frameworks/trillium-tuned/src/handlers/ws.rs | 9 +- frameworks/trillium-tuned/src/main.rs | 201 ++------ frameworks/trillium-tuned/src/runtime.rs | 42 -- frameworks/trillium-tuned/src/state.rs | 31 +- .../trillium-tuned/src/static_preload.rs | 32 +- .../trillium-tuned/templates/fortunes.html | 10 + frameworks/trillium/Cargo.lock | 402 ++++++++-------- frameworks/trillium/Cargo.toml | 11 +- frameworks/trillium/Dockerfile | 2 + frameworks/trillium/askama.toml | 3 + frameworks/trillium/compose.gateway-h3.yml | 4 +- frameworks/trillium/compose.gateway.yml | 4 +- frameworks/trillium/meta.json | 1 + frameworks/trillium/proxy/src/main.rs | 142 ++++-- frameworks/trillium/src/handlers.rs | 3 + frameworks/trillium/src/handlers/fortunes.rs | 86 ++++ frameworks/trillium/src/handlers/ws.rs | 9 +- frameworks/trillium/src/main.rs | 112 ++--- frameworks/trillium/src/state.rs | 16 +- frameworks/trillium/templates/fortunes.html | 10 + 27 files changed, 907 insertions(+), 765 deletions(-) create mode 100644 frameworks/trillium-tuned/askama.toml create mode 100644 frameworks/trillium-tuned/src/handlers/fortunes.rs delete mode 100644 frameworks/trillium-tuned/src/runtime.rs create mode 100644 frameworks/trillium-tuned/templates/fortunes.html create mode 100644 frameworks/trillium/askama.toml create mode 100644 frameworks/trillium/src/handlers/fortunes.rs create mode 100644 frameworks/trillium/templates/fortunes.html diff --git a/frameworks/trillium-tuned/Cargo.lock b/frameworks/trillium-tuned/Cargo.lock index b98434a46..b16bf38db 100644 --- a/frameworks/trillium-tuned/Cargo.lock +++ b/frameworks/trillium-tuned/Cargo.lock @@ -107,6 +107,59 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "askama" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf825125edd887a019d0a3a837dcc5499a68b0d034cc3eb594070c3e18addc" +dependencies = [ + "askama_macros", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1c7065972a130eafa84215f21352ae15b4a7393da48c1f5e103904490736738" +dependencies = [ + "askama_parser", + "basic-toml", + "glob", + "memchr", + "proc-macro2", + "quote", + "rustc-hash", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "askama_macros" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e23b1d2c4bd39a41971f6124cef4cc6fd0540913ecb90919b69ab3bbe44ae1a" +dependencies = [ + "askama_derive", +] + +[[package]] +name = "askama_parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7db09fde9143e7ac4513358fb32ee32847125b63b18ea715afd487956da715da" +dependencies = [ + "rustc-hash", + "serde", + "serde_derive", + "unicode-ident", + "winnow", +] + [[package]] name = "async-channel" version = "2.5.0" @@ -187,15 +240,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "aws-lc-rs" -version = "1.16.3" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" +checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00" dependencies = [ "aws-lc-sys", "zeroize", @@ -203,9 +256,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" +checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4" dependencies = [ "cc", "cmake", @@ -219,6 +272,15 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "basic-toml" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "2.11.1" @@ -245,9 +307,9 @@ dependencies = [ [[package]] name = "brotli" -version = "8.0.2" +version = "8.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +checksum = "8119e4516436f5708bbc474a9d395bf12f1b5395e93a92a56e647ac3388c8610" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -256,9 +318,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "5.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +checksum = "5962523e1b92ce1b5e793d9169b9943eece10d39f62550bc04bb605d75b94924" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -266,9 +328,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "byteorder" @@ -284,9 +346,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.61" +version = "1.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" dependencies = [ "find-msvc-tools", "jobserver", @@ -334,9 +396,9 @@ dependencies = [ [[package]] name = "cmov" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" [[package]] name = "colorchoice" @@ -346,12 +408,11 @@ checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "colored" -version = "2.2.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "lazy_static", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -460,9 +521,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" dependencies = [ "hybrid-array", ] @@ -478,9 +539,9 @@ dependencies = [ [[package]] name = "dashmap" -version = "6.1.0" +version = "6.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" dependencies = [ "cfg-if", "crossbeam-utils", @@ -552,15 +613,15 @@ checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ "block-buffer 0.12.0", "const-oid", - "crypto-common 0.2.1", + "crypto-common 0.2.2", "ctutils", ] [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", @@ -668,18 +729,18 @@ dependencies = [ [[package]] name = "fieldwork" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4ce2198f558616d979bf4e13c0684f695ffeebe1a541ca466c928ddf42185b" +checksum = "16b5ff57d22899405076c15dd38c2735eb8ff261a37fd0d1b0e841f3fd298433" dependencies = [ "fieldwork-derive", ] [[package]] name = "fieldwork-derive" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4ce202eae2f2828b8f461bb6e8c40ed5358db1c3dce9e34108c94e68fe580" +checksum = "d9aca8417ff665ef605a5d6f8f7670df33f74f3226003a1021582940878730b3" dependencies = [ "proc-macro2", "quote", @@ -802,9 +863,9 @@ dependencies = [ [[package]] name = "generator" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" +checksum = "b3b854b0e584ead1a33f18b2fcad7cf7be18b3875c78816b753639aa501513ae" dependencies = [ "cc", "cfg-if", @@ -866,15 +927,17 @@ dependencies = [ "wasip3", ] +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] [[package]] name = "hashbrown" @@ -887,9 +950,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.17.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" dependencies = [ "allocator-api2", "equivalent", @@ -921,6 +984,7 @@ dependencies = [ name = "httparena-trillium-tuned" version = "0.1.0" dependencies = [ + "askama", "dashmap", "deadpool-postgres", "env_logger", @@ -931,12 +995,13 @@ dependencies = [ "querystrong", "serde", "serde_json", - "signal-hook 0.3.18", - "socket2 0.5.10", + "signal-hook", + "socket2", "sonic-rs", "swansong", "tokio-postgres", - "trillium 1.1.0", + "trillium", + "trillium-askama", "trillium-compression", "trillium-logger", "trillium-quinn", @@ -960,9 +1025,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hybrid-array" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d46837a0ed51fe95bd3b05de33cd64a1ee88fc797477ca48446872504507c5" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" dependencies = [ "typenum", ] @@ -1083,7 +1148,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.17.0", + "hashbrown 0.17.1", "serde", "serde_core", ] @@ -1102,9 +1167,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" -version = "0.2.24" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d" +checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102" dependencies = [ "jiff-static", "log", @@ -1115,9 +1180,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.24" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7" +checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47" dependencies = [ "proc-macro2", "quote", @@ -1180,9 +1245,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.98" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" +checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" dependencies = [ "cfg-if", "futures-util", @@ -1210,18 +1275,18 @@ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libmimalloc-sys" -version = "0.1.47" +version = "0.1.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1eacfa31c33ec25e873c136ba5669f00f9866d0688bea7be4d3f7e43067df6" +checksum = "6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9" dependencies = [ "cc", ] [[package]] name = "libredox" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" +checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" dependencies = [ "libc", ] @@ -1254,9 +1319,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" [[package]] name = "loom" @@ -1298,15 +1363,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" [[package]] name = "mimalloc" -version = "0.1.50" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3627c4272df786b9260cabaa46aec1d59c93ede723d4c3ef646c503816b0640" +checksum = "2d4139bb28d14ad1facf21d5eb8825051b326e172d216b39f6d31df53cc97862" dependencies = [ "libmimalloc-sys", ] @@ -1329,9 +1394,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "wasi 0.11.1+wasi-snapshot-preview1", @@ -1369,9 +1434,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num_cpus" @@ -1626,7 +1691,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.6.3", + "socket2", "thiserror 2.0.18", "tokio", "tracing", @@ -1664,7 +1729,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.3", + "socket2", "tracing", "windows-sys 0.60.2", ] @@ -1830,7 +1895,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73389e0c99e664f919275ab5b5b0471391fe9a8de61e1dff9b1eaf56a90f16e3" dependencies = [ "bytes", - "hashbrown 0.17.0", + "hashbrown 0.17.1", "indexmap", "munge", "ptr_meta", @@ -1895,9 +1960,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" dependencies = [ "openssl-probe", "rustls-pki-types", @@ -2060,9 +2125,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "itoa", "memchr", @@ -2104,19 +2169,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook" -version = "0.3.18" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" -dependencies = [ - "libc", - "signal-hook-registry", -] +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signal-hook" @@ -2146,7 +2201,7 @@ checksum = "e513e435a8898a0002270f29d0a708b7879708fb5c4d00e46983ca2d2d378cf0" dependencies = [ "futures-core", "libc", - "signal-hook 0.4.4", + "signal-hook", "tokio", ] @@ -2170,9 +2225,9 @@ checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" [[package]] name = "size" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fed904c7fb2856d868b92464fc8fa597fce366edea1a9cbfaa8cb5fe080bd6d" +checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b" [[package]] name = "slab" @@ -2208,19 +2263,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "socket2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", "windows-sys 0.61.2", @@ -2277,17 +2322,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "stopper" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bc3cb56a90ab1d29db096b9a448424e2c80cb57b4598a392b01bb4e9f5e021" -dependencies = [ - "event-listener", - "futures-lite", - "pin-project-lite", -] - [[package]] name = "stringprep" version = "0.1.5" @@ -2454,15 +2488,15 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.52.2" +version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "110a78583f19d5cdb2c5ccf321d1290344e71313c6c37d43520d386027d18386" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", "libc", "mio", "pin-project-lite", - "socket2 0.6.3", + "socket2", "windows-sys 0.61.2", ] @@ -2486,7 +2520,7 @@ dependencies = [ "postgres-protocol", "postgres-types", "rand 0.10.1", - "socket2 0.6.3", + "socket2", "tokio", "tokio-util", "whoami", @@ -2580,66 +2614,44 @@ dependencies = [ [[package]] name = "trillium" -version = "0.2.20" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84b5b14b3b2dda42a660fd7476a00f25c7565c4f1dc63b4322a7855a1c5384f" +checksum = "616f6b4783efa17cd96b35ce691de520aefe69c2ef0af3f422e92eb25dc39392" dependencies = [ - "async-trait", + "futures-lite", "log", - "trillium-http 0.3.17", + "trillium-http", + "trillium-macros", ] [[package]] -name = "trillium" -version = "1.1.0" +name = "trillium-askama" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42555814b00d06d4e3ea4dc1ee1929cfab2d776512b8850a907da51393ef9bc7" +checksum = "4fbaedec266e8969d05bccd12e0cc827d07c8594109ee9344ab4f02ffc08d116" dependencies = [ - "futures-lite", + "askama", "log", - "trillium-http 1.2.0", - "trillium-macros 0.1.0", + "trillium", ] [[package]] name = "trillium-compression" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bbdb555021d201e16c7f6cc8e974187304bef6a93e93173ea2e53f8f51d3d3" +checksum = "c2b3bdd9df5958f7da6ea6d53c7f5a6b6b420df6f884dc8eecf66a397c6917c0" dependencies = [ "async-compression", "futures-lite", "log", - "trillium 1.1.0", + "trillium", ] [[package]] name = "trillium-http" -version = "0.3.17" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4c063660875422d9f85a334931963fc301a3ede9a5c39de7c968ab0801ce33" -dependencies = [ - "encoding_rs", - "futures-lite", - "hashbrown 0.14.5", - "httparse", - "httpdate", - "log", - "memchr", - "mime", - "smallvec", - "smartcow", - "smartstring", - "stopper", - "thiserror 1.0.69", - "trillium-macros 0.0.6", -] - -[[package]] -name = "trillium-http" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0839041d8e319613bec2d04c0534a3801378866b1643d44b5ff820a828f21e5" +checksum = "b326aef316f0d8944ef28d844553f963e88e9ef8c027f23ffa0c0890fbf50e2b" dependencies = [ "atomic-waker", "encoding_rs", @@ -2647,7 +2659,7 @@ dependencies = [ "fastrand", "fieldwork", "futures-lite", - "hashbrown 0.17.0", + "hashbrown 0.17.1", "httparse", "httpdate", "log", @@ -2660,32 +2672,23 @@ dependencies = [ "swansong", "sync_wrapper", "thiserror 2.0.18", - "trillium-macros 0.1.0", + "trillium-macros", "type-set", ] [[package]] name = "trillium-logger" -version = "0.4.5" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da5e9b6c08a27d991b4a9c73dd7276c6f181fd4dee7218723b0fbd7fca3a1659" +checksum = "417cb361e181e34ba9300d8e32b8dda76a1220e926051425f470c3c38c0e40ac" dependencies = [ "colored", "log", "size", "time", - "trillium 0.2.20", -] - -[[package]] -name = "trillium-macros" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916e37646d33632b88ca02d4b8c4e2e6376f2a89d9888de71b7d82c150ed1f6c" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "trillium", + "trillium-http", + "url", ] [[package]] @@ -2701,9 +2704,9 @@ dependencies = [ [[package]] name = "trillium-quinn" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3935766f08636bf455dc713cf645702fa139f169608858e2da76bd9e0377b59" +checksum = "bca938d12b6a598c2fd9ba074f794c799296e5d7db791436c2a26cb244709be4" dependencies = [ "async-compat", "futures-lite", @@ -2711,7 +2714,7 @@ dependencies = [ "quinn", "rustls", "rustls-pemfile", - "trillium-macros 0.1.0", + "trillium-macros", "trillium-server-common", ] @@ -2723,14 +2726,14 @@ checksum = "67c56f83644b5a88362f8b0ce76fdc9d58cec068794bfc0add81e86986096c7f" dependencies = [ "log", "routefinder", - "trillium 1.1.0", + "trillium", ] [[package]] name = "trillium-rustls" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf428f82c0bcb0da509db3d4040d4ab921d3d2a6dd8796d128fb75639b00667" +checksum = "934aca932b8126485f4df30d3767b6da54cb9b292d57d77fde4a67e0c7418a7e" dependencies = [ "futures-rustls", "log", @@ -2742,39 +2745,41 @@ dependencies = [ [[package]] name = "trillium-server-common" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f22c217fbc86faed25a782cea0cbb726d82a8cc486962d49c3bd6ecf124bb53c" +checksum = "bdfd4fadcb61c240282901bc27424147780e556714a2d602f7e4afa187d2a521" dependencies = [ "async-channel", "async_cell", + "cfg_aliases", "fieldwork", "futures-lite", "listenfd", "log", "pin-project-lite", "rlimit", + "socket2", "swansong", - "trillium 1.1.0", - "trillium-http 1.2.0", + "trillium", + "trillium-http", "url", ] [[package]] name = "trillium-tokio" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b0d2e388eae1c568fb0ec5fe8d44253cbd338aa56139da9bb5663b22de01e2d" +checksum = "29f9fc3d83c93ca60d33c070b4d40add11ccd5fd1a9e90a2938960ad5f6c413e" dependencies = [ "async-compat", "log", - "signal-hook 0.4.4", + "signal-hook", "signal-hook-tokio", "tokio", "tokio-stream", - "trillium 1.1.0", - "trillium-http 1.2.0", - "trillium-macros 0.1.0", + "trillium", + "trillium-http", + "trillium-macros", "trillium-server-common", ] @@ -2793,8 +2798,8 @@ dependencies = [ "sha-1", "swansong", "thiserror 2.0.18", - "trillium 1.1.0", - "trillium-http 1.2.0", + "trillium", + "trillium-http", ] [[package]] @@ -2817,9 +2822,9 @@ checksum = "845e18586b78ef401c37d9d2d2cca631c19816d5aa26af12647e828739bd6614" [[package]] name = "typenum" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "unicode-bidi" @@ -2886,9 +2891,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.1" +version = "1.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7" dependencies = [ "js-sys", "wasm-bindgen", @@ -2960,9 +2965,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" +checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" dependencies = [ "cfg-if", "once_cell", @@ -2973,9 +2978,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" +checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2983,9 +2988,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" +checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" dependencies = [ "bumpalo", "proc-macro2", @@ -2996,9 +3001,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" +checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" dependencies = [ "unicode-ident", ] @@ -3039,9 +3044,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.98" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa" +checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" dependencies = [ "js-sys", "wasm-bindgen", @@ -3152,15 +3157,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" @@ -3365,6 +3361,15 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +[[package]] +name = "winnow" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +dependencies = [ + "memchr", +] + [[package]] name = "wit-bindgen" version = "0.51.0" @@ -3490,18 +3495,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" dependencies = [ "proc-macro2", "quote", @@ -3510,9 +3515,9 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] diff --git a/frameworks/trillium-tuned/Cargo.toml b/frameworks/trillium-tuned/Cargo.toml index 4e31941ab..1cedc0d0b 100644 --- a/frameworks/trillium-tuned/Cargo.toml +++ b/frameworks/trillium-tuned/Cargo.toml @@ -4,14 +4,16 @@ version = "0.1.0" edition = "2024" [dependencies] -trillium = "1.1" -trillium-tokio = "0.6" +trillium = "1.3" +trillium-tokio = { version = "0.6", features = ["reuseport"] } trillium-router = "0.5" trillium-rustls = "0.11" trillium-quinn = "0.1" trillium-websockets = "0.8" -trillium-compression = "0.2" -trillium-logger = "0.4" +trillium-compression = "0.3" +trillium-askama = "0.5" +askama = "0.16" +trillium-logger = "0.5" swansong = "0.3.4" futures-lite = "2" @@ -27,9 +29,9 @@ dashmap = "6" log = "0.4" env_logger = "0.11" mimalloc = { version = "0.1", default-features = false } -socket2 = { version = "0.5", features = ["all"] } +socket2 = { version = "0.6", features = ["all"] } num_cpus = "1" -signal-hook = "0.3" +signal-hook = "0.4" [profile.release] opt-level = 3 diff --git a/frameworks/trillium-tuned/Dockerfile b/frameworks/trillium-tuned/Dockerfile index a4313c70d..279f54119 100644 --- a/frameworks/trillium-tuned/Dockerfile +++ b/frameworks/trillium-tuned/Dockerfile @@ -5,6 +5,8 @@ RUN mkdir src && echo "fn main() {}" > src/main.rs && \ cargo build --release && \ rm -rf src/ target/release/httparena-trillium-tuned* target/release/deps/httparena_trillium_tuned* COPY src ./src +COPY templates ./templates +COPY askama.toml . RUN RUSTFLAGS="-C target-cpu=native" cargo build --release FROM debian:bookworm-slim diff --git a/frameworks/trillium-tuned/askama.toml b/frameworks/trillium-tuned/askama.toml new file mode 100644 index 000000000..e42939b1a --- /dev/null +++ b/frameworks/trillium-tuned/askama.toml @@ -0,0 +1,3 @@ +[[escaper]] +path = "crate::handlers::fortunes::NamedHtmlEscaper" +extensions = ["html"] diff --git a/frameworks/trillium-tuned/meta.json b/frameworks/trillium-tuned/meta.json index de5ab6aa4..8db2316f5 100644 --- a/frameworks/trillium-tuned/meta.json +++ b/frameworks/trillium-tuned/meta.json @@ -17,6 +17,7 @@ "static", "async-db", "crud", + "fortunes", "api-4", "api-16", "baseline-h2", diff --git a/frameworks/trillium-tuned/src/handlers.rs b/frameworks/trillium-tuned/src/handlers.rs index 6a69889ed..3707c0062 100644 --- a/frameworks/trillium-tuned/src/handlers.rs +++ b/frameworks/trillium-tuned/src/handlers.rs @@ -3,15 +3,18 @@ //! - [`h1`] — `/pipeline`, `/baseline11`, `/baseline2`, `/json/:count`, `/upload` //! - [`db`] — `/async-db` //! - [`crud`] — `/crud/items` and `/crud/items/:id` +//! - [`fortunes`] — `/fortunes` //! - [`ws`] — `/ws` echo mod crud; mod db; +mod fortunes; mod h1; mod ws; pub use crud::{crud_create, crud_list, crud_read, crud_update}; pub use db::async_db; +pub use fortunes::fortunes; pub use h1::{baseline_any, baseline_get, json_handler, pipeline, upload}; use querystrong::QueryStrong; use trillium::{Conn, KnownHeaderName, Status}; diff --git a/frameworks/trillium-tuned/src/handlers/fortunes.rs b/frameworks/trillium-tuned/src/handlers/fortunes.rs new file mode 100644 index 000000000..561ca0123 --- /dev/null +++ b/frameworks/trillium-tuned/src/handlers/fortunes.rs @@ -0,0 +1,86 @@ +use crate::state::AppState; +use askama::filters::Escaper; +use deadpool_postgres::Pool; +use std::{fmt, sync::Arc}; +use trillium::{Conn, KnownHeaderName, Status}; +use trillium_askama::{AskamaConnExt, Template}; + +pub struct Fortune { + pub id: i32, + pub message: String, +} + +#[derive(Template)] +#[template(path = "fortunes.html")] +struct FortunesTemplate { + fortunes: Vec, +} + +/// Auto-escaper used for the `.html` extension via `askama.toml`. +/// +/// Askama 0.15's built-in `Html` escaper writes numeric entities (`<`), +/// but the validator greps for the literal `<script>`. This emits +/// the named entities instead. +#[derive(Copy, Clone)] +pub struct NamedHtmlEscaper; + +impl Escaper for NamedHtmlEscaper { + fn write_escaped_str(&self, mut dest: W, s: &str) -> fmt::Result { + let mut last = 0; + for (i, b) in s.bytes().enumerate() { + let replacement = match b { + b'<' => "<", + b'>' => ">", + b'&' => "&", + b'"' => """, + b'\'' => "'", + _ => continue, + }; + dest.write_str(&s[last..i])?; + dest.write_str(replacement)?; + last = i + 1; + } + dest.write_str(&s[last..]) + } +} + +pub async fn fortunes(conn: Conn) -> Conn { + let state = Arc::clone(conn.shared_state::>().expect("AppState set")); + let Some(pool) = &state.pg else { + return conn.with_status(Status::ServiceUnavailable).halt(); + }; + + let mut fortunes = match query_fortunes(pool).await { + Ok(rows) => rows, + Err(e) => { + log::warn!("fortunes query failed: {e}"); + return conn.with_status(Status::InternalServerError).halt(); + } + }; + + fortunes.push(Fortune { + id: 0, + message: "Additional fortune added at request time.".into(), + }); + fortunes.sort_by(|a, b| a.message.as_bytes().cmp(b.message.as_bytes())); + + conn.render(FortunesTemplate { fortunes }) + .with_response_header(KnownHeaderName::ContentType, "text/html; charset=utf-8") +} + +async fn query_fortunes( + pool: &Pool, +) -> Result, Box> { + let client = pool.get().await?; + let stmt = client + .prepare_cached("SELECT id, message FROM fortune") + .await?; + let rows = client.query(&stmt, &[]).await?; + Ok(rows + .into_iter() + .map(|row| Fortune { + id: row.get(0), + message: row.get(1), + }) + .collect()) +} diff --git a/frameworks/trillium-tuned/src/handlers/ws.rs b/frameworks/trillium-tuned/src/handlers/ws.rs index ea2c2ea10..66eaf43f5 100644 --- a/frameworks/trillium-tuned/src/handlers/ws.rs +++ b/frameworks/trillium-tuned/src/handlers/ws.rs @@ -3,13 +3,12 @@ use trillium_websockets::{Message, WebSocketConn}; pub async fn ws_echo(mut conn: WebSocketConn) { use futures_lite::StreamExt; while let Some(Ok(msg)) = conn.next().await { - let result = match msg { - Message::Text(t) => conn.send_string(t.to_string()).await, - Message::Binary(b) => conn.send_bytes(b.to_vec()).await, + match &msg { Message::Ping(_) | Message::Pong(_) | Message::Frame(_) => continue, Message::Close(_) => break, - }; - if let Err(e) = result { + Message::Text(_) | Message::Binary(_) => {} + } + if let Err(e) = conn.send(msg).await { log::debug!("ws send failed: {e}"); break; } diff --git a/frameworks/trillium-tuned/src/main.rs b/frameworks/trillium-tuned/src/main.rs index caf772b92..1b4f995b5 100644 --- a/frameworks/trillium-tuned/src/main.rs +++ b/frameworks/trillium-tuned/src/main.rs @@ -2,30 +2,27 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; mod handlers; -mod runtime; mod state; mod static_preload; -use crate::{ - handlers::{ - async_db, baseline_any, baseline_get, crud_create, crud_list, crud_read, crud_update, - json_handler, pipeline, upload, ws_echo, - }, - runtime::bind_reuseport, - state::{AppState, SharedState, build_pg_pool}, - static_preload::StaticPreload, +use env_logger::Env; +use handlers::{ + async_db, baseline_any, baseline_get, crud_create, crud_list, crud_read, crud_update, fortunes, + json_handler, pipeline, upload, ws_echo, }; -use std::sync::Arc; -use trillium::Handler; +use state::{AppState, SharedState, build_pg_pool}; +use static_preload::StaticPreload; +use std::{env, error::Error, fs, sync::Arc}; +use trillium::{Handler, HttpConfig, Method}; use trillium_compression::Compression; use trillium_quinn::QuicConfig; use trillium_router::Router; use trillium_rustls::RustlsAcceptor; -use trillium_tokio::tokio; +use trillium_tokio::config; use trillium_websockets::websocket; -fn tuned_http_config() -> trillium::HttpConfig { - trillium::HttpConfig::default() +fn tuned_http_config() -> HttpConfig { + HttpConfig::default() .with_response_buffer_len(8192) .with_received_body_max_len(32 * 1024 * 1024) .with_received_body_initial_len(64 * 1024) @@ -40,12 +37,13 @@ fn build_handler(static_files: StaticPreload) -> impl Handler { Compression::new(), Router::new() .get("/pipeline", pipeline) - .any(&["get", "post"], "/baseline11", baseline_any) + .any(&[Method::Get, Method::Post], "/baseline11", baseline_any) .get("/baseline2", baseline_get) .get("/json/:count", json_handler) .post("/upload", upload) .get("/static/*", static_files) .get("/async-db", async_db) + .get("/fortunes", fortunes) .get("/crud/items", crud_list) .post("/crud/items", crud_create) .get("/crud/items/:id", crud_read) @@ -54,163 +52,56 @@ fn build_handler(static_files: StaticPreload) -> impl Handler { ) } -struct WorkerInputs { - shared: SharedState, - static_files: StaticPreload, - cert: Option>, - key: Option>, - swansong: swansong::Swansong, - tls_port: u16, - workers: usize, - is_quic_worker: bool, -} - -fn run_worker(idx: usize, inputs: WorkerInputs) { - let WorkerInputs { - shared, - static_files, - cert, - key, - swansong, - tls_port, - workers, - is_quic_worker, - } = inputs; - - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .expect("build current_thread runtime"); - - rt.block_on(async move { - // Build pool inside this worker's runtime so its tokio_postgres driver tasks - // are owned by this reactor. - let state = Arc::new(AppState { - dataset: shared.dataset.clone(), - crud_cache: shared.crud_cache.clone(), - pg: build_pg_pool(workers), - }); - let l8080 = bind_reuseport(8080).expect("bind 8080"); - log::info!("worker {idx}: bound 8080"); - - // 8080: cleartext h1 + ws - trillium_tokio::config() - .with_prebound_server(l8080) - .with_swansong(swansong.clone()) - .without_signals() - .with_nodelay() - .with_http_config(tuned_http_config()) - .with_shared_state(state.clone()) - .spawn(build_handler(static_files.clone())); - - if let (Some(cert), Some(key)) = (cert.as_deref(), key.as_deref()) { - let l8081 = bind_reuseport(8081).expect("bind 8081"); - trillium_tokio::config() - .with_prebound_server(l8081) - .with_swansong(swansong.clone()) - .without_signals() - .with_nodelay() - .with_http_config(tuned_http_config()) - .with_shared_state(state.clone()) - .with_acceptor(RustlsAcceptor::from_single_cert_no_h2(cert, key)) - .spawn(build_handler(static_files.clone())); - - let l_tls = bind_reuseport(tls_port).expect("bind TLS port"); - let tls_cfg = trillium_tokio::config() - .with_prebound_server(l_tls) - .with_swansong(swansong.clone()) - .without_signals() - .with_nodelay() - .with_http_config(tuned_http_config()) - .with_shared_state(state.clone()) - .with_acceptor(RustlsAcceptor::from_single_cert(cert, key)); - - if is_quic_worker { - tls_cfg - .with_quic(QuicConfig::from_single_cert(cert, key)) - .spawn(build_handler(static_files.clone())); - log::info!("worker {idx}: bound TLS + QUIC on {tls_port}"); - } else { - tls_cfg.spawn(build_handler(static_files.clone())); - log::info!("worker {idx}: bound TLS on {tls_port}"); - } - } else if idx == 0 { - log::warn!("TLS cert/key not found; only port 8080 is listening"); - } - - swansong.await; - }); -} - -fn main() { - env_logger::init_from_env(env_logger::Env::default().default_filter_or("info")); +fn main() -> Result<(), Box> { + env_logger::init_from_env(Env::default().default_filter_or("info")); let shared = SharedState::init(); - let static_dir = std::env::var("STATIC_DIR").unwrap_or_else(|_| "/data/static".into()); + let static_dir = env::var("STATIC_DIR").unwrap_or_else(|_| "/data/static".into()); let static_files = StaticPreload::load(&static_dir); - let cert = - std::fs::read(std::env::var("TLS_CERT").unwrap_or_else(|_| "/certs/server.crt".into())) - .ok(); - let key = - std::fs::read(std::env::var("TLS_KEY").unwrap_or_else(|_| "/certs/server.key".into())).ok(); + let cert = fs::read(env::var("TLS_CERT").unwrap_or_else(|_| "/certs/server.crt".into())).ok(); + let key = fs::read(env::var("TLS_KEY").unwrap_or_else(|_| "/certs/server.key".into())).ok(); - let tls_port: u16 = std::env::var("TLS_PORT") + let tls_port: u16 = env::var("TLS_PORT") .ok() .and_then(|s| s.parse().ok()) .unwrap_or(8443); - let n_workers: usize = std::env::var("WORKERS") + let n_workers: usize = env::var("WORKERS") .ok() .and_then(|s| s.parse().ok()) .unwrap_or_else(num_cpus::get) .max(1); - let swansong = swansong::Swansong::new(); + let state = Arc::new(AppState { + dataset: shared.dataset.clone(), + crud_cache: shared.crud_cache.clone(), + pg: build_pg_pool(), + }); - // Signal handler runs in its own OS thread (blocking iterator API), drives swansong on signal. - { - let swansong = swansong.clone(); - std::thread::Builder::new() - .name("signals".into()) - .spawn(move || { - let mut signals = signal_hook::iterator::Signals::new([ - signal_hook::consts::SIGINT, - signal_hook::consts::SIGTERM, - ]) - .expect("install signal handler"); - if signals.forever().next().is_some() { - log::info!("shutdown signal received"); - swansong.shut_down(); - } - }) - .expect("spawn signal thread"); + let mut builder = config() + .with_nodelay() + .with_http_config(tuned_http_config()) + .with_shared_state(state) + .listeners() + .with_reuseport_workers(n_workers) + .bind_reuseport_tcp(8080)?; + + if let (Some(cert), Some(key)) = (cert.as_deref(), key.as_deref()) { + builder = builder + .bind_reuseport_tls(8081, RustlsAcceptor::from_single_cert_no_h2(cert, key))? + .bind_reuseport_tls(tls_port, RustlsAcceptor::from_single_cert(cert, key))? + .bind_quic(tls_port, QuicConfig::from_single_cert(cert, key))?; + } else { + log::warn!("TLS cert/key not found; only port 8080 is listening"); } - log::info!("starting {n_workers} workers"); - - let mut handles = Vec::with_capacity(n_workers); - for idx in 0..n_workers { - let inputs = WorkerInputs { - shared: shared.clone(), - static_files: static_files.clone(), - cert: cert.clone(), - key: key.clone(), - swansong: swansong.clone(), - tls_port, - workers: n_workers, - is_quic_worker: idx == 0, - }; - handles.push( - std::thread::Builder::new() - .name(format!("worker-{idx}")) - .spawn(move || run_worker(idx, inputs)) - .expect("spawn worker thread"), - ); - } + log::info!( + "starting trillium-tuned via server(): {n_workers} reuseport worker(s) + shared runtime \ + for h3" + ); - for h in handles { - h.join().expect("worker join"); - } + builder.run(build_handler(static_files)); + Ok(()) } diff --git a/frameworks/trillium-tuned/src/runtime.rs b/frameworks/trillium-tuned/src/runtime.rs deleted file mode 100644 index 96b215227..000000000 --- a/frameworks/trillium-tuned/src/runtime.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! Per-CPU current_thread tokio runtimes with SO_REUSEPORT TCP listeners. -//! -//! Each worker OS thread: -//! 1. Builds a `current_thread` tokio runtime. -//! 2. Creates one `socket2::Socket` per port (8080, optionally 8081/8443) with `SO_REUSEPORT` + -//! `SO_REUSEADDR` + `TCP_NODELAY`, binds it to the same address as every other worker, and -//! converts to `tokio::net::TcpListener`. -//! 3. Hands each listener to a `trillium_tokio::config().with_prebound_server(...)`. -//! 4. Awaits a shared `Swansong` to coordinate graceful shutdown. -//! -//! The kernel's SO_REUSEPORT load-balancer hashes incoming SYNs across listeners by 4-tuple, -//! so connections fan out across workers without any user-space dispatch hop. -//! -//! Worker 0 additionally binds the QUIC endpoint (single endpoint, not sharded — see comments -//! in main.rs). - -use socket2::{Domain, SockAddr, Socket, Type}; -use std::{ - io, - net::{Ipv4Addr, SocketAddr}, -}; -use trillium_tokio::tokio::net::TcpListener; - -const LISTEN_BACKLOG: i32 = 4096; - -/// Build a fresh TCP listener with SO_REUSEPORT, SO_REUSEADDR, and TCP_NODELAY, -/// bound to `0.0.0.0:port` and ready for tokio. -pub fn bind_reuseport(port: u16) -> io::Result { - let addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, port)); - let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?; - - #[cfg(unix)] - socket.set_reuse_port(true)?; - socket.set_reuse_address(true)?; - socket.set_nodelay(true)?; - socket.set_nonblocking(true)?; - socket.bind(&SockAddr::from(addr))?; - socket.listen(LISTEN_BACKLOG)?; - - let std_listener: std::net::TcpListener = socket.into(); - TcpListener::from_std(std_listener) -} diff --git a/frameworks/trillium-tuned/src/state.rs b/frameworks/trillium-tuned/src/state.rs index 0ba840d98..157c960b3 100644 --- a/frameworks/trillium-tuned/src/state.rs +++ b/frameworks/trillium-tuned/src/state.rs @@ -1,7 +1,10 @@ use dashmap::DashMap; -use deadpool_postgres::{Config as PgConfig, ManagerConfig, Pool, RecyclingMethod, Runtime}; +use deadpool_postgres::{ + Config as PgConfig, ManagerConfig, Pool, PoolConfig, RecyclingMethod, Runtime, +}; use serde::{Deserialize, Serialize}; use std::{ + env, fs, sync::Arc, time::{Duration, Instant}, }; @@ -25,13 +28,6 @@ pub struct Rating { pub count: u32, } -/// State each handler reads from `conn.shared_state`. -/// -/// `dataset` and `crud_cache` are `Arc`-wrapped so workers share them (cross-worker cache hits -/// satisfy the CRUD spec's "in-process cache" rule). `pg` is per-worker — its connections, and -/// the tokio_postgres driver tasks behind them, live on whichever worker's `current_thread` -/// runtime created the pool. Sharing one pool across runtimes would risk getting a connection -/// driven by another runtime back from `pool.get()`. pub struct AppState { pub dataset: Arc>, pub crud_cache: Arc>, @@ -45,7 +41,6 @@ pub struct CacheEntry { pub const CRUD_CACHE_TTL: Duration = Duration::from_millis(200); -/// Cross-worker pieces. Built once in main, cloned (cheaply, Arc) into each worker's `AppState`. #[derive(Clone)] pub struct SharedState { pub dataset: Arc>, @@ -54,9 +49,8 @@ pub struct SharedState { impl SharedState { pub fn init() -> Self { - let dataset_path = - std::env::var("DATASET_PATH").unwrap_or_else(|_| "/data/dataset.json".into()); - let dataset: Vec = std::fs::read(&dataset_path) + let dataset_path = env::var("DATASET_PATH").unwrap_or_else(|_| "/data/dataset.json".into()); + let dataset: Vec = fs::read(&dataset_path) .ok() .and_then(|bytes| sonic_rs::from_slice(&bytes).ok()) .unwrap_or_default(); @@ -67,22 +61,17 @@ impl SharedState { } } -/// Build the per-worker postgres pool. Returns `None` when `DATABASE_URL` is unset. -/// -/// Must be called from inside the worker's tokio runtime so the connections, when first -/// established, register their I/O resources with that runtime's reactor. -pub fn build_pg_pool(workers: usize) -> Option { - let url = std::env::var("DATABASE_URL").ok()?; +pub fn build_pg_pool() -> Option { + let url = env::var("DATABASE_URL").ok()?; let mut cfg = PgConfig::new(); cfg.url = Some(url); cfg.manager = Some(ManagerConfig { recycling_method: RecyclingMethod::Fast, }); - let total: usize = std::env::var("DATABASE_MAX_CONN") + let total: usize = env::var("DATABASE_MAX_CONN") .ok() .and_then(|s| s.parse().ok()) .unwrap_or(256); - let per_worker = (total / workers.max(1)).max(2); - cfg.pool = Some(deadpool_postgres::PoolConfig::new(per_worker)); + cfg.pool = Some(PoolConfig::new(total)); cfg.create_pool(Some(Runtime::Tokio1), NoTls).ok() } diff --git a/frameworks/trillium-tuned/src/static_preload.rs b/frameworks/trillium-tuned/src/static_preload.rs index 352e19179..4a7687460 100644 --- a/frameworks/trillium-tuned/src/static_preload.rs +++ b/frameworks/trillium-tuned/src/static_preload.rs @@ -9,9 +9,13 @@ use trillium::{Conn, Handler, KnownHeaderName, Status}; #[derive(Debug)] struct StaticFile { content_type: &'static str, - plain: Vec, - br: Option>, - gz: Option>, + plain: &'static [u8], + br: Option<&'static [u8]>, + gz: Option<&'static [u8]>, +} + +fn leak(bytes: Vec) -> &'static [u8] { + Box::leak(bytes.into_boxed_slice()) } #[derive(Clone)] @@ -65,29 +69,29 @@ impl StaticPreload { .entry(base.to_string()) .or_insert_with(|| StaticFile { content_type: content_type_for(base), - plain: Vec::new(), + plain: &[], br: None, gz: None, }) - .br = Some(bytes); + .br = Some(leak(bytes)); } else if let Some(base) = name.strip_suffix(".gz") { files .entry(base.to_string()) .or_insert_with(|| StaticFile { content_type: content_type_for(base), - plain: Vec::new(), + plain: &[], br: None, gz: None, }) - .gz = Some(bytes); + .gz = Some(leak(bytes)); } else { let entry = files.entry(name.clone()).or_insert_with(|| StaticFile { content_type: content_type_for(&name), - plain: Vec::new(), + plain: &[], br: None, gz: None, }); - entry.plain = bytes; + entry.plain = leak(bytes); } } @@ -110,19 +114,19 @@ impl Handler for StaticPreload { .get_str(KnownHeaderName::AcceptEncoding) .unwrap_or(""); - let (body, encoding): (&Vec, Option<&str>) = - if let (Some(br), true) = (file.br.as_ref(), accept.contains("br")) { + let (body, encoding): (&'static [u8], Option<&str>) = + if let (Some(br), true) = (file.br, accept.contains("br")) { (br, Some("br")) - } else if let (Some(gz), true) = (file.gz.as_ref(), accept.contains("gzip")) { + } else if let (Some(gz), true) = (file.gz, accept.contains("gzip")) { (gz, Some("gzip")) } else { - (&file.plain, None) + (file.plain, None) }; let mut conn = conn .with_status(Status::Ok) .with_response_header(KnownHeaderName::ContentType, file.content_type) - .with_body(body.clone()); + .with_body(body); if let Some(enc) = encoding { conn = conn.with_response_header(KnownHeaderName::ContentEncoding, enc); diff --git a/frameworks/trillium-tuned/templates/fortunes.html b/frameworks/trillium-tuned/templates/fortunes.html new file mode 100644 index 000000000..f0b19c159 --- /dev/null +++ b/frameworks/trillium-tuned/templates/fortunes.html @@ -0,0 +1,10 @@ + + +Fortunes + + + +{% for f in fortunes %} +{% endfor %}
idmessage
{{ f.id }}{{ f.message }}
+ + diff --git a/frameworks/trillium/Cargo.lock b/frameworks/trillium/Cargo.lock index 7b1a176ce..6a7b46701 100644 --- a/frameworks/trillium/Cargo.lock +++ b/frameworks/trillium/Cargo.lock @@ -107,6 +107,59 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "askama" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf825125edd887a019d0a3a837dcc5499a68b0d034cc3eb594070c3e18addc" +dependencies = [ + "askama_macros", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1c7065972a130eafa84215f21352ae15b4a7393da48c1f5e103904490736738" +dependencies = [ + "askama_parser", + "basic-toml", + "glob", + "memchr", + "proc-macro2", + "quote", + "rustc-hash", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "askama_macros" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e23b1d2c4bd39a41971f6124cef4cc6fd0540913ecb90919b69ab3bbe44ae1a" +dependencies = [ + "askama_derive", +] + +[[package]] +name = "askama_parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7db09fde9143e7ac4513358fb32ee32847125b63b18ea715afd487956da715da" +dependencies = [ + "rustc-hash", + "serde", + "serde_derive", + "unicode-ident", + "winnow", +] + [[package]] name = "async-channel" version = "2.5.0" @@ -187,15 +240,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "aws-lc-rs" -version = "1.16.3" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" +checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00" dependencies = [ "aws-lc-sys", "zeroize", @@ -203,9 +256,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" +checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4" dependencies = [ "cc", "cmake", @@ -219,6 +272,15 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "basic-toml" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "2.11.1" @@ -245,9 +307,9 @@ dependencies = [ [[package]] name = "brotli" -version = "8.0.2" +version = "8.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +checksum = "8119e4516436f5708bbc474a9d395bf12f1b5395e93a92a56e647ac3388c8610" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -256,9 +318,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "5.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +checksum = "5962523e1b92ce1b5e793d9169b9943eece10d39f62550bc04bb605d75b94924" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -266,9 +328,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "byteorder" @@ -284,9 +346,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.61" +version = "1.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" dependencies = [ "find-msvc-tools", "jobserver", @@ -334,9 +396,9 @@ dependencies = [ [[package]] name = "cmov" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" [[package]] name = "colorchoice" @@ -346,12 +408,11 @@ checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "colored" -version = "2.2.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "lazy_static", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -460,9 +521,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" dependencies = [ "hybrid-array", ] @@ -478,9 +539,9 @@ dependencies = [ [[package]] name = "dashmap" -version = "6.1.0" +version = "6.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" dependencies = [ "cfg-if", "crossbeam-utils", @@ -552,15 +613,15 @@ checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ "block-buffer 0.12.0", "const-oid", - "crypto-common 0.2.1", + "crypto-common 0.2.2", "ctutils", ] [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", @@ -678,18 +739,18 @@ dependencies = [ [[package]] name = "fieldwork" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4ce2198f558616d979bf4e13c0684f695ffeebe1a541ca466c928ddf42185b" +checksum = "16b5ff57d22899405076c15dd38c2735eb8ff261a37fd0d1b0e841f3fd298433" dependencies = [ "fieldwork-derive", ] [[package]] name = "fieldwork-derive" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4ce202eae2f2828b8f461bb6e8c40ed5358db1c3dce9e34108c94e68fe580" +checksum = "d9aca8417ff665ef605a5d6f8f7670df33f74f3226003a1021582940878730b3" dependencies = [ "proc-macro2", "quote", @@ -812,9 +873,9 @@ dependencies = [ [[package]] name = "generator" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" +checksum = "b3b854b0e584ead1a33f18b2fcad7cf7be18b3875c78816b753639aa501513ae" dependencies = [ "cc", "cfg-if", @@ -876,15 +937,17 @@ dependencies = [ "wasip3", ] +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] [[package]] name = "hashbrown" @@ -897,9 +960,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.17.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" dependencies = [ "allocator-api2", "equivalent", @@ -931,6 +994,7 @@ dependencies = [ name = "httparena-trillium" version = "0.1.0" dependencies = [ + "askama", "dashmap", "deadpool-postgres", "env_logger", @@ -943,7 +1007,8 @@ dependencies = [ "sonic-rs", "swansong", "tokio-postgres", - "trillium 1.1.0", + "trillium", + "trillium-askama", "trillium-compression", "trillium-logger", "trillium-quinn", @@ -968,9 +1033,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hybrid-array" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d46837a0ed51fe95bd3b05de33cd64a1ee88fc797477ca48446872504507c5" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" dependencies = [ "typenum", ] @@ -1091,7 +1156,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.17.0", + "hashbrown 0.17.1", "serde", "serde_core", ] @@ -1110,9 +1175,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" -version = "0.2.24" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d" +checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102" dependencies = [ "jiff-static", "log", @@ -1123,9 +1188,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.24" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7" +checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47" dependencies = [ "proc-macro2", "quote", @@ -1188,9 +1253,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.98" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" +checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" dependencies = [ "cfg-if", "futures-util", @@ -1218,18 +1283,18 @@ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libmimalloc-sys" -version = "0.1.47" +version = "0.1.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1eacfa31c33ec25e873c136ba5669f00f9866d0688bea7be4d3f7e43067df6" +checksum = "6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9" dependencies = [ "cc", ] [[package]] name = "libredox" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" +checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" dependencies = [ "libc", ] @@ -1262,9 +1327,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" [[package]] name = "loom" @@ -1306,15 +1371,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" [[package]] name = "mimalloc" -version = "0.1.50" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3627c4272df786b9260cabaa46aec1d59c93ede723d4c3ef646c503816b0640" +checksum = "2d4139bb28d14ad1facf21d5eb8825051b326e172d216b39f6d31df53cc97862" dependencies = [ "libmimalloc-sys", ] @@ -1347,9 +1412,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "wasi 0.11.1+wasi-snapshot-preview1", @@ -1387,9 +1452,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num_cpus" @@ -1857,7 +1922,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73389e0c99e664f919275ab5b5b0471391fe9a8de61e1dff9b1eaf56a90f16e3" dependencies = [ "bytes", - "hashbrown 0.17.0", + "hashbrown 0.17.1", "indexmap", "munge", "ptr_meta", @@ -1922,9 +1987,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" dependencies = [ "openssl-probe", "rustls-pki-types", @@ -2087,9 +2152,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "itoa", "memchr", @@ -2131,9 +2196,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signal-hook" @@ -2187,9 +2252,9 @@ checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" [[package]] name = "size" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fed904c7fb2856d868b92464fc8fa597fce366edea1a9cbfaa8cb5fe080bd6d" +checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b" [[package]] name = "slab" @@ -2225,9 +2290,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", "windows-sys 0.61.2", @@ -2284,17 +2349,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "stopper" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bc3cb56a90ab1d29db096b9a448424e2c80cb57b4598a392b01bb4e9f5e021" -dependencies = [ - "event-listener", - "futures-lite", - "pin-project-lite", -] - [[package]] name = "str-buf" version = "3.0.3" @@ -2467,9 +2521,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.52.2" +version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "110a78583f19d5cdb2c5ccf321d1290344e71313c6c37d43520d386027d18386" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", "libc", @@ -2593,66 +2647,44 @@ dependencies = [ [[package]] name = "trillium" -version = "0.2.20" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84b5b14b3b2dda42a660fd7476a00f25c7565c4f1dc63b4322a7855a1c5384f" +checksum = "616f6b4783efa17cd96b35ce691de520aefe69c2ef0af3f422e92eb25dc39392" dependencies = [ - "async-trait", + "futures-lite", "log", - "trillium-http 0.3.17", + "trillium-http", + "trillium-macros", ] [[package]] -name = "trillium" -version = "1.1.0" +name = "trillium-askama" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42555814b00d06d4e3ea4dc1ee1929cfab2d776512b8850a907da51393ef9bc7" +checksum = "4fbaedec266e8969d05bccd12e0cc827d07c8594109ee9344ab4f02ffc08d116" dependencies = [ - "futures-lite", + "askama", "log", - "trillium-http 1.2.0", - "trillium-macros 0.1.0", + "trillium", ] [[package]] name = "trillium-compression" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bbdb555021d201e16c7f6cc8e974187304bef6a93e93173ea2e53f8f51d3d3" +checksum = "c2b3bdd9df5958f7da6ea6d53c7f5a6b6b420df6f884dc8eecf66a397c6917c0" dependencies = [ "async-compression", "futures-lite", "log", - "trillium 1.1.0", -] - -[[package]] -name = "trillium-http" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4c063660875422d9f85a334931963fc301a3ede9a5c39de7c968ab0801ce33" -dependencies = [ - "encoding_rs", - "futures-lite", - "hashbrown 0.14.5", - "httparse", - "httpdate", - "log", - "memchr", - "mime", - "smallvec", - "smartcow", - "smartstring", - "stopper", - "thiserror 1.0.69", - "trillium-macros 0.0.6", + "trillium", ] [[package]] name = "trillium-http" -version = "1.2.0" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0839041d8e319613bec2d04c0534a3801378866b1643d44b5ff820a828f21e5" +checksum = "b326aef316f0d8944ef28d844553f963e88e9ef8c027f23ffa0c0890fbf50e2b" dependencies = [ "atomic-waker", "encoding_rs", @@ -2660,7 +2692,7 @@ dependencies = [ "fastrand", "fieldwork", "futures-lite", - "hashbrown 0.17.0", + "hashbrown 0.17.1", "httparse", "httpdate", "log", @@ -2673,32 +2705,23 @@ dependencies = [ "swansong", "sync_wrapper", "thiserror 2.0.18", - "trillium-macros 0.1.0", + "trillium-macros", "type-set", ] [[package]] name = "trillium-logger" -version = "0.4.5" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da5e9b6c08a27d991b4a9c73dd7276c6f181fd4dee7218723b0fbd7fca3a1659" +checksum = "417cb361e181e34ba9300d8e32b8dda76a1220e926051425f470c3c38c0e40ac" dependencies = [ "colored", "log", "size", "time", - "trillium 0.2.20", -] - -[[package]] -name = "trillium-macros" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916e37646d33632b88ca02d4b8c4e2e6376f2a89d9888de71b7d82c150ed1f6c" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "trillium", + "trillium-http", + "url", ] [[package]] @@ -2714,9 +2737,9 @@ dependencies = [ [[package]] name = "trillium-quinn" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3935766f08636bf455dc713cf645702fa139f169608858e2da76bd9e0377b59" +checksum = "bca938d12b6a598c2fd9ba074f794c799296e5d7db791436c2a26cb244709be4" dependencies = [ "async-compat", "futures-lite", @@ -2724,7 +2747,7 @@ dependencies = [ "quinn", "rustls", "rustls-pemfile", - "trillium-macros 0.1.0", + "trillium-macros", "trillium-server-common", ] @@ -2736,14 +2759,14 @@ checksum = "67c56f83644b5a88362f8b0ce76fdc9d58cec068794bfc0add81e86986096c7f" dependencies = [ "log", "routefinder", - "trillium 1.1.0", + "trillium", ] [[package]] name = "trillium-rustls" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf428f82c0bcb0da509db3d4040d4ab921d3d2a6dd8796d128fb75639b00667" +checksum = "934aca932b8126485f4df30d3767b6da54cb9b292d57d77fde4a67e0c7418a7e" dependencies = [ "futures-rustls", "log", @@ -2755,12 +2778,13 @@ dependencies = [ [[package]] name = "trillium-server-common" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f22c217fbc86faed25a782cea0cbb726d82a8cc486962d49c3bd6ecf124bb53c" +checksum = "bdfd4fadcb61c240282901bc27424147780e556714a2d602f7e4afa187d2a521" dependencies = [ "async-channel", "async_cell", + "cfg_aliases", "fieldwork", "futures-lite", "listenfd", @@ -2768,16 +2792,16 @@ dependencies = [ "pin-project-lite", "rlimit", "swansong", - "trillium 1.1.0", - "trillium-http 1.2.0", + "trillium", + "trillium-http", "url", ] [[package]] name = "trillium-static" -version = "0.5.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0a53adb5573d5effc5d7172cecfbfa4fb11c1f6ca9643d273c68419fd0077d3" +checksum = "df1cef5a91ac06c19ccab57a7a8cf53b1013ee8df22512ea604db4e380d55c11" dependencies = [ "async-compat", "cfg-if", @@ -2788,14 +2812,14 @@ dependencies = [ "mime_guess", "relative-path", "tokio", - "trillium 1.1.0", + "trillium", ] [[package]] name = "trillium-tokio" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b0d2e388eae1c568fb0ec5fe8d44253cbd338aa56139da9bb5663b22de01e2d" +checksum = "29f9fc3d83c93ca60d33c070b4d40add11ccd5fd1a9e90a2938960ad5f6c413e" dependencies = [ "async-compat", "log", @@ -2803,9 +2827,9 @@ dependencies = [ "signal-hook-tokio", "tokio", "tokio-stream", - "trillium 1.1.0", - "trillium-http 1.2.0", - "trillium-macros 0.1.0", + "trillium", + "trillium-http", + "trillium-macros", "trillium-server-common", ] @@ -2824,8 +2848,8 @@ dependencies = [ "sha-1", "swansong", "thiserror 2.0.18", - "trillium 1.1.0", - "trillium-http 1.2.0", + "trillium", + "trillium-http", ] [[package]] @@ -2848,9 +2872,9 @@ checksum = "845e18586b78ef401c37d9d2d2cca631c19816d5aa26af12647e828739bd6614" [[package]] name = "typenum" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "unicase" @@ -2923,9 +2947,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.1" +version = "1.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7" dependencies = [ "js-sys", "wasm-bindgen", @@ -2997,9 +3021,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" +checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" dependencies = [ "cfg-if", "once_cell", @@ -3010,9 +3034,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" +checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3020,9 +3044,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" +checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" dependencies = [ "bumpalo", "proc-macro2", @@ -3033,9 +3057,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" +checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" dependencies = [ "unicode-ident", ] @@ -3076,9 +3100,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.98" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa" +checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" dependencies = [ "js-sys", "wasm-bindgen", @@ -3189,15 +3213,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" @@ -3402,6 +3417,15 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +[[package]] +name = "winnow" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +dependencies = [ + "memchr", +] + [[package]] name = "wit-bindgen" version = "0.51.0" @@ -3533,18 +3557,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" dependencies = [ "proc-macro2", "quote", @@ -3553,9 +3577,9 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] diff --git a/frameworks/trillium/Cargo.toml b/frameworks/trillium/Cargo.toml index 2f91f3c3a..031961d31 100644 --- a/frameworks/trillium/Cargo.toml +++ b/frameworks/trillium/Cargo.toml @@ -4,15 +4,17 @@ version = "0.1.0" edition = "2024" [dependencies] -trillium = "1.1" +trillium = "1.3" trillium-tokio = "0.6" trillium-router = "0.5" trillium-rustls = "0.11" trillium-quinn = "0.1" trillium-websockets = "0.8" -trillium-static = { version = "0.5", features = ["tokio"] } -trillium-compression = "0.2" -trillium-logger = "0.4" +trillium-static = { version = "0.6", features = ["tokio"] } +trillium-compression = "0.3" +trillium-askama = "0.5" +askama = "0.16" +trillium-logger = "0.5" swansong = "0.3.4" futures-lite = "2" @@ -35,3 +37,4 @@ codegen-units = 1 lto = "fat" panic = "abort" strip = true + diff --git a/frameworks/trillium/Dockerfile b/frameworks/trillium/Dockerfile index 4bcc1024a..e92fc54e4 100644 --- a/frameworks/trillium/Dockerfile +++ b/frameworks/trillium/Dockerfile @@ -5,6 +5,8 @@ RUN mkdir src && echo "fn main() {}" > src/main.rs && \ cargo build --release && \ rm -rf src/ target/release/httparena-trillium* target/release/deps/httparena_trillium* COPY src ./src +COPY templates ./templates +COPY askama.toml . RUN RUSTFLAGS="-C target-cpu=native" cargo build --release FROM debian:bookworm-slim diff --git a/frameworks/trillium/askama.toml b/frameworks/trillium/askama.toml new file mode 100644 index 000000000..e42939b1a --- /dev/null +++ b/frameworks/trillium/askama.toml @@ -0,0 +1,3 @@ +[[escaper]] +path = "crate::handlers::fortunes::NamedHtmlEscaper" +extensions = ["html"] diff --git a/frameworks/trillium/compose.gateway-h3.yml b/frameworks/trillium/compose.gateway-h3.yml index e865c8106..af3148a4f 100644 --- a/frameworks/trillium/compose.gateway-h3.yml +++ b/frameworks/trillium/compose.gateway-h3.yml @@ -3,7 +3,7 @@ services: build: context: ./proxy network_mode: host - cpuset: "0-7,64-71" + cpuset: "${PROXY_CPUSET:-0-7,64-71}" ulimits: memlock: -1 nofile: @@ -30,7 +30,7 @@ services: context: . dockerfile: Dockerfile network_mode: host - cpuset: "8-31,72-95" + cpuset: "${SERVER_CPUSET:-8-31,72-95}" ulimits: memlock: -1 nofile: diff --git a/frameworks/trillium/compose.gateway.yml b/frameworks/trillium/compose.gateway.yml index 84cfa1a63..8349f514d 100644 --- a/frameworks/trillium/compose.gateway.yml +++ b/frameworks/trillium/compose.gateway.yml @@ -3,7 +3,7 @@ services: build: context: ./proxy network_mode: host - cpuset: "0-7,64-71" + cpuset: "${PROXY_CPUSET:-0-7,64-71}" ulimits: memlock: -1 nofile: @@ -29,7 +29,7 @@ services: context: . dockerfile: Dockerfile network_mode: host - cpuset: "8-31,72-95" + cpuset: "${SERVER_CPUSET:-8-31,72-95}" ulimits: memlock: -1 nofile: diff --git a/frameworks/trillium/meta.json b/frameworks/trillium/meta.json index 141f671ff..00e86637e 100644 --- a/frameworks/trillium/meta.json +++ b/frameworks/trillium/meta.json @@ -17,6 +17,7 @@ "static", "async-db", "crud", + "fortunes", "api-4", "api-16", "baseline-h2", diff --git a/frameworks/trillium/proxy/src/main.rs b/frameworks/trillium/proxy/src/main.rs index 748ae08a3..358f66b39 100644 --- a/frameworks/trillium/proxy/src/main.rs +++ b/frameworks/trillium/proxy/src/main.rs @@ -79,10 +79,9 @@ fn upstream_rustls_config() -> rustls::ClientConfig { config } -/// Build a fresh per-worker `Client`. Cross-runtime sharing of pooled connections is risky -/// (tokio I/O resources are tied to the runtime that opened them), so each worker gets its -/// own pool. h2/h3 multiplex hundreds of streams per upstream connection, so the upstream -/// connection-count multiplier here is fine. +/// Build a fresh `Client` for the runtime currently calling this fn. The Client's pool opens +/// upstream connections via the calling runtime's reactor; tasks awaiting those connections +/// must run on the same runtime, so each worker / MT runtime gets its own. fn build_client() -> Client { let rustls_client = upstream_rustls_config(); let quic_client = ClientQuicConfig::from_rustls_client_config(rustls_client.clone()); @@ -90,14 +89,10 @@ fn build_client() -> Client { Client::new_with_quic(rustls_layer, quic_client) } -fn build_handler() -> impl Handler { - let static_dir = std::env::var("STATIC_DIR").unwrap_or_else(|_| "/data/static".into()); - let upstream = - std::env::var("PROXY_UPSTREAM").unwrap_or_else(|_| "https://localhost:9443".into()); - +fn build_handler(client: Client, upstream: String, static_dir: String) -> impl Handler { ( Router::new().get("/static/*", files(static_dir)), - Proxy::new(build_client(), upstream).with_via_pseudonym("trillium-proxy"), + Proxy::new(client, upstream).with_via_pseudonym("trillium-proxy"), ) } @@ -119,18 +114,19 @@ struct WorkerInputs { cert: Vec, key: Vec, port: u16, - enable_h3: bool, - is_quic_worker: bool, + upstream: String, + static_dir: String, swansong: swansong::Swansong, } +/// Per-worker current_thread runtime: TCP-only proxy (h1, h2). No QUIC. fn run_worker(idx: usize, inputs: WorkerInputs) { let WorkerInputs { cert, key, port, - enable_h3, - is_quic_worker, + upstream, + static_dir, swansong, } = inputs; @@ -141,22 +137,66 @@ fn run_worker(idx: usize, inputs: WorkerInputs) { rt.block_on(async move { let listener = bind_reuseport(port).expect("bind proxy port"); - log::info!("worker {idx}: bound {port} (h3={})", enable_h3 && is_quic_worker); + let client = build_client(); + log::info!("proxy worker {idx}: bound TCP on {port}"); - let config = trillium_tokio::config() + trillium_tokio::config() .with_prebound_server(listener) .with_swansong(swansong.clone()) .without_signals() .with_nodelay() - .with_acceptor(RustlsAcceptor::from_single_cert(&cert, &key)); + .with_acceptor(RustlsAcceptor::from_single_cert(&cert, &key)) + .spawn(build_handler(client, upstream, static_dir)); + + swansong.await; + }); +} + +struct QuicRuntimeInputs { + cert: Vec, + key: Vec, + port: u16, + upstream: String, + static_dir: String, + n_threads: usize, + swansong: swansong::Swansong, +} - if enable_h3 && is_quic_worker { - config - .with_quic(QuicConfig::from_single_cert(&cert, &key)) - .spawn(build_handler()); - } else { - config.spawn(build_handler()); - } +/// Dedicated multi-thread runtime: TCP reuseport participant on `port` plus the QUIC endpoint. +/// h3 stream tasks spawned by quinn's accept loop spread across `n_threads` threads via tokio's +/// work-stealing scheduler. The per-worker current_thread runtimes still absorb most TCP traffic +/// (kernel reuseport hash gives the MT runtime ~1/(N+1) of TCP), preserving per-core hot caches. +fn run_quic_runtime(inputs: QuicRuntimeInputs) { + let QuicRuntimeInputs { + cert, + key, + port, + upstream, + static_dir, + n_threads, + swansong, + } = inputs; + + let rt = tokio::runtime::Builder::new_multi_thread() + .worker_threads(n_threads) + .enable_all() + .thread_name("quic-mt") + .build() + .expect("build quic multi_thread runtime"); + + rt.block_on(async move { + let listener = bind_reuseport(port).expect("bind proxy port on quic runtime"); + let client = build_client(); + log::info!("proxy quic-mt runtime: bound TCP + QUIC on {port} ({n_threads} threads)"); + + trillium_tokio::config() + .with_prebound_server(listener) + .with_swansong(swansong.clone()) + .without_signals() + .with_nodelay() + .with_acceptor(RustlsAcceptor::from_single_cert(&cert, &key)) + .with_quic(QuicConfig::from_single_cert(&cert, &key)) + .spawn(build_handler(client, upstream, static_dir)); swansong.await; }); @@ -183,6 +223,25 @@ fn main() { .unwrap_or_else(num_cpus::get) .max(1); + // Default the QUIC runtime size proportionally to N, capped at 8 (Zen2/3/4 CCX size = 4 + // physical cores / 8 SMT threads — keeping the MT runtime ≤1 CCX worth keeps h3 work + // L3-local and avoids paying the ~70-cycle inter-CCX hop on every steal). Override with + // QUIC_THREADS for tuning. + // + // Empirical 8-core measurements: Q=2 preserves full per-worker TCP performance (≤3% delta) + // while doubling h3 capacity over the previous worker-0-only design. Q=8 maximizes h3 (~4 + // cores' worth) at a 12-17% TCP cost. The proportional default lands users near the Q=2 + // point on small boxes and the Q=8 point on the bench machine. + let quic_threads: usize = std::env::var("QUIC_THREADS") + .ok() + .and_then(|s| s.parse().ok()) + .unwrap_or_else(|| (n_workers / 4).max(2).min(8)) + .max(1); + + let upstream = + std::env::var("PROXY_UPSTREAM").unwrap_or_else(|_| "https://localhost:9443".into()); + let static_dir = std::env::var("STATIC_DIR").unwrap_or_else(|_| "/data/static".into()); + let swansong = swansong::Swansong::new(); { @@ -203,16 +262,25 @@ fn main() { .expect("spawn signal thread"); } - log::info!("proxy starting {n_workers} workers (port={port}, h3={enable_h3})"); + if enable_h3 { + log::info!( + "proxy starting: {n_workers} per-worker current_thread workers (TCP) + 1 quic-mt runtime ({quic_threads} threads, h3 enabled, port={port})" + ); + } else { + log::info!( + "proxy starting: {n_workers} per-worker current_thread workers (TCP, port={port})" + ); + } + + let mut handles = Vec::with_capacity(n_workers + 1); - let mut handles = Vec::with_capacity(n_workers); for idx in 0..n_workers { let inputs = WorkerInputs { cert: cert.clone(), key: key.clone(), port, - enable_h3, - is_quic_worker: idx == 0, + upstream: upstream.clone(), + static_dir: static_dir.clone(), swansong: swansong.clone(), }; handles.push( @@ -223,6 +291,24 @@ fn main() { ); } + if enable_h3 { + let inputs = QuicRuntimeInputs { + cert: cert.clone(), + key: key.clone(), + port, + upstream: upstream.clone(), + static_dir: static_dir.clone(), + n_threads: quic_threads, + swansong: swansong.clone(), + }; + handles.push( + std::thread::Builder::new() + .name("quic-mt-driver".into()) + .spawn(move || run_quic_runtime(inputs)) + .expect("spawn quic-mt driver thread"), + ); + } + for h in handles { h.join().expect("worker join"); } diff --git a/frameworks/trillium/src/handlers.rs b/frameworks/trillium/src/handlers.rs index 6a69889ed..3707c0062 100644 --- a/frameworks/trillium/src/handlers.rs +++ b/frameworks/trillium/src/handlers.rs @@ -3,15 +3,18 @@ //! - [`h1`] — `/pipeline`, `/baseline11`, `/baseline2`, `/json/:count`, `/upload` //! - [`db`] — `/async-db` //! - [`crud`] — `/crud/items` and `/crud/items/:id` +//! - [`fortunes`] — `/fortunes` //! - [`ws`] — `/ws` echo mod crud; mod db; +mod fortunes; mod h1; mod ws; pub use crud::{crud_create, crud_list, crud_read, crud_update}; pub use db::async_db; +pub use fortunes::fortunes; pub use h1::{baseline_any, baseline_get, json_handler, pipeline, upload}; use querystrong::QueryStrong; use trillium::{Conn, KnownHeaderName, Status}; diff --git a/frameworks/trillium/src/handlers/fortunes.rs b/frameworks/trillium/src/handlers/fortunes.rs new file mode 100644 index 000000000..561ca0123 --- /dev/null +++ b/frameworks/trillium/src/handlers/fortunes.rs @@ -0,0 +1,86 @@ +use crate::state::AppState; +use askama::filters::Escaper; +use deadpool_postgres::Pool; +use std::{fmt, sync::Arc}; +use trillium::{Conn, KnownHeaderName, Status}; +use trillium_askama::{AskamaConnExt, Template}; + +pub struct Fortune { + pub id: i32, + pub message: String, +} + +#[derive(Template)] +#[template(path = "fortunes.html")] +struct FortunesTemplate { + fortunes: Vec, +} + +/// Auto-escaper used for the `.html` extension via `askama.toml`. +/// +/// Askama 0.15's built-in `Html` escaper writes numeric entities (`<`), +/// but the validator greps for the literal `<script>`. This emits +/// the named entities instead. +#[derive(Copy, Clone)] +pub struct NamedHtmlEscaper; + +impl Escaper for NamedHtmlEscaper { + fn write_escaped_str(&self, mut dest: W, s: &str) -> fmt::Result { + let mut last = 0; + for (i, b) in s.bytes().enumerate() { + let replacement = match b { + b'<' => "<", + b'>' => ">", + b'&' => "&", + b'"' => """, + b'\'' => "'", + _ => continue, + }; + dest.write_str(&s[last..i])?; + dest.write_str(replacement)?; + last = i + 1; + } + dest.write_str(&s[last..]) + } +} + +pub async fn fortunes(conn: Conn) -> Conn { + let state = Arc::clone(conn.shared_state::>().expect("AppState set")); + let Some(pool) = &state.pg else { + return conn.with_status(Status::ServiceUnavailable).halt(); + }; + + let mut fortunes = match query_fortunes(pool).await { + Ok(rows) => rows, + Err(e) => { + log::warn!("fortunes query failed: {e}"); + return conn.with_status(Status::InternalServerError).halt(); + } + }; + + fortunes.push(Fortune { + id: 0, + message: "Additional fortune added at request time.".into(), + }); + fortunes.sort_by(|a, b| a.message.as_bytes().cmp(b.message.as_bytes())); + + conn.render(FortunesTemplate { fortunes }) + .with_response_header(KnownHeaderName::ContentType, "text/html; charset=utf-8") +} + +async fn query_fortunes( + pool: &Pool, +) -> Result, Box> { + let client = pool.get().await?; + let stmt = client + .prepare_cached("SELECT id, message FROM fortune") + .await?; + let rows = client.query(&stmt, &[]).await?; + Ok(rows + .into_iter() + .map(|row| Fortune { + id: row.get(0), + message: row.get(1), + }) + .collect()) +} diff --git a/frameworks/trillium/src/handlers/ws.rs b/frameworks/trillium/src/handlers/ws.rs index ea2c2ea10..66eaf43f5 100644 --- a/frameworks/trillium/src/handlers/ws.rs +++ b/frameworks/trillium/src/handlers/ws.rs @@ -3,13 +3,12 @@ use trillium_websockets::{Message, WebSocketConn}; pub async fn ws_echo(mut conn: WebSocketConn) { use futures_lite::StreamExt; while let Some(Ok(msg)) = conn.next().await { - let result = match msg { - Message::Text(t) => conn.send_string(t.to_string()).await, - Message::Binary(b) => conn.send_bytes(b.to_vec()).await, + match &msg { Message::Ping(_) | Message::Pong(_) | Message::Frame(_) => continue, Message::Close(_) => break, - }; - if let Err(e) = result { + Message::Text(_) | Message::Binary(_) => {} + } + if let Err(e) = conn.send(msg).await { log::debug!("ws send failed: {e}"); break; } diff --git a/frameworks/trillium/src/main.rs b/frameworks/trillium/src/main.rs index b4be31c34..d874dece6 100644 --- a/frameworks/trillium/src/main.rs +++ b/frameworks/trillium/src/main.rs @@ -4,34 +4,38 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; mod handlers; mod state; -use crate::{ - handlers::{ - async_db, baseline_any, baseline_get, crud_create, crud_list, crud_read, crud_update, - json_handler, pipeline, upload, ws_echo, - }, - state::AppState, +use env_logger::Env; +use handlers::{ + async_db, baseline_any, baseline_get, crud_create, crud_list, crud_read, crud_update, fortunes, + json_handler, pipeline, upload, ws_echo, }; -use trillium::Handler; +use state::AppState; +use std::{env, error::Error, fs}; +use trillium::{Handler, HttpConfig, Method}; use trillium_compression::Compression; use trillium_quinn::QuicConfig; use trillium_router::Router; use trillium_rustls::RustlsAcceptor; -use trillium_static::files; -use trillium_tokio::tokio; +use trillium_static::StaticFileHandler; +use trillium_tokio::config; use trillium_websockets::websocket; fn build_handler() -> impl Handler { - let static_dir = std::env::var("STATIC_DIR").unwrap_or_else(|_| "/data/static".into()); + let static_dir = env::var("STATIC_DIR").unwrap_or_else(|_| "/data/static".into()); ( Compression::new(), Router::new() .get("/pipeline", pipeline) - .any(&["get", "post"], "/baseline11", baseline_any) + .any(&[Method::Get, Method::Post], "/baseline11", baseline_any) .get("/baseline2", baseline_get) .get("/json/:count", json_handler) .post("/upload", upload) - .get("/static/*", files(static_dir)) + .get( + "/static/*", + StaticFileHandler::new(static_dir).with_precompressed(), + ) .get("/async-db", async_db) + .get("/fortunes", fortunes) .get("/crud/items", crud_list) .post("/crud/items", crud_create) .get("/crud/items/:id", crud_read) @@ -40,71 +44,37 @@ fn build_handler() -> impl Handler { ) } -fn main() { - env_logger::init_from_env(env_logger::Env::default().default_filter_or("info")); +fn main() -> Result<(), Box> { + env_logger::init_from_env(Env::default().default_filter_or("info")); let state = AppState::init(); - let cert = - std::fs::read(std::env::var("TLS_CERT").unwrap_or_else(|_| "/certs/server.crt".into())) - .ok(); - let key = - std::fs::read(std::env::var("TLS_KEY").unwrap_or_else(|_| "/certs/server.key".into())).ok(); + let cert = fs::read(env::var("TLS_CERT").unwrap_or_else(|_| "/certs/server.crt".into())).ok(); + let key = fs::read(env::var("TLS_KEY").unwrap_or_else(|_| "/certs/server.key".into())).ok(); - let http_config = trillium::HttpConfig::default().with_received_body_max_len(32 * 1024 * 1024); + let tls_port: u16 = env::var("TLS_PORT") + .ok() + .and_then(|s| s.parse().ok()) + .unwrap_or(8443); - let runtime = tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .unwrap(); + let http_config = HttpConfig::default().with_received_body_max_len(32 * 1024 * 1024); - let swansong = swansong::Swansong::new(); + let mut builder = config() + .with_nodelay() + .with_http_config(http_config) + .with_shared_state(state) + .listeners() + .bind_tcp(8080)?; - runtime.block_on(async move { - if let (Some(cert), Some(key)) = (cert.as_deref(), key.as_deref()) { - let tls_port: u16 = std::env::var("TLS_PORT") - .ok() - .and_then(|s| s.parse().ok()) - .unwrap_or(8443); + if let (Some(cert), Some(key)) = (cert.as_deref(), key.as_deref()) { + builder = builder + .bind_tls(8081, RustlsAcceptor::from_single_cert_no_h2(cert, key))? + .bind_tls(tls_port, RustlsAcceptor::from_single_cert(cert, key))? + .bind_quic(tls_port, QuicConfig::from_single_cert(cert, key))?; + } else { + log::warn!("TLS cert/key not found; only port 8080 is listening"); + } - // 8081: h1 only over TLS (ALPN http/1.1) — for json-tls - trillium_tokio::config() - .with_port(8081) - .with_host("0.0.0.0") - .with_nodelay() - .with_swansong(swansong.clone()) - .without_signals() - .with_http_config(http_config) - .with_shared_state(state.clone()) - .with_acceptor(RustlsAcceptor::from_single_cert_no_h2(cert, key)) - .spawn(build_handler()); - - // TLS_PORT (default 8443): h1 + h2 over TLS, plus h3 over QUIC - trillium_tokio::config() - .with_port(tls_port) - .with_host("0.0.0.0") - .with_nodelay() - .with_swansong(swansong.clone()) - .without_signals() - .with_http_config(http_config) - .with_shared_state(state.clone()) - .with_acceptor(RustlsAcceptor::from_single_cert(cert, key)) - .with_quic(QuicConfig::from_single_cert(cert, key)) - .spawn(build_handler()); - } else { - log::warn!("TLS cert/key not found; only port 8080 is listening"); - } - - // 8080: h1 cleartext (also serves /ws and h2c-prior-knowledge); registers signal handlers - trillium_tokio::config() - .with_port(8080) - .with_host("0.0.0.0") - .with_nodelay() - .with_swansong(swansong.clone()) - .with_http_config(http_config) - .with_shared_state(state.clone()) - .spawn(build_handler()); - - swansong.await - }); + builder.run(build_handler()); + Ok(()) } diff --git a/frameworks/trillium/src/state.rs b/frameworks/trillium/src/state.rs index 5423f69f1..e77bb05b3 100644 --- a/frameworks/trillium/src/state.rs +++ b/frameworks/trillium/src/state.rs @@ -1,7 +1,10 @@ use dashmap::DashMap; -use deadpool_postgres::{Config as PgConfig, ManagerConfig, Pool, RecyclingMethod, Runtime}; +use deadpool_postgres::{ + Config as PgConfig, ManagerConfig, Pool, PoolConfig, RecyclingMethod, Runtime, +}; use serde::{Deserialize, Serialize}; use std::{ + env, fs, sync::Arc, time::{Duration, Instant}, }; @@ -40,24 +43,23 @@ pub const CRUD_CACHE_TTL: Duration = Duration::from_millis(200); impl AppState { pub fn init() -> Arc { - let dataset_path = - std::env::var("DATASET_PATH").unwrap_or_else(|_| "/data/dataset.json".into()); - let dataset = std::fs::read(&dataset_path) + let dataset_path = env::var("DATASET_PATH").unwrap_or_else(|_| "/data/dataset.json".into()); + let dataset = fs::read(&dataset_path) .ok() .and_then(|bytes| sonic_rs::from_slice(&bytes).ok()) .unwrap_or_default(); - let pg = std::env::var("DATABASE_URL").ok().and_then(|url| { + let pg = env::var("DATABASE_URL").ok().and_then(|url| { let mut cfg = PgConfig::new(); cfg.url = Some(url); cfg.manager = Some(ManagerConfig { recycling_method: RecyclingMethod::Fast, }); - let max_size: usize = std::env::var("DATABASE_MAX_CONN") + let max_size: usize = env::var("DATABASE_MAX_CONN") .ok() .and_then(|s| s.parse().ok()) .unwrap_or(256); - cfg.pool = Some(deadpool_postgres::PoolConfig::new(max_size)); + cfg.pool = Some(PoolConfig::new(max_size)); cfg.create_pool(Some(Runtime::Tokio1), NoTls).ok() }); diff --git a/frameworks/trillium/templates/fortunes.html b/frameworks/trillium/templates/fortunes.html new file mode 100644 index 000000000..f0b19c159 --- /dev/null +++ b/frameworks/trillium/templates/fortunes.html @@ -0,0 +1,10 @@ + + +Fortunes + + + +{% for f in fortunes %} +{% endfor %}
idmessage
{{ f.id }}{{ f.message }}
+ + From 24eb98995e2cb642078f195d817092b81bd2ba48 Mon Sep 17 00:00:00 2001 From: Jacob Rothstein Date: Sun, 31 May 2026 17:43:32 -0700 Subject: [PATCH 2/4] [trillium] add grpc --- frameworks/trillium-tuned/Cargo.lock | 90 ++++++++++ frameworks/trillium-tuned/Cargo.toml | 1 + frameworks/trillium-tuned/meta.json | 6 +- .../trillium-tuned/proto/benchmark.proto | 37 ++++ frameworks/trillium-tuned/src/grpc.rs | 75 ++++++++ .../trillium-tuned/src/grpc/benchmark.rs | 162 ++++++++++++++++++ frameworks/trillium-tuned/src/main.rs | 3 + frameworks/trillium/Cargo.lock | 90 ++++++++++ frameworks/trillium/Cargo.toml | 1 + frameworks/trillium/README.md | 13 ++ frameworks/trillium/meta.json | 6 +- frameworks/trillium/proto/benchmark.proto | 37 ++++ frameworks/trillium/src/grpc.rs | 75 ++++++++ frameworks/trillium/src/grpc/benchmark.rs | 162 ++++++++++++++++++ frameworks/trillium/src/main.rs | 3 + 15 files changed, 759 insertions(+), 2 deletions(-) create mode 100644 frameworks/trillium-tuned/proto/benchmark.proto create mode 100644 frameworks/trillium-tuned/src/grpc.rs create mode 100644 frameworks/trillium-tuned/src/grpc/benchmark.rs create mode 100644 frameworks/trillium/proto/benchmark.proto create mode 100644 frameworks/trillium/src/grpc.rs create mode 100644 frameworks/trillium/src/grpc/benchmark.rs diff --git a/frameworks/trillium-tuned/Cargo.lock b/frameworks/trillium-tuned/Cargo.lock index b16bf38db..5a62c0b37 100644 --- a/frameworks/trillium-tuned/Cargo.lock +++ b/frameworks/trillium-tuned/Cargo.lock @@ -503,6 +503,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -634,6 +643,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -1003,6 +1018,7 @@ dependencies = [ "trillium", "trillium-askama", "trillium-compression", + "trillium-grpc", "trillium-logger", "trillium-quinn", "trillium-router", @@ -1159,6 +1175,15 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.18" @@ -1648,6 +1673,29 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ptr_meta" version = "0.3.1" @@ -2635,6 +2683,26 @@ dependencies = [ "trillium", ] +[[package]] +name = "trillium-client" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa5b4aa0d3bbe68026a9c090b7bed0a639a27cec404635fc34a9e6aa099c7790" +dependencies = [ + "crossbeam-queue", + "dashmap", + "encoding_rs", + "fieldwork", + "futures-lite", + "httparse", + "log", + "memchr", + "mime", + "trillium-http", + "trillium-macros", + "trillium-server-common", +] + [[package]] name = "trillium-compression" version = "0.3.0" @@ -2647,6 +2715,28 @@ dependencies = [ "trillium", ] +[[package]] +name = "trillium-grpc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "108f779d7722ebd5e321640523316c2272588476b96b79be46673372c33ec524" +dependencies = [ + "async-channel", + "base64", + "bytes", + "flate2", + "futures-lite", + "log", + "pin-project-lite", + "prost", + "sync_wrapper", + "thiserror 2.0.18", + "trillium", + "trillium-client", + "trillium-http", + "trillium-server-common", +] + [[package]] name = "trillium-http" version = "1.3.3" diff --git a/frameworks/trillium-tuned/Cargo.toml b/frameworks/trillium-tuned/Cargo.toml index 1cedc0d0b..91cab30af 100644 --- a/frameworks/trillium-tuned/Cargo.toml +++ b/frameworks/trillium-tuned/Cargo.toml @@ -11,6 +11,7 @@ trillium-rustls = "0.11" trillium-quinn = "0.1" trillium-websockets = "0.8" trillium-compression = "0.3" +trillium-grpc = "0.2" trillium-askama = "0.5" askama = "0.16" trillium-logger = "0.5" diff --git a/frameworks/trillium-tuned/meta.json b/frameworks/trillium-tuned/meta.json index 8db2316f5..c6ced42f4 100644 --- a/frameworks/trillium-tuned/meta.json +++ b/frameworks/trillium-tuned/meta.json @@ -3,7 +3,7 @@ "language": "Rust", "type": "tuned", "engine": "trillium-http", - "description": "Trillium 1.x with one current_thread tokio runtime per CPU, SO_REUSEPORT TCP sharding (single QUIC endpoint for h3), tuned HttpConfig (larger response/body buffers, 64K h2 frames, eager body preallocation), and static files preloaded into memory at startup. sonic-rs for JSON, deadpool-postgres, mimalloc.", + "description": "Trillium 1.x with one current_thread tokio runtime per CPU, SO_REUSEPORT TCP sharding (single QUIC endpoint for h3), tuned HttpConfig (larger response/body buffers, 64K h2 frames, eager body preallocation), and static files preloaded into memory at startup. sonic-rs for JSON, deadpool-postgres, mimalloc, trillium-grpc for the benchmark.BenchmarkService gRPC endpoints.", "repo": "https://github.com/trillium-rs/trillium", "enabled": true, "tests": [ @@ -24,6 +24,10 @@ "static-h2", "baseline-h3", "static-h3", + "unary-grpc", + "unary-grpc-tls", + "stream-grpc", + "stream-grpc-tls", "echo-ws", "echo-ws-pipeline" ], diff --git a/frameworks/trillium-tuned/proto/benchmark.proto b/frameworks/trillium-tuned/proto/benchmark.proto new file mode 100644 index 000000000..e7c962370 --- /dev/null +++ b/frameworks/trillium-tuned/proto/benchmark.proto @@ -0,0 +1,37 @@ +// Canonical benchmark.proto used by ghz for gRPC streaming tests. +// Each gRPC framework must implement the RPCs it subscribes to in its own +// service; the shapes must match this file exactly. + +syntax = "proto3"; + +package benchmark; + +service BenchmarkService { + // Unary — 1 request, 1 reply. Used by unary-grpc (h2load). + rpc GetSum (SumRequest) returns (SumReply); + + // Server streaming — 1 request, server emits `count` replies. Used by + // stream-grpc / stream-grpc-tls (ghz). + rpc StreamSum (StreamRequest) returns (stream SumReply); + + // Client streaming — N requests streamed in, 1 reply with the total. + rpc CollectSum (stream SumRequest) returns (SumReply); + + // Bidirectional streaming — echo: 1 reply per request over a persistent stream. + rpc EchoSum (stream SumRequest) returns (stream SumReply); +} + +message SumRequest { + int32 a = 1; + int32 b = 2; +} + +message StreamRequest { + int32 a = 1; + int32 b = 2; + int32 count = 3; +} + +message SumReply { + int32 result = 1; +} diff --git a/frameworks/trillium-tuned/src/grpc.rs b/frameworks/trillium-tuned/src/grpc.rs new file mode 100644 index 000000000..636018433 --- /dev/null +++ b/frameworks/trillium-tuned/src/grpc.rs @@ -0,0 +1,75 @@ +//! gRPC `benchmark.BenchmarkService`, served over trillium-grpc. +//! +//! Mounts into the same handler tree as the HTTP endpoints — the server handler +//! matches its own `/benchmark.BenchmarkService/*` path prefix and passes every +//! other request through. Exercised by the `unary-grpc` (`GetSum`) and +//! `stream-grpc` (`StreamSum`) profiles over h2c on 8080 and h2-over-TLS on 8443; +//! `CollectSum` and `EchoSum` round out the service the proto defines. + +use futures_lite::stream; +use trillium_grpc::{BidiResponder, Channel, GrpcServerConn, Status, Stream}; + +#[allow(dead_code)] // the generated client half is unused on the server +mod benchmark { + include!("grpc/benchmark.rs"); +} + +pub use benchmark::BenchmarkServiceServer; +use benchmark::{BenchmarkService, StreamRequest, SumReply, SumRequest}; + +pub struct Benchmark; + +impl BenchmarkService for Benchmark { + async fn get_sum( + &self, + _conn: &mut GrpcServerConn, + request: SumRequest, + ) -> Result { + Ok(SumReply { + result: request.a + request.b, + }) + } + + async fn stream_sum( + &self, + _conn: &mut GrpcServerConn, + request: StreamRequest, + ) -> Result> + Send + use<>, Status> { + let result = request.a + request.b; + let count = request.count.max(0) as usize; + Ok(stream::iter( + (0..count).map(move |_| Ok(SumReply { result })), + )) + } + + async fn collect_sum(&self, conn: &mut GrpcServerConn) -> Result { + let mut result = 0; + let mut requests = conn.requests::(); + while let Some(request) = requests.recv().await? { + result += request.a + request.b; + } + Ok(SumReply { result }) + } + + async fn echo_sum( + &self, + _conn: &mut GrpcServerConn, + ) -> Result + use<>, Status> { + Ok(EchoSum) + } +} + +struct EchoSum; + +impl BidiResponder for EchoSum { + async fn respond(self, mut channel: Channel<'_, SumRequest, SumReply>) -> Result<(), Status> { + while let Some(request) = channel.recv().await.transpose()? { + channel + .send(SumReply { + result: request.a + request.b, + }) + .await?; + } + Ok(()) + } +} diff --git a/frameworks/trillium-tuned/src/grpc/benchmark.rs b/frameworks/trillium-tuned/src/grpc/benchmark.rs new file mode 100644 index 000000000..6a5f09a17 --- /dev/null +++ b/frameworks/trillium-tuned/src/grpc/benchmark.rs @@ -0,0 +1,162 @@ +use std::sync::Arc; +use trillium::{Conn, Handler, Method, Upgrade}; +use trillium_grpc::{ + BidiConn, BidiResponder, GrpcServerConn, Prost, Server, ServiceClient, Status, + Stream, StreamingConn, UnaryConn, prepare_grpc_conn, +}; +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::trillium_grpc::prost::Message)] +#[prost(prost_path = "::trillium_grpc::prost")] +pub struct SumRequest { + #[prost(int32, tag = "1")] + pub a: i32, + #[prost(int32, tag = "2")] + pub b: i32, +} +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::trillium_grpc::prost::Message)] +#[prost(prost_path = "::trillium_grpc::prost")] +pub struct StreamRequest { + #[prost(int32, tag = "1")] + pub a: i32, + #[prost(int32, tag = "2")] + pub b: i32, + #[prost(int32, tag = "3")] + pub count: i32, +} +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::trillium_grpc::prost::Message)] +#[prost(prost_path = "::trillium_grpc::prost")] +pub struct SumReply { + #[prost(int32, tag = "1")] + pub result: i32, +} +pub trait BenchmarkService: Send + Sync + 'static { + fn get_sum( + &self, + conn: &mut GrpcServerConn, + request: SumRequest, + ) -> impl Future> + Send; + fn stream_sum( + &self, + conn: &mut GrpcServerConn, + request: StreamRequest, + ) -> impl Future< + Output = Result< + impl Stream> + Send + use, + Status, + >, + > + Send; + fn collect_sum( + &self, + conn: &mut GrpcServerConn, + ) -> impl Future> + Send; + fn echo_sum( + &self, + conn: &mut GrpcServerConn, + ) -> impl Future< + Output = Result + use, Status>, + > + Send; +} +pub struct BenchmarkServiceServer(Arc); +impl BenchmarkServiceServer { + pub fn new(inner: T) -> Self { + Self(Arc::new(inner)) + } +} +#[allow(clippy::enum_variant_names)] +#[derive(Debug, Clone, Copy)] +enum BenchmarkServiceDispatch { + GetSum, + StreamSum, + CollectSum, + EchoSum, +} +impl Handler for BenchmarkServiceServer { + async fn run(&self, conn: Conn) -> Conn { + const PREFIX: &str = "/benchmark.BenchmarkService"; + let Some(method) = conn.path().strip_prefix(PREFIX) else { + return conn; + }; + if conn.method() != Method::Post { + return conn; + } + let dispatch = match method { + "/GetSum" => BenchmarkServiceDispatch::GetSum, + "/StreamSum" => BenchmarkServiceDispatch::StreamSum, + "/CollectSum" => BenchmarkServiceDispatch::CollectSum, + "/EchoSum" => BenchmarkServiceDispatch::EchoSum, + _ => return conn, + }; + let conn = match prepare_grpc_conn(conn, "proto") { + Ok(c) => c, + Err(c) => return c, + }; + let inner = Arc::clone(&self.0); + match dispatch { + BenchmarkServiceDispatch::GetSum => { + Prost::unary(conn, async move |grpc, req| inner.get_sum(grpc, req).await) + .await + } + BenchmarkServiceDispatch::StreamSum => { + Prost::server_streaming( + conn, + async move |grpc, req| inner.stream_sum(grpc, req).await, + ) + .await + } + BenchmarkServiceDispatch::CollectSum => { + Prost::client_streaming( + conn, + async move |grpc| inner.collect_sum(grpc).await, + ) + .await + } + BenchmarkServiceDispatch::EchoSum => { + Prost::bidi::< + SumRequest, + SumReply, + _, + >(conn, async move |grpc| inner.echo_sum(grpc).await) + .await + } + } + } + fn has_upgrade(&self, upgrade: &Upgrade) -> bool { + trillium_grpc::has_bidi_upgrade(upgrade) + } + async fn upgrade(&self, upgrade: Upgrade) { + trillium_grpc::drive_bidi_upgrade(upgrade).await; + } +} +pub struct BenchmarkServiceClient(::trillium_grpc::trillium_client::Client); +impl From<::trillium_grpc::trillium_client::Client> for BenchmarkServiceClient { + fn from(client: ::trillium_grpc::trillium_client::Client) -> Self { + Self(trillium_grpc::with_service_prefix(client, "benchmark.BenchmarkService")) + } +} +impl ServiceClient for BenchmarkServiceClient { + fn client(&self) -> &::trillium_grpc::trillium_client::Client { + &self.0 + } + fn client_mut(&mut self) -> &mut ::trillium_grpc::trillium_client::Client { + &mut self.0 + } +} +impl BenchmarkServiceClient { + pub fn get_sum(&self, request: SumRequest) -> UnaryConn { + UnaryConn::unary::(&self.0, "GetSum", request) + } + pub fn stream_sum( + &self, + request: StreamRequest, + ) -> StreamingConn { + StreamingConn::server_streaming::(&self.0, "StreamSum", request) + } + pub fn collect_sum( + &self, + requests: impl Stream + Send + 'static, + ) -> UnaryConn { + UnaryConn::client_streaming::(&self.0, "CollectSum", requests) + } + pub fn echo_sum(&self) -> BidiConn { + BidiConn::bidi::(&self.0, "EchoSum") + } +} diff --git a/frameworks/trillium-tuned/src/main.rs b/frameworks/trillium-tuned/src/main.rs index 1b4f995b5..f86a32d39 100644 --- a/frameworks/trillium-tuned/src/main.rs +++ b/frameworks/trillium-tuned/src/main.rs @@ -1,11 +1,13 @@ #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +mod grpc; mod handlers; mod state; mod static_preload; use env_logger::Env; +use grpc::{Benchmark, BenchmarkServiceServer}; use handlers::{ async_db, baseline_any, baseline_get, crud_create, crud_list, crud_read, crud_update, fortunes, json_handler, pipeline, upload, ws_echo, @@ -34,6 +36,7 @@ fn tuned_http_config() -> HttpConfig { fn build_handler(static_files: StaticPreload) -> impl Handler { ( + BenchmarkServiceServer::new(Benchmark), Compression::new(), Router::new() .get("/pipeline", pipeline) diff --git a/frameworks/trillium/Cargo.lock b/frameworks/trillium/Cargo.lock index 6a7b46701..f64b310ef 100644 --- a/frameworks/trillium/Cargo.lock +++ b/frameworks/trillium/Cargo.lock @@ -503,6 +503,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -634,6 +643,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -1010,6 +1025,7 @@ dependencies = [ "trillium", "trillium-askama", "trillium-compression", + "trillium-grpc", "trillium-logger", "trillium-quinn", "trillium-router", @@ -1167,6 +1183,15 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.18" @@ -1666,6 +1691,29 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ptr_meta" version = "0.3.1" @@ -2668,6 +2716,26 @@ dependencies = [ "trillium", ] +[[package]] +name = "trillium-client" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa5b4aa0d3bbe68026a9c090b7bed0a639a27cec404635fc34a9e6aa099c7790" +dependencies = [ + "crossbeam-queue", + "dashmap", + "encoding_rs", + "fieldwork", + "futures-lite", + "httparse", + "log", + "memchr", + "mime", + "trillium-http", + "trillium-macros", + "trillium-server-common", +] + [[package]] name = "trillium-compression" version = "0.3.0" @@ -2680,6 +2748,28 @@ dependencies = [ "trillium", ] +[[package]] +name = "trillium-grpc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "108f779d7722ebd5e321640523316c2272588476b96b79be46673372c33ec524" +dependencies = [ + "async-channel", + "base64", + "bytes", + "flate2", + "futures-lite", + "log", + "pin-project-lite", + "prost", + "sync_wrapper", + "thiserror 2.0.18", + "trillium", + "trillium-client", + "trillium-http", + "trillium-server-common", +] + [[package]] name = "trillium-http" version = "1.3.3" diff --git a/frameworks/trillium/Cargo.toml b/frameworks/trillium/Cargo.toml index 031961d31..29a934327 100644 --- a/frameworks/trillium/Cargo.toml +++ b/frameworks/trillium/Cargo.toml @@ -12,6 +12,7 @@ trillium-quinn = "0.1" trillium-websockets = "0.8" trillium-static = { version = "0.6", features = ["tokio"] } trillium-compression = "0.3" +trillium-grpc = "0.2" trillium-askama = "0.5" askama = "0.16" trillium-logger = "0.5" diff --git a/frameworks/trillium/README.md b/frameworks/trillium/README.md index 67ec3b29e..ae9ae3cfa 100644 --- a/frameworks/trillium/README.md +++ b/frameworks/trillium/README.md @@ -7,6 +7,7 @@ Trillium 1.x async Rust web framework on tokio. - **Language:** Rust 1.94 - **Engine:** trillium-http (h1 + h2 prior-knowledge), trillium-quinn (h3) - **TLS:** trillium-rustls (h1 + h2 via ALPN), trillium-quinn for QUIC +- **gRPC:** trillium-grpc (`benchmark.BenchmarkService` over h2c + h2/TLS) - **JSON:** sonic-rs - **DB:** deadpool-postgres + tokio-postgres - **Build:** Multi-stage, `debian:bookworm-slim` runtime, `-C target-cpu=native` @@ -19,6 +20,8 @@ Trillium 1.x async Rust web framework on tokio. | 8081 | HTTP/1.1 + TLS | ALPN advertises `http/1.1` only | | 8443 | HTTP/1.1 + HTTP/2 + HTTP/3 | TLS via ALPN; QUIC via UDP | +gRPC shares these listeners: `unary-grpc` / `stream-grpc` run over h2c prior-knowledge on 8080, and `unary-grpc-tls` / `stream-grpc-tls` over h2-via-ALPN on 8443. + ## Endpoints | Endpoint | Method | Description | @@ -34,9 +37,19 @@ Trillium 1.x async Rust web framework on tokio. | `/crud/items/:id` | GET / PUT | Cached read (200 ms TTL) / update with cache invalidation | | `/ws` | GET (upgrade) | WebSocket echo | +## gRPC — `benchmark.BenchmarkService` + +| RPC | Shape | Description | +|-----|-------|-------------| +| `GetSum` | unary | Returns `a + b` | +| `StreamSum` | server-streaming | Emits `count` replies of `a + b` | +| `CollectSum` | client-streaming | Sums `a + b` over all requests, one reply | +| `EchoSum` | bidirectional | One `a + b` reply per request | + ## Notes - Trillium serves h1.1, h2 (TLS+ALPN or prior-knowledge), and h3 from the same handler tree — endpoint code is protocol-agnostic. +- The gRPC service is just another `Handler` in the tuple (`trillium-grpc`'s generated `BenchmarkServiceServer`), mounted first so its `/benchmark.BenchmarkService/*` paths are handled before compression/routing and all other requests pass through. The service module is checked in at `src/grpc/benchmark.rs`, generated from `proto/benchmark.proto`. - Compression is wired via `trillium-compression` middleware: gzip/brotli on demand per `Accept-Encoding`. No `Content-Encoding` is set when the client doesn't advertise one. - Static files are read from disk on every request (`trillium-static::files`). - Dataset (`/data/dataset.json`) is loaded once at startup; per-request totals are computed and the response is serialized fresh each request. diff --git a/frameworks/trillium/meta.json b/frameworks/trillium/meta.json index 00e86637e..7f14e1699 100644 --- a/frameworks/trillium/meta.json +++ b/frameworks/trillium/meta.json @@ -3,7 +3,7 @@ "language": "Rust", "type": "production", "engine": "trillium-http", - "description": "Trillium 1.x async Rust web framework on tokio. trillium-rustls for TLS (h1 + h2 via ALPN), trillium-quinn for HTTP/3, trillium-websockets for /ws, trillium-static for /static/* served from disk per request, trillium-compression middleware for runtime gzip/brotli, trillium-api for JSON handlers, deadpool-postgres for async-db and crud.", + "description": "Trillium 1.x async Rust web framework on tokio. trillium-rustls for TLS (h1 + h2 via ALPN), trillium-quinn for HTTP/3, trillium-websockets for /ws, trillium-static for /static/* served from disk per request, trillium-compression middleware for runtime gzip/brotli, trillium-api for JSON handlers, trillium-grpc for the benchmark.BenchmarkService gRPC endpoints, deadpool-postgres for async-db and crud.", "repo": "https://github.com/trillium-rs/trillium", "enabled": true, "tests": [ @@ -24,6 +24,10 @@ "static-h2", "baseline-h3", "static-h3", + "unary-grpc", + "unary-grpc-tls", + "stream-grpc", + "stream-grpc-tls", "echo-ws", "echo-ws-pipeline", "gateway-64", diff --git a/frameworks/trillium/proto/benchmark.proto b/frameworks/trillium/proto/benchmark.proto new file mode 100644 index 000000000..e7c962370 --- /dev/null +++ b/frameworks/trillium/proto/benchmark.proto @@ -0,0 +1,37 @@ +// Canonical benchmark.proto used by ghz for gRPC streaming tests. +// Each gRPC framework must implement the RPCs it subscribes to in its own +// service; the shapes must match this file exactly. + +syntax = "proto3"; + +package benchmark; + +service BenchmarkService { + // Unary — 1 request, 1 reply. Used by unary-grpc (h2load). + rpc GetSum (SumRequest) returns (SumReply); + + // Server streaming — 1 request, server emits `count` replies. Used by + // stream-grpc / stream-grpc-tls (ghz). + rpc StreamSum (StreamRequest) returns (stream SumReply); + + // Client streaming — N requests streamed in, 1 reply with the total. + rpc CollectSum (stream SumRequest) returns (SumReply); + + // Bidirectional streaming — echo: 1 reply per request over a persistent stream. + rpc EchoSum (stream SumRequest) returns (stream SumReply); +} + +message SumRequest { + int32 a = 1; + int32 b = 2; +} + +message StreamRequest { + int32 a = 1; + int32 b = 2; + int32 count = 3; +} + +message SumReply { + int32 result = 1; +} diff --git a/frameworks/trillium/src/grpc.rs b/frameworks/trillium/src/grpc.rs new file mode 100644 index 000000000..636018433 --- /dev/null +++ b/frameworks/trillium/src/grpc.rs @@ -0,0 +1,75 @@ +//! gRPC `benchmark.BenchmarkService`, served over trillium-grpc. +//! +//! Mounts into the same handler tree as the HTTP endpoints — the server handler +//! matches its own `/benchmark.BenchmarkService/*` path prefix and passes every +//! other request through. Exercised by the `unary-grpc` (`GetSum`) and +//! `stream-grpc` (`StreamSum`) profiles over h2c on 8080 and h2-over-TLS on 8443; +//! `CollectSum` and `EchoSum` round out the service the proto defines. + +use futures_lite::stream; +use trillium_grpc::{BidiResponder, Channel, GrpcServerConn, Status, Stream}; + +#[allow(dead_code)] // the generated client half is unused on the server +mod benchmark { + include!("grpc/benchmark.rs"); +} + +pub use benchmark::BenchmarkServiceServer; +use benchmark::{BenchmarkService, StreamRequest, SumReply, SumRequest}; + +pub struct Benchmark; + +impl BenchmarkService for Benchmark { + async fn get_sum( + &self, + _conn: &mut GrpcServerConn, + request: SumRequest, + ) -> Result { + Ok(SumReply { + result: request.a + request.b, + }) + } + + async fn stream_sum( + &self, + _conn: &mut GrpcServerConn, + request: StreamRequest, + ) -> Result> + Send + use<>, Status> { + let result = request.a + request.b; + let count = request.count.max(0) as usize; + Ok(stream::iter( + (0..count).map(move |_| Ok(SumReply { result })), + )) + } + + async fn collect_sum(&self, conn: &mut GrpcServerConn) -> Result { + let mut result = 0; + let mut requests = conn.requests::(); + while let Some(request) = requests.recv().await? { + result += request.a + request.b; + } + Ok(SumReply { result }) + } + + async fn echo_sum( + &self, + _conn: &mut GrpcServerConn, + ) -> Result + use<>, Status> { + Ok(EchoSum) + } +} + +struct EchoSum; + +impl BidiResponder for EchoSum { + async fn respond(self, mut channel: Channel<'_, SumRequest, SumReply>) -> Result<(), Status> { + while let Some(request) = channel.recv().await.transpose()? { + channel + .send(SumReply { + result: request.a + request.b, + }) + .await?; + } + Ok(()) + } +} diff --git a/frameworks/trillium/src/grpc/benchmark.rs b/frameworks/trillium/src/grpc/benchmark.rs new file mode 100644 index 000000000..6a5f09a17 --- /dev/null +++ b/frameworks/trillium/src/grpc/benchmark.rs @@ -0,0 +1,162 @@ +use std::sync::Arc; +use trillium::{Conn, Handler, Method, Upgrade}; +use trillium_grpc::{ + BidiConn, BidiResponder, GrpcServerConn, Prost, Server, ServiceClient, Status, + Stream, StreamingConn, UnaryConn, prepare_grpc_conn, +}; +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::trillium_grpc::prost::Message)] +#[prost(prost_path = "::trillium_grpc::prost")] +pub struct SumRequest { + #[prost(int32, tag = "1")] + pub a: i32, + #[prost(int32, tag = "2")] + pub b: i32, +} +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::trillium_grpc::prost::Message)] +#[prost(prost_path = "::trillium_grpc::prost")] +pub struct StreamRequest { + #[prost(int32, tag = "1")] + pub a: i32, + #[prost(int32, tag = "2")] + pub b: i32, + #[prost(int32, tag = "3")] + pub count: i32, +} +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::trillium_grpc::prost::Message)] +#[prost(prost_path = "::trillium_grpc::prost")] +pub struct SumReply { + #[prost(int32, tag = "1")] + pub result: i32, +} +pub trait BenchmarkService: Send + Sync + 'static { + fn get_sum( + &self, + conn: &mut GrpcServerConn, + request: SumRequest, + ) -> impl Future> + Send; + fn stream_sum( + &self, + conn: &mut GrpcServerConn, + request: StreamRequest, + ) -> impl Future< + Output = Result< + impl Stream> + Send + use, + Status, + >, + > + Send; + fn collect_sum( + &self, + conn: &mut GrpcServerConn, + ) -> impl Future> + Send; + fn echo_sum( + &self, + conn: &mut GrpcServerConn, + ) -> impl Future< + Output = Result + use, Status>, + > + Send; +} +pub struct BenchmarkServiceServer(Arc); +impl BenchmarkServiceServer { + pub fn new(inner: T) -> Self { + Self(Arc::new(inner)) + } +} +#[allow(clippy::enum_variant_names)] +#[derive(Debug, Clone, Copy)] +enum BenchmarkServiceDispatch { + GetSum, + StreamSum, + CollectSum, + EchoSum, +} +impl Handler for BenchmarkServiceServer { + async fn run(&self, conn: Conn) -> Conn { + const PREFIX: &str = "/benchmark.BenchmarkService"; + let Some(method) = conn.path().strip_prefix(PREFIX) else { + return conn; + }; + if conn.method() != Method::Post { + return conn; + } + let dispatch = match method { + "/GetSum" => BenchmarkServiceDispatch::GetSum, + "/StreamSum" => BenchmarkServiceDispatch::StreamSum, + "/CollectSum" => BenchmarkServiceDispatch::CollectSum, + "/EchoSum" => BenchmarkServiceDispatch::EchoSum, + _ => return conn, + }; + let conn = match prepare_grpc_conn(conn, "proto") { + Ok(c) => c, + Err(c) => return c, + }; + let inner = Arc::clone(&self.0); + match dispatch { + BenchmarkServiceDispatch::GetSum => { + Prost::unary(conn, async move |grpc, req| inner.get_sum(grpc, req).await) + .await + } + BenchmarkServiceDispatch::StreamSum => { + Prost::server_streaming( + conn, + async move |grpc, req| inner.stream_sum(grpc, req).await, + ) + .await + } + BenchmarkServiceDispatch::CollectSum => { + Prost::client_streaming( + conn, + async move |grpc| inner.collect_sum(grpc).await, + ) + .await + } + BenchmarkServiceDispatch::EchoSum => { + Prost::bidi::< + SumRequest, + SumReply, + _, + >(conn, async move |grpc| inner.echo_sum(grpc).await) + .await + } + } + } + fn has_upgrade(&self, upgrade: &Upgrade) -> bool { + trillium_grpc::has_bidi_upgrade(upgrade) + } + async fn upgrade(&self, upgrade: Upgrade) { + trillium_grpc::drive_bidi_upgrade(upgrade).await; + } +} +pub struct BenchmarkServiceClient(::trillium_grpc::trillium_client::Client); +impl From<::trillium_grpc::trillium_client::Client> for BenchmarkServiceClient { + fn from(client: ::trillium_grpc::trillium_client::Client) -> Self { + Self(trillium_grpc::with_service_prefix(client, "benchmark.BenchmarkService")) + } +} +impl ServiceClient for BenchmarkServiceClient { + fn client(&self) -> &::trillium_grpc::trillium_client::Client { + &self.0 + } + fn client_mut(&mut self) -> &mut ::trillium_grpc::trillium_client::Client { + &mut self.0 + } +} +impl BenchmarkServiceClient { + pub fn get_sum(&self, request: SumRequest) -> UnaryConn { + UnaryConn::unary::(&self.0, "GetSum", request) + } + pub fn stream_sum( + &self, + request: StreamRequest, + ) -> StreamingConn { + StreamingConn::server_streaming::(&self.0, "StreamSum", request) + } + pub fn collect_sum( + &self, + requests: impl Stream + Send + 'static, + ) -> UnaryConn { + UnaryConn::client_streaming::(&self.0, "CollectSum", requests) + } + pub fn echo_sum(&self) -> BidiConn { + BidiConn::bidi::(&self.0, "EchoSum") + } +} diff --git a/frameworks/trillium/src/main.rs b/frameworks/trillium/src/main.rs index d874dece6..0c388691c 100644 --- a/frameworks/trillium/src/main.rs +++ b/frameworks/trillium/src/main.rs @@ -1,10 +1,12 @@ #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +mod grpc; mod handlers; mod state; use env_logger::Env; +use grpc::{Benchmark, BenchmarkServiceServer}; use handlers::{ async_db, baseline_any, baseline_get, crud_create, crud_list, crud_read, crud_update, fortunes, json_handler, pipeline, upload, ws_echo, @@ -23,6 +25,7 @@ use trillium_websockets::websocket; fn build_handler() -> impl Handler { let static_dir = env::var("STATIC_DIR").unwrap_or_else(|_| "/data/static".into()); ( + BenchmarkServiceServer::new(Benchmark), Compression::new(), Router::new() .get("/pipeline", pipeline) From 568dc4015554160020fdc97854d62ca6093c60f5 Mon Sep 17 00:00:00 2001 From: Jacob Rothstein Date: Mon, 1 Jun 2026 18:14:57 -0700 Subject: [PATCH 3/4] [trillium] replace trillium-proxy with caddy-over-uds --- frameworks/trillium-tuned/Cargo.toml | 3 +- .../trillium-tuned/compose.gateway-h3.yml | 51 + frameworks/trillium-tuned/compose.gateway.yml | 58 + frameworks/trillium-tuned/meta.json | 4 +- frameworks/trillium-tuned/proxy/Caddyfile | 46 + frameworks/trillium-tuned/proxy/Dockerfile | 10 + frameworks/trillium-tuned/src/main.rs | 5 + frameworks/trillium/Cargo.toml | 2 +- frameworks/trillium/compose.gateway-h3.yml | 26 +- frameworks/trillium/compose.gateway.yml | 31 +- frameworks/trillium/proxy/Caddyfile | 47 + frameworks/trillium/proxy/Cargo.lock | 2509 ----------------- frameworks/trillium/proxy/Cargo.toml | 28 - frameworks/trillium/proxy/Dockerfile | 19 +- frameworks/trillium/proxy/src/main.rs | 315 --- frameworks/trillium/src/main.rs | 5 + 16 files changed, 266 insertions(+), 2893 deletions(-) create mode 100644 frameworks/trillium-tuned/compose.gateway-h3.yml create mode 100644 frameworks/trillium-tuned/compose.gateway.yml create mode 100644 frameworks/trillium-tuned/proxy/Caddyfile create mode 100644 frameworks/trillium-tuned/proxy/Dockerfile create mode 100644 frameworks/trillium/proxy/Caddyfile delete mode 100644 frameworks/trillium/proxy/Cargo.lock delete mode 100644 frameworks/trillium/proxy/Cargo.toml delete mode 100644 frameworks/trillium/proxy/src/main.rs diff --git a/frameworks/trillium-tuned/Cargo.toml b/frameworks/trillium-tuned/Cargo.toml index 91cab30af..a8e3616e9 100644 --- a/frameworks/trillium-tuned/Cargo.toml +++ b/frameworks/trillium-tuned/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] -trillium = "1.3" +trillium = "1" trillium-tokio = { version = "0.6", features = ["reuseport"] } trillium-router = "0.5" trillium-rustls = "0.11" @@ -40,3 +40,4 @@ codegen-units = 1 lto = "fat" panic = "abort" strip = true + diff --git a/frameworks/trillium-tuned/compose.gateway-h3.yml b/frameworks/trillium-tuned/compose.gateway-h3.yml new file mode 100644 index 000000000..ea7f6d6b6 --- /dev/null +++ b/frameworks/trillium-tuned/compose.gateway-h3.yml @@ -0,0 +1,51 @@ +# gateway-h3 — same two-service stack as compose.gateway.yml, but the edge is +# exercised over HTTP/3 (QUIC/UDP). Stock Caddy already binds 8443 on both tcp +# and udp with `protocols h1 h2 h3`, so the proxy config is identical; only the +# load generator differs (h2load-h3). The proxy->server upstream stays UDS h1. +services: + proxy: + build: + context: ./proxy + network_mode: host + cpuset: "${PROXY_CPUSET:-0-15,64-79}" + ulimits: + memlock: -1 + nofile: + soft: 1048576 + hard: 1048576 + security_opt: + - seccomp:unconfined + volumes: + - ${CERTS_DIR}:/certs:ro + - ${DATA_DIR}/static:/data/static:ro + - appsock:/run/app + depends_on: + - server + + server: + build: + context: . + dockerfile: Dockerfile + network_mode: host + cpuset: "${SERVER_CPUSET:-16-31,80-95}" + ulimits: + memlock: -1 + nofile: + soft: 1048576 + hard: 1048576 + security_opt: + - seccomp:unconfined + environment: + - LISTEN_UDS=/run/app/app.sock + - DATABASE_URL=${DATABASE_URL} + - DATABASE_MAX_CONN=256 + - DATASET_PATH=/data/dataset.json + - STATIC_DIR=/data/static + - RUST_LOG=info + volumes: + - ${DATA_DIR}/dataset.json:/data/dataset.json:ro + - ${DATA_DIR}/static:/data/static:ro + - appsock:/run/app + +volumes: + appsock: diff --git a/frameworks/trillium-tuned/compose.gateway.yml b/frameworks/trillium-tuned/compose.gateway.yml new file mode 100644 index 000000000..9f6bf3732 --- /dev/null +++ b/frameworks/trillium-tuned/compose.gateway.yml @@ -0,0 +1,58 @@ +# gateway-64 — stock Caddy (TLS + h2 on 8443) in front of the trillium-tuned +# server, forwarding dynamic endpoints over a shared Unix domain socket (h1 +# keepalive). The server gets no certs, so it comes up cleartext on 8080 + the +# UDS only. n_workers auto-sizes to the server's cpuset via num_cpus. +# +# CPU split is the #1 tuning knob — start even 16/16 physical and sweep via +# PROXY_CPUSET / SERVER_CPUSET. The TLS-terminating proxy is often the +# bottleneck under multiplexed h2 load, so give it more if it saturates. +services: + proxy: + build: + context: ./proxy + network_mode: host + cpuset: "${PROXY_CPUSET:-0-15,64-79}" + ulimits: + memlock: -1 + nofile: + soft: 1048576 + hard: 1048576 + security_opt: + - seccomp:unconfined + volumes: + - ${CERTS_DIR}:/certs:ro + - ${DATA_DIR}/static:/data/static:ro + - appsock:/run/app + depends_on: + - server + + server: + build: + context: . + dockerfile: Dockerfile + network_mode: host + cpuset: "${SERVER_CPUSET:-16-31,80-95}" + ulimits: + memlock: -1 + nofile: + soft: 1048576 + hard: 1048576 + security_opt: + - seccomp:unconfined + environment: + - LISTEN_UDS=/run/app/app.sock + - DATABASE_URL=${DATABASE_URL} + - DATABASE_MAX_CONN=256 + - DATASET_PATH=/data/dataset.json + - STATIC_DIR=/data/static + - RUST_LOG=info + volumes: + - ${DATA_DIR}/dataset.json:/data/dataset.json:ro + - ${DATA_DIR}/static:/data/static:ro + - appsock:/run/app + +# Shared rendezvous for the UDS. network_mode: host shares the net namespace +# but not the filesystem, so the socket needs an explicit shared volume mounted +# into both services at the same path. +volumes: + appsock: diff --git a/frameworks/trillium-tuned/meta.json b/frameworks/trillium-tuned/meta.json index c6ced42f4..36981b684 100644 --- a/frameworks/trillium-tuned/meta.json +++ b/frameworks/trillium-tuned/meta.json @@ -29,7 +29,9 @@ "stream-grpc", "stream-grpc-tls", "echo-ws", - "echo-ws-pipeline" + "echo-ws-pipeline", + "gateway-64", + "gateway-h3" ], "maintainers": ["jbr"] } diff --git a/frameworks/trillium-tuned/proxy/Caddyfile b/frameworks/trillium-tuned/proxy/Caddyfile new file mode 100644 index 000000000..31340e111 --- /dev/null +++ b/frameworks/trillium-tuned/proxy/Caddyfile @@ -0,0 +1,46 @@ +# Trillium-tuned gateway edge. +# +# Caddy terminates TLS + h1/h2/h3 on 8443, serves /static/* directly from disk +# with precompressed sidecars, and forwards every dynamic endpoint to the +# trillium-tuned server over a Unix domain socket (h1 + keepalive pool). +# +# Same neutral standard-proxy shape as the production entry; "tuned" here means +# the *backend* is the optimized trillium-tuned server (sonic-rs, mimalloc, +# tuned HttpConfig). Tuned rules also allow more aggressive proxy tuning, so the +# keepalive pool is sized generously for the multiplexed gateway load. + +{ + admin off + auto_https off + servers { + protocols h1 h2 h3 + } +} + +https://localhost:8443 { + tls /certs/server.crt /certs/server.key + + # Static assets served by Caddy directly from /data/static. `precompressed` + # prefers foo.br / foo.gz sidecars per Accept-Encoding, falling back to the + # raw file. (root /data + request /static/foo -> /data/static/foo.) + handle /static/* { + root * /data + file_server { + precompressed br gzip + } + } + + # Dynamic endpoints -> trillium-tuned server over the shared UDS. Plain h1 + # with a large keepalive pool: many independent streams fan out across the + # backend's per-core workers without h2c's single-connection HoL blocking. + handle { + reverse_proxy unix//run/app/app.sock { + transport http { + versions 1.1 + keepalive 5m + keepalive_idle_conns 4096 + keepalive_idle_conns_per_host 4096 + } + } + } +} diff --git a/frameworks/trillium-tuned/proxy/Dockerfile b/frameworks/trillium-tuned/proxy/Dockerfile new file mode 100644 index 000000000..9f5167c79 --- /dev/null +++ b/frameworks/trillium-tuned/proxy/Dockerfile @@ -0,0 +1,10 @@ +# Stock Caddy — ships h1/h2/h3 (QUIC) in the base image, no custom build. +# Covers both gateway-64 (h2 over TCP) and gateway-h3 (QUIC over UDP) from +# the same Caddyfile, which binds 8443 on both tcp and udp. +FROM caddy:2-alpine + +COPY Caddyfile /etc/caddy/Caddyfile + +EXPOSE 8443/tcp 8443/udp + +CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"] diff --git a/frameworks/trillium-tuned/src/main.rs b/frameworks/trillium-tuned/src/main.rs index f86a32d39..bce9044ea 100644 --- a/frameworks/trillium-tuned/src/main.rs +++ b/frameworks/trillium-tuned/src/main.rs @@ -91,6 +91,11 @@ fn main() -> Result<(), Box> { .with_reuseport_workers(n_workers) .bind_reuseport_tcp(8080)?; + if let Ok(uds) = env::var("LISTEN_UDS") { + let _ = std::fs::remove_file(&uds); + builder = builder.bind_uds(uds)?; + } + if let (Some(cert), Some(key)) = (cert.as_deref(), key.as_deref()) { builder = builder .bind_reuseport_tls(8081, RustlsAcceptor::from_single_cert_no_h2(cert, key))? diff --git a/frameworks/trillium/Cargo.toml b/frameworks/trillium/Cargo.toml index 29a934327..c0db9551c 100644 --- a/frameworks/trillium/Cargo.toml +++ b/frameworks/trillium/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] -trillium = "1.3" +trillium = "1" trillium-tokio = "0.6" trillium-router = "0.5" trillium-rustls = "0.11" diff --git a/frameworks/trillium/compose.gateway-h3.yml b/frameworks/trillium/compose.gateway-h3.yml index af3148a4f..ea7f6d6b6 100644 --- a/frameworks/trillium/compose.gateway-h3.yml +++ b/frameworks/trillium/compose.gateway-h3.yml @@ -1,9 +1,13 @@ +# gateway-h3 — same two-service stack as compose.gateway.yml, but the edge is +# exercised over HTTP/3 (QUIC/UDP). Stock Caddy already binds 8443 on both tcp +# and udp with `protocols h1 h2 h3`, so the proxy config is identical; only the +# load generator differs (h2load-h3). The proxy->server upstream stays UDS h1. services: proxy: build: context: ./proxy network_mode: host - cpuset: "${PROXY_CPUSET:-0-7,64-71}" + cpuset: "${PROXY_CPUSET:-0-15,64-79}" ulimits: memlock: -1 nofile: @@ -11,17 +15,10 @@ services: hard: 1048576 security_opt: - seccomp:unconfined - environment: - - PROXY_PORT=8443 - - PROXY_H3=1 - - PROXY_UPSTREAM=https://localhost:9443 - - STATIC_DIR=/data/static - - TLS_CERT=/certs/server.crt - - TLS_KEY=/certs/server.key - - RUST_LOG=info volumes: - ${CERTS_DIR}:/certs:ro - ${DATA_DIR}/static:/data/static:ro + - appsock:/run/app depends_on: - server @@ -30,7 +27,7 @@ services: context: . dockerfile: Dockerfile network_mode: host - cpuset: "${SERVER_CPUSET:-8-31,72-95}" + cpuset: "${SERVER_CPUSET:-16-31,80-95}" ulimits: memlock: -1 nofile: @@ -39,15 +36,16 @@ services: security_opt: - seccomp:unconfined environment: + - LISTEN_UDS=/run/app/app.sock - DATABASE_URL=${DATABASE_URL} - DATABASE_MAX_CONN=256 - DATASET_PATH=/data/dataset.json - STATIC_DIR=/data/static - - TLS_CERT=/certs/server.crt - - TLS_KEY=/certs/server.key - - TLS_PORT=9443 - RUST_LOG=info volumes: - - ${CERTS_DIR}:/certs:ro - ${DATA_DIR}/dataset.json:/data/dataset.json:ro - ${DATA_DIR}/static:/data/static:ro + - appsock:/run/app + +volumes: + appsock: diff --git a/frameworks/trillium/compose.gateway.yml b/frameworks/trillium/compose.gateway.yml index 8349f514d..981b0376d 100644 --- a/frameworks/trillium/compose.gateway.yml +++ b/frameworks/trillium/compose.gateway.yml @@ -1,9 +1,16 @@ +# gateway-64 — stock Caddy (TLS + h2 on 8443) in front of the trillium server, +# forwarding dynamic endpoints over a shared Unix domain socket (h1 keepalive). +# The server gets no certs, so it comes up cleartext on 8080 + the UDS only. +# +# CPU split is the #1 tuning knob — start even 16/16 physical and sweep via +# PROXY_CPUSET / SERVER_CPUSET. The TLS-terminating proxy is often the +# bottleneck under multiplexed h2 load, so give it more if it saturates. services: proxy: build: context: ./proxy network_mode: host - cpuset: "${PROXY_CPUSET:-0-7,64-71}" + cpuset: "${PROXY_CPUSET:-0-15,64-79}" ulimits: memlock: -1 nofile: @@ -11,16 +18,10 @@ services: hard: 1048576 security_opt: - seccomp:unconfined - environment: - - PROXY_PORT=8443 - - PROXY_UPSTREAM=https://localhost:9443 - - STATIC_DIR=/data/static - - TLS_CERT=/certs/server.crt - - TLS_KEY=/certs/server.key - - RUST_LOG=info volumes: - ${CERTS_DIR}:/certs:ro - ${DATA_DIR}/static:/data/static:ro + - appsock:/run/app depends_on: - server @@ -29,7 +30,7 @@ services: context: . dockerfile: Dockerfile network_mode: host - cpuset: "${SERVER_CPUSET:-8-31,72-95}" + cpuset: "${SERVER_CPUSET:-16-31,80-95}" ulimits: memlock: -1 nofile: @@ -38,15 +39,19 @@ services: security_opt: - seccomp:unconfined environment: + - LISTEN_UDS=/run/app/app.sock - DATABASE_URL=${DATABASE_URL} - DATABASE_MAX_CONN=256 - DATASET_PATH=/data/dataset.json - STATIC_DIR=/data/static - - TLS_CERT=/certs/server.crt - - TLS_KEY=/certs/server.key - - TLS_PORT=9443 - RUST_LOG=info volumes: - - ${CERTS_DIR}:/certs:ro - ${DATA_DIR}/dataset.json:/data/dataset.json:ro - ${DATA_DIR}/static:/data/static:ro + - appsock:/run/app + +# Shared rendezvous for the UDS. network_mode: host shares the net namespace +# but not the filesystem, so the socket needs an explicit shared volume mounted +# into both services at the same path. +volumes: + appsock: diff --git a/frameworks/trillium/proxy/Caddyfile b/frameworks/trillium/proxy/Caddyfile new file mode 100644 index 000000000..b13836885 --- /dev/null +++ b/frameworks/trillium/proxy/Caddyfile @@ -0,0 +1,47 @@ +# Trillium gateway edge. +# +# Caddy terminates TLS + h1/h2/h3 on 8443, serves /static/* directly from disk +# with precompressed sidecars, and forwards every dynamic endpoint to the +# trillium server over a Unix domain socket (h1 + keepalive pool). +# +# The proxy is a neutral, standard front door: the gateway profile measures the +# trillium *server* behind it, so this stays a `production` framework entry. +# UDS is the host-local transport the benchmark itself flags as lowest-latency +# (no TCP stack overhead), and is exactly how you'd wire a co-located proxy in +# production. + +{ + admin off + auto_https off + servers { + protocols h1 h2 h3 + } +} + +https://localhost:8443 { + tls /certs/server.crt /certs/server.key + + # Static assets served by Caddy directly from /data/static. `precompressed` + # prefers foo.br / foo.gz sidecars per Accept-Encoding, falling back to the + # raw file. (root /data + request /static/foo -> /data/static/foo.) + handle /static/* { + root * /data + file_server { + precompressed br gzip + } + } + + # Dynamic endpoints -> trillium server over the shared UDS. Plain h1 with a + # large keepalive pool: many independent streams fan out across the backend + # cores without h2c's single-connection head-of-line blocking. + handle { + reverse_proxy unix//run/app/app.sock { + transport http { + versions 1.1 + keepalive 5m + keepalive_idle_conns 2048 + keepalive_idle_conns_per_host 2048 + } + } + } +} diff --git a/frameworks/trillium/proxy/Cargo.lock b/frameworks/trillium/proxy/Cargo.lock deleted file mode 100644 index 57c32391e..000000000 --- a/frameworks/trillium/proxy/Cargo.lock +++ /dev/null @@ -1,2509 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -[[package]] -name = "anstream" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" - -[[package]] -name = "anstyle-parse" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.61.2", -] - -[[package]] -name = "async-channel" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-compat" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ba85bc55464dcbf728b56d97e119d673f4cf9062be330a9a26f3acf504a590" -dependencies = [ - "futures-core", - "futures-io", - "once_cell", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "async_cell" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447ab28afbb345f5408b120702a44e5529ebf90b1796ec76e9528df8e288e6c2" -dependencies = [ - "loom", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "aws-lc-rs" -version = "1.16.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" -dependencies = [ - "aws-lc-sys", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" -dependencies = [ - "cc", - "cmake", - "dunce", - "fs_extra", -] - -[[package]] -name = "bitflags" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" - -[[package]] -name = "bumpalo" -version = "3.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" - -[[package]] -name = "bytes" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" - -[[package]] -name = "cc" -version = "1.2.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" -dependencies = [ - "find-msvc-tools", - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "cidr" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579504560394e388085d0c080ea587dfa5c15f7e251b4d5247d1e1a61d1d6928" - -[[package]] -name = "cmake" -version = "0.1.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" -dependencies = [ - "cc", -] - -[[package]] -name = "colorchoice" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "crossbeam-queue" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "dashmap" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "env_filter" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "jiff", - "log", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "etag" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b3d0661a2ccddc26cba0b834e9b717959ed6fdd76c7129ee159c170a875bf44" -dependencies = [ - "str-buf", - "xxhash-rust", -] - -[[package]] -name = "event-listener" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" -dependencies = [ - "event-listener", - "pin-project-lite", -] - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fastrand" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" - -[[package]] -name = "fieldwork" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4ce2198f558616d979bf4e13c0684f695ffeebe1a541ca466c928ddf42185b" -dependencies = [ - "fieldwork-derive", -] - -[[package]] -name = "fieldwork-derive" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4ce202eae2f2828b8f461bb6e8c40ed5358db1c3dce9e34108c94e68fe580" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - -[[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - -[[package]] -name = "full-duplex-async-copy" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb69fcc211c8359cc56981e36370c21f6410d6f9820c68dab273bed4bc58d99e" -dependencies = [ - "fastrand 1.9.0", - "futures-lite 1.13.0", - "pin-project-lite", -] - -[[package]] -name = "futures-core" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" - -[[package]] -name = "futures-io" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" - -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-lite" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" -dependencies = [ - "fastrand 2.4.1", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - -[[package]] -name = "futures-rustls" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" -dependencies = [ - "futures-io", - "rustls", - "rustls-pki-types", -] - -[[package]] -name = "futures-task" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" - -[[package]] -name = "futures-util" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "slab", -] - -[[package]] -name = "generator" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" -dependencies = [ - "cc", - "cfg-if", - "libc", - "log", - "rustversion", - "windows-link", - "windows-result", -] - -[[package]] -name = "getrandom" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi", - "wasip2", - "wasm-bindgen", -] - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "hashbrown" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", -] - -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "httparena-trillium-proxy" -version = "0.1.0" -dependencies = [ - "env_logger", - "log", - "mimalloc", - "num_cpus", - "signal-hook 0.3.18", - "socket2 0.5.10", - "swansong", - "trillium", - "trillium-proxy", - "trillium-quinn", - "trillium-router", - "trillium-rustls", - "trillium-static", - "trillium-tokio", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "icu_collections" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" -dependencies = [ - "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" - -[[package]] -name = "icu_properties" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" - -[[package]] -name = "icu_provider" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - -[[package]] -name = "jiff" -version = "0.2.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d" -dependencies = [ - "jiff-static", - "log", - "portable-atomic", - "portable-atomic-util", - "serde_core", -] - -[[package]] -name = "jiff-static" -version = "0.2.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "jni" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine", - "jni-sys 0.3.1", - "log", - "thiserror 1.0.69", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "jni-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" -dependencies = [ - "jni-sys 0.4.1", -] - -[[package]] -name = "jni-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" -dependencies = [ - "jni-sys-macros", -] - -[[package]] -name = "jni-sys-macros" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "jobserver" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" -dependencies = [ - "getrandom 0.3.4", - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" -dependencies = [ - "cfg-if", - "futures-util", - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.186" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" - -[[package]] -name = "libmimalloc-sys" -version = "0.1.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1eacfa31c33ec25e873c136ba5669f00f9866d0688bea7be4d3f7e43067df6" -dependencies = [ - "cc", -] - -[[package]] -name = "listenfd" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87bc54a4629b4294d0b3ef041b64c40c611097a677d9dc07b2c67739fe39dba" -dependencies = [ - "libc", - "uuid", - "winapi", -] - -[[package]] -name = "litemap" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" - -[[package]] -name = "loom" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - -[[package]] -name = "matchers" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "memchr" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - -[[package]] -name = "mimalloc" -version = "0.1.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3627c4272df786b9260cabaa46aec1d59c93ede723d4c3ef646c503816b0640" -dependencies = [ - "libmimalloc-sys", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "mio" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.61.2", -] - -[[package]] -name = "nu-ansi-term" -version = "0.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "once_cell_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" - -[[package]] -name = "openssl-probe" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" - -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", -] - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "pin-project-lite" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" - -[[package]] -name = "portable-atomic" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" - -[[package]] -name = "portable-atomic-util" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" -dependencies = [ - "portable-atomic", -] - -[[package]] -name = "potential_utf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" -dependencies = [ - "zerovec", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quinn" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" -dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2 0.6.3", - "thiserror 2.0.18", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" -dependencies = [ - "aws-lc-rs", - "bytes", - "getrandom 0.3.4", - "lru-slab", - "rand", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.18", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2 0.6.3", - "tracing", - "windows-sys 0.60.2", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "rand" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" -dependencies = [ - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom 0.3.4", -] - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" - -[[package]] -name = "relative-path" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca40a312222d8ba74837cb474edef44b37f561da5f773981007a10bbaa992b0" -dependencies = [ - "serde", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.17", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rlimit" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f35ee2729c56bb610f6dba436bf78135f728b7373bdffae2ec815b2d3eb98cc3" -dependencies = [ - "libc", -] - -[[package]] -name = "routefinder" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0971d3c8943a6267d6bd0d782fdc4afa7593e7381a92a3df950ff58897e066b5" -dependencies = [ - "memchr", - "smartcow", - "smartstring", -] - -[[package]] -name = "rustc-hash" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" - -[[package]] -name = "rustls" -version = "0.23.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" -dependencies = [ - "aws-lc-rs", - "log", - "once_cell", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" -dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" -dependencies = [ - "web-time", - "zeroize", -] - -[[package]] -name = "rustls-platform-verifier" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" -dependencies = [ - "core-foundation", - "core-foundation-sys", - "jni", - "log", - "once_cell", - "rustls", - "rustls-native-certs", - "rustls-platform-verifier-android", - "rustls-webpki", - "security-framework", - "security-framework-sys", - "webpki-root-certs", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls-platform-verifier-android" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" - -[[package]] -name = "rustls-webpki" -version = "0.103.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" -dependencies = [ - "aws-lc-rs", - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "security-framework" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a0c28ca5908dbdbcd52e6fdaa00358ab88637f8ab33e1f188dd510eb44b53d" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] - -[[package]] -name = "signal-hook-tokio" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e513e435a8898a0002270f29d0a708b7879708fb5c4d00e46983ca2d2d378cf0" -dependencies = [ - "futures-core", - "libc", - "signal-hook 0.4.4", - "tokio", -] - -[[package]] -name = "size" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b" - -[[package]] -name = "slab" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" - -[[package]] -name = "sluice" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "160b744a45e8261307bcfe03c98e2f8274502207d534c9a64b675c4db1b6bd58" -dependencies = [ - "async-channel", - "futures-core", - "futures-io", -] - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "smartcow" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "656fcb1c1fca8c4655372134ce87d8afdf5ec5949ebabe8d314be0141d8b5da2" -dependencies = [ - "smartstring", -] - -[[package]] -name = "smartstring" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" -dependencies = [ - "autocfg", - "static_assertions", - "version_check", -] - -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "socket2" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "str-buf" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceb97b7225c713c2fd4db0153cb6b3cab244eb37900c3f634ed4d43310d8c34" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "swansong" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e547d6edfcd09568f663d6340c48478cec8cac1403db95e8072c9a7e513253" -dependencies = [ - "event-listener", - "futures-core", - "log", - "pin-project-lite", -] - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" -dependencies = [ - "thiserror-impl 2.0.18", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "tinystr" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tinyvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.52.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "110a78583f19d5cdb2c5ccf321d1290344e71313c6c37d43520d386027d18386" -dependencies = [ - "libc", - "mio", - "pin-project-lite", - "socket2 0.6.3", - "windows-sys 0.61.2", -] - -[[package]] -name = "tokio-stream" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "log", - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex-automata", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "trillium" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42555814b00d06d4e3ea4dc1ee1929cfab2d776512b8850a907da51393ef9bc7" -dependencies = [ - "futures-lite 2.6.1", - "log", - "trillium-http", - "trillium-macros", -] - -[[package]] -name = "trillium-client" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb7e10b2802fce4bac578ab34040981ddd20f609f7ba522d41599cbb51783ab" -dependencies = [ - "crossbeam-queue", - "dashmap", - "encoding_rs", - "fieldwork", - "futures-lite 2.6.1", - "httparse", - "log", - "memchr", - "mime", - "size", - "trillium-http", - "trillium-macros", - "trillium-server-common", -] - -[[package]] -name = "trillium-forwarding" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6650af48b790287c7f824fe7ccd8dca7c694ec4d9c37d41436a544c4c6fda83" -dependencies = [ - "cidr", - "log", - "trillium", - "trillium-http", -] - -[[package]] -name = "trillium-http" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09720465ae91a53d8b7b60d4434e36aff6a79112b1d4ed854939e007b5d87ecf" -dependencies = [ - "atomic-waker", - "encoding_rs", - "event-listener", - "fastrand 2.4.1", - "fieldwork", - "futures-lite 2.6.1", - "hashbrown 0.17.0", - "httparse", - "httpdate", - "log", - "memchr", - "mime", - "pin-project-lite", - "smallvec", - "smartcow", - "smartstring", - "swansong", - "sync_wrapper", - "thiserror 2.0.18", - "trillium-macros", - "type-set", -] - -[[package]] -name = "trillium-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3caa8c474e8cfacd96ca0692f57f932891543db2147beca4758a075a7d26a0b2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "trillium-proxy" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b29c4c6075f2dce2d249e7f6aa70a93d14c344dc35a94ccdb2c7c038a92d168" -dependencies = [ - "event-listener", - "fastrand 2.4.1", - "full-duplex-async-copy", - "futures-lite 2.6.1", - "log", - "size", - "sluice", - "trillium", - "trillium-client", - "trillium-forwarding", - "trillium-http", - "trillium-server-common", - "url", -] - -[[package]] -name = "trillium-quinn" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3935766f08636bf455dc713cf645702fa139f169608858e2da76bd9e0377b59" -dependencies = [ - "async-compat", - "futures-lite 2.6.1", - "log", - "quinn", - "rustls", - "rustls-pemfile", - "trillium-macros", - "trillium-server-common", -] - -[[package]] -name = "trillium-router" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c56f83644b5a88362f8b0ce76fdc9d58cec068794bfc0add81e86986096c7f" -dependencies = [ - "log", - "routefinder", - "trillium", -] - -[[package]] -name = "trillium-rustls" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf428f82c0bcb0da509db3d4040d4ab921d3d2a6dd8796d128fb75639b00667" -dependencies = [ - "futures-rustls", - "log", - "rustls-pemfile", - "rustls-platform-verifier", - "trillium-server-common", - "webpki-roots", -] - -[[package]] -name = "trillium-server-common" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e25af92ce1701de85c077898deb6c3d5f63ac1c4b4c1b3a83c3ede637e99283" -dependencies = [ - "async-channel", - "async_cell", - "fieldwork", - "futures-lite 2.6.1", - "listenfd", - "log", - "pin-project-lite", - "rlimit", - "swansong", - "trillium", - "trillium-http", - "url", -] - -[[package]] -name = "trillium-static" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0a53adb5573d5effc5d7172cecfbfa4fb11c1f6ca9643d273c68419fd0077d3" -dependencies = [ - "async-compat", - "cfg-if", - "etag", - "futures-lite 2.6.1", - "httpdate", - "log", - "mime_guess", - "relative-path", - "tokio", - "trillium", -] - -[[package]] -name = "trillium-tokio" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b0d2e388eae1c568fb0ec5fe8d44253cbd338aa56139da9bb5663b22de01e2d" -dependencies = [ - "async-compat", - "log", - "signal-hook 0.4.4", - "signal-hook-tokio", - "tokio", - "tokio-stream", - "trillium", - "trillium-http", - "trillium-macros", - "trillium-server-common", -] - -[[package]] -name = "type-set" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "845e18586b78ef401c37d9d2d2cca631c19816d5aa26af12647e828739bd6614" - -[[package]] -name = "unicase" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "uuid" -version = "1.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasip2" -version = "1.0.3+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.121" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.121" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.121" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.121" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-root-certs" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "webpki-roots" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - -[[package]] -name = "wit-bindgen" -version = "0.57.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" - -[[package]] -name = "writeable" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" - -[[package]] -name = "xxhash-rust" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" - -[[package]] -name = "yoke" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.8.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zerofrom" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" - -[[package]] -name = "zerotrie" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/frameworks/trillium/proxy/Cargo.toml b/frameworks/trillium/proxy/Cargo.toml deleted file mode 100644 index 663da9287..000000000 --- a/frameworks/trillium/proxy/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "httparena-trillium-proxy" -version = "0.1.0" -edition = "2024" - -[dependencies] -trillium = "1.1" -trillium-tokio = "0.6" -trillium-router = "0.5" -trillium-rustls = "0.11" -trillium-quinn = "0.1" -trillium-static = { version = "0.5", features = ["tokio"] } -trillium-proxy = "0.7" - -log = "0.4" -env_logger = "0.11" -mimalloc = { version = "0.1", default-features = false } -swansong = "0.3.4" -socket2 = { version = "0.5", features = ["all"] } -num_cpus = "1" -signal-hook = "0.3" - -[profile.release] -opt-level = 3 -codegen-units = 1 -lto = "fat" -panic = "abort" -strip = true diff --git a/frameworks/trillium/proxy/Dockerfile b/frameworks/trillium/proxy/Dockerfile index 645904b3d..9f5167c79 100644 --- a/frameworks/trillium/proxy/Dockerfile +++ b/frameworks/trillium/proxy/Dockerfile @@ -1,13 +1,10 @@ -FROM rust:1.94-bookworm AS build -WORKDIR /app -COPY Cargo.toml . -RUN mkdir src && echo "fn main() {}" > src/main.rs && \ - cargo build --release && \ - rm -rf src/ target/release/httparena-trillium-proxy* target/release/deps/httparena_trillium_proxy* -COPY src ./src -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release +# Stock Caddy — ships h1/h2/h3 (QUIC) in the base image, no custom build. +# Covers both gateway-64 (h2 over TCP) and gateway-h3 (QUIC over UDP) from +# the same Caddyfile, which binds 8443 on both tcp and udp. +FROM caddy:2-alpine + +COPY Caddyfile /etc/caddy/Caddyfile -FROM debian:bookworm-slim -COPY --from=build /app/target/release/httparena-trillium-proxy /server EXPOSE 8443/tcp 8443/udp -CMD ["/server"] + +CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"] diff --git a/frameworks/trillium/proxy/src/main.rs b/frameworks/trillium/proxy/src/main.rs deleted file mode 100644 index 358f66b39..000000000 --- a/frameworks/trillium/proxy/src/main.rs +++ /dev/null @@ -1,315 +0,0 @@ -#[global_allocator] -static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; - -use std::{ - io, - net::{Ipv4Addr, SocketAddr}, - sync::Arc, -}; - -use socket2::{Domain, SockAddr, Socket, Type}; -use trillium::Handler; -use trillium_proxy::{Client, Proxy}; -use trillium_quinn::{ClientQuicConfig, QuicConfig}; -use trillium_router::Router; -use trillium_rustls::{ - RustlsAcceptor, RustlsConfig, - futures_rustls::rustls::{ - self, DigitallySignedStruct, SignatureScheme, - client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}, - crypto::{ - CryptoProvider, aws_lc_rs, verify_tls12_signature, verify_tls13_signature, - }, - pki_types::{CertificateDer, ServerName, UnixTime}, - }, -}; -use trillium_static::files; -use trillium_tokio::{ClientConfig, tokio, tokio::net::TcpListener}; - -const LISTEN_BACKLOG: i32 = 4096; - -#[derive(Debug)] -struct AcceptAnyServerCert(Arc); - -impl ServerCertVerifier for AcceptAnyServerCert { - fn verify_server_cert( - &self, - _end_entity: &CertificateDer<'_>, - _intermediates: &[CertificateDer<'_>], - _server_name: &ServerName<'_>, - _ocsp_response: &[u8], - _now: UnixTime, - ) -> Result { - Ok(ServerCertVerified::assertion()) - } - - fn verify_tls12_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - ) -> Result { - verify_tls12_signature(message, cert, dss, &self.0.signature_verification_algorithms) - } - - fn verify_tls13_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - ) -> Result { - verify_tls13_signature(message, cert, dss, &self.0.signature_verification_algorithms) - } - - fn supported_verify_schemes(&self) -> Vec { - self.0.signature_verification_algorithms.supported_schemes() - } -} - -fn upstream_rustls_config() -> rustls::ClientConfig { - let provider = Arc::new(aws_lc_rs::default_provider()); - let verifier = Arc::new(AcceptAnyServerCert(provider.clone())); - let mut config = rustls::ClientConfig::builder_with_provider(provider) - .with_safe_default_protocol_versions() - .expect("crypto provider supports default protocol versions") - .dangerous() - .with_custom_certificate_verifier(verifier) - .with_no_client_auth(); - config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()]; - config -} - -/// Build a fresh `Client` for the runtime currently calling this fn. The Client's pool opens -/// upstream connections via the calling runtime's reactor; tasks awaiting those connections -/// must run on the same runtime, so each worker / MT runtime gets its own. -fn build_client() -> Client { - let rustls_client = upstream_rustls_config(); - let quic_client = ClientQuicConfig::from_rustls_client_config(rustls_client.clone()); - let rustls_layer = RustlsConfig::new(rustls_client, ClientConfig::default()); - Client::new_with_quic(rustls_layer, quic_client) -} - -fn build_handler(client: Client, upstream: String, static_dir: String) -> impl Handler { - ( - Router::new().get("/static/*", files(static_dir)), - Proxy::new(client, upstream).with_via_pseudonym("trillium-proxy"), - ) -} - -fn bind_reuseport(port: u16) -> io::Result { - let addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, port)); - let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?; - #[cfg(unix)] - socket.set_reuse_port(true)?; - socket.set_reuse_address(true)?; - socket.set_nodelay(true)?; - socket.set_nonblocking(true)?; - socket.bind(&SockAddr::from(addr))?; - socket.listen(LISTEN_BACKLOG)?; - let std_listener: std::net::TcpListener = socket.into(); - TcpListener::from_std(std_listener) -} - -struct WorkerInputs { - cert: Vec, - key: Vec, - port: u16, - upstream: String, - static_dir: String, - swansong: swansong::Swansong, -} - -/// Per-worker current_thread runtime: TCP-only proxy (h1, h2). No QUIC. -fn run_worker(idx: usize, inputs: WorkerInputs) { - let WorkerInputs { - cert, - key, - port, - upstream, - static_dir, - swansong, - } = inputs; - - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .expect("build current_thread runtime"); - - rt.block_on(async move { - let listener = bind_reuseport(port).expect("bind proxy port"); - let client = build_client(); - log::info!("proxy worker {idx}: bound TCP on {port}"); - - trillium_tokio::config() - .with_prebound_server(listener) - .with_swansong(swansong.clone()) - .without_signals() - .with_nodelay() - .with_acceptor(RustlsAcceptor::from_single_cert(&cert, &key)) - .spawn(build_handler(client, upstream, static_dir)); - - swansong.await; - }); -} - -struct QuicRuntimeInputs { - cert: Vec, - key: Vec, - port: u16, - upstream: String, - static_dir: String, - n_threads: usize, - swansong: swansong::Swansong, -} - -/// Dedicated multi-thread runtime: TCP reuseport participant on `port` plus the QUIC endpoint. -/// h3 stream tasks spawned by quinn's accept loop spread across `n_threads` threads via tokio's -/// work-stealing scheduler. The per-worker current_thread runtimes still absorb most TCP traffic -/// (kernel reuseport hash gives the MT runtime ~1/(N+1) of TCP), preserving per-core hot caches. -fn run_quic_runtime(inputs: QuicRuntimeInputs) { - let QuicRuntimeInputs { - cert, - key, - port, - upstream, - static_dir, - n_threads, - swansong, - } = inputs; - - let rt = tokio::runtime::Builder::new_multi_thread() - .worker_threads(n_threads) - .enable_all() - .thread_name("quic-mt") - .build() - .expect("build quic multi_thread runtime"); - - rt.block_on(async move { - let listener = bind_reuseport(port).expect("bind proxy port on quic runtime"); - let client = build_client(); - log::info!("proxy quic-mt runtime: bound TCP + QUIC on {port} ({n_threads} threads)"); - - trillium_tokio::config() - .with_prebound_server(listener) - .with_swansong(swansong.clone()) - .without_signals() - .with_nodelay() - .with_acceptor(RustlsAcceptor::from_single_cert(&cert, &key)) - .with_quic(QuicConfig::from_single_cert(&cert, &key)) - .spawn(build_handler(client, upstream, static_dir)); - - swansong.await; - }); -} - -fn main() { - env_logger::init_from_env(env_logger::Env::default().default_filter_or("info")); - - let cert = - std::fs::read(std::env::var("TLS_CERT").unwrap_or_else(|_| "/certs/server.crt".into())) - .expect("TLS_CERT not readable"); - let key = std::fs::read(std::env::var("TLS_KEY").unwrap_or_else(|_| "/certs/server.key".into())) - .expect("TLS_KEY not readable"); - - let port: u16 = std::env::var("PROXY_PORT") - .ok() - .and_then(|s| s.parse().ok()) - .unwrap_or(8443); - let enable_h3 = std::env::var("PROXY_H3").is_ok_and(|v| v != "0" && !v.is_empty()); - - let n_workers: usize = std::env::var("WORKERS") - .ok() - .and_then(|s| s.parse().ok()) - .unwrap_or_else(num_cpus::get) - .max(1); - - // Default the QUIC runtime size proportionally to N, capped at 8 (Zen2/3/4 CCX size = 4 - // physical cores / 8 SMT threads — keeping the MT runtime ≤1 CCX worth keeps h3 work - // L3-local and avoids paying the ~70-cycle inter-CCX hop on every steal). Override with - // QUIC_THREADS for tuning. - // - // Empirical 8-core measurements: Q=2 preserves full per-worker TCP performance (≤3% delta) - // while doubling h3 capacity over the previous worker-0-only design. Q=8 maximizes h3 (~4 - // cores' worth) at a 12-17% TCP cost. The proportional default lands users near the Q=2 - // point on small boxes and the Q=8 point on the bench machine. - let quic_threads: usize = std::env::var("QUIC_THREADS") - .ok() - .and_then(|s| s.parse().ok()) - .unwrap_or_else(|| (n_workers / 4).max(2).min(8)) - .max(1); - - let upstream = - std::env::var("PROXY_UPSTREAM").unwrap_or_else(|_| "https://localhost:9443".into()); - let static_dir = std::env::var("STATIC_DIR").unwrap_or_else(|_| "/data/static".into()); - - let swansong = swansong::Swansong::new(); - - { - let swansong = swansong.clone(); - std::thread::Builder::new() - .name("signals".into()) - .spawn(move || { - let mut signals = signal_hook::iterator::Signals::new([ - signal_hook::consts::SIGINT, - signal_hook::consts::SIGTERM, - ]) - .expect("install signal handler"); - if signals.forever().next().is_some() { - log::info!("shutdown signal received"); - swansong.shut_down(); - } - }) - .expect("spawn signal thread"); - } - - if enable_h3 { - log::info!( - "proxy starting: {n_workers} per-worker current_thread workers (TCP) + 1 quic-mt runtime ({quic_threads} threads, h3 enabled, port={port})" - ); - } else { - log::info!( - "proxy starting: {n_workers} per-worker current_thread workers (TCP, port={port})" - ); - } - - let mut handles = Vec::with_capacity(n_workers + 1); - - for idx in 0..n_workers { - let inputs = WorkerInputs { - cert: cert.clone(), - key: key.clone(), - port, - upstream: upstream.clone(), - static_dir: static_dir.clone(), - swansong: swansong.clone(), - }; - handles.push( - std::thread::Builder::new() - .name(format!("worker-{idx}")) - .spawn(move || run_worker(idx, inputs)) - .expect("spawn worker thread"), - ); - } - - if enable_h3 { - let inputs = QuicRuntimeInputs { - cert: cert.clone(), - key: key.clone(), - port, - upstream: upstream.clone(), - static_dir: static_dir.clone(), - n_threads: quic_threads, - swansong: swansong.clone(), - }; - handles.push( - std::thread::Builder::new() - .name("quic-mt-driver".into()) - .spawn(move || run_quic_runtime(inputs)) - .expect("spawn quic-mt driver thread"), - ); - } - - for h in handles { - h.join().expect("worker join"); - } -} diff --git a/frameworks/trillium/src/main.rs b/frameworks/trillium/src/main.rs index 0c388691c..dcc2f715a 100644 --- a/frameworks/trillium/src/main.rs +++ b/frameworks/trillium/src/main.rs @@ -69,6 +69,11 @@ fn main() -> Result<(), Box> { .listeners() .bind_tcp(8080)?; + if let Ok(uds) = env::var("LISTEN_UDS") { + let _ = std::fs::remove_file(&uds); + builder = builder.bind_uds(uds)?; + } + if let (Some(cert), Some(key)) = (cert.as_deref(), key.as_deref()) { builder = builder .bind_tls(8081, RustlsAcceptor::from_single_cert_no_h2(cert, key))? From 5564fdcb488510ed9584157ab334f46d86a97cf6 Mon Sep 17 00:00:00 2001 From: Jacob Rothstein Date: Tue, 2 Jun 2026 14:43:43 -0700 Subject: [PATCH 4/4] [trillium] arc-clone the cached crud entries --- frameworks/trillium-tuned/Cargo.lock | 12 ++++++------ frameworks/trillium-tuned/src/handlers/crud.rs | 4 ++-- frameworks/trillium-tuned/src/state.rs | 2 +- frameworks/trillium/Cargo.lock | 12 ++++++------ frameworks/trillium/src/handlers/crud.rs | 4 ++-- frameworks/trillium/src/state.rs | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/frameworks/trillium-tuned/Cargo.lock b/frameworks/trillium-tuned/Cargo.lock index 5a62c0b37..9e2035c33 100644 --- a/frameworks/trillium-tuned/Cargo.lock +++ b/frameworks/trillium-tuned/Cargo.lock @@ -283,9 +283,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.11.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" [[package]] name = "block-buffer" @@ -1344,9 +1344,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.30" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" +checksum = "113b30b4cd05f7c06868fdb2854f66a7b9fece9a48425351cd532e810d74024f" [[package]] name = "loom" @@ -2739,9 +2739,9 @@ dependencies = [ [[package]] name = "trillium-http" -version = "1.3.3" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b326aef316f0d8944ef28d844553f963e88e9ef8c027f23ffa0c0890fbf50e2b" +checksum = "ac97f904f7f57860124edba0c51a727d6fa11dd8881603d1ce97d70c56d3157a" dependencies = [ "atomic-waker", "encoding_rs", diff --git a/frameworks/trillium-tuned/src/handlers/crud.rs b/frameworks/trillium-tuned/src/handlers/crud.rs index 7c396ed1b..292f7ffd6 100644 --- a/frameworks/trillium-tuned/src/handlers/crud.rs +++ b/frameworks/trillium-tuned/src/handlers/crud.rs @@ -136,11 +136,11 @@ pub async fn crud_read(conn: Conn) -> Conn { } }; - let body = sonic_rs::to_vec(&row).unwrap_or_default(); + let body: Arc<[u8]> = sonic_rs::to_vec(&row).unwrap_or_default().into(); state.crud_cache.insert( id, CacheEntry { - body: body.clone(), + body: Arc::clone(&body), expires: Instant::now() + CRUD_CACHE_TTL, }, ); diff --git a/frameworks/trillium-tuned/src/state.rs b/frameworks/trillium-tuned/src/state.rs index 157c960b3..e5744db67 100644 --- a/frameworks/trillium-tuned/src/state.rs +++ b/frameworks/trillium-tuned/src/state.rs @@ -35,7 +35,7 @@ pub struct AppState { } pub struct CacheEntry { - pub body: Vec, + pub body: Arc<[u8]>, pub expires: Instant, } diff --git a/frameworks/trillium/Cargo.lock b/frameworks/trillium/Cargo.lock index f64b310ef..6c428f0f8 100644 --- a/frameworks/trillium/Cargo.lock +++ b/frameworks/trillium/Cargo.lock @@ -283,9 +283,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.11.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" [[package]] name = "block-buffer" @@ -1352,9 +1352,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.30" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" +checksum = "113b30b4cd05f7c06868fdb2854f66a7b9fece9a48425351cd532e810d74024f" [[package]] name = "loom" @@ -2772,9 +2772,9 @@ dependencies = [ [[package]] name = "trillium-http" -version = "1.3.3" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b326aef316f0d8944ef28d844553f963e88e9ef8c027f23ffa0c0890fbf50e2b" +checksum = "ac97f904f7f57860124edba0c51a727d6fa11dd8881603d1ce97d70c56d3157a" dependencies = [ "atomic-waker", "encoding_rs", diff --git a/frameworks/trillium/src/handlers/crud.rs b/frameworks/trillium/src/handlers/crud.rs index 7c396ed1b..292f7ffd6 100644 --- a/frameworks/trillium/src/handlers/crud.rs +++ b/frameworks/trillium/src/handlers/crud.rs @@ -136,11 +136,11 @@ pub async fn crud_read(conn: Conn) -> Conn { } }; - let body = sonic_rs::to_vec(&row).unwrap_or_default(); + let body: Arc<[u8]> = sonic_rs::to_vec(&row).unwrap_or_default().into(); state.crud_cache.insert( id, CacheEntry { - body: body.clone(), + body: Arc::clone(&body), expires: Instant::now() + CRUD_CACHE_TTL, }, ); diff --git a/frameworks/trillium/src/state.rs b/frameworks/trillium/src/state.rs index e77bb05b3..3a68a9a3d 100644 --- a/frameworks/trillium/src/state.rs +++ b/frameworks/trillium/src/state.rs @@ -35,7 +35,7 @@ pub struct AppState { } pub struct CacheEntry { - pub body: Vec, + pub body: Arc<[u8]>, pub expires: Instant, }