From 71f3d182a6ca9022431c1654a852d2649721d20d Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Tue, 21 Nov 2023 05:53:45 +0800 Subject: [PATCH 1/4] feat: upgrade to hyper v1.0 --- Cargo.toml | 21 ++++++----- examples/otel/metrics/Cargo.toml | 3 +- examples/otel/metrics/src/main.rs | 11 +++--- examples/otel/tracing/Cargo.toml | 3 +- examples/otel/tracing/src/main.rs | 6 ++-- examples/routing/openapi/Cargo.toml | 4 +-- examples/templates/markup/Cargo.toml | 2 +- examples/templates/markup/src/main.rs | 2 ++ viz-core/Cargo.toml | 2 +- viz-core/src/middleware/otel/tracing.rs | 47 +++++++++++++------------ viz-core/tests/request.rs | 20 +++++++++-- viz-core/tests/type_payload.rs | 3 +- viz-test/Cargo.toml | 1 + viz-test/src/lib.rs | 1 + viz/src/serve.rs | 2 +- 15 files changed, 75 insertions(+), 53 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 025fb5f5..507d8de3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,12 +61,13 @@ thiserror = "1.0" path-tree = "0.7" # http -headers = "0.3" -http = "0.2" -http-body = "=1.0.0-rc.2" -http-body-util = "=0.1.0-rc.3" -hyper = { version = "=1.0.0-rc.4", features = ["server"] } -hyper-util = { git = "https://github.com/hyperium/hyper-util", rev = "63e84bf", features = ["auto"] } +# TODO: wait headers-v1.0 +headers = { git = "https://github.com/hyperium/headers.git", rev = "4400aa9" } +http = "1" +http-body = "1" +http-body-util = "0.1" +hyper = { version = "1", features = ["server"] } +hyper-util = { version = "0.1", features = ["server-auto", "tokio"] } futures-util = "0.3" tokio = { version = "1.33", features = ["net"] } @@ -86,11 +87,12 @@ hex = "0.4" rust-embed = "8" # OpenTelemetry -opentelemetry = { version = "0.20", default-features = false } -opentelemetry-prometheus = { version = "0.13", features = [ +opentelemetry = { version = "0.21", default-features = false } +opentelemetry_sdk = { version = "0.21", default-features = false } +opentelemetry-prometheus = { version = "0.14", features = [ "prometheus-encoding", ] } -opentelemetry-semantic-conventions = { version = "0.12" } +opentelemetry-semantic-conventions = { version = "0.13" } prometheus = "0.13" # Tracing @@ -102,6 +104,7 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [profile.dev] +opt-level = 1 split-debuginfo = "unpacked" [profile.dev.package."*"] diff --git a/examples/otel/metrics/Cargo.toml b/examples/otel/metrics/Cargo.toml index c577fbb1..853e4632 100644 --- a/examples/otel/metrics/Cargo.toml +++ b/examples/otel/metrics/Cargo.toml @@ -8,4 +8,5 @@ publish = false viz = { workspace = true, features = ["otel-metrics", "otel-prometheus"] } tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] } -opentelemetry = { workspace = true, default-features = false, features = ["metrics"]} +opentelemetry = { workspace = true, features = ["metrics"]} +opentelemetry_sdk = { workspace = true, features = ["metrics"] } diff --git a/examples/otel/metrics/src/main.rs b/examples/otel/metrics/src/main.rs index af23ed30..237ae5d6 100644 --- a/examples/otel/metrics/src/main.rs +++ b/examples/otel/metrics/src/main.rs @@ -4,13 +4,10 @@ use std::{net::SocketAddr, sync::Arc}; use tokio::net::TcpListener; -use opentelemetry::{ - global, - sdk::{ - metrics::{self, Aggregation, Instrument, MeterProvider, Stream}, - Resource, - }, - KeyValue, +use opentelemetry::{global, KeyValue}; +use opentelemetry_sdk::{ + metrics::{self, Aggregation, Instrument, MeterProvider, Stream}, + Resource, }; use viz::{ diff --git a/examples/otel/tracing/Cargo.toml b/examples/otel/tracing/Cargo.toml index 82154c54..e70e7dde 100644 --- a/examples/otel/tracing/Cargo.toml +++ b/examples/otel/tracing/Cargo.toml @@ -9,4 +9,5 @@ viz = { workspace = true, features = ["otel-tracing"] } tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] } opentelemetry.workspace = true -opentelemetry-jaeger = { version = "0.19.0", features = ["rt-tokio-current-thread"]} +opentelemetry_sdk = { workspace = true, features = ["trace", "rt-tokio-current-thread"] } +opentelemetry-jaeger = { version = "0.20", features = ["rt-tokio-current-thread"]} diff --git a/examples/otel/tracing/src/main.rs b/examples/otel/tracing/src/main.rs index 1c34ea3b..b53fd236 100644 --- a/examples/otel/tracing/src/main.rs +++ b/examples/otel/tracing/src/main.rs @@ -1,10 +1,10 @@ #![deny(warnings)] #![allow(clippy::unused_async)] -use opentelemetry::{ - global, +use opentelemetry::global; +use opentelemetry_sdk::{ runtime::TokioCurrentThread, - sdk::{propagation::TraceContextPropagator, trace::Tracer}, + {propagation::TraceContextPropagator, trace::Tracer}, }; use std::{net::SocketAddr, sync::Arc}; use tokio::net::TcpListener; diff --git a/examples/routing/openapi/Cargo.toml b/examples/routing/openapi/Cargo.toml index 9b7fa56b..c2daeaf6 100644 --- a/examples/routing/openapi/Cargo.toml +++ b/examples/routing/openapi/Cargo.toml @@ -12,5 +12,5 @@ serde = { workspace = true, features = ["derive"] } serde_json.workspace = true tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } -utoipa = "4.0" -utoipa-swagger-ui = "4.0" +utoipa = "4" +utoipa-swagger-ui = "4" diff --git a/examples/templates/markup/Cargo.toml b/examples/templates/markup/Cargo.toml index d653cab0..ee497407 100644 --- a/examples/templates/markup/Cargo.toml +++ b/examples/templates/markup/Cargo.toml @@ -9,5 +9,5 @@ viz.workspace = true tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] } -markup = "0.13" +markup = "0.14" v_htmlescape = "0.15" diff --git a/examples/templates/markup/src/main.rs b/examples/templates/markup/src/main.rs index 7eaf7e87..6383c845 100644 --- a/examples/templates/markup/src/main.rs +++ b/examples/templates/markup/src/main.rs @@ -1,5 +1,7 @@ #![deny(warnings)] #![allow(clippy::unused_async)] +#![allow(clippy::must_use_candidate)] +#![allow(clippy::inherent_to_string_shadow_display)] use std::{net::SocketAddr, sync::Arc}; use tokio::net::TcpListener; diff --git a/viz-core/Cargo.toml b/viz-core/Cargo.toml index 13605439..45694cd0 100644 --- a/viz-core/Cargo.toml +++ b/viz-core/Cargo.toml @@ -70,7 +70,7 @@ thiserror.workspace = true rfc7239 = "0.1" # realip cookie = { version = "0.18", features = ["percent-encode"], optional = true } -form-data = { version = "0.5.0-rc.2", optional = true } +form-data = { version = "0.5.0", optional = true } serde = { workspace = true, features = ["derive"], optional = true } serde_json = { workspace = true, optional = true } serde_urlencoded = { workspace = true, optional = true } diff --git a/viz-core/src/middleware/otel/tracing.rs b/viz-core/src/middleware/otel/tracing.rs index 127e6a4a..82043035 100644 --- a/viz-core/src/middleware/otel/tracing.rs +++ b/viz-core/src/middleware/otel/tracing.rs @@ -8,10 +8,8 @@ use http::uri::Scheme; use opentelemetry::{ global, propagation::Extractor, - trace::{ - FutureExt as OtelFutureExt, OrderMap, Span, SpanKind, Status, TraceContextExt, Tracer, - }, - Context, Key, Value, + trace::{FutureExt as OtelFutureExt, Span, SpanKind, Status, TraceContextExt, Tracer}, + Context, KeyValue, }; use opentelemetry_semantic_conventions::trace::{ CLIENT_ADDRESS, CLIENT_SOCKET_ADDRESS, EXCEPTION_MESSAGE, HTTP_REQUEST_BODY_SIZE, @@ -82,7 +80,7 @@ where .tracer .span_builder(format!("{} {}", req.method(), http_route)) .with_kind(SpanKind::Server) - .with_attributes_map(attributes) + .with_attributes(attributes) .start_with_context(&*self.tracer, &parent_context); span.add_event("request.started".to_string(), vec![]); @@ -153,62 +151,65 @@ impl<'a> Extractor for RequestHeaderCarrier<'a> { } } -fn build_attributes(req: &Request, http_route: &str) -> OrderMap { - let mut attributes = OrderMap::::with_capacity(10); +fn build_attributes(req: &Request, http_route: &str) -> Vec { + let mut attributes = Vec::with_capacity(10); // - attributes.insert(HTTP_ROUTE, http_route.to_string().into()); + attributes.push(KeyValue::new(HTTP_ROUTE, http_route.to_string())); // - attributes.insert(HTTP_REQUEST_METHOD, req.method().to_string().into()); - attributes.insert( + attributes.push(KeyValue::new(HTTP_REQUEST_METHOD, req.method().to_string())); + attributes.push(KeyValue::new( NETWORK_PROTOCOL_VERSION, - format!("{:?}", req.version()).into(), - ); + format!("{:?}", req.version()), + )); let remote_addr = req.remote_addr(); if let Some(remote_addr) = remote_addr { - attributes.insert(CLIENT_ADDRESS, remote_addr.to_string().into()); + attributes.push(KeyValue::new(CLIENT_ADDRESS, remote_addr.to_string())); } if let Some(realip) = req.realip().map(|value| value.0).filter(|realip| { remote_addr .map(SocketAddr::ip) .map_or(true, |remoteip| &remoteip != realip) }) { - attributes.insert(CLIENT_SOCKET_ADDRESS, realip.to_string().into()); + attributes.push(KeyValue::new(CLIENT_SOCKET_ADDRESS, realip.to_string())); } let uri = req.uri(); if let Some(host) = uri.host() { - attributes.insert(SERVER_ADDRESS, host.to_string().into()); + attributes.push(KeyValue::new(SERVER_ADDRESS, host.to_string())); } if let Some(port) = uri .port_u16() .map(i64::from) .filter(|port| *port != 80 && *port != 443) { - attributes.insert(SERVER_PORT, port.into()); + attributes.push(KeyValue::new(SERVER_PORT, port.to_string())); } if let Some(path_query) = uri.path_and_query() { if path_query.path() != "/" { - attributes.insert(URL_PATH, path_query.path().to_string().into()); + attributes.push(KeyValue::new(URL_PATH, path_query.path().to_string())); } if let Some(query) = path_query.query() { - attributes.insert(URL_QUERY, query.to_string().into()); + attributes.push(KeyValue::new(URL_QUERY, query.to_string())); } } - attributes.insert( + attributes.push(KeyValue::new( URL_SCHEME, - uri.scheme().unwrap_or(&Scheme::HTTP).to_string().into(), - ); + uri.scheme().unwrap_or(&Scheme::HTTP).to_string(), + )); if let Some(content_length) = req .content_length() .and_then(|len| i64::try_from(len).ok()) .filter(|len| *len > 0) { - attributes.insert(HTTP_REQUEST_BODY_SIZE, content_length.into()); + attributes.push(KeyValue::new( + HTTP_REQUEST_BODY_SIZE, + content_length.to_string(), + )); } if let Some(user_agent) = req @@ -216,7 +217,7 @@ fn build_attributes(req: &Request, http_route: &str) -> OrderMap { .as_ref() .map(UserAgent::as_str) { - attributes.insert(USER_AGENT_ORIGINAL, user_agent.to_string().into()); + attributes.push(KeyValue::new(USER_AGENT_ORIGINAL, user_agent.to_string())); } attributes diff --git a/viz-core/tests/request.rs b/viz-core/tests/request.rs index 30f52e28..eb46bc95 100644 --- a/viz-core/tests/request.rs +++ b/viz-core/tests/request.rs @@ -4,10 +4,19 @@ use headers::{authorization::Bearer, Authorization, ContentType, HeaderValue}; use http::uri::Scheme; use serde::{Deserialize, Serialize}; use viz_core::{ - header::{AUTHORIZATION, CONTENT_TYPE, COOKIE, SET_COOKIE}, + // TODO: reqwest and hyper haven't used the same version of `http`. + // header::{AUTHORIZATION, CONTENT_TYPE, COOKIE, SET_COOKIE}, + // StatusCode, + header::CONTENT_TYPE, types::{self, PayloadError}, - Error, IncomingBody, IntoResponse, Request, RequestExt, Response, ResponseExt, Result, - StatusCode, + Error, + IncomingBody, + IntoResponse, + Request, + RequestExt, + Response, + ResponseExt, + Result, }; #[derive(Debug, Deserialize, Serialize, PartialEq)] @@ -70,6 +79,10 @@ async fn request_body() -> Result<()> { middleware::{cookie, limits}, Router, }; + use viz_test::http::{ + header::{AUTHORIZATION, COOKIE}, + StatusCode, + }; use viz_test::TestServer; let router = Router::new() @@ -300,6 +313,7 @@ async fn request_session() -> Result<()> { middleware::{cookie, helper::CookieOptions, session}, Router, }; + use viz_test::http::header::{COOKIE, SET_COOKIE}; use viz_test::{nano_id, sessions, TestServer}; let router = Router::new() diff --git a/viz-core/tests/type_payload.rs b/viz-core/tests/type_payload.rs index 233bca61..b8db5383 100644 --- a/viz-core/tests/type_payload.rs +++ b/viz-core/tests/type_payload.rs @@ -1,9 +1,10 @@ use std::collections::HashMap; -use viz_core::{types, Error, Request, RequestExt, Response, ResponseExt, Result, StatusCode}; +use viz_core::{types, Error, Request, RequestExt, Response, ResponseExt, Result}; #[tokio::test] async fn payload() -> Result<()> { use viz::{middleware::limits, Router}; + use viz_test::http::StatusCode; use viz_test::TestServer; let router = Router::new() diff --git a/viz-test/Cargo.toml b/viz-test/Cargo.toml index 7a7aa053..a46ea389 100644 --- a/viz-test/Cargo.toml +++ b/viz-test/Cargo.toml @@ -19,5 +19,6 @@ viz.workspace = true sessions = { version = "0.5", features = ["memory"] } nano-id = "0.3" +http = "0.2" reqwest = { version = "0.11", features = ["cookies", "json", "multipart"]} tokio = { workspace = true, features = ["full"] } diff --git a/viz-test/src/lib.rs b/viz-test/src/lib.rs index 169d06f8..7267bd22 100644 --- a/viz-test/src/lib.rs +++ b/viz-test/src/lib.rs @@ -3,6 +3,7 @@ use std::{net::SocketAddr, sync::Arc}; use tokio::net::TcpListener; use viz::{serve, Error, Result, Router, Tree}; +pub use http; pub use nano_id; pub use sessions; diff --git a/viz/src/serve.rs b/viz/src/serve.rs index cd4b62c9..99f655e7 100644 --- a/viz/src/serve.rs +++ b/viz/src/serve.rs @@ -18,7 +18,7 @@ where I: AsyncRead + AsyncWrite + Unpin + Send + 'static, { Builder::new(TokioExecutor::new()) - .serve_connection_with_upgrades(Io::new(stream).into_inner(), Responder::new(tree, addr)) + .serve_connection_with_upgrades(Io::new(stream), Responder::new(tree, addr)) .await .map_err(Into::into) } From a2d31a22f262346d27ebed31253acc3d1a2e50c9 Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Tue, 21 Nov 2023 07:04:59 +0800 Subject: [PATCH 2/4] feat(examples): htmlx --- examples/htmlx/Cargo.toml | 10 ++++++++++ examples/htmlx/public/index.html | 12 ++++++++++++ examples/htmlx/src/main.rs | 3 +++ 3 files changed, 25 insertions(+) create mode 100644 examples/htmlx/Cargo.toml create mode 100644 examples/htmlx/public/index.html create mode 100644 examples/htmlx/src/main.rs diff --git a/examples/htmlx/Cargo.toml b/examples/htmlx/Cargo.toml new file mode 100644 index 00000000..d02315c1 --- /dev/null +++ b/examples/htmlx/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "htmlx" +version = "0.1.0" +edition.workspace = true +publish = false + +[dependencies] +viz.workspace = true + +tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] } diff --git a/examples/htmlx/public/index.html b/examples/htmlx/public/index.html new file mode 100644 index 00000000..b1e330bd --- /dev/null +++ b/examples/htmlx/public/index.html @@ -0,0 +1,12 @@ + + + + Viz & htmlx + + + +
+ Put To Messages +
+ + diff --git a/examples/htmlx/src/main.rs b/examples/htmlx/src/main.rs new file mode 100644 index 00000000..e7a11a96 --- /dev/null +++ b/examples/htmlx/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} From 0c9289edf25c5e7f282e676f28db41ec5455aa9e Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Sun, 10 Dec 2023 22:05:51 +0800 Subject: [PATCH 3/4] feat(examples): htmlx --- Cargo.toml | 3 +- examples/databases/sea-orm/Cargo.toml | 2 +- examples/forms/form/Cargo.toml | 5 +- examples/graceful-shutdown/Cargo.toml | 2 +- examples/hello-world/Cargo.toml | 2 +- examples/htmlx/Cargo.toml | 9 +- examples/htmlx/public/index.html | 12 --- examples/htmlx/src/main.rs | 112 ++++++++++++++++++++++- examples/htmlx/templates/index.html | 30 ++++++ examples/htmlx/templates/todos.html | 5 + examples/limits/Cargo.toml | 7 +- examples/otel/metrics/Cargo.toml | 2 +- examples/otel/tracing/Cargo.toml | 2 +- examples/templates/README.md | 1 + examples/templates/askama/Cargo.toml | 2 +- examples/templates/markup/Cargo.toml | 2 +- examples/templates/maud/Cargo.toml | 2 +- examples/templates/minijinja/Cargo.toml | 2 +- examples/templates/minijinja/src/main.rs | 5 +- examples/templates/tera/Cargo.toml | 2 +- examples/templates/tera/src/main.rs | 4 +- viz-test/Cargo.toml | 2 +- 22 files changed, 173 insertions(+), 42 deletions(-) delete mode 100644 examples/htmlx/public/index.html create mode 100644 examples/htmlx/templates/index.html create mode 100644 examples/htmlx/templates/todos.html diff --git a/Cargo.toml b/Cargo.toml index a3c094f1..7eb11688 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "2" members = [ "viz", "viz-core", @@ -30,8 +31,8 @@ members = [ "examples/tracing", "examples/graceful-shutdown", "examples/databases/*", + "examples/htmlx", ] -resolver = "2" [workspace.package] version = "0.5.1" diff --git a/examples/databases/sea-orm/Cargo.toml b/examples/databases/sea-orm/Cargo.toml index 2f4199b7..747f675a 100644 --- a/examples/databases/sea-orm/Cargo.toml +++ b/examples/databases/sea-orm/Cargo.toml @@ -8,7 +8,7 @@ publish = false viz = { workspace = true, features = ["serve"] } serde.workspace = true -tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } sea-orm = { version = "0.12", features = ["runtime-tokio-rustls", "sqlx-sqlite"] } [lints] diff --git a/examples/forms/form/Cargo.toml b/examples/forms/form/Cargo.toml index cdb88888..14589d2f 100644 --- a/examples/forms/form/Cargo.toml +++ b/examples/forms/form/Cargo.toml @@ -8,7 +8,4 @@ publish = false viz.workspace = true serde = { workspace = true, features = ["derive"] } -tokio = { workspace = true, features = [ - "rt-multi-thread", - "macros", -] } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } diff --git a/examples/graceful-shutdown/Cargo.toml b/examples/graceful-shutdown/Cargo.toml index e76f6e0b..a61f2df9 100644 --- a/examples/graceful-shutdown/Cargo.toml +++ b/examples/graceful-shutdown/Cargo.toml @@ -7,4 +7,4 @@ publish = false [dependencies] viz.workspace = true -tokio = { workspace = true, features = [ "rt-multi-thread", "macros", "time" ] } +tokio = { workspace = true, features = ["rt-multi-thread", "macros", "time"] } diff --git a/examples/hello-world/Cargo.toml b/examples/hello-world/Cargo.toml index 01368560..83109cdc 100644 --- a/examples/hello-world/Cargo.toml +++ b/examples/hello-world/Cargo.toml @@ -7,4 +7,4 @@ publish = false [dependencies] viz.workspace = true -tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } diff --git a/examples/htmlx/Cargo.toml b/examples/htmlx/Cargo.toml index d02315c1..6c9786fc 100644 --- a/examples/htmlx/Cargo.toml +++ b/examples/htmlx/Cargo.toml @@ -5,6 +5,11 @@ edition.workspace = true publish = false [dependencies] -viz.workspace = true +viz = { workspace = true, features = ["serve"] } -tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] } +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } + +handlebars = { version = "4.5", features = ["dir_source"] } +once_cell = "1.19" diff --git a/examples/htmlx/public/index.html b/examples/htmlx/public/index.html deleted file mode 100644 index b1e330bd..00000000 --- a/examples/htmlx/public/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - Viz & htmlx - - - -
- Put To Messages -
- - diff --git a/examples/htmlx/src/main.rs b/examples/htmlx/src/main.rs index e7a11a96..315f8dbe 100644 --- a/examples/htmlx/src/main.rs +++ b/examples/htmlx/src/main.rs @@ -1,3 +1,111 @@ -fn main() { - println!("Hello, world!"); +// #![deny(warnings)] + +use handlebars::Handlebars; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use std::{ + net::SocketAddr, + sync::{Arc, Mutex, PoisonError}, +}; +use tokio::net::TcpListener; +use viz::{ + header::HeaderValue, middleware::limits, serve, types::State, Error, IntoResponse, Request, + RequestExt, Response, ResponseExt, Result, Router, StatusCode, Tree, +}; + +/// In-memory todo store +type DB = Arc>>; + +#[derive(Debug, Clone, Deserialize, Serialize)] +struct Todo { + pub text: String, + pub completed: bool, +} + +static TPLS: Lazy = Lazy::new(|| { + let mut h = Handlebars::new(); + h.register_templates_directory(".html", "examples/htmlx/templates") + .unwrap(); + h +}); + +#[allow(clippy::needless_pass_by_value)] +fn into_error(e: PoisonError) -> Error { + e.to_string().into_error() +} + +async fn index(req: Request) -> Result { + let todos = req + .state::() + .unwrap() + .lock() + .map_err(into_error)? + .clone(); + let body = TPLS + .render( + "index", + &json!({ + "todos": todos + }), + ) + .map_err(Error::normal)?; + Ok(Response::html(body)) +} + +async fn list(req: Request) -> Result { + let todos = req + .state::() + .unwrap() + .lock() + .map_err(into_error)? + .clone(); + let body = TPLS + .render( + "todos", + &json!({ + "todos": todos + }), + ) + .map_err(Error::normal)?; + Ok(Response::html(body)) +} + +async fn create(mut req: Request) -> Result { + let todo = req.form::().await?; + let db = req.state::().unwrap(); + + let mut todos = db.lock().map_err(into_error)?; + todos.push(todo); + + let mut resp = StatusCode::CREATED.into_response(); + resp.headers_mut() + .insert("HX-Trigger", HeaderValue::from_static("newTodo")); + Ok(resp) +} + +#[tokio::main] +async fn main() -> Result<()> { + let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); + let listener = TcpListener::bind(addr).await?; + println!("listening on http://{addr}"); + + let app = Router::new() + .get("/", index) + .get("/todos", list) + .post("/todos", create) + .any("/*", |_| async { Ok(Response::text("Welcome!")) }) + .with(State::new(DB::default())) + .with(limits::Config::default()); + let tree = Arc::new(Tree::from(app)); + + loop { + let (stream, addr) = listener.accept().await?; + let tree = tree.clone(); + tokio::task::spawn(async move { + if let Err(err) = serve(stream, tree, Some(addr)).await { + eprintln!("Error while serving HTTP connection: {err}"); + } + }); + } } diff --git a/examples/htmlx/templates/index.html b/examples/htmlx/templates/index.html new file mode 100644 index 00000000..43c005e6 --- /dev/null +++ b/examples/htmlx/templates/index.html @@ -0,0 +1,30 @@ + + + + Viz & htmlx + + + +
+ + + + +
+
+
    + {{#each todos as | todo |}} +
  • {{text}}
  • + {{/each}} +
+
+ + diff --git a/examples/htmlx/templates/todos.html b/examples/htmlx/templates/todos.html new file mode 100644 index 00000000..4fc12737 --- /dev/null +++ b/examples/htmlx/templates/todos.html @@ -0,0 +1,5 @@ +
    +{{#each todos as | todo |}} +
  • {{text}} {{complated}}
  • +{{/each}} +
diff --git a/examples/limits/Cargo.toml b/examples/limits/Cargo.toml index c9345e38..c9567055 100644 --- a/examples/limits/Cargo.toml +++ b/examples/limits/Cargo.toml @@ -7,8 +7,5 @@ publish = false [dependencies] viz = { workspace = true, features = ["limits", "json", "form", "multipart"] } -serde = {version = "1.0", features = ["derive"] } -tokio = { workspace = true, features = [ - "rt-multi-thread", - "macros", -] } +serde = { version = "1.0", features = ["derive"] } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } diff --git a/examples/otel/metrics/Cargo.toml b/examples/otel/metrics/Cargo.toml index 853e4632..30123c37 100644 --- a/examples/otel/metrics/Cargo.toml +++ b/examples/otel/metrics/Cargo.toml @@ -7,6 +7,6 @@ publish = false [dependencies] viz = { workspace = true, features = ["otel-metrics", "otel-prometheus"] } -tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } opentelemetry = { workspace = true, features = ["metrics"]} opentelemetry_sdk = { workspace = true, features = ["metrics"] } diff --git a/examples/otel/tracing/Cargo.toml b/examples/otel/tracing/Cargo.toml index e70e7dde..b7686c51 100644 --- a/examples/otel/tracing/Cargo.toml +++ b/examples/otel/tracing/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] viz = { workspace = true, features = ["otel-tracing"] } -tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } opentelemetry.workspace = true opentelemetry_sdk = { workspace = true, features = ["trace", "rt-tokio-current-thread"] } opentelemetry-jaeger = { version = "0.20", features = ["rt-tokio-current-thread"]} diff --git a/examples/templates/README.md b/examples/templates/README.md index 7c93879a..f514642d 100644 --- a/examples/templates/README.md +++ b/examples/templates/README.md @@ -5,6 +5,7 @@ ## Examples * [askama](askama) +* [handlebars](../htmlx) * [markup](markup) * [maud](maud) * [minijinja](minijinja) diff --git a/examples/templates/askama/Cargo.toml b/examples/templates/askama/Cargo.toml index c7e1771f..5d153ae9 100644 --- a/examples/templates/askama/Cargo.toml +++ b/examples/templates/askama/Cargo.toml @@ -7,5 +7,5 @@ publish = false [dependencies] viz.workspace = true -tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } askama = "0.12" diff --git a/examples/templates/markup/Cargo.toml b/examples/templates/markup/Cargo.toml index 58245d05..836ffe6d 100644 --- a/examples/templates/markup/Cargo.toml +++ b/examples/templates/markup/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] viz.workspace = true -tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } markup = "0.15" v_htmlescape = "0.15" diff --git a/examples/templates/maud/Cargo.toml b/examples/templates/maud/Cargo.toml index bcc2847e..8e39acb3 100644 --- a/examples/templates/maud/Cargo.toml +++ b/examples/templates/maud/Cargo.toml @@ -7,5 +7,5 @@ publish = false [dependencies] viz.workspace = true -tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } maud = "0.25" diff --git a/examples/templates/minijinja/Cargo.toml b/examples/templates/minijinja/Cargo.toml index 7e9d07ef..a68e658e 100644 --- a/examples/templates/minijinja/Cargo.toml +++ b/examples/templates/minijinja/Cargo.toml @@ -8,6 +8,6 @@ publish = false viz.workspace = true serde.workspace = true -tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } minijinja = { version = "1", features = ["loader"] } once_cell = "1.19" diff --git a/examples/templates/minijinja/src/main.rs b/examples/templates/minijinja/src/main.rs index df72c376..46fad820 100644 --- a/examples/templates/minijinja/src/main.rs +++ b/examples/templates/minijinja/src/main.rs @@ -9,7 +9,7 @@ use serde::Serialize; use tokio::net::TcpListener; use viz::{serve, BytesMut, Error, Request, Response, ResponseExt, Result, Router, Tree}; -static MINIJINJA: Lazy = Lazy::new(|| { +static TPLS: Lazy = Lazy::new(|| { let mut env = Environment::new(); env.set_loader(path_loader("examples/templates/minijinja/templates")); env @@ -24,8 +24,7 @@ struct User<'a> { async fn index(_: Request) -> Result { let mut buf = BytesMut::with_capacity(512); buf.extend( - MINIJINJA - .get_template("index.html") + TPLS.get_template("index.html") .map_err(Error::normal)? .render(context! { title => "Viz.rs", diff --git a/examples/templates/tera/Cargo.toml b/examples/templates/tera/Cargo.toml index 13b740a7..d94d18d2 100644 --- a/examples/templates/tera/Cargo.toml +++ b/examples/templates/tera/Cargo.toml @@ -8,6 +8,6 @@ publish = false viz.workspace = true serde.workspace = true -tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } tera = "1.18" once_cell = "1.19" diff --git a/examples/templates/tera/src/main.rs b/examples/templates/tera/src/main.rs index 47b49b0f..1ec3438e 100644 --- a/examples/templates/tera/src/main.rs +++ b/examples/templates/tera/src/main.rs @@ -9,7 +9,7 @@ use tera::{Context, Tera}; use tokio::net::TcpListener; use viz::{serve, BytesMut, Error, Request, Response, ResponseExt, Result, Router, Tree}; -static TERA: Lazy = +static TPLS: Lazy = Lazy::new(|| Tera::new("examples/templates/tera/templates/**/*").unwrap()); #[derive(Serialize)] @@ -36,7 +36,7 @@ async fn index(_: Request) -> Result { ); let mut buf = BytesMut::with_capacity(512); buf.extend( - TERA.render("index.html", &ctx) + TPLS.render("index.html", &ctx) .map_err(Error::normal)? .as_bytes(), ); diff --git a/viz-test/Cargo.toml b/viz-test/Cargo.toml index e364b578..05e8b342 100644 --- a/viz-test/Cargo.toml +++ b/viz-test/Cargo.toml @@ -27,6 +27,6 @@ serde.workspace = true sessions = { version = "0.5", features = ["memory"] } nano-id = "0.3" -http = "0.2" +http = "=0.2" reqwest = { version = "0.11", features = ["cookies", "json", "multipart"]} tokio = { workspace = true, features = ["full"] } From 4095d534a29bc17080d4e29f40d7ac472374d16b Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Sun, 10 Dec 2023 22:13:39 +0800 Subject: [PATCH 4/4] feat(examples): htmlx --- examples/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/README.md b/examples/README.md index 0382ddb3..39130b1c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -31,6 +31,7 @@ Here you can find a lot of small crabs 🦀. * [maud](templates/maud) * [minijinja](templates/minijinja) * [Tracing aka logging](tracing) +* [htmlx](htmlx) ## Usage