Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,795 changes: 1,795 additions & 0 deletions frameworks/Rust/hyperlane/Cargo.lock

Large diffs are not rendered by default.

45 changes: 45 additions & 0 deletions frameworks/Rust/hyperlane/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[package]
name = "hyperlane_techempower"
version = "0.0.1"
edition = "2021"
authors = ["ltpp-universe <[email protected]>"]
license = "MIT"
description = """Hyperlane is a lightweight and high-performance Rust HTTP server library designed to simplify network service development. It supports HTTP request parsing, response building, and TCP communication, making it ideal for building modern web services. Additionally, it provides support for request and response middleware, WebSocket, and Server-Sent Events (SSE), enabling flexible and efficient real-time communication."""
keywords = ["http", "request", "response", "tcp", "redirect"]
repository = "https://github.com/ltpp-universe/hyperlane.git"
categories = ["network-programming", "web-programming"]
exclude = [
"target",
"Cargo.lock",
"sh",
".github",
"logs",
"**/*.log"
]

[dependencies]
hyperlane = "4.31.1"
bb8 = "0.9.0"
bb8-postgres = "0.9.0"
rand = "0.9.0"
tokio-postgres = { version = "0.7.13", features = ["with-uuid-0_8"] }
chrono = "0.4.40"
serde = "1.0.219"

[profile.dev]
incremental = false
opt-level = 3
lto = true
panic = "unwind"
debug = false
codegen-units = 1
strip = "debuginfo"

[profile.release]
incremental = false
opt-level = 3
lto = true
panic = "unwind"
debug = false
codegen-units = 1
strip = "debuginfo"
27 changes: 27 additions & 0 deletions frameworks/Rust/hyperlane/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# [hyperlane](https://github.com/ltpp-universe/hyperlane) web framework

## Description

Hyperlane is a lightweight and high-performance Rust HTTP server library designed to simplify network service development. It supports HTTP request parsing, response building, and TCP communication, making it ideal for building modern web services. Additionally, it provides support for request and response middleware, WebSocket, and Server-Sent Events (SSE), enabling flexible and efficient real-time communication.

## Database

PostgreSQL

## Test URLs

### Test 1: JSON Encoding

http://localhost:8080/json

### Test 2: Single Row Query

http://localhost:8080/db

### Test 3: Multi Row Query

http://localhost:8080/queries?q=20

### Test 4: Plaintext

http://localhost:8080/plaintext
26 changes: 26 additions & 0 deletions frameworks/Rust/hyperlane/benchmark_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"framework": "hyperlane",
"tests": [
{
"default": {
"dockerfile": "hyperlane.dockerfile",
"json_url": "/json",
"plaintext_url": "/plaintext",
"db_url": "/db",
"query_url": "/queries?q=",
"port": 8080,
"approach": "Realistic",
"classification": "Micro",
"database": "Postgres",
"framework": "hyperlane",
"language": "Rust",
"orm": "raw",
"platform": "Rust",
"webserver": "hyperlane",
"os": "Linux",
"database_os": "Linux",
"display_name": "hyperlane"
}
}
]
}
17 changes: 17 additions & 0 deletions frameworks/Rust/hyperlane/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[framework]
name = "hyperlane"

[main]
urls.plaintext = "/plaintext"
urls.json = "/json"
urls.db = "/db"
urls.query = "/queries?q="
approach = "Realistic"
classification = "Micro"
database = "Postgres"
database_os = "Linux"
os = "Linux"
orm = "raw"
platform = "Rust"
webserver = "hyperlane"
versus = "None"
13 changes: 13 additions & 0 deletions frameworks/Rust/hyperlane/hyperlane.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM rust:1.85

ENV POSTGRES_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world

ADD ./ /hyperlane_techempower
WORKDIR /hyperlane_techempower

RUN cargo clean
RUN RUSTFLAGS="-C target-cpu=native" cargo build --release

EXPOSE 8080

CMD ./target/release/hyperlane_techempower
10 changes: 10 additions & 0 deletions frameworks/Rust/hyperlane/src/constant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
pub static RESPONSEDATA: &str = "Hello, World!";
pub static DATABASE_TYPE: &str = "postgres";
pub static DATABASE_HOST: &str = "tfb-database";
pub static DATABASE_USER_NAME: &str = "benchmarkdbuser";
pub static DATABASE_USER_PASSWORD: &str = "benchmarkdbpass";
pub static DATABASE_PORT: usize = 5432;
pub static DATABASE_NAME: &str = "hello_world";
pub static TABLE_NAME: &str = "World";
pub static ROW_LIMIT: i32 = 500;
pub static HYPERLANE: &str = "hyperlane";
135 changes: 135 additions & 0 deletions frameworks/Rust/hyperlane/src/db.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
use crate::*;

