Initial commit
This commit is contained in:
214
src/main.rs
Normal file
214
src/main.rs
Normal file
@@ -0,0 +1,214 @@
|
||||
use axum::{
|
||||
Router, extract::Json, http::StatusCode, response::IntoResponse, routing::get, routing::post,
|
||||
};
|
||||
use rusqlite::{Connection, Error as RusqliteError, Result, params};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha256::digest;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum AccError {
|
||||
WrongPassword,
|
||||
UnknownAccount,
|
||||
DatabaseError(RusqliteError),
|
||||
}
|
||||
|
||||
impl fmt::Display for AccError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
AccError::WrongPassword => write!(f, "Incorrect password provided"),
|
||||
AccError::UnknownAccount => write!(f, "Account not found"),
|
||||
AccError::DatabaseError(e) => write!(f, "Database error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for AccError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
match self {
|
||||
AccError::DatabaseError(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RusqliteError> for AccError {
|
||||
fn from(err: RusqliteError) -> AccError {
|
||||
AccError::DatabaseError(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct NewPerson {
|
||||
name: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct GetID {
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct GetName {
|
||||
id: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct SendMoney {
|
||||
sender: i32,
|
||||
password: String,
|
||||
reciever: i32,
|
||||
amount: i64,
|
||||
message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct Person {
|
||||
id: i32,
|
||||
name: String,
|
||||
password: String,
|
||||
money: i64,
|
||||
}
|
||||
|
||||
fn init_database() -> Result<()> {
|
||||
println!("Initing database");
|
||||
let conn = Connection::open("financials.db")?;
|
||||
conn.execute(
|
||||
"CREATE TABLE persons (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
money INTEGER
|
||||
)",
|
||||
(),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn make_person(person: &NewPerson) -> Result<()> {
|
||||
let conn = Connection::open("financials.db")?;
|
||||
conn.execute(
|
||||
"INSERT INTO persons (name, password, money) VALUES (?1, ?2, ?3)",
|
||||
(&person.name, &digest(person.password.clone()), 1000),
|
||||
)?;
|
||||
println!("Successfully inserted person into database!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_money_to_id(request: &SendMoney) -> Result<(), AccError> {
|
||||
let conn = Connection::open("financials.db")?;
|
||||
let result = conn.query_row(
|
||||
"SELECT * FROM persons WHERE id = ?1 AND password = ?2",
|
||||
params![&request.sender, &digest(request.password.clone())],
|
||||
|_row| Ok(()),
|
||||
);
|
||||
match result {
|
||||
Ok(()) => {
|
||||
println!("Found a person! Yay!");
|
||||
conn.execute(
|
||||
"UPDATE persons SET money = money - ?1 WHERE id = ?2",
|
||||
params![request.amount, request.sender],
|
||||
)?;
|
||||
conn.execute(
|
||||
"UPDATE persons SET money = money + ?1 WHERE id = ?2",
|
||||
params![request.amount, request.reciever],
|
||||
)?;
|
||||
}
|
||||
Err(RusqliteError::QueryReturnedNoRows) => {
|
||||
let result2 = conn.query_row(
|
||||
"SELECT * FROM persons WHERE id = ?1",
|
||||
params![&request.sender],
|
||||
|_row| Ok(()),
|
||||
);
|
||||
match result2 {
|
||||
Ok(()) => {
|
||||
return Err(AccError::WrongPassword);
|
||||
}
|
||||
Err(RusqliteError::QueryReturnedNoRows) => {
|
||||
return Err(AccError::UnknownAccount);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error: {:?}", e);
|
||||
return Err(AccError::DatabaseError(e));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn process_request() -> String {
|
||||
"dingle".to_string()
|
||||
}
|
||||
|
||||
async fn create_person_request(Json(payload): Json<NewPerson>) -> impl IntoResponse {
|
||||
match make_person(&payload) {
|
||||
Ok(_) => (
|
||||
StatusCode::CREATED,
|
||||
"Person created successfully!".to_string(),
|
||||
),
|
||||
Err(e) => {
|
||||
eprintln!("Failed to create person: {}", e);
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Failed to create person: {}", e),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_money_request(Json(payload): Json<SendMoney>) -> impl IntoResponse {
|
||||
match send_money_to_id(&payload) {
|
||||
Ok(_) => (
|
||||
StatusCode::ACCEPTED,
|
||||
"Transaction was successful!".to_string(),
|
||||
),
|
||||
Err(e) => (
|
||||
StatusCode::IM_A_TEAPOT,
|
||||
format!("Transaction failed! Error: {}", e),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_id_by_name(name: &GetID) -> Result<i32, AccError> {
|
||||
let conn = Connection::open("financials.db")?;
|
||||
let id = conn.query_row(
|
||||
"SELECT id FROM persons WHERE name = ?1",
|
||||
params![name.name],
|
||||
|row| row.get(0),
|
||||
)?;
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
async fn get_id_request(Json(payload): Json<GetID>) -> impl IntoResponse {
|
||||
let id = get_id_by_name(&payload);
|
||||
match id {
|
||||
Ok(_) => (StatusCode::OK, id.unwrap().to_string()),
|
||||
Err(e) => (StatusCode::NOT_FOUND, format!("Error: {}", e)),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
println!("Server starting up...");
|
||||
if !Path::new("financials.db").exists() {
|
||||
if init_database() != Ok(()) {
|
||||
panic!(
|
||||
"Couldn't init database! Check to see if you've got permissions to write the database in the current directory."
|
||||
);
|
||||
};
|
||||
};
|
||||
let app = Router::new()
|
||||
.route("/", get(process_request))
|
||||
.route("/api/createperson", post(create_person_request))
|
||||
.route("/api/sendmoneytoid", post(send_money_request))
|
||||
.route("/api/getidfromname", post(get_id_request));
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
}
|
Reference in New Issue
Block a user