···1919| `LUMINA_SERVER_PORT` | `"8085"` | Port for Lumina to accept HTTP requests on. |
2020| `LUMINA_SERVER_ADDR` | `127.0.0.1` | Address for Lumina to accept HTTP requests on. (usually `127.0.0.1` or `0.0.0.0`) |
2121| `LUMINA_SERVER_HTTPS` | `"false"` | Wether to use 'https' rather than 'http' in links, etc. (please do!) |
2222-| `LUMINA_SYNCHRONISATION_IID` | `"localhost"` | A name Lumina uses when communicating with other instances, must be equal to where it's http is facing the public internet |
2323-| `LUMINA_SYNCHRONISATION_INTERVAL` | `"30"` | Specifies the interval between syncs. Minimum is 30. |
2222+| `LUMINA_SYNC_IID` | `"localhost"` | A name Lumina uses when communicating with other instances, must be equal to where it's http is facing the public internet |
2323+| `LUMINA_SYNC_INTERVAL` | `"30"` | Specifies the interval between syncs. Minimum is 30. |
+2-3
server/Cargo.toml
···1212[dependencies]
1313tokio = { version = "1.0", features = ["full"] }
1414serde = { version = "1.0", features = ["derive"] }
1515-tracing = "0.1"
1616-tracing-subscriber = { version = "0.3", features = ["env-filter"] }
1715rocket = "0.5.1"
1816ws = { package = "rocket_ws", version = "0.1.1" }
1917serde_json = "1.0.140"
2018uuid = { version = "1.16.0", features = ["v4", "serde"] }
2121-cynthia_con = "0.1.1"
1919+cynthia_con = { version = "0.1.2" }
2220dotenv = "0.15.0"
2321tokio-postgres = { version = "0.7.13", features = ["with-uuid-1"] }
2422bcrypt = "0.17.0"
2523r2d2 = "0.8.10"
2624r2d2_sqlite = {version = "0.27.0", features = ["bundled"]}
2525+tabled = "0.18.0"
+5-5
server/src/client_communication.rs
···33use cynthia_con::{CynthiaColors, CynthiaStyles};
44extern crate rocket;
55use rocket::State;
66-use tracing::info;
7687#[get("/connection")]
98pub(crate) fn wsconnection<'k>(ws: ws::WebSocket, state: &'k State<AppState>) -> ws::Channel<'k> {
109 use rocket::futures::{SinkExt, StreamExt};
1110 // Just a few log prefixes
1111+ let info = "[INFO]".color_green().style_bold();
1212 let incoming = "[INCOMING]".color_lilac().style_bold();
1313 let registrationerror = "[RegistrationError]".color_bright_red().style_bold();
1414+ // End of log prefixes
1415 ws.channel(move |mut stream| {
1516 Box::pin(async move {
1617 let mut client_session_data: SessionData = SessionData {
···3940 password,
4041 }) => {
4142 println!(
4242- "{incoming} {} {} {}",
4343- "Register request"
4343+ "{incoming} Register request: {} {}",
4444 email.clone().color_orange(),
4545 username.clone().color_bright_cyan()
4646 );
···5252 match User::create_user(email.clone(), username.clone(), password, db).await
5353 {
5454 Ok(user) => {
5555- info!(
5656- "User created: {}",
5555+ println!(
5656+ "{info} User created: {}",
5757 user.clone().username.color_bright_cyan()
5858 );
5959 match User::create_session_token(user, db).await {
+2-2
server/src/database.rs
···66use tokio_postgres::tls::NoTlsStream;
77use tokio_postgres::{Client, Connection, Socket};
8899-pub(crate) async fn setup(config: crate::ServerConfig) -> Result<DbConn, LuminaError> {
99+pub(crate) async fn setup() -> Result<DbConn, LuminaError> {
1010 let warn = "[WARN]".color_bright_orange().style_bold();
1111 match (std::env::var("LUMINA_DB_TYPE")
1212 .map_err(|_| ConfMissing("LUMINA_DB_TYPE".to_string()))
···5353 .map_err(|_| ConfMissing("LUMINA_POSTGRES_DATABASE".to_string()))?
5454 });
5555 pg_config.port(std::env::var("LUMINA_POSTGRES_PORT").unwrap_or_else(|_| {
5656- eprintln!("{warn} No Postgres database port provided under environment variable '_LUMINA_POSTGRES_PORT_'. Using default value '5432'.");
5656+ eprintln!("{warn} No Postgres database port provided under environment variable 'LUMINA_POSTGRES_PORT'. Using default value '5432'.");
5757 "5432".to_string()
5858 }).parse::<u16>().map_err(|_| { LuminaError::ConfInvalid("LUMINA_POSTGRES_PORT is not a valid integer number".to_string()) })?);
5959 match std::env::var("LUMINA_POSTGRES_HOST") {
+267-95
server/src/main.rs
···11+extern crate dotenv;
22+#[macro_use]
33+extern crate rocket;
14mod client_communication;
25pub mod errors;
36mod staticroutes;
···58mod database;
69mod tests;
71088-#[macro_use]
99-extern crate rocket;
1010-use std::{
1111- net::{IpAddr, Ipv4Addr, Ipv6Addr},
1212- process,
1313- sync::Arc,
1414-};
1111+use std::io::ErrorKind;
1212+use std::{net::IpAddr, process, sync::Arc};
1513use tokio::sync::Mutex;
1614mod user;
1717-use r2d2_sqlite::rusqlite as sqlite;
1815use tokio_postgres as postgres;
1916struct AppState(Arc<(ServerConfig, Mutex<DbConn>)>);
2017···2522 port: u16,
2623 host: IpAddr,
2724}
2828-2929-extern crate dotenv;
30253126use crate::errors::LuminaError;
3227use cynthia_con::{CynthiaColors, CynthiaStyles};
···48434944#[rocket::main]
5045async fn main() {
5151- dotenv().ok();
5252-5353- match config_get() {
5454- Ok(config) => {
5555- let db = match database::setup(config.clone()).await {
5656- Ok(db) => db,
4646+ // Some print prefixes
4747+ let error = "[ERROR]".color_error_red().style_bold();
4848+ let info = "[INFO]".color_green().style_bold();
4949+ // End of print prefixes
5050+ let me = format!("Lumina Server, version {}", env!("CARGO_PKG_VERSION"));
5151+ let args: Vec<String> = std::env::args().skip(1).collect();
5252+ match (
5353+ args.is_empty(),
5454+ args.first().unwrap_or(&String::new()).as_str(),
5555+ ) {
5656+ (true, _) | (false, "start") | (false, "") => {
5757+ dotenv().ok();
5858+ println!("{info} Starting {}.", me.clone().color_lightblue());
5959+ println!(
6060+ "{info} {} and contributors, licenced under {}.",
6161+ "MLC Bloeiman".color_pink(),
6262+ "BSD-3".color_blue()
6363+ );
6464+ println!("{}", cynthia_con::horizline());
6565+ match config_get() {
6666+ Ok(config) => {
6767+ let db = match database::setup().await {
6868+ Ok(db) => db,
6969+ Err(LuminaError::ConfMissing(a)) => {
7070+ eprintln!(
7171+ "{error} Missing environment variable {}, which is required to continue. Please make sure it is set, or change other variables to make it redundant, if possible.",
7272+ a.color_bright_orange()
7373+ );
7474+ process::exit(1);
7575+ }
7676+ Err(LuminaError::ConfInvalid(a)) => {
7777+ eprintln!(
7878+ "{error} Invalid environment variable: {}",
7979+ a.color_bright_orange()
8080+ );
8181+ process::exit(1);
8282+ }
8383+ Err(LuminaError::Sqlite(a)) => {
8484+ eprintln!("{error} While opening sqlite database: {}", a);
8585+ process::exit(1);
8686+ }
8787+ Err(LuminaError::Postgres(a)) => {
8888+ eprintln!("{error} While connecting to postgres database: {}", a);
8989+ process::exit(1);
9090+ }
9191+ Err(_) => {
9292+ eprintln!(
9393+ "{error} Unknown error: could not setup database connection.",
9494+ );
9595+ process::exit(1);
9696+ }
9797+ };
9898+ let appstate = AppState(Arc::from((config.clone(), Mutex::from(db))));
9999+ let def = rocket::Config {
100100+ port: config.port,
101101+ address: config.host,
102102+ ident: rocket::config::Ident::try_new(me.clone()).unwrap_or_default(),
103103+ log_level: rocket::config::LogLevel::Off,
104104+ ..rocket::Config::default()
105105+ };
106106+ let result = rocket::build()
107107+ .configure(def)
108108+ .mount(
109109+ "/",
110110+ routes![
111111+ staticroutes::index,
112112+ staticroutes::lumina_js,
113113+ staticroutes::lumina_css,
114114+ client_communication::wsconnection,
115115+ staticroutes::logo_svg,
116116+ staticroutes::logo_png,
117117+ staticroutes::favicon,
118118+ ],
119119+ )
120120+ .manage(appstate)
121121+ .launch()
122122+ .await
123123+ .map_err(LuminaError::RocketFaillure);
124124+ match result {
125125+ Ok(_) => {}
126126+ Err(LuminaError::RocketFaillure(e)) => {
127127+ // This handling should slowly expand as I run into newer ones, the 'defh' (default handling) is good enough, but for the most-bumped into errors, I'd like to give more human responses.
128128+ let defh = || eprintln!("{error} Error starting server: {:?}", e);
129129+ match e.kind() {
130130+ rocket::error::ErrorKind::Bind(e) => match e.kind() {
131131+ ErrorKind::AddrInUse => {
132132+ println!(
133133+ "{error} Another program or instance is running on this port or adress."
134134+ );
135135+ println!(
136136+ "{error} Make sure you have not double-started Lumina, or have a different program serving on this port!"
137137+ );
138138+ println!(
139139+ "{error} {}",
140140+ format!("Technical explanation: {}", e).style_dim()
141141+ );
142142+ }
143143+ _ => defh(),
144144+ },
145145+ _ => defh(),
146146+ }
147147+ process::exit(1);
148148+ }
149149+ Err(_) => {
150150+ eprintln!("{error} Unknown error starting server.",);
151151+ }
152152+ }
153153+ }
57154 Err(LuminaError::ConfMissing(a)) => {
58155 eprintln!(
5959- "{} Missing environment variable {}, which is required to continue. Please make sure it is set, or change other variables to make it redundant, if possible.",
6060- "[ERROR]".color_error_red().style_bold(),
156156+ "{error} Missing environment variable {}, which is required to continue. Please make sure it is set, or change other variables to make it redundant, if possible.",
61157 a.color_bright_orange()
62158 );
63159 process::exit(1);
···70166 );
71167 process::exit(1);
72168 }
7373- Err(LuminaError::Sqlite(a)) => {
7474- eprintln!(
7575- "{} While opening sqlite database: {}",
7676- "[ERROR]".color_error_red().style_bold(),
7777- a
7878- );
7979- process::exit(1);
8080- }
8181- Err(LuminaError::Postgres(a)) => {
8282- eprintln!(
8383- "{} While connecting to postgres database: {}",
8484- "[ERROR]".color_error_red().style_bold(),
8585- a
8686- );
8787- process::exit(1);
8888- }
89169 Err(_) => {
90170 eprintln!(
9191- "{} Unknown error: could not setup database connection.",
171171+ "{} Unknown error: could not setup server configuration.",
92172 "[ERROR]".color_error_red().style_bold()
93173 );
94174 process::exit(1);
95175 }
96176 };
9797- let appstate = AppState(Arc::from((config.clone(), Mutex::from(db))));
9898- let def = rocket::Config {
9999- port: config.port,
100100- address: config.host,
101101- ..rocket::Config::default()
102102- };
103103- let result = rocket::build()
104104- .configure(def)
105105- .mount(
106106- "/",
107107- routes![
108108- staticroutes::index,
109109- staticroutes::lumina_js,
110110- staticroutes::lumina_css,
111111- client_communication::wsconnection,
112112- staticroutes::logo_svg,
113113- staticroutes::logo_png,
114114- staticroutes::favicon,
115115- ],
116116- )
117117- .manage(appstate)
118118- .launch()
119119- .await
120120- .map_err(LuminaError::RocketFaillure);
121121- match result {
122122- Ok(_) => {}
123123- Err(LuminaError::RocketFaillure(e)) => {
124124- eprintln!(
125125- "{} Error starting server: {:?}",
126126- "[ERROR]".color_error_red().style_bold(),
127127- e
128128- );
129129- }
130130- Err(_) => {
131131- eprintln!(
132132- "{} Unknown error starting server.",
133133- "[ERROR]".color_error_red().style_bold()
134134- );
135135- }
136136- }
137177 }
138138- Err(LuminaError::ConfMissing(a)) => {
139139- eprintln!(
140140- "{} Missing environment variable {}, which is required to continue. Please make sure it is set, or change other variables to make it redundant, if possible.",
141141- "[ERROR]".color_error_red().style_bold(),
142142- a.color_bright_orange()
178178+ (false, "licence") | (false, "license") => {
179179+ println!(
180180+ "Licence for {} and its {}.",
181181+ me.color_lightblue().style_italic(),
182182+ "Lumina Client".color_yellow().style_italic()
143183 );
144144- process::exit(1);
184184+ println!("MLC Bloeiman and contributors.");
185185+ println!("{}", cynthia_con::horizline());
186186+ println!("{}", include_str!("../../LICENSE"));
145187 }
146146- Err(LuminaError::ConfInvalid(a)) => {
147147- eprintln!(
148148- "{} Invalid environment variable: {}",
149149- "[ERROR]".color_error_red().style_bold(),
150150- a.color_bright_orange()
151151- );
152152- process::exit(1);
188188+ (false, "help") | (false, "man") => {
189189+ fn table_to_centered_string(a: &mut tabled::Table) -> String {
190190+ let s: Vec<String> = a
191191+ .to_string()
192192+ .split("\n")
193193+ .map(|s| s.style_centered())
194194+ .collect();
195195+ let d = s.join("\n");
196196+ d
197197+ }
198198+ println!("{}", me);
199199+ {
200200+ println!("{}", "Subcommands".style_centered().style_bold());
201201+ println!();
202202+ println!(
203203+ "\t\t{}|{}\tShow this help",
204204+ "help".color_lightblue().style_italic(),
205205+ "man".color_lightblue().style_italic()
206206+ );
207207+ println!(
208208+ "\t\t{}\t\tShow version and exit",
209209+ "version".color_lightblue().style_italic()
210210+ );
211211+ println!(
212212+ "\t\t{}\t\tShow licence and exit",
213213+ "licence".color_lightblue().style_italic()
214214+ );
215215+ println!(
216216+ "\t\t{}\t\tStart Lumina server",
217217+ "start".color_lightblue().style_italic()
218218+ );
219219+ }
220220+ println!();
221221+ {
222222+ println!("{}", "Environment variables".style_centered().style_bold());
223223+ println!();
224224+ let mut builder = tabled::builder::Builder::new();
225225+ builder.push_record(["Name", "Default value", "Description"]);
226226+ builder.push_record(["LUMINA_DB_TYPE", r#""sqlite""#, r#"The kind of database to use. Options are 'postgres' (recommended) or 'sqlite'."#]);
227227+ builder.push_record([
228228+ "LUMINA_DB_SALT",
229229+ r#""sal""#,
230230+ r#"The salting to use for some data on the database."#,
231231+ ]);
232232+ builder.push_record([
233233+ "LUMINA_SERVER_PORT",
234234+ r#"8085"#,
235235+ r#"Port for Lumina to accept HTTP requests on."#,
236236+ ]);
237237+ builder.push_record(["LUMINA_SERVER_ADDR", r#"127.0.0.1"#, "Address for Lumina to accept HTTP requests on. (usually '127.0.0.1' or '0.0.0.0')"]);
238238+ builder.push_record(["LUMINA_SERVER_HTTPS", r#"false"#, "Wether to use 'https' rather than 'http' in links, etc. Recommendation is to set to true."]);
239239+ builder.push_record([
240240+ "LUMINA_SYNC_IID",
241241+ r#""localhost""#,
242242+ "Broadcasted domain name, should be equal to public domain name.",
243243+ ]);
244244+ builder.push_record([
245245+ "LUMINA_SYNC_INTERVAL",
246246+ r#"30"#,
247247+ "Specifies the interval between syncs. Minimum is 30.",
248248+ ]);
249249+ println!(
250250+ "{}",
251251+ table_to_centered_string(
252252+ builder.build().with(tabled::settings::Style::modern())
253253+ )
254254+ .style_dim()
255255+ );
256256+ println!();
257257+ println!(
258258+ "{}",
259259+ format!(
260260+ r#"When having "LUMINA_DB_TYPE" set to '{}': (recommended)"#,
261261+ "postgres".color_lilac().style_bold()
262262+ )
263263+ .style_centered()
264264+ .style_italic()
265265+ );
266266+ let mut builder = tabled::builder::Builder::new();
267267+ builder.push_record(["Name", "Default value", "Description"]);
268268+ builder.push_record([
269269+ "LUMINA_POSTGRES_PORT",
270270+ r#"5432"#,
271271+ r#"The port to contact the database on."#,
272272+ ]);
273273+ builder.push_record([
274274+ "LUMINA_POSTGRES_HOST",
275275+ r#""localhost""#,
276276+ r#"The address to contact the database on."#,
277277+ ]);
278278+ builder.push_record([
279279+ "LUMINA_POSTGRES_USERNAME",
280280+ r#""#,
281281+ r#"The username to log in to the database with."#,
282282+ ]);
283283+ builder.push_record(["LUMINA_POSTGRES_PASSWORD", r#""#, r#"The password to log in to the database with. If not set, Lumina will try without."#]);
284284+ builder.push_record([
285285+ "LUMINA_POSTGRES_DATABASE",
286286+ r#""#,
287287+ r#"The name of the database to use."#,
288288+ ]);
289289+ println!(
290290+ "{}",
291291+ table_to_centered_string(
292292+ builder.build().with(tabled::settings::Style::modern())
293293+ )
294294+ .color_lilac()
295295+ .style_dim()
296296+ );
297297+298298+ println!();
299299+ println!(
300300+ "{}",
301301+ format!(
302302+ r#"When having "LUMINA_DB_TYPE" set to '{}':"#,
303303+ "sqlite".color_bright_orange().style_bold()
304304+ )
305305+ .style_centered()
306306+ .style_italic()
307307+ );
308308+ let mut builder = tabled::builder::Builder::new();
309309+ builder.push_record(["Name", "Default value", "Description"]);
310310+311311+ builder.push_record([
312312+ "LUMINA_SQLITE_FILE",
313313+ r#""instance.sqlite""#,
314314+ "SQLite file to connect to. Always a relative path from the instance folder.",
315315+ ]);
316316+ println!(
317317+ "{}",
318318+ table_to_centered_string(
319319+ builder.build().with(tabled::settings::Style::modern())
320320+ )
321321+ .color_bright_orange()
322322+ .style_dim()
323323+ )
324324+ }
153325 }
154154- Err(_) => {
155155- eprintln!(
156156- "{} Unknown error: could not setup server configuration.",
157157- "[ERROR]".color_error_red().style_bold()
158158- );
159159- process::exit(1);
326326+ (false, unknown) => {
327327+ println!(
328328+ "{error} Unknown subcommand, '{}', use '{}' for available commands.'",
329329+ unknown.color_blue().style_italic(),
330330+ "help".color_lightblue().style_italic()
331331+ )
160332 }
161161- };
333333+ }
162334}
+4-4
server/src/user.rs
···11use crate::{LuminaError, database::DbConn};
22-use cynthia_con::CynthiaColors;
22+use cynthia_con::{CynthiaColors, CynthiaStyles};
33use std::str::FromStr;
44-use tracing::info;
54use uuid::Uuid;
6576#[derive(Debug, Clone)]
···242241 user: User,
243242 db: &DbConn,
244243 ) -> Result<(String, User), LuminaError> {
244244+ let info = "[INFO]".color_green().style_bold();
245245 let user_id = user.id;
246246 match db {
247247 DbConn::PgsqlConnection(client) => {
···253253 )
254254 .await
255255 .map_err(LuminaError::Postgres)?;
256256- info!(
257257- "New session created by {}",
256256+ println!(
257257+ "{info} New session created by {}",
258258 user.clone().username.color_bright_cyan()
259259 );
260260 Ok((session_key, user))