From c2e6ba5b966c9da33c24f94ad9ca310830059fb4 Mon Sep 17 00:00:00 2001 From: "glm-5.2" Date: Wed, 1 Jul 2026 16:41:14 +0000 Subject: [PATCH] feat(http): initialize alknet-http crate with module skeleton MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add crates/alknet-http with Cargo.toml, src/lib.rs, and the five subsystem modules (server, gateway, client, adapters, websocket) per ADR-039 (server + client host colocated). The mcp feature gate pulls in rmcp with streamable HTTP transport features only (ADR-037 — no stdio); h3/WebTransport is absent (deferred per ADR-044). alknet-core and alknet-call use workspace path deps. The crate is added to the workspace members list. --- Cargo.lock | 368 +++++++++++++++++++++++- Cargo.toml | 1 + crates/alknet-http/Cargo.toml | 40 +++ crates/alknet-http/src/adapters/mod.rs | 11 + crates/alknet-http/src/client/mod.rs | 6 + crates/alknet-http/src/gateway/mod.rs | 7 + crates/alknet-http/src/lib.rs | 13 + crates/alknet-http/src/server/mod.rs | 9 + crates/alknet-http/src/websocket/mod.rs | 7 + 9 files changed, 458 insertions(+), 4 deletions(-) create mode 100644 crates/alknet-http/Cargo.toml create mode 100644 crates/alknet-http/src/adapters/mod.rs create mode 100644 crates/alknet-http/src/client/mod.rs create mode 100644 crates/alknet-http/src/gateway/mod.rs create mode 100644 crates/alknet-http/src/lib.rs create mode 100644 crates/alknet-http/src/server/mod.rs create mode 100644 crates/alknet-http/src/websocket/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 98231df..8c6edf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,6 +99,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "alknet-http" +version = "0.1.0" +dependencies = [ + "alknet-call", + "alknet-core", + "async-trait", + "axum", + "futures", + "hyper", + "openapiv3", + "reqwest 0.13.4", + "reqwest-middleware", + "reqwest-retry", + "rmcp", + "serde", + "serde_json", + "thiserror 2.0.18", + "tokio", + "tracing", + "uuid", +] + [[package]] name = "alknet-vault" version = "0.1.0" @@ -381,6 +404,61 @@ dependencies = [ "fs_extra", ] +[[package]] +name = "axum" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" +dependencies = [ + "axum-core", + "base64", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper", + "tokio", + "tokio-tungstenite", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "backon" version = "1.6.0" @@ -1804,6 +1882,8 @@ checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", "hashbrown 0.17.1", + "serde", + "serde_core", ] [[package]] @@ -1885,7 +1965,7 @@ dependencies = [ "portmapper", "rand 0.8.6", "rcgen 0.13.2", - "reqwest", + "reqwest 0.12.28", "ring", "rustls", "rustls-webpki 0.102.8", @@ -2031,7 +2111,7 @@ dependencies = [ "pkarr", "postcard", "rand 0.8.6", - "reqwest", + "reqwest 0.12.28", "rustls", "rustls-webpki 0.102.8", "serde", @@ -2248,6 +2328,12 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + [[package]] name = "md5" version = "0.7.0" @@ -2260,6 +2346,12 @@ version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2690,6 +2782,17 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "openapiv3" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8d427828b22ae1fff2833a03d8486c2c881367f1c336349f307f321e7f4d05" +dependencies = [ + "indexmap", + "serde", + "serde_json", +] + [[package]] name = "openssl-probe" version = "0.2.1" @@ -2731,6 +2834,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pastey" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4" + [[package]] name = "pem" version = "3.0.6" @@ -2835,6 +2944,12 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "piper" version = "0.2.5" @@ -2865,7 +2980,7 @@ dependencies = [ "log", "lru 0.13.0", "ntimestamp", - "reqwest", + "reqwest 0.12.28", "self_cell", "serde", "sha1_smol", @@ -3313,6 +3428,26 @@ dependencies = [ "bitflags 2.13.0", ] +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "regex" version = "1.12.4" @@ -3384,17 +3519,95 @@ dependencies = [ "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", + "wasm-streams 0.4.2", "web-sys", "webpki-roots 1.0.8", ] +[[package]] +name = "reqwest" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" +dependencies = [ + "base64", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "sync_wrapper", + "tokio", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams 0.5.0", + "web-sys", +] + +[[package]] +name = "reqwest-middleware" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc3f1384cffa4f274dad2d4ddd73aed32fed8f786d96c6be8aa4e5fd3c3b58" +dependencies = [ + "anyhow", + "async-trait", + "http", + "reqwest 0.13.4", + "thiserror 2.0.18", + "tower-service", +] + +[[package]] +name = "reqwest-retry" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe2412db2af7d2268e7a5406be0431f37d9eb67ff390f35b395716f5f06c2eaa" +dependencies = [ + "anyhow", + "async-trait", + "futures", + "getrandom 0.2.17", + "http", + "hyper", + "reqwest 0.13.4", + "reqwest-middleware", + "retry-policies", + "thiserror 2.0.18", + "tokio", + "tracing", + "wasmtimer", +] + [[package]] name = "resolv-conf" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" +[[package]] +name = "retry-policies" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc05fbf560421a0357a750cbe78c7ca19d4923918490daabba313d5dbc871e47" +dependencies = [ + "rand 0.10.1", +] + [[package]] name = "ring" version = "0.17.14" @@ -3409,6 +3622,36 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rmcp" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1f571c72940a19d9532fe52dbea8bc9912bf1d766c2970bb824056b86f3f59" +dependencies = [ + "async-trait", + "bytes", + "chrono", + "futures", + "http", + "http-body", + "http-body-util", + "pastey", + "pin-project-lite", + "rand 0.10.1", + "reqwest 0.13.4", + "schemars", + "serde", + "serde_json", + "sse-stream", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tokio-util", + "tower-service", + "tracing", + "uuid", +] + [[package]] name = "rustc-hash" version = "2.1.2" @@ -3608,6 +3851,32 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "chrono", + "dyn-clone", + "ref-cast", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -3709,6 +3978,17 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "serde_json" version = "1.0.150" @@ -3722,6 +4002,17 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + [[package]] name = "serde_spanned" version = "0.6.9" @@ -3922,6 +4213,19 @@ dependencies = [ "der", ] +[[package]] +name = "sse-stream" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3962b63f038885f15bce2c6e02c0e7925c072f1ac86bb60fd44c5c6b762fb72" +dependencies = [ + "bytes", + "futures-util", + "http-body", + "http-body-util", + "pin-project-lite", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -4222,6 +4526,18 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "tokio-tungstenite" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + [[package]] name = "tokio-util" version = "0.7.18" @@ -4342,6 +4658,7 @@ dependencies = [ "tokio", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -4442,6 +4759,22 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.4", + "sha1", + "thiserror 2.0.18", +] + [[package]] name = "typenum" version = "1.20.1" @@ -4650,6 +4983,33 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-streams" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasmtimer" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] + [[package]] name = "web-sys" version = "0.3.102" diff --git a/Cargo.toml b/Cargo.toml index 54debac..7dc73cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "crates/alknet-vault", "crates/alknet-core", "crates/alknet-call", + "crates/alknet-http", ] resolver = "2" diff --git a/crates/alknet-http/Cargo.toml b/crates/alknet-http/Cargo.toml new file mode 100644 index 0000000..621112f --- /dev/null +++ b/crates/alknet-http/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "alknet-http" +version.workspace = true +edition.workspace = true +license.workspace = true +description = "HTTP interface for alknet: serves HTTP/1.1 + HTTP/2 on standard ALPNs (with WebSocket upgrade for browser bidirectional access) and hosts the HTTP-backed call-protocol adapters" +repository.workspace = true + +[lib] +name = "alknet_http" + +[features] +default = ["h2", "http1"] +mcp = ["dep:rmcp"] +h2 = ["dep:hyper"] +http1 = ["dep:hyper"] + +[dependencies] +alknet-core = { path = "../alknet-core" } +alknet-call = { path = "../alknet-call" } +axum = { version = "0.8", features = ["ws"] } +hyper = { version = "1", optional = true, features = ["server", "http1", "http2"] } +reqwest = { version = "0.13", default-features = false, features = ["json", "stream"] } +reqwest-middleware = "0.5" +reqwest-retry = "0.9" +tokio = { version = "1", features = ["full"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +async-trait = "0.1" +tracing = "0.1" +thiserror = "2" +uuid = { version = "1", features = ["v4"] } +futures = "0.3" +openapiv3 = "2" +rmcp = { version = "1.8", optional = true, default-features = false, features = [ + "client", + "server", + "transport-streamable-http-client-reqwest", + "transport-streamable-http-server", +] } \ No newline at end of file diff --git a/crates/alknet-http/src/adapters/mod.rs b/crates/alknet-http/src/adapters/mod.rs new file mode 100644 index 0000000..2d98f74 --- /dev/null +++ b/crates/alknet-http/src/adapters/mod.rs @@ -0,0 +1,11 @@ +//! HTTP-backed call-protocol adapters: `from_openapi`, `to_openapi`, +//! `from_mcp`, `to_mcp`. +//! +//! `from_openapi`/`from_mcp` are the no-env-vars credential injection point +//! (ADR-014); `to_openapi`/`to_mcp` are projections of the local registry +//! (ADR-017). `from_mcp`/`to_mcp` are feature-gated behind `mcp` +//! (streamable HTTP only — ADR-037). See +//! `docs/architecture/crates/http/http-adapters.md` and +//! `docs/architecture/crates/http/http-mcp.md`. + +// TODO: implement diff --git a/crates/alknet-http/src/client/mod.rs b/crates/alknet-http/src/client/mod.rs new file mode 100644 index 0000000..a301713 --- /dev/null +++ b/crates/alknet-http/src/client/mod.rs @@ -0,0 +1,6 @@ +//! Shared HTTP client (`ClientWithMiddleware`): reqwest + retry middleware +//! stack, used by `from_openapi`/`from_mcp` forwarding handlers. +//! +//! See `docs/architecture/crates/http/http-adapters.md` and OQ-40. + +// TODO: implement diff --git a/crates/alknet-http/src/gateway/mod.rs b/crates/alknet-http/src/gateway/mod.rs new file mode 100644 index 0000000..941bfc0 --- /dev/null +++ b/crates/alknet-http/src/gateway/mod.rs @@ -0,0 +1,7 @@ +//! Gateway: shared dispatch spine (`GatewayDispatch`) and error mapping. +//! +//! The 5 fixed gateway endpoints (`/search`, `/schema`, `/call`, `/batch`, +//! `/subscribe`) are the sole HTTP invoke path (ADR-042/047). See +//! `docs/architecture/crates/http/http-server.md`. + +// TODO: implement diff --git a/crates/alknet-http/src/lib.rs b/crates/alknet-http/src/lib.rs new file mode 100644 index 0000000..ad36208 --- /dev/null +++ b/crates/alknet-http/src/lib.rs @@ -0,0 +1,13 @@ +//! alknet-http: HTTP interface for alknet — serves HTTP/1.1 + HTTP/2 on +//! standard ALPNs (with WebSocket upgrade for browser bidirectional access) +//! and hosts the HTTP-backed call-protocol adapters. +//! +//! Two roles in one crate (ADR-039): HTTP server (HttpAdapter, a +//! ProtocolHandler for h2/http1.1 + WS upgrade) and HTTP client host +//! (from_openapi/from_mcp forwarding, to_openapi/to_mcp projections). + +pub mod adapters; +pub mod client; +pub mod gateway; +pub mod server; +pub mod websocket; diff --git a/crates/alknet-http/src/server/mod.rs b/crates/alknet-http/src/server/mod.rs new file mode 100644 index 0000000..e34f777 --- /dev/null +++ b/crates/alknet-http/src/server/mod.rs @@ -0,0 +1,9 @@ +//! HTTP server: `HttpAdapter`, axum-over-QUIC, gateway routes, `/healthz`, +//! decoy, and custom routes. +//! +//! Implements `alknet_core::types::ProtocolHandler` for the standard HTTP +//! ALPNs (`h2`, `http/1.1`) with WebSocket upgrade for browser +//! bidirectional access (ADR-044). See +//! `docs/architecture/crates/http/http-server.md`. + +// TODO: implement diff --git a/crates/alknet-http/src/websocket/mod.rs b/crates/alknet-http/src/websocket/mod.rs new file mode 100644 index 0000000..1ec437f --- /dev/null +++ b/crates/alknet-http/src/websocket/mod.rs @@ -0,0 +1,7 @@ +//! WebSocket upgrade handler, framing, and dispatch handoff. +//! +//! WebSocket is the browser bidirectional path (ADR-044) and carries the +//! native `EventEnvelope` call-protocol session, not the gateway shape +//! (ADR-048). See `docs/architecture/crates/http/websocket.md`. + +// TODO: implement