use std::net::TcpListener;
use async_std::task;
use futures::join;
use lazy_static::lazy_static;
use tracing::{error, info, span, Level};
use crate::{
plugins::{
self,
manager::PluginsManagerType,
prelude::{EventData, EventType},
},
server::Client,
CLIENTS, CLIENT_NEXT,
};
pub const PLUGINS_DIR: &str = "plugins";
lazy_static! {
pub static ref PLUGINS_MANAGER: PluginsManagerType =
plugins::loader(PLUGINS_DIR).expect("failed to load plugins");
}
pub fn run(tcp_host: String, ws_host: String) -> anyhow::Result<()> {
info!("Loaded {} plugins", PLUGINS_MANAGER.plugins.len());
info!("Loaded {} commands", PLUGINS_MANAGER.commands.len());
info!("Loaded {} events", PLUGINS_MANAGER.events.len());
let tcp_child = task::spawn(async move {
start_tcp(tcp_host).await.unwrap();
});
let ws_child = task::spawn(async move {
start_websocket(ws_host).await.unwrap();
});
task::block_on(async {
join!(tcp_child, ws_child);
});
Ok(())
}
async fn process(client: Client) -> anyhow::Result<()> {
let client_addr = client.peer_addr()?;
info!("Processing client connection: {}", client_addr);
client
.run_events(EventType::OnConnect, EventData::None)
.await?;
loop {
let buf = client.read()?;
async fn handle(client: &Client, buf: String) -> anyhow::Result<()> {
client
.run_events(EventType::OnSend, EventData::None)
.await?;
let mut args: Vec<&str> = buf.split_ascii_whitespace().collect();
if args.is_empty() {
client.send("empty buffer")?;
return Ok(());
}
let cmd = args[0];
args = args[1..args.len()].to_vec();
let command = client
.plugins_manager
.commands
.iter()
.enumerate()
.find(|&(_i, command)| command.name() == cmd || command.aliases().contains(&cmd));
if let Some((_i, cmd)) = command {
if client
.run_events(
EventType::OnCommand,
EventData::Command(cmd.name().to_string()),
)
.await
.is_ok()
{
cmd.execute(client, args).await?;
}
} else {
client.send("unknown command")?;
}
Ok(())
}
if let Err(err) = handle(&client, buf).await {
error!("Unexpected error in message handler: {}", err);
client.send("Unexpected error")?;
}
client.flush()?;
}
}
async fn start_tcp(host: String) -> anyhow::Result<()> {
let listener = TcpListener::bind(host)?;
let incoming = listener.incoming();
for stream in incoming {
let stream = stream?;
let id = *CLIENT_NEXT.lock().unwrap();
*CLIENT_NEXT.lock().unwrap() += 1;
task::spawn(async move {
let client = Client::new_tcp(stream, id);
CLIENTS.lock().unwrap().insert(id, client.clone());
let span = span!(Level::ERROR, "TCP", id = client.id);
let _enter = span.enter();
if let Err(err) = process(client).await {
error!("{}", err);
}
CLIENTS.lock().unwrap().remove(&id);
});
}
Ok(())
}
async fn start_websocket(host: String) -> anyhow::Result<()> {
let listener = TcpListener::bind(host)?;
let incoming = listener.incoming();
for stream in incoming {
let stream = stream?;
let id = *CLIENT_NEXT.lock().unwrap();
*CLIENT_NEXT.lock().unwrap() += 1;
task::spawn(async move {
let client = Client::new_websocket(stream, id).unwrap();
CLIENTS.lock().unwrap().insert(id, client.clone());
let span = span!(Level::ERROR, "UDP", id = client.id);
let _enter = span.enter();
if let Err(err) = process(client).await {
error!("{}", err);
}
CLIENTS.lock().unwrap().remove(&id);
});
}
Ok(())
}