Browse Source

actix: use markup.rs templates engine for fortunes test (#4729)

* use markup.rs templates engine for fortunes test

* reduce number of connections
Nikolay Kim 6 years ago
parent
commit
74602b49cd

+ 3 - 2
frameworks/Rust/actix/Cargo.toml

@@ -21,13 +21,14 @@ path = "src/main_pg.rs"
 
 [dependencies]
 actix = { version="0.8.1", features=["http"] }
-actix-web = { version="1.0.0-beta.1", default-features = false }
-actix-http = { version="0.1.1", default-features = false }
+actix-web = { version="1.0.0-beta.3", default-features = false }
+actix-http = { version="0.1.5", default-features = false }
 actix-rt = "0.2.2"
 actix-server = "0.4.2"
 actix-service = "0.3.6"
 jemallocator = "0.3.0"
 askama = "0.8"
+markup = "0.3.1"
 serde = "1.0"
 serde_json = "1.0"
 serde_derive = "1.0"

+ 25 - 17
frameworks/Rust/actix/src/db_pg.rs

@@ -2,11 +2,13 @@ use std::io;
 
 use actix::fut;
 use actix::prelude::*;
+use bytes::{Bytes, BytesMut};
 use futures::{stream, Future, Stream};
 use rand::{thread_rng, Rng, ThreadRng};
 use tokio_postgres::{connect, Client, NoTls, Statement};
 
-use crate::models::{Fortune, World};
+use crate::models::World;
+use crate::utils::{Fortune, Writer};
 
 /// Postgres interface
 pub struct PgConnection {
@@ -68,11 +70,11 @@ impl PgConnection {
 pub struct RandomWorld;
 
 impl Message for RandomWorld {
-    type Result = io::Result<World>;
+    type Result = io::Result<Bytes>;
 }
 
 impl Handler<RandomWorld> for PgConnection {
-    type Result = ResponseFuture<World, io::Error>;
+    type Result = ResponseFuture<Bytes, io::Error>;
 
     fn handle(&mut self, _: RandomWorld, _: &mut Self::Context) -> Self::Result {
         let random_id = self.rng.gen_range::<i32>(1, 10_001);
@@ -84,12 +86,18 @@ impl Handler<RandomWorld> for PgConnection {
                 .query(self.world.as_ref().unwrap(), &[&random_id])
                 .into_future()
                 .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{:?}", e.0)))
-                .and_then(|(row, _)| {
+                .map(|(row, _)| {
                     let row = row.unwrap();
-                    Ok(World {
-                        id: row.get(0),
-                        randomnumber: row.get(1),
-                    })
+                    let mut body = BytesMut::with_capacity(33);
+                    serde_json::to_writer(
+                        Writer(&mut body),
+                        &World {
+                            id: row.get(0),
+                            randomnumber: row.get(1),
+                        },
+                    )
+                    .unwrap();
+                    body.freeze()
                 }),
         )
     }
@@ -117,12 +125,12 @@ impl Handler<RandomWorlds> for PgConnection {
                     .map_err(|e| {
                         io::Error::new(io::ErrorKind::Other, format!("{:?}", e.0))
                     })
-                    .and_then(|(row, _)| {
+                    .map(|(row, _)| {
                         let row = row.unwrap();
-                        Ok(World {
+                        World {
                             id: row.get(0),
                             randomnumber: row.get(1),
-                        })
+                        }
                     }),
             );
         }
@@ -154,12 +162,12 @@ impl Handler<UpdateWorld> for PgConnection {
                     .map_err(|e| {
                         io::Error::new(io::ErrorKind::Other, format!("{:?}", e.0))
                     })
-                    .and_then(move |(row, _)| {
+                    .map(move |(row, _)| {
                         let row = row.unwrap();
-                        Ok(World {
+                        World {
                             id: row.get(0),
                             randomnumber: id,
-                        })
+                        }
                     }),
             );
         }
@@ -189,7 +197,7 @@ impl Handler<UpdateWorld> for PgConnection {
                         .collect()
                         .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{:?}", e)))
                         .into_actor(act)
-                        .and_then(|_, _, _| fut::ok(worlds))
+                        .map(|_, _, _| worlds)
                 }),
         )
     }
@@ -224,9 +232,9 @@ impl Handler<TellFortune> for PgConnection {
                     Ok::<_, io::Error>(items)
                 })
                 .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{:?}", e)))
-                .and_then(|mut items| {
+                .map(|mut items| {
                     items.sort_by(|it, next| it.message.cmp(&next.message));
-                    Ok(items)
+                    items
                 }),
         )
     }

+ 2 - 2
frameworks/Rust/actix/src/db_pg_direct.rs

@@ -7,8 +7,8 @@ use futures::{stream, Future, Stream};
 use rand::{thread_rng, Rng, ThreadRng};
 use tokio_postgres::{connect, Client, NoTls, Statement};
 
-use crate::models::{Fortune, World};
-use crate::utils::Writer;
+use crate::models::World;
+use crate::utils::{Fortune, Writer};
 
 /// Postgres interface
 pub struct PgConnection {

+ 13 - 18
frameworks/Rust/actix/src/main_pg.rs

@@ -6,12 +6,13 @@ extern crate serde_derive;
 #[macro_use]
 extern crate diesel;
 
+use std::io::Write;
+
 use actix::prelude::*;
 use actix_http::{HttpService, KeepAlive};
 use actix_server::Server;
 use actix_web::http::{header::CONTENT_TYPE, header::SERVER, HeaderValue, StatusCode};
 use actix_web::{dev::Body, web, App, Error, HttpRequest, HttpResponse};
-use askama::Template;
 use bytes::BytesMut;
 use futures::Future;
 
@@ -19,7 +20,7 @@ mod db_pg;
 mod models;
 mod utils;
 use crate::db_pg::{PgConnection, RandomWorld, RandomWorlds, TellFortune, UpdateWorld};
-use crate::utils::Writer;
+use crate::utils::{FortunesTemplate, Writer};
 
 fn world_row(
     db: web::Data<Addr<PgConnection>>,
@@ -27,11 +28,8 @@ fn world_row(
     db.send(RandomWorld)
         .from_err()
         .and_then(move |res| match res {
-            Ok(row) => {
-                let mut body = BytesMut::with_capacity(33);
-                serde_json::to_writer(Writer(&mut body), &row).unwrap();
-                let mut res =
-                    HttpResponse::with_body(StatusCode::OK, Body::Bytes(body.freeze()));
+            Ok(body) => {
+                let mut res = HttpResponse::with_body(StatusCode::OK, Body::Bytes(body));
                 res.headers_mut()
                     .insert(SERVER, HeaderValue::from_static("Actix"));
                 res.headers_mut()
@@ -92,24 +90,21 @@ fn updates(
     })
 }
 
-#[derive(Template)]
-#[template(path = "fortune.html")]
-struct FortuneTemplate<'a> {
-    items: &'a Vec<models::Fortune>,
-}
-
 fn fortune(
     db: web::Data<Addr<PgConnection>>,
 ) -> impl Future<Item = HttpResponse, Error = Error> {
     db.send(TellFortune)
         .from_err()
         .and_then(move |res| match res {
-            Ok(rows) => {
-                let tmpl = FortuneTemplate { items: &rows };
-                let body = tmpl.render().unwrap();
+            Ok(fortunes) => {
+                let mut body = BytesMut::with_capacity(2048);
+                let mut writer = Writer(&mut body);
+                let _ = write!(writer, "{}", FortunesTemplate { fortunes });
 
-                let mut res =
-                    HttpResponse::with_body(StatusCode::OK, Body::Bytes(body.into()));
+                let mut res = HttpResponse::with_body(
+                    StatusCode::OK,
+                    Body::Bytes(body.freeze().into()),
+                );
                 res.headers_mut()
                     .insert(SERVER, HeaderValue::from_static("Actix"));
                 res.headers_mut().insert(

+ 11 - 31
frameworks/Rust/actix/src/main_platform.rs

@@ -14,7 +14,7 @@ use actix_http::http::{HeaderValue, StatusCode};
 use actix_http::{Error, HttpService, KeepAlive, Request, Response};
 use actix_server::{Server, ServerConfig};
 use actix_service::{NewService, Service};
-use bytes::{BufMut, Bytes, BytesMut};
+use bytes::{Bytes, BytesMut};
 use futures::future::{join_all, ok, Either, FutureResult};
 use futures::{Async, Future, Poll};
 use serde_json::to_writer;
@@ -24,13 +24,7 @@ mod models;
 mod utils;
 
 use crate::db_pg_direct::PgConnection;
-use crate::utils::{Message, Writer, SIZE};
-
-const FORTUNES_START: &[u8] = b"<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>";
-const FORTUNES_ROW_START: &[u8] = b"<tr><td>";
-const FORTUNES_COLUMN: &[u8] = b"</td><td>";
-const FORTUNES_ROW_END: &[u8] = b"</td></tr>";
-const FORTUNES_END: &[u8] = b"</table></body></html>";
+use crate::utils::{FortunesTemplate, Message, Writer, SIZE};
 
 struct App {
     dbs: Vec<PgConnection>,
@@ -53,7 +47,7 @@ impl App {
         if self.useall {
             match db {
                 Db::All => {
-                    self.next = (self.next + 1) % 5;
+                    self.next = (self.next + 1) % 4;
                     &mut self.dbs[self.next]
                 }
                 Db::Multi => {
@@ -89,9 +83,8 @@ impl Service for App {
                     StatusCode::OK,
                     Body::Bytes(Bytes::from_static(b"Hello, World!")),
                 );
-                let hdrs = res.headers_mut();
-                hdrs.insert(SERVER, self.hdr_srv.clone());
-                hdrs.insert(CONTENT_TYPE, self.hdr_ct.clone());
+                res.headers_mut().insert(SERVER, self.hdr_srv.clone());
+                res.headers_mut().insert(CONTENT_TYPE, self.hdr_ct.clone());
                 Either::A(ok(res))
             }
             5 if path == "/json" => {
@@ -102,9 +95,9 @@ impl Service for App {
                 to_writer(Writer(&mut body), &message).unwrap();
                 let mut res =
                     Response::with_body(StatusCode::OK, Body::Bytes(body.freeze()));
-                let hdrs = res.headers_mut();
-                hdrs.insert(SERVER, self.hdr_srv.clone());
-                hdrs.insert(CONTENT_TYPE, self.hdr_ctjson.clone());
+                res.headers_mut().insert(SERVER, self.hdr_srv.clone());
+                res.headers_mut()
+                    .insert(CONTENT_TYPE, self.hdr_ctjson.clone());
                 Either::A(ok(res))
             }
             3 if path == "/db" => {
@@ -128,20 +121,7 @@ impl Service for App {
                 Either::B(Box::new(fut.from_err().map(move |fortunes| {
                     let mut body = BytesMut::with_capacity(2048);
                     let mut writer = Writer(&mut body);
-                    let _ = writer.0.put_slice(FORTUNES_START);
-                    fortunes.into_iter().fold((), |_, row| {
-                        let _ = writer.0.put_slice(FORTUNES_ROW_START);
-                        let _ = write!(&mut writer, "{}", row.id);
-                        let _ = writer.0.put_slice(FORTUNES_COLUMN);
-                        let _ = write!(
-                            &mut writer,
-                            "{}",
-                            v_htmlescape::escape(&row.message)
-                        );
-                        let _ = writer.0.put_slice(FORTUNES_ROW_END);
-                        ()
-                    });
-                    let _ = writer.write(FORTUNES_END);
+                    let _ = write!(writer, "{}", FortunesTemplate { fortunes });
                     let mut res =
                         Response::with_body(StatusCode::OK, Body::Bytes(body.freeze()));
                     let hdrs = res.headers_mut();
@@ -152,7 +132,7 @@ impl Service for App {
             }
             8 if path == "/queries" => {
                 let q = utils::get_query_param(req.uri().query().unwrap_or("")) as usize;
-                let fut = self.get_db(Db::Multi).get_worlds(q);
+                let fut = self.dbs[0].get_worlds(q);
                 let h_srv = self.hdr_srv.clone();
                 let h_ct = self.hdr_ctjson.clone();
 
@@ -205,7 +185,7 @@ impl NewService<ServerConfig> for AppFactory {
             "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world";
 
         let mut conns = Vec::new();
-        for _ in 0..5 {
+        for _ in 0..4 {
             conns.push(PgConnection::connect(DB_URL));
         }
         Box::new(join_all(conns).map(|dbs| App {

+ 2 - 0
frameworks/Rust/actix/src/models.rs

@@ -1,3 +1,5 @@
+#![allow(dead_code)]
+
 #[derive(Serialize, Deserialize)]
 pub struct Message {
     pub message: &'static str,

+ 29 - 0
frameworks/Rust/actix/src/utils.rs

@@ -3,6 +3,13 @@ use std::{cmp, io};
 
 use bytes::{BufMut, BytesMut};
 
+#[allow(non_snake_case)]
+#[derive(Serialize, Debug)]
+pub struct Fortune {
+    pub id: i32,
+    pub message: String,
+}
+
 pub const SIZE: usize = 27;
 
 #[derive(Serialize, Deserialize)]
@@ -73,3 +80,25 @@ pub fn escape(writer: &mut Writer, s: String) {
         let _ = writer.0.put_slice(&bytes[last_pos..]);
     }
 }
+
+markup::define! {
+    FortunesTemplate(fortunes: Vec<Fortune>) {
+        {markup::doctype()}
+        html {
+            head {
+                title { "Fortunes" }
+            }
+            body {
+                table {
+                    tr { th { "id" } th { "message" } }
+                    @for item in {fortunes} {
+                        tr {
+                            td { {item.id} }
+                            td { {markup::raw(v_htmlescape::escape(&item.message))} }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}