Compare commits
10 commits
Author | SHA1 | Date | |
---|---|---|---|
68e8a9cd6e | |||
fa690d48bd | |||
f1facae8a2 | |||
a2536696ce | |||
634eefb8e6 | |||
|
122f33eae9 | ||
32f0ed27a7 | |||
cab6b92c52 | |||
bf627f6003 | |||
|
9496d107f9 |
10 changed files with 323 additions and 55 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,2 @@
|
||||||
.idea
|
.idea
|
||||||
db/*
|
db/*
|
||||||
backend/target/*
|
|
||||||
|
|
||||||
|
|
0
server/.gitignore → backend/.gitignore
vendored
0
server/.gitignore → backend/.gitignore
vendored
24
backend/Cargo.toml
Normal file
24
backend/Cargo.toml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
[package]
|
||||||
|
name = "server"
|
||||||
|
version = "1.0.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# rust
|
||||||
|
actix-web ="4"
|
||||||
|
actix-files = "*"
|
||||||
|
utoipa-swagger-ui = { version = "3", features = ["actix-web"] }
|
||||||
|
|
||||||
|
# db-connection
|
||||||
|
sqlx = { version = "0.6.2", features = ["runtime-tokio-native-tls", "sqlite"]}
|
||||||
|
tokio = { version = "1.20.0", features = ["macros"]}
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "webserver"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "db_access"
|
||||||
|
path = "src/main_db.rs"
|
19
backend/openapi.json
Normal file
19
backend/openapi.json
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"openapi": "3.0.0",
|
||||||
|
"info": {
|
||||||
|
"title": "My API",
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
"paths": {
|
||||||
|
"/example": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Get example",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
backend/readme.md
Normal file
25
backend/readme.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# installation
|
||||||
|
|
||||||
|
Rustup gets you the ability to install rust in any version, from stable to cutting edge.
|
||||||
|
|
||||||
|
## Linux, macos (step 1)
|
||||||
|
|
||||||
|
use apt, pacman, curl, brew or whatever, to install _rustup_.
|
||||||
|
|
||||||
|
## windows (alternate step 1)
|
||||||
|
|
||||||
|
choco install -y rustup
|
||||||
|
|
||||||
|
## Always (steps 2 and so on)
|
||||||
|
|
||||||
|
- `rustup-init.sh` (Windows: rustup-init.ex, e.g. %AppData%\Local\Temp\chocolatey\rustup.install\1.25.1\rustup-init.exe)
|
||||||
|
- select a good match in the dialog of this CLI installer,
|
||||||
|
- i.e. stable and default amount of features should be fine
|
||||||
|
- rust comes with `cargo` as a ``crate'' manager for package installation
|
||||||
|
|
||||||
|
## Get dependencies and run
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cargo build # gets dependencies from Cargo.toml
|
||||||
|
cargo run # re-runs on (some?) changes
|
||||||
|
```
|
30
backend/src/main.rs
Normal file
30
backend/src/main.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
use actix_web::{web, App, HttpResponse, HttpServer};
|
||||||
|
use utoipa_swagger_ui::{get_swagger_ui, DefaultConfig};
|
||||||
|
|
||||||
|
#[actix_web::main]
|
||||||
|
async fn main() -> std::io::Result<()> {
|
||||||
|
HttpServer::new(|| {
|
||||||
|
let swagger_config = DefaultConfig::new("http://localhost:8080", "/openapi.json");
|
||||||
|
App::new()
|
||||||
|
.service(get_swagger_ui(&swagger_config))
|
||||||
|
.route("/openapi.json", web::get().to(get_openapi_spec))
|
||||||
|
})
|
||||||
|
.bind("0.0.0.0:8080")?
|
||||||
|
.run()
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_openapi_spec() -> HttpResponse {
|
||||||
|
let openapi_spec = r#"
|
||||||
|
{
|
||||||
|
"openapi": "3.0.0",
|
||||||
|
"info": {
|
||||||
|
"title": "Dummy API",
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
"paths": {}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
HttpResponse::Ok().body(openapi_spec)
|
||||||
|
}
|
225
backend/src/main_db.rs
Normal file
225
backend/src/main_db.rs
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
use sqlx::{migrate::MigrateDatabase, FromRow, Sqlite, SqlitePool};
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
const DB_URL: &str = "sqlite://db/test.db";
|
||||||
|
|
||||||
|
const COMMANDS :[(i32, &str, &str); 5] = [
|
||||||
|
(0, "createDB", "creates the database if not already."),
|
||||||
|
(1, "initDB", "initializes the data of the db with given file"),
|
||||||
|
(2, "connect", "connecting to the db."),
|
||||||
|
(3, "execute sql", "execute SQL that is entered"),
|
||||||
|
(4, "disconnect", "closing connection to db."),
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Clone, FromRow, Debug)]
|
||||||
|
struct User {
|
||||||
|
id: i64,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
// game loop
|
||||||
|
|
||||||
|
let mut db: Option<SqlitePool> = None;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
println!("What do you want to do?\n");
|
||||||
|
print_commands();
|
||||||
|
println!("");
|
||||||
|
|
||||||
|
let mut choice = String::new();
|
||||||
|
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut choice)
|
||||||
|
.expect("Failed to read line");
|
||||||
|
|
||||||
|
let choice: u32 = choice
|
||||||
|
.trim()
|
||||||
|
.parse()
|
||||||
|
.expect("Please type a number!");
|
||||||
|
|
||||||
|
match choice {
|
||||||
|
0 => create_db().await,
|
||||||
|
1 => init_db(),
|
||||||
|
2 => db = connect_db().await,
|
||||||
|
3 => execute_sql(&db).await,
|
||||||
|
4 => {
|
||||||
|
db.clone().unwrap().close().await;
|
||||||
|
db = None;
|
||||||
|
}
|
||||||
|
_ => println!("This Command does not exists")
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_commands() {
|
||||||
|
|
||||||
|
for command in COMMANDS {
|
||||||
|
let (num, name, desc) = command;
|
||||||
|
|
||||||
|
println!("{num}. {name} \t{desc}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_db() {
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
if !Sqlite::database_exists(DB_URL).await.unwrap_or(false) {
|
||||||
|
println!("Creating database {}", DB_URL);
|
||||||
|
match Sqlite::create_database(DB_URL).await {
|
||||||
|
Ok(_) => println!("Create db success"),
|
||||||
|
Err(error) => panic!("error: {}", error),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("database already exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_db() {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn connect_db() -> Option<SqlitePool>{
|
||||||
|
|
||||||
|
let db = Some(SqlitePool::connect(DB_URL).await.unwrap());
|
||||||
|
println!("Connected to DB.");
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute_sql(opt_db: &Option<SqlitePool>) {
|
||||||
|
|
||||||
|
if opt_db.is_none() {
|
||||||
|
println!("There is no active connection to the db.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let db = opt_db.clone().unwrap();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut choice = String::new();
|
||||||
|
|
||||||
|
println!("0: freely (danger!)\n1: create \n2: insert\n3: query\n4: delete\n5: drop table");
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut choice)
|
||||||
|
.expect("Failed to read line");
|
||||||
|
|
||||||
|
let choice: u32 = choice
|
||||||
|
.trim()
|
||||||
|
.parse()
|
||||||
|
.expect("Please type a number!");
|
||||||
|
|
||||||
|
match choice {
|
||||||
|
0 => freely(&db).await,
|
||||||
|
1 => create(&db).await,
|
||||||
|
2 => insert(&db).await,
|
||||||
|
3 => query(&db).await,
|
||||||
|
4 => delete(&db).await,
|
||||||
|
5 => drop_table(&db).await,
|
||||||
|
_ => {
|
||||||
|
println!("This Command does not exists");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create(db : &SqlitePool) {
|
||||||
|
let result = sqlx::query(
|
||||||
|
"CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
name WARCHAR(250) NOT NULL
|
||||||
|
);")
|
||||||
|
.execute(db)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("Create user table result: {:?}", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn insert(db : &SqlitePool) {
|
||||||
|
|
||||||
|
let mut name = String::new();
|
||||||
|
|
||||||
|
println!("insert what name?");
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut name)
|
||||||
|
.expect("Failed to read line");
|
||||||
|
|
||||||
|
let result = sqlx::query("INSERT INTO users (name) VALUES (?)")
|
||||||
|
.bind(name)
|
||||||
|
.execute(db)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("result: {:?}", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn query(db : &SqlitePool) {
|
||||||
|
|
||||||
|
let data = match sqlx::query_as::<_, User>("SELECT id, name FROM users")
|
||||||
|
.fetch_all(db)
|
||||||
|
.await {
|
||||||
|
Ok(d) => d,
|
||||||
|
Err(_) => {
|
||||||
|
println!("something went wrong.");
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for user in data {
|
||||||
|
println!("[{}] name: {}", user.id, &user.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn delete(db : &SqlitePool) {
|
||||||
|
|
||||||
|
let mut name = String::new();
|
||||||
|
|
||||||
|
println!("delete what name?");
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut name)
|
||||||
|
.expect("Failed to read line");
|
||||||
|
|
||||||
|
let result = match sqlx::query("DELETE FROM users WHERE name=$1")
|
||||||
|
.bind(name)
|
||||||
|
.execute(db)
|
||||||
|
.await {
|
||||||
|
Ok(r) => Some(r),
|
||||||
|
Err(_) => {
|
||||||
|
println!("user could not be deleted.");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if result.is_some() {
|
||||||
|
println!("result: {:?}", result.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn freely(db : &SqlitePool) {
|
||||||
|
|
||||||
|
let mut sql = String::new();
|
||||||
|
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut sql)
|
||||||
|
.expect("Failed to read line");
|
||||||
|
|
||||||
|
let result = sqlx::query(&sql)
|
||||||
|
.execute(db)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("result: {:?}", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn drop_table(db : &SqlitePool) {
|
||||||
|
let result = sqlx::query("DROP TABLE users;")
|
||||||
|
.execute(db)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("result: {:?}", result);
|
||||||
|
}
|
|
@ -1,10 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "server"
|
|
||||||
version = "1.0.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
actix-web ="4"
|
|
||||||
utoipa = { version = "3", features = ["actix_extras"] }
|
|
|
@ -1,15 +0,0 @@
|
||||||
# installation
|
|
||||||
|
|
||||||
## windows (step 1)
|
|
||||||
|
|
||||||
choco install -y
|
|
||||||
|
|
||||||
## Linux, macos (alernate step 1)
|
|
||||||
|
|
||||||
use apt, pacman, curl, brew or whatever.
|
|
||||||
|
|
||||||
## Always (steps 2 and so on)
|
|
||||||
|
|
||||||
- `rustup-init.sh` (Windows: rustup-init.ex, e.g. %AppData%\Local\Temp\chocolatey\rustup.install\1.25.1\rustup-init.exe)
|
|
||||||
- select a good match in the dialog of this CLI installer
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
|
|
||||||
|
|
||||||
#[get("/")]
|
|
||||||
async fn hello() -> impl Responder {
|
|
||||||
HttpResponse::Ok().body("Hello world!")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[post("/echo")]
|
|
||||||
async fn echo(req_body: String) -> impl Responder {
|
|
||||||
HttpResponse::Ok().body(req_body)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn manual_hello() -> impl Responder {
|
|
||||||
HttpResponse::Ok().body("Hey there!")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[actix_web::main]
|
|
||||||
async fn main() -> std::io::Result<()> {
|
|
||||||
HttpServer::new(|| {
|
|
||||||
App::new()
|
|
||||||
.service(hello)
|
|
||||||
.service(echo)
|
|
||||||
.route("/hey", web::get().to(manual_hello))
|
|
||||||
})
|
|
||||||
.bind(("127.0.0.1", 8080))?
|
|
||||||
.run()
|
|
||||||
.await
|
|
||||||
}
|
|
Loading…
Reference in a new issue