Compare commits

..

10 commits

10 changed files with 323 additions and 55 deletions

2
.gitignore vendored
View file

@ -1,4 +1,2 @@
.idea .idea
db/* db/*
backend/target/*

24
backend/Cargo.toml Normal file
View 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
View 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
View 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
View 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
View 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);
}

View file

@ -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"] }

View file

@ -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

View file

@ -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
}