#![deny(clippy::pedantic)]
#![allow(clippy::missing_errors_doc)]
mod config;
mod entities;
mod error;
mod models;
mod server;
use std::path::PathBuf;
use crate::{
error::Result,
server::{Connection, Server},
};
use actix::{Actor, AsyncContext, System};
use clap::Clap;
use displaydoc::Display;
use sqlx::migrate::Migrator;
use thiserror::Error;
use tokio::net::TcpListener;
static MIGRATOR: Migrator = sqlx::migrate!();
#[derive(Error, Debug, Display)]
pub enum InitError {
TcpBind(std::io::Error),
ConfigRead(std::io::Error),
ConfigParse(toml::de::Error),
SqlConnect(sqlx::Error),
SqlMigrate(sqlx::migrate::MigrateError),
}
#[derive(Clap)]
#[clap(version = clap::crate_version!(), author = clap::crate_authors!())]
struct Opts {
#[clap(short, long)]
config: PathBuf,
}
#[actix_rt::main]
async fn main() -> Result<()> {
let opts: Opts = Opts::parse();
let config = std::fs::read(&opts.config).map_err(InitError::ConfigRead)?;
let config: config::Config = toml::from_slice(&config).map_err(InitError::ConfigParse)?;
let sql_pool = sqlx::SqlitePool::connect(&config.database_uri)
.await
.map_err(InitError::SqlConnect)?;
MIGRATOR
.run(&sql_pool)
.await
.map_err(InitError::SqlMigrate)?;
let listener = TcpListener::bind(&config.socket_address)
.await
.map_err(InitError::TcpBind)?;
let stream = async_stream::stream! {
loop {
match listener.accept().await {
Ok((socket, remote)) => yield Connection(socket, remote),
Err(e) => eprintln!("Couldn't establish connection: {:?}", e)
}
}
};
Server::create(move |ctx| {
ctx.add_message_stream(stream);
Server::new(sql_pool)
});
println!("Running IRC server on {}", &config.socket_address);
tokio::signal::ctrl_c().await.expect("ctrl-c io");
System::current().stop();
Ok(())
}