Initial commit
Has the super barebones of a server State API is next I think
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
confetti.toml
|
||||||
Generated
+1870
File diff suppressed because it is too large
Load Diff
+16
@@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
name = "confetti"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
diesel = { version = "2.3.9", features = ["postgres"] }
|
||||||
|
quinn = "0.11.9"
|
||||||
|
fedichat-lib = {path = "../fedichat-lib"}
|
||||||
|
tracing = "0.1.44"
|
||||||
|
tracing-subscriber = "0.3.23"
|
||||||
|
clap = { version = "4.6.1", features = ["derive"] }
|
||||||
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
|
thiserror = "2.0.18"
|
||||||
|
toml = "1.1.2"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
hostname = "confetti.example.com"
|
||||||
|
port = 53512
|
||||||
|
listen_address = "0.0.0.0"
|
||||||
|
certfile = "/etc/letsencrypt/confetti/fullchain.pem"
|
||||||
|
keyfile = "/etc/letsencrypt/confetti/privkey.pem"
|
||||||
|
|
||||||
|
[database]
|
||||||
|
url = "my.db.server"
|
||||||
|
user = "confetti"
|
||||||
|
password = "my_secret_password"
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Read,self};
|
||||||
|
use serde::{Serialize,Deserialize};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Default,Clone,Serialize,Deserialize)]
|
||||||
|
pub struct Config {
|
||||||
|
pub hostname: String,
|
||||||
|
pub port: u16,
|
||||||
|
pub listen_address: String,
|
||||||
|
pub database: DBConfig,
|
||||||
|
pub certfile: String,
|
||||||
|
pub keyfile: String,
|
||||||
|
|
||||||
|
}
|
||||||
|
#[derive(Default,Clone,Serialize,Deserialize)]
|
||||||
|
pub struct DBConfig {
|
||||||
|
pub url: String,
|
||||||
|
pub user: String,
|
||||||
|
pub password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
const LOCATIONS: [&'static str; 3] = [
|
||||||
|
"confetti.toml",
|
||||||
|
"~/.config/confetti/confetti.toml",
|
||||||
|
"/etc/confetti/confetti.toml"
|
||||||
|
];
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn load() -> Result<Config,ConfigError> {
|
||||||
|
for filename in LOCATIONS {
|
||||||
|
match File::open(filename) {
|
||||||
|
Ok(mut f) => {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
f.read_to_end(&mut buf)?;
|
||||||
|
return Ok(toml::from_slice(&buf)?);
|
||||||
|
},
|
||||||
|
Err(_) => continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(ConfigError::ConfigNotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum ConfigError {
|
||||||
|
#[error("Unable to find config file. Create a confetti.toml to run the application")]
|
||||||
|
ConfigNotFound,
|
||||||
|
#[error("Error while parsing config file: {0:?}")]
|
||||||
|
ParseError(#[from] toml::de::Error),
|
||||||
|
#[error("IO Error detected while processing config file")]
|
||||||
|
IOError(#[from] io::Error),
|
||||||
|
}
|
||||||
+80
@@ -0,0 +1,80 @@
|
|||||||
|
mod config;
|
||||||
|
|
||||||
|
use diesel::{Connection,PgConnection};
|
||||||
|
use quinn::rustls::pki_types::{PrivateKeyDer,CertificateDer,pem::PemObject};
|
||||||
|
|
||||||
|
use std::net::{IpAddr,SocketAddr};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use quinn::Endpoint;
|
||||||
|
use tracing::{error,instrument};
|
||||||
|
|
||||||
|
|
||||||
|
use std::process::ExitCode;
|
||||||
|
use crate::config::Config;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
#[instrument]
|
||||||
|
async fn main() -> ExitCode {
|
||||||
|
// Read in config
|
||||||
|
let config = match Config::load() {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Problem while reading config file");
|
||||||
|
error!("{:?}",e);
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set up database connection
|
||||||
|
let db_connection = PgConnection::establish(&config.database.url);
|
||||||
|
|
||||||
|
|
||||||
|
// Read certificate file
|
||||||
|
let certs = CertificateDer::pem_file_iter(&config.certfile)
|
||||||
|
.unwrap()
|
||||||
|
.map(|cert| cert.unwrap())
|
||||||
|
.collect();
|
||||||
|
let key = PrivateKeyDer::from_pem_file(&config.keyfile).unwrap();
|
||||||
|
|
||||||
|
let address = match IpAddr::from_str(&config.listen_address) {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Could not parse IP address: {:?}",e);
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let quinn_config = match quinn::ServerConfig::with_single_cert(certs, key){
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Unable to intialize quinn server configuration: {:?}",e);
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bind this endpoint to a UDP socket on the given server address.
|
||||||
|
let endpoint = match Endpoint::server(
|
||||||
|
quinn_config,
|
||||||
|
SocketAddr::new(address,config.port)
|
||||||
|
) {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Could not create incoming socket");
|
||||||
|
error!("{:?}",e);
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Start iterating over incoming connections.
|
||||||
|
while let Some(conn) = endpoint.accept().await {
|
||||||
|
let connection = conn.await;
|
||||||
|
|
||||||
|
// Save connection somewhere, start transferring, receiving data, see DataTransfer tutorial.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should never reach this
|
||||||
|
// How should I gracefully shutdown? Can I trap ctrlc
|
||||||
|
ExitCode::SUCCESS
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user