extern crate rand; extern crate uuid; extern crate bcrypt; extern crate chrono; extern crate dotenv; extern crate postgres; extern crate r2d2; extern crate r2d2_postgres; extern crate fallible_iterator; extern crate serde; extern crate serde_cbor; #[macro_use] extern crate serde_derive; #[macro_use] extern crate failure; extern crate fern; #[macro_use] extern crate log; extern crate stripe; extern crate iron; extern crate bodyparser; extern crate urlencoded; extern crate persistent; extern crate router; extern crate mount; extern crate cookie; extern crate lettre; extern crate lettre_email; extern crate ws; extern crate crossbeam_channel; mod account; mod acp; mod construct; mod effect; mod game; mod instance; mod item; mod img; mod mail; mod mob; mod mtx; mod names; mod http; mod payments; mod pg; mod player; mod events; mod rpc; mod skill; mod spec; mod util; mod vbox; mod warden; use std::thread::{spawn}; use std::path::{Path}; use fern::colors::{Color, ColoredLevelConfig}; use crossbeam_channel::{unbounded}; #[derive(Serialize)] struct JsonLog { time: String, module: String, level: String, msg: String, } fn setup_logger() -> Result<(), fern::InitError> { let colors_line = ColoredLevelConfig::new() .error(Color::Red) .warn(Color::Yellow) .info(Color::BrightWhite) .debug(Color::BrightWhite) .trace(Color::BrightBlack); let colors_level = colors_line.clone().info(Color::Green); let term = fern::Dispatch::new() .format(move |out, message, record| { out.finish(format_args!( "{color_line}{date} {target} {level}{color_line} {message}\x1B[0m", color_line = format_args!("\x1B[{}m", colors_line.get_color(&record.level()).to_fg_str()), date = chrono::Local::now().format("%Y-%m-%d %H:%M:%S"), target = record.target(), level = colors_level.color(record.level()), message = message, )); }) .chain(std::io::stdout()); let json = fern::Dispatch::new() .format(|out, message, record| { let json = JsonLog { time: chrono::Local::now().to_rfc3339(), module: record.target().to_string(), level: record.level().to_string(), msg: message.to_string() }; out.finish(format_args!( "{}", serde_json::to_string(&json).unwrap(), )) }) .chain(fern::log_file("/var/log/mnml/mnml.log")?); fern::Dispatch::new() .level_for("postgres", log::LevelFilter::Info) .level_for("ws", log::LevelFilter::Warn) .level_for("iron", log::LevelFilter::Info) .level(log::LevelFilter::Info) .chain(term) .chain(json) .apply()?; Ok(()) } fn main() { setup_logger().unwrap(); dotenv::from_path(Path::new("/etc/mnml/gs.conf")).ok(); let pool = pg::create_pool(); let http_pool = pool.clone(); let (events_tx, events_rx) = unbounded(); let pg_events_tx = events_tx.clone(); let rpc_events_tx = events_tx.clone(); let (warden_tx, warden_rx) = unbounded(); let events_warden_tx = warden_tx.clone(); let warden_tick_tx = warden_tx.clone(); let (mail_tx, mail_rx) = unbounded(); let http_mail_tx = mail_tx.clone(); // create a clone of the tx so ws handler can tell events // about connection status let events = events::Events::new(events_tx, events_rx, events_warden_tx, mail_tx); let warden = warden::Warden::new(warden_tx, warden_rx, events.tx.clone(), pool.clone()); let pg_pool = pool.clone(); let mailer = mail::listen(mail_rx); spawn(move || http::start(http_pool, mailer)); spawn(move || warden.listen()); spawn(move || warden::upkeep_tick(warden_tick_tx)); spawn(move || pg::listen(pg_pool, pg_events_tx)); spawn(move || events.listen()); // the main thread becomes this ws listener let rpc_pool = pool.clone(); rpc::start(rpc_pool, rpc_events_tx); }