pub async fn get_db_connection() -> DbPoolConnection {
let db_pool: DbPoolConnection = DB.read().await.clone().unwrap();
db_pool
}

pub async fn create_batabase() {
let db_pool: DbPoolConnection = get_db_connection().await;
let connection: DbConnection = db_pool.get().await.unwrap();
let db_exists: bool = connection
.query_one(
"SELECT EXISTS(SELECT 1 FROM pg_database WHERE datname = $1);",
&[&DATABASE_NAME],
)
.await
.unwrap()
.get(0);
if !db_exists {
println_warning!(
"database `",
DATABASE_NAME,
"` not found. Creating database..."
);
connection
.batch_execute(&format!("CREATE DATABASE {};", DATABASE_NAME))
.await
.unwrap();
println_success!("database `", DATABASE_NAME, "` created successfully");
}
println_success!("database `", DATABASE_NAME, "` ready");
}

pub async fn create_table() {
let db_pool: DbPoolConnection = get_db_connection().await;
let connection: DbConnection = db_pool.get().await.unwrap();
connection
.batch_execute(&format!(
"CREATE TABLE IF NOT EXISTS {} (
id SERIAL PRIMARY KEY,
randomNumber INTEGER NOT NULL
);",
TABLE_NAME
))
.await
.unwrap();
println_success!("table `", TABLE_NAME, "` ready");
}

pub async fn insert_records() {
let db_pool: DbPoolConnection = get_db_connection().await;
let connection: DbConnection = db_pool.get().await.unwrap();
let row: Row = connection
.query_one(&format!("SELECT COUNT(*) FROM {}", TABLE_NAME), &[])
.await
.unwrap();
let count: i64 = row.get(0);
let limit: i64 = ROW_LIMIT as i64;
if count >= limit {
println_warning!(format!(
"table '{}' already has {} records. No need to insert.",
TABLE_NAME, count
));
return;
}
let missing_count: i64 = limit - count;
println_warning!(format!(
"table '{}' has {} records. Inserting {} missing records...",
TABLE_NAME, count, missing_count
));
let mut rng: rand::prelude::ThreadRng = rand::rng();
let mut values: Vec<String> = Vec::new();
for _ in 0..missing_count {
let random_number: i32 = rng.random_range(1..=10000);
values.push(format!("(DEFAULT, {})", random_number));
}
let query: String = format!(
"INSERT INTO {} (id, randomNumber) VALUES {}",
TABLE_NAME,
values.join(",")
);
connection.batch_execute(&query).await.unwrap();
println_success!(format!(
"successfully inserted {} missing records into '{}' table.",
TABLE_NAME, missing_count
));
}

pub async fn init_db() {
let db_url: &str = match option_env!("POSTGRES_URL") {
Some(it) => it,
_ => &format!(
"{}://{}:{}@{}:{}/{}",
DATABASE_TYPE,
DATABASE_USER_NAME,
DATABASE_USER_PASSWORD,
DATABASE_HOST,
DATABASE_PORT,
DATABASE_NAME
),
};
println_warning!("db url: ", db_url);
let config: Config = db_url.parse::<Config>().unwrap();
let db_manager: PostgresConnectionManager<NoTls> =
PostgresConnectionManager::new(config, NoTls);
let db_pool: DbPoolConnection = Pool::builder().build(db_manager).await.unwrap();
{
let mut db_pool_lock: RwLockWriteGuard<'_, Option<DbPoolConnection>> = DB.write().await;
*db_pool_lock = Some(db_pool.clone());
}
create_batabase().await;
create_table().await;
insert_records().await;
}

