progress on overall structure
This commit is contained in:
parent
5235ca9308
commit
3938b2032d
18 changed files with 272 additions and 58 deletions
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -59,6 +59,12 @@ dependencies = [
|
|||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
@ -221,6 +227,7 @@ dependencies = [
|
|||
"axum",
|
||||
"chrono",
|
||||
"colored",
|
||||
"ron",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sled",
|
||||
|
@ -527,6 +534,17 @@ dependencies = [
|
|||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ron"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b861ecaade43ac97886a512b360d01d66be9f41f3c61088b42cedf92e03d678"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bitflags",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -7,7 +7,7 @@ description = "Harmony server application"
|
|||
[dependencies]
|
||||
|
||||
# async engine
|
||||
tokio = { version = "1.0", features = ["full"] }
|
||||
tokio = { version = "1.13.0", features = ["full"] }
|
||||
|
||||
# http client
|
||||
axum = "0.3.2"
|
||||
|
@ -16,9 +16,12 @@ axum = "0.3.2"
|
|||
sled = "0.34.7"
|
||||
|
||||
# serialization
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0.68"
|
||||
serde = { version = "1.0.130", features = ["derive"] }
|
||||
serde_json = "1.0.69"
|
||||
|
||||
# useful for logging
|
||||
chrono = "0.4"
|
||||
chrono = "0.4.19"
|
||||
colored = "2.0.0"
|
||||
|
||||
# serialization format of config files
|
||||
ron = "0.7.0"
|
||||
|
|
4
config.ron
Normal file
4
config.ron
Normal file
|
@ -0,0 +1,4 @@
|
|||
(
|
||||
database_path: "./database",
|
||||
port: 42069
|
||||
)
|
4
database/conf
Normal file
4
database/conf
Normal file
|
@ -0,0 +1,4 @@
|
|||
segment_size: 524288
|
||||
use_compression: false
|
||||
version: 0.34
|
||||
vQÁ
|
BIN
database/db
Normal file
BIN
database/db
Normal file
Binary file not shown.
BIN
database/snap.0000000000000060
Normal file
BIN
database/snap.0000000000000060
Normal file
Binary file not shown.
|
@ -1,13 +1,61 @@
|
|||
use std::fs::{read_to_string, write};
|
||||
|
||||
use ron;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::harsh::Error;
|
||||
|
||||
///
|
||||
/// Encapsulate a configuration for the server
|
||||
///
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct Configuration {
|
||||
pub path: String, //
|
||||
pub database_path: String, //
|
||||
pub port: u32,
|
||||
}
|
||||
|
||||
static CONFIG_PATHS: [&str; 2] = ["./config.ron", "/etc/harsh/harsh.ron"];
|
||||
|
||||
impl Configuration {
|
||||
/// try to read the configuration from local file or load default
|
||||
pub fn read() -> Self {
|
||||
todo!()
|
||||
pub fn get() -> Self {
|
||||
match Self::try_from_file() {
|
||||
Ok(config) => config,
|
||||
Err(_) => {
|
||||
let result = Configuration::default();
|
||||
Configuration::write_config(&result);
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_from_file() -> Result<Self, Error> {
|
||||
let content = Self::try_read()?;
|
||||
let config: Configuration = ron::from_str(&content)?;
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
fn try_read() -> Result<String, Error> {
|
||||
for path in CONFIG_PATHS {
|
||||
match read_to_string(path) {
|
||||
Ok(serialized) => return Ok(serialized),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
Err("unable to locate or read config file".to_string().into())
|
||||
}
|
||||
|
||||
fn write_config(data: &Self) {
|
||||
let serialized = ron::to_string(data).unwrap();
|
||||
write(CONFIG_PATHS[0], serialized);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Configuration {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
database_path: "./database".to_string(),
|
||||
port: 42069, // haha funny number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
use super::config::Configuration;
|
||||
|
||||
///
|
||||
/// handle the database access
|
||||
///
|
||||
pub struct DbManager {
|
||||
//
|
||||
}
|
||||
|
||||
impl DbManager {
|
||||
/// constructor
|
||||
pub fn new(_config: &Configuration) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
20
src/lib/db/mod.rs
Normal file
20
src/lib/db/mod.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
pub mod models;
|
||||
|
||||
use sled::Db;
|
||||
|
||||
use super::{config::Configuration, harsh::Error};
|
||||
|
||||
///
|
||||
/// handle the database access
|
||||
///
|
||||
pub struct DbManager {
|
||||
handle: Db,
|
||||
}
|
||||
|
||||
impl DbManager {
|
||||
/// constructor
|
||||
pub fn new(config: Configuration) -> Result<Self, Error> {
|
||||
let handle = sled::open(config.database_path)?;
|
||||
Ok(DbManager { handle })
|
||||
}
|
||||
}
|
18
src/lib/db/models.rs
Normal file
18
src/lib/db/models.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
type Id = u64;
|
||||
|
||||
pub struct User {
|
||||
username: String,
|
||||
password: String,
|
||||
id: Id,
|
||||
}
|
||||
|
||||
pub struct Channel {
|
||||
name: String,
|
||||
id: Id,
|
||||
messages: Vec<Id>,
|
||||
}
|
||||
|
||||
pub struct Message {
|
||||
content: String,
|
||||
id: Id,
|
||||
}
|
|
@ -1,33 +1,68 @@
|
|||
use std::error;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use super::config::Configuration;
|
||||
use super::database::DbManager;
|
||||
use super::db::DbManager;
|
||||
use super::http::HttpManager;
|
||||
use super::log::Logger;
|
||||
|
||||
///
|
||||
/// main function
|
||||
///
|
||||
pub fn main() {
|
||||
let configuration = Configuration::read();
|
||||
pub async fn main() {
|
||||
let configuration = Configuration::get();
|
||||
let instance = Harsh::new(configuration);
|
||||
instance.serve().await;
|
||||
}
|
||||
|
||||
pub struct Harsh {
|
||||
db_manager: DbManager,
|
||||
logger: Logger,
|
||||
http_manager: HttpManager,
|
||||
pub shared_state: SharedState,
|
||||
pub http_manager: HttpManager,
|
||||
}
|
||||
|
||||
impl Harsh {
|
||||
pub fn new(configuration: Configuration) -> Self {
|
||||
let db_manager = DbManager::new(&configuration);
|
||||
let logger = Logger::new(&configuration);
|
||||
let http_manager = HttpManager::new();
|
||||
let db_manager =
|
||||
DbManager::new(configuration.clone()).expect("failed to open / create the database");
|
||||
let logger = Logger::new(configuration.clone());
|
||||
let shared_state = State::new_shared(db_manager, logger);
|
||||
let http_manager = HttpManager::new(configuration.clone(), shared_state.clone());
|
||||
|
||||
Harsh {
|
||||
logger,
|
||||
db_manager,
|
||||
shared_state,
|
||||
http_manager,
|
||||
}
|
||||
}
|
||||
|
||||
fn serve(&mut self) {}
|
||||
pub async fn serve(self) {
|
||||
self.http_manager.serve().await;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// shared state arround the app
|
||||
///
|
||||
pub struct State {
|
||||
pub db_manager: RwLock<DbManager>,
|
||||
pub logger: RwLock<Logger>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn new_shared(db_manager: DbManager, logger: Logger) -> SharedState {
|
||||
let state = State {
|
||||
db_manager: RwLock::new(db_manager),
|
||||
logger: RwLock::new(logger),
|
||||
};
|
||||
Arc::new(state)
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// safe pointer to the shared state
|
||||
///
|
||||
pub type SharedState = Arc<State>;
|
||||
|
||||
///
|
||||
/// error type for now..
|
||||
///
|
||||
pub type Error = Box<dyn error::Error>;
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
use super::config::Configuration;
|
||||
use super::database::DbManager;
|
||||
|
||||
///
|
||||
/// listen for incoming requests and handle both incoming and outgoing requests
|
||||
///
|
||||
pub struct HttpManager {
|
||||
//
|
||||
}
|
||||
|
||||
impl HttpManager {
|
||||
pub fn new() -> Self {
|
||||
HttpManager {}
|
||||
}
|
||||
|
||||
/// listen for and handle received requests
|
||||
pub fn serve(_config: &Configuration, _db_manager: &mut DbManager) {
|
||||
todo!()
|
||||
}
|
||||
}
|
45
src/lib/http/mod.rs
Normal file
45
src/lib/http/mod.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
///
|
||||
/// contains every route handlers
|
||||
///
|
||||
mod routes;
|
||||
|
||||
///
|
||||
/// contains every models used by the http server
|
||||
///
|
||||
pub mod models;
|
||||
|
||||
use axum::{AddExtensionLayer, Router};
|
||||
|
||||
use self::routes::setup_routes;
|
||||
|
||||
use super::config::Configuration;
|
||||
use super::harsh::SharedState;
|
||||
|
||||
///
|
||||
/// listen for incoming requests and handle both incoming and outgoing requests
|
||||
///
|
||||
pub struct HttpManager {
|
||||
_shared_state: SharedState,
|
||||
app: Router,
|
||||
}
|
||||
|
||||
impl HttpManager {
|
||||
/// constructor
|
||||
pub fn new(_config: Configuration, shared_state: SharedState) -> Self {
|
||||
let app = setup_routes(Router::new()).layer(AddExtensionLayer::new(shared_state.clone()));
|
||||
|
||||
HttpManager {
|
||||
_shared_state: shared_state.clone(),
|
||||
app,
|
||||
}
|
||||
}
|
||||
|
||||
/// listen for and handle received requests
|
||||
pub async fn serve(self) {
|
||||
let address = "0.0.0.0:3000".parse().unwrap();
|
||||
axum::Server::bind(&address)
|
||||
.serve(self.app.into_make_service())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
16
src/lib/http/models.rs
Normal file
16
src/lib/http/models.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CreateUser {
|
||||
name: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
pub struct EditUser {
|
||||
//
|
||||
}
|
||||
|
||||
pub struct DeleteUser {
|
||||
name: String,
|
||||
password: String,
|
||||
}
|
15
src/lib/http/routes.rs
Normal file
15
src/lib/http/routes.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
use axum::extract::{Extension, Json};
|
||||
use axum::routing::get;
|
||||
use axum::Router;
|
||||
|
||||
use crate::lib::harsh::SharedState;
|
||||
|
||||
use super::models::*;
|
||||
|
||||
pub fn setup_routes(app: Router) -> Router {
|
||||
app.route("/user/create", get(create_user))
|
||||
}
|
||||
|
||||
async fn create_user(Extension(state): Extension<SharedState>, Json(payload): Json<CreateUser>) {
|
||||
//
|
||||
}
|
|
@ -11,7 +11,7 @@ pub struct Logger {
|
|||
|
||||
impl Logger {
|
||||
/// adapt the static instance according to parameters specified by the configuration
|
||||
pub fn new(_config: &Configuration) -> Self {
|
||||
pub fn new(_config: Configuration) -> Self {
|
||||
Logger {}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,24 @@
|
|||
///
|
||||
/// encapsulate the logic responsible for reading and parsing the server configuration
|
||||
///
|
||||
pub mod config;
|
||||
pub mod database;
|
||||
|
||||
///
|
||||
/// encapsulate the logic responsible for interacting with the database
|
||||
///
|
||||
pub mod db;
|
||||
|
||||
///
|
||||
/// main module, exposes the highest level structure holding the whole server runtime logic
|
||||
///
|
||||
pub mod harsh;
|
||||
|
||||
///
|
||||
/// encapsulate the logic responsible for receiving and routing http requests
|
||||
///
|
||||
pub mod http;
|
||||
|
||||
///
|
||||
/// encapsulate the logic responsible for logging events occuring while the server is running
|
||||
///
|
||||
pub mod log;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
///
|
||||
/// library module
|
||||
///
|
||||
pub mod lib;
|
||||
|
||||
pub fn main() {
|
||||
#[tokio::main]
|
||||
pub async fn main() {
|
||||
println!("Hello, harmony!");
|
||||
lib::harsh::main();
|
||||
lib::harsh::main().await;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue