Преглед на файлове

feat: Add test for ntex with sailfish template engine (#6233)

Kogia-sima преди 4 години
родител
ревизия
0ae216eb34

+ 5 - 0
frameworks/Rust/ntex/Cargo.toml

@@ -15,6 +15,10 @@ path = "src/main_db.rs"
 name = "ntex-raw"
 path = "src/main_raw.rs"
 
+[[bin]]
+name = "ntex-sailfish"
+path = "src/main_sailfish.rs"
+
 [dependencies]
 ntex = "0.1.21"
 mimalloc = { version = "0.1.21", default-features = false }
@@ -33,6 +37,7 @@ serde = { version = "1.0", features = ["derive"] }
 log = { version = "0.4", features = ["release_max_level_off"] }
 tokio = "=0.2.6"
 tokio-postgres = { git="https://github.com/fafhrd91/postgres.git" }
+sailfish = "0.3.0"
 
 [profile.release]
 lto = true

+ 17 - 0
frameworks/Rust/ntex/benchmark_config.json

@@ -39,6 +39,23 @@
       "notes": "",
       "versus": ""
     },
+    "sailfish": {
+      "fortune_url": "/fortunes",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "Postgres",
+      "framework": "ntex",
+      "language": "Rust",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "ntex",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "ntex [sailfish]",
+      "notes": "",
+      "versus": ""
+    },
     "raw": {
       "json_url": "/json",
       "plaintext_url": "/plaintext",

+ 11 - 0
frameworks/Rust/ntex/ntex-sailfish.dockerfile

@@ -0,0 +1,11 @@
+FROM rust:1.46
+
+RUN apt-get update -yqq && apt-get install -yqq cmake g++
+
+ADD ./ /ntex
+WORKDIR /ntex
+
+RUN cargo clean
+RUN RUSTFLAGS="-C target-cpu=native" cargo build --release
+
+CMD ./target/release/ntex-sailfish

+ 151 - 0
frameworks/Rust/ntex/src/main_sailfish.rs

@@ -0,0 +1,151 @@
+#[global_allocator]
+static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+
+use std::borrow::Cow;
+use std::future::Future;
+use std::io;
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+use bytes::Bytes;
+use futures::future::{ok, FutureExt};
+use futures::stream::StreamExt;
+use ntex::http::body::Body;
+use ntex::http::header::{HeaderValue, CONTENT_TYPE, SERVER};
+use ntex::http::{HttpService, KeepAlive, Request, Response, StatusCode};
+use ntex::service::{Service, ServiceFactory};
+use ntex::web::Error;
+use sailfish::TemplateOnce;
+use smallvec::{smallvec, SmallVec};
+use tokio_postgres::{connect, Client, NoTls, Statement};
+
+struct Fortune {
+    id: i32,
+    message: Cow<'static, str>,
+}
+
+#[derive(TemplateOnce)]
+#[template(path = "fortune.stpl", rm_whitespace = true)]
+struct Fortunes {
+    items: SmallVec<[Fortune; 32]>,
+}
+
+struct App {
+    hdr_srv: HeaderValue,
+    hdr_cthtml: HeaderValue,
+    db: Client,
+    fortune: Statement,
+}
+
+impl Service for App {
+    type Request = Request;
+    type Response = Response;
+    type Error = Error;
+    type Future = Pin<Box<dyn Future<Output = Result<Response, Error>>>>;
+
+    #[inline]
+    fn poll_ready(&self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+        Poll::Ready(Ok(()))
+    }
+
+    fn call(&self, req: Request) -> Self::Future {
+        let path = req.path();
+        match path {
+            "/fortunes" => {
+                let h_srv = self.hdr_srv.clone();
+                let h_ct = self.hdr_cthtml.clone();
+                let fut = self.db.query_raw(&self.fortune, &[]);
+
+                Box::pin(async move {
+                    let mut stream = fut.await.map_err(|e| {
+                        io::Error::new(io::ErrorKind::Other, format!("{:?}", e))
+                    })?;
+
+                    let mut items: SmallVec<[_; 32]> = smallvec![Fortune {
+                        id: 0,
+                        message: Cow::Borrowed(
+                            "Additional fortune added at request time."
+                        ),
+                    }];
+
+                    while let Some(row) = stream.next().await {
+                        let row = row.map_err(|e| {
+                            io::Error::new(io::ErrorKind::Other, format!("{:?}", e))
+                        })?;
+                        items.push(Fortune {
+                            id: row.get(0),
+                            message: Cow::Owned(row.get(1)),
+                        });
+                    }
+
+                    items.sort_by(|it, next| it.message.cmp(&next.message));
+
+                    let body = match (Fortunes { items }).render_once() {
+                        Ok(body) => Ok(Bytes::from(body)),
+                        Err(e) => {
+                            Err(io::Error::new(io::ErrorKind::Other, e.to_string()))
+                        }
+                    }?;
+
+                    let mut res = Response::with_body(StatusCode::OK, Body::Bytes(body));
+                    let hdrs = res.headers_mut();
+                    hdrs.insert(SERVER, h_srv);
+                    hdrs.insert(CONTENT_TYPE, h_ct);
+                    Ok(res)
+                })
+            }
+            _ => Box::pin(ok(Response::new(http::StatusCode::NOT_FOUND))),
+        }
+    }
+}
+
+#[derive(Clone)]
+struct AppFactory;
+
+impl ServiceFactory for AppFactory {
+    type Config = ();
+    type Request = Request;
+    type Response = Response;
+    type Error = Error;
+    type Service = App;
+    type InitError = ();
+    type Future = Pin<Box<dyn Future<Output = Result<Self::Service, Self::InitError>>>>;
+
+    fn new_service(&self, _: ()) -> Self::Future {
+        const DB_URL: &str =
+            "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world";
+
+        Box::pin(async move {
+            let (db, conn) = connect(DB_URL, NoTls)
+                .await
+                .expect("can not connect to postgresql");
+            ntex::rt::spawn(conn.map(|_| ()));
+
+            let fortune = db.prepare("SELECT * FROM fortune").await.unwrap();
+
+            Ok(App {
+                hdr_srv: HeaderValue::from_static("N"),
+                hdr_cthtml: HeaderValue::from_static("text/html; charset=utf-8"),
+                db,
+                fortune,
+            })
+        })
+    }
+}
+
+#[ntex::main]
+async fn main() -> std::io::Result<()> {
+    println!("Starting http server: 127.0.0.1:8080");
+
+    ntex::server::build()
+        .backlog(1024)
+        .bind("techempower", "0.0.0.0:8080", || {
+            HttpService::build()
+                .keep_alive(KeepAlive::Os)
+                .client_timeout(0)
+                .h1(AppFactory)
+                .tcp()
+        })?
+        .start()
+        .await
+}

+ 10 - 0
frameworks/Rust/ntex/templates/fortune.stpl

@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <head><title>Fortunes</title></head>
+  <body>
+    <table>
+      <tr><th>id</th><th>message</th></tr>
+      <% for item in items { %><tr><td><%= item.id %></td><td><%= &*item.message %></td></tr><% } %>
+    </table>
+  </body>
+</html>