From f090fbafe73f4a1711f84c3576098c8e01d8f37a Mon Sep 17 00:00:00 2001 From: Radical Date: Mon, 28 Apr 2025 23:20:37 +0200 Subject: [PATCH] Create initial api --- Cargo.toml | 10 +++++-- src/api/mod.rs | 2 ++ src/api/v1/mod.rs | 8 +++++ src/api/v1/stats.rs | 28 ++++++++++++++++++ src/api/versions.rs | 23 +++++++++++++++ src/config.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 48 ++++++++++++++++++------------ 7 files changed, 169 insertions(+), 21 deletions(-) create mode 100644 src/api/mod.rs create mode 100644 src/api/v1/mod.rs create mode 100644 src/api/v1/stats.rs create mode 100644 src/api/versions.rs create mode 100644 src/config.rs diff --git a/Cargo.toml b/Cargo.toml index 28fb1bc..e10a3ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,12 @@ version = "0.1.0" edition = "2024" [dependencies] -actix = "0.13" actix-web = "4.10" -#tokio = { version = "1.44", features = ["full"] } maybe +serde = { version = "1.0.219", features = ["derive"] } +sqlx = "0.8" +toml = "0.8.21" +url = { version = "2.5.4", features = ["serde"] } + +[dependencies.tokio] +version = "1.44" +features = ["full"] diff --git a/src/api/mod.rs b/src/api/mod.rs new file mode 100644 index 0000000..80dc442 --- /dev/null +++ b/src/api/mod.rs @@ -0,0 +1,2 @@ +pub mod v1; +pub mod versions; diff --git a/src/api/v1/mod.rs b/src/api/v1/mod.rs new file mode 100644 index 0000000..3ff97a9 --- /dev/null +++ b/src/api/v1/mod.rs @@ -0,0 +1,8 @@ +use actix_web::{web, Scope}; + +mod stats; + +pub fn web() -> Scope { + web::scope("/v1") + .service(stats::res) +} diff --git a/src/api/v1/stats.rs b/src/api/v1/stats.rs new file mode 100644 index 0000000..258160e --- /dev/null +++ b/src/api/v1/stats.rs @@ -0,0 +1,28 @@ +use std::time::SystemTime; + +use actix_web::{get, web, HttpResponse, Responder}; +use serde::Serialize; + +use crate::Data; + +const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION"); + +#[derive(Serialize)] +struct Response { + accounts: usize, + uptime: u64, + version: String, + build_number: String, +} + +#[get("/stats")] +pub async fn res(data: web::Data) -> impl Responder { + let response = Response { + accounts: 0, + uptime: SystemTime::now().duration_since(data.start_time).expect("Seriously why dont you have time??").as_secs(), + version: String::from(VERSION.unwrap_or_else(|| "UNKNOWN")), + build_number: String::from("how do i implement this?"), + }; + + HttpResponse::Ok().json(response) +} diff --git a/src/api/versions.rs b/src/api/versions.rs new file mode 100644 index 0000000..a7e49b2 --- /dev/null +++ b/src/api/versions.rs @@ -0,0 +1,23 @@ +use actix_web::{get, HttpResponse, Responder}; +use serde::Serialize; + +#[derive(Serialize)] +struct Response { + unstable_features: UnstableFeatures, + versions: Vec, +} + +#[derive(Serialize)] +struct UnstableFeatures; + +#[get("/versions")] +pub async fn res() -> impl Responder { + let response = Response { + unstable_features: UnstableFeatures, + versions: vec![ + String::from("1"), + ] + }; + + HttpResponse::Ok().json(response) +} diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..a58718e --- /dev/null +++ b/src/config.rs @@ -0,0 +1,71 @@ +use serde::Deserialize; +use tokio::fs::read_to_string; +use crate::Error; +use url::Url; + + +#[derive(Debug, Deserialize)] +pub struct ConfigBuilder { + database: Database, + web: Option, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct Database { + username: String, + password: String, + hostname: String, + port: u16 +} + +#[derive(Debug, Deserialize)] +struct WebBuilder { + url: Option, + port: Option, + ssl: Option, +} + +impl ConfigBuilder { + pub async fn load() -> Result { + let raw = read_to_string("./config.toml").await?; + + let config = toml::from_str(&raw)?; + + Ok(config) + } + + pub fn build(self) -> Config { + + let web = if let Some(web) = self.web { + Web { + url: web.url.unwrap_or(String::from("0.0.0.0")), + port: web.port.unwrap_or(8080), + ssl: web.ssl.unwrap_or_default() + } + } else { + Web { + url: String::from("0.0.0.0"), + port: 8080, + ssl: false + } + }; + + Config { + database: self.database, + web, + } + } +} + +#[derive(Debug, Clone)] +pub struct Config { + pub database: Database, + pub web: Web, +} + +#[derive(Debug, Clone)] +pub struct Web { + pub url: String, + pub port: u16, + pub ssl: bool, +} diff --git a/src/main.rs b/src/main.rs index f3f7914..414f320 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,28 +1,38 @@ -use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder}; +use std::time::SystemTime; +use actix_web::{web, App, HttpServer}; +mod config; +use config::{Config, ConfigBuilder}; +mod api; -#[get("/")] -async fn hello() -> impl Responder { - HttpResponse::Ok().body("Hello world!") +type Error = Box; + +#[derive(Clone)] +struct Data { + pub config: Config, + pub start_time: SystemTime, } -#[post("/echo")] -async fn echo(req_body: String) -> impl Responder { - HttpResponse::Ok().body(req_body) -} +#[tokio::main] +async fn main() -> Result<(), Error> { + let config = ConfigBuilder::load().await?.build(); -async fn manual_hello() -> impl Responder { - HttpResponse::Ok().body("Hey there!") -} + let web = config.web.clone(); + + let data = Data { + config, + start_time: SystemTime::now(), + }; + + HttpServer::new(move || { + let data = data.clone(); -#[actix_web::main] -async fn main() -> std::io::Result<()> { - HttpServer::new(|| { App::new() - .service(hello) - .service(echo) - .route("/hey", web::get().to(manual_hello)) + .app_data(web::Data::new(data)) + .service(api::versions::res) + .service(api::v1::web()) }) - .bind(("127.0.0.1", 8080))? + .bind((web.url, web.port))? .run() - .await + .await?; + Ok(()) }