pub async fn random_world_row() -> Result<QueryRow, Box<dyn std::error::Error>> {
let random_id: i32 = rand::rng().random_range(1..ROW_LIMIT);
let db_pool: DbPoolConnection = get_db_connection().await;
let connection: DbConnection = db_pool
.get()
.await
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("timeout: {}", e)))?;
let stmt: Statement = connection
.prepare(&format!(
"SELECT id, randomNumber FROM {} WHERE id = $1",
TABLE_NAME
))
.await?;
if let Some(rows) = connection.query_opt(&stmt, &[&random_id]).await? {
let id: i32 = rows.get(0);
let random_number: i32 = rows.get(1);
return Ok(QueryRow::new(id, random_number));
}
return Ok(QueryRow::new(0, 0));
}
4 changes: 4 additions & 0 deletions frameworks/Rust/hyperlane/src/lazy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
use crate::*;

pub static DB: Lazy<ArcRwLock<Option<DbPoolConnection>>> =
Lazy::new(|| Arc::new(RwLock::new(None)));
43 changes: 43 additions & 0 deletions frameworks/Rust/hyperlane/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
pub(crate) mod constant;
pub(crate) mod db;
pub(crate) mod lazy;
pub(crate) mod request_middleware;
pub(crate) mod response_middleware;
pub(crate) mod route;
pub(crate) mod server;
pub(crate) mod r#type;
pub(crate) mod utils;

pub(crate) use bb8::{Pool, PooledConnection};
pub(crate) use bb8_postgres::PostgresConnectionManager;
pub(crate) use chrono::{DateTime, Utc};
pub(crate) use constant::*;
pub(crate) use db::*;
pub(crate) use hyperlane::{
once_cell::sync::Lazy,
serde::*,
serde_json::json,
tokio::sync::{RwLock, RwLockWriteGuard},
*,
};
pub(crate) use lazy::*;
pub(crate) use r#type::*;
pub(crate) use rand::Rng;
pub(crate) use request_middleware::*;
pub(crate) use response_middleware::*;
pub(crate) use route::*;

pub(crate) use server::*;
pub(crate) use std::time::SystemTime;
pub(crate) use std::{io, sync::Arc};
pub(crate) use tokio_postgres::{Config, NoTls, Row, Statement};
pub(crate) use utils::*;

#[tokio::main]
async fn main() {
println_warning!("start connect db");
init_db().await;
println_success!("connect db finish");
println_warning!("start init server");
run_server().await;
}
18 changes: 18 additions & 0 deletions frameworks/Rust/hyperlane/src/request_middleware.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use crate::*;

pub async fn request(controller_data: ControllerData) {
let _ = controller_data
.set_response_header(CONNECTION, CONNECTION_KEEP_ALIVE)
.await
.set_response_header(
CONTENT_TYPE,
format!("{}; {}", APPLICATION_JSON, CHARSET_UTF_8),
)
.await
.set_response_header(SERVER, HYPERLANE)
.await
.set_response_header(DATE, generate_rfc1123_timestamp())
.await
.set_response_status_code(200)
.await;
}
5 changes: 5 additions & 0 deletions frameworks/Rust/hyperlane/src/response_middleware.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use crate::*;

pub async fn response(controller_data: ControllerData) {
let _ = controller_data.send().await;
}
44 changes: 44 additions & 0 deletions frameworks/Rust/hyperlane/src/route.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use crate::*;

pub async fn json(controller_data: ControllerData) {
let json: serde_json::Value = json!({
"message": RESPONSEDATA
});
let _ = controller_data
.set_response_body(serde_json::to_string(&json).unwrap_or_default())
.await;
}

pub async fn plaintext(controller_data: ControllerData) {
let _ = controller_data
.set_response_header(CONTENT_TYPE, TEXT_PLAIN)
.await
.set_response_body(RESPONSEDATA)
.await;
}

pub async fn db(controller_data: ControllerData) {
let query_row: QueryRow = random_world_row().await.unwrap();
let _ = controller_data
.set_response_body(serde_json::to_string(&query_row).unwrap_or_default())
.await;
}

pub async fn queries(controller_data: ControllerData) {
let queries: Queries = controller_data
.get_request_query("q")
.await
.and_then(|queries| queries.parse::<Queries>().ok())
.unwrap_or_default()
.min(ROW_LIMIT as usize)
.max(1);
let mut data: Vec<QueryRow> = Vec::with_capacity(queries);
for _ in 0..queries {
let _ = random_world_row().await.map(|row| {
data.push(row);
});
}
let _ = controller_data
.set_response_body(serde_json::to_string(&data).unwrap_or_default())
.await;
}
Loading
Loading