Shutdown command
This commit is contained in:
@@ -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])),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|
||||||
Command::new(plugin_json.file)
|
let child = Arc::new(Mutex::new(
|
||||||
.args(plugin_json.args)
|
Command::new(plugin_json.file)
|
||||||
.current_dir(path)
|
.args(plugin_json.args)
|
||||||
.spawn()
|
.current_dir(path)
|
||||||
.unwrap();
|
.spawn()
|
||||||
|
.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
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user