Shutdown command

This commit is contained in:
2025-12-21 15:09:44 +01:00
parent c45f9a59ca
commit 8aa3fe17c1
7 changed files with 66 additions and 9 deletions
+4
View File
@@ -113,6 +113,10 @@ pub fn start_cli(server: Arc<Server>, plugin_loader: PluginLoader) {
"ping" => { "ping" => {
LOGGER.info("pong"); LOGGER.info("pong");
} }
"shutdown" => {
server.shutdown();
break;
}
_ => LOGGER.error(format!("Command not found: {}", args[0])), _ => LOGGER.error(format!("Command not found: {}", args[0])),
} }
} }
+5 -1
View File
@@ -33,11 +33,13 @@ impl PluginLoader {
let plugin_json: PluginJson = serde_json::from_str(&json_string).unwrap(); let plugin_json: PluginJson = serde_json::from_str(&json_string).unwrap();
LOGGER.info(format!("Loading {}", plugin_json.id)); LOGGER.info(format!("Loading {}", plugin_json.id));
let child = Arc::new(Mutex::new(
Command::new(plugin_json.file) Command::new(plugin_json.file)
.args(plugin_json.args) .args(plugin_json.args)
.current_dir(path) .current_dir(path)
.spawn() .spawn()
.unwrap(); .unwrap(),
));
while self while self
.plugin_clients .plugin_clients
@@ -59,6 +61,7 @@ impl PluginLoader {
stream: a.try_clone().unwrap(), stream: a.try_clone().unwrap(),
reader: BufReader::new(a), reader: BufReader::new(a),
id: plugin_json.id, id: plugin_json.id,
child,
} }
} }
@@ -88,6 +91,7 @@ impl Clone for Plugin {
stream: self.stream.try_clone().unwrap(), stream: self.stream.try_clone().unwrap(),
reader: BufReader::new(self.stream.try_clone().unwrap()), reader: BufReader::new(self.stream.try_clone().unwrap()),
id: self.id.clone(), id: self.id.clone(),
child: self.child.clone(),
} }
} }
} }
+9 -1
View File
@@ -4,7 +4,8 @@ pub mod types;
use std::{ use std::{
io::{BufRead, BufReader, Write}, io::{BufRead, BufReader, Write},
net::TcpStream, net::TcpStream,
sync::Arc, process::Child,
sync::{Arc, Mutex},
}; };
use crate::{ use crate::{
@@ -17,6 +18,7 @@ pub struct Plugin {
stream: TcpStream, stream: TcpStream,
reader: BufReader<TcpStream>, reader: BufReader<TcpStream>,
id: String, id: String,
child: Arc<Mutex<Child>>,
} }
impl Plugin { impl Plugin {
@@ -60,4 +62,10 @@ impl Plugin {
} }
} }
} }
pub fn stop(&mut self) {
self.send(&LoaderMessage::Shutdown).unwrap();
self.stream.shutdown(std::net::Shutdown::Both).unwrap();
self.child.lock().unwrap().kill().unwrap();
}
} }
+2
View File
@@ -31,6 +31,8 @@ pub enum LoaderMessage {
user_id: String, user_id: String,
msg: Message, msg: Message,
}, },
Shutdown,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
+33 -3
View File
@@ -3,7 +3,10 @@ use std::{
fs::{self}, fs::{self},
net::{TcpListener, TcpStream}, net::{TcpListener, TcpStream},
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::{Arc, Mutex}, sync::{
Arc, Mutex,
atomic::{AtomicBool, Ordering},
},
}; };
use crate::{ use crate::{
@@ -22,13 +25,13 @@ pub struct ServerConfig {
pub channels: Vec<types::data::Channel>, pub channels: Vec<types::data::Channel>,
} }
#[allow(dead_code)]
pub struct Server { pub struct Server {
pub root: PathBuf, pub root: PathBuf,
pub config: ServerConfig, pub config: ServerConfig,
pub clients: Mutex<HashSet<Client>>, pub clients: Mutex<HashSet<Client>>,
pub plugins: Mutex<Vec<Plugin>>, pub plugins: Mutex<Vec<Plugin>>,
pub db: utils::database::Database, pub db: utils::database::Database,
pub shutting_down: AtomicBool,
} }
impl Default for ServerConfig { impl Default for ServerConfig {
@@ -63,6 +66,7 @@ impl Server {
config, config,
clients: Mutex::new(HashSet::new()), clients: Mutex::new(HashSet::new()),
plugins: Mutex::new(Vec::new()), plugins: Mutex::new(Vec::new()),
shutting_down: AtomicBool::new(false),
}) })
} }
@@ -182,7 +186,7 @@ impl Server {
fn handle_client(self: &Arc<Self>, client: &Client) -> crate::Result<()> { fn handle_client(self: &Arc<Self>, client: &Client) -> crate::Result<()> {
// The main req/res loop // The main req/res loop
loop { while !self.shutting_down.load(Ordering::SeqCst) {
let req = client.read()?; let req = client.read()?;
if let Some(r) = &req { if let Some(r) = &req {
self.send_plugin_message(&LoaderMessage::Request { self.send_plugin_message(&LoaderMessage::Request {
@@ -192,6 +196,7 @@ impl Server {
self.wrap_err(&client, self.call_request(r, &client))?; self.wrap_err(&client, self.call_request(r, &client))?;
} }
} }
Ok(())
} }
/// When there is a error it removes the client /// When there is a error it removes the client
@@ -217,4 +222,29 @@ impl Server {
} }
Ok(()) Ok(())
} }
pub fn shutdown(self: &Arc<Self>) {
Self::LOGGER.info("Server shutting down...");
// Signal shutdown
self.shutting_down.store(true, Ordering::SeqCst);
// Disconnect clients
let clients = self.clients.lock().unwrap();
for client in clients.iter() {
let _ = client.send(types::message::ServerMessage::Shutdown {
message: format!("Server shutting down... we'll be back shortly"),
});
let _ = client.close();
}
// Stop plugins
for plugin in self.plugins.lock().unwrap().iter_mut() {
let _ = plugin.stop();
}
Self::LOGGER.info("Shutdown complete");
Self::LOGGER.info("Exiting process..");
std::process::exit(0);
}
} }
+4
View File
@@ -115,6 +115,10 @@ pub mod message {
user_id: Author, user_id: Author,
channel_id: String, channel_id: String,
}, },
Shutdown {
message: String,
},
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
+5
View File
@@ -346,6 +346,11 @@ impl Client {
pub fn set_uuid(&mut self, uuid: &str) { pub fn set_uuid(&mut self, uuid: &str) {
self.1 = Some(uuid.to_string()) self.1 = Some(uuid.to_string())
} }
pub fn close(&self) -> crate::Result<()> {
self.0.shutdown(std::net::Shutdown::Both)?;
Ok(())
}
} }
impl Clone for Client { impl Clone for Client {