Simple plugin server example
This commit is contained in:
@@ -1,11 +1,13 @@
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! logger {
|
macro_rules! logger {
|
||||||
(const $i:ident $name:expr) => {
|
(const $i:ident $name:expr) => {
|
||||||
|
#[allow(unused)]
|
||||||
pub const $i: $crate::once_cell::sync::Lazy<$crate::utils::logger::Logger> =
|
pub const $i: $crate::once_cell::sync::Lazy<$crate::utils::logger::Logger> =
|
||||||
$crate::once_cell::sync::Lazy::new(|| $crate::utils::logger::Logger::new($name));
|
$crate::once_cell::sync::Lazy::new(|| $crate::utils::logger::Logger::new($name));
|
||||||
};
|
};
|
||||||
|
|
||||||
($i:ident $name:expr) => {
|
($i:ident $name:expr) => {
|
||||||
|
#[allow(unused)]
|
||||||
pub const $i: $crate::once_cell::sync::Lazy<$crate::utils::logger::Logger> =
|
pub const $i: $crate::once_cell::sync::Lazy<$crate::utils::logger::Logger> =
|
||||||
$crate::once_cell::sync::Lazy::new(|| $crate::utils::logger::Logger::new($name));
|
$crate::once_cell::sync::Lazy::new(|| $crate::utils::logger::Logger::new($name));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
mod macros;
|
mod macros;
|
||||||
|
mod plugin;
|
||||||
mod requests;
|
mod requests;
|
||||||
mod server;
|
mod server;
|
||||||
mod types;
|
mod types;
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
use crate::{logger, plugin::Plugin};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fs,
|
||||||
|
io::Read,
|
||||||
|
net::{TcpListener, TcpStream},
|
||||||
|
path::Path,
|
||||||
|
process::Command,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
|
logger!(LOGGER "Plugin Loader");
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct PluginJson {
|
||||||
|
pub id: String,
|
||||||
|
pub version: String,
|
||||||
|
pub supported_versions: Vec<String>,
|
||||||
|
pub file: String,
|
||||||
|
pub args: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct PluginHandshake {
|
||||||
|
pub id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PluginLoader {
|
||||||
|
plugins: Vec<Plugin>,
|
||||||
|
plugin_clients: Arc<Mutex<HashMap<String, TcpStream>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PluginLoader {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
plugins: Vec::new(),
|
||||||
|
plugin_clients: Arc::new(Mutex::new(HashMap::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load(&self, json_path: &Path) -> Plugin {
|
||||||
|
let json_string = fs::read_to_string(json_path).unwrap();
|
||||||
|
let plugin_json: PluginJson = serde_json::from_str(&json_string).unwrap();
|
||||||
|
LOGGER.info(format!("Loading {}", plugin_json.id));
|
||||||
|
|
||||||
|
Command::new(plugin_json.file)
|
||||||
|
.args(plugin_json.args)
|
||||||
|
.current_dir("plugins")
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
while self
|
||||||
|
.plugin_clients
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.get(&plugin_json.id)
|
||||||
|
.is_none()
|
||||||
|
{}
|
||||||
|
Plugin(
|
||||||
|
self.plugin_clients
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.get(&plugin_json.id)
|
||||||
|
.unwrap()
|
||||||
|
.try_clone()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_server(&self) {
|
||||||
|
let plugin_clients = self.plugin_clients.clone();
|
||||||
|
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let listener = TcpListener::bind("0.0.0.0:7243").unwrap();
|
||||||
|
LOGGER.info("Server listening at 0.0.0.0:7243");
|
||||||
|
|
||||||
|
for stream in listener.incoming() {
|
||||||
|
let mut stream = stream.unwrap();
|
||||||
|
let mut s = String::new();
|
||||||
|
stream.read_to_string(&mut s).unwrap();
|
||||||
|
let plugin_handshake: PluginHandshake = serde_json::from_str(&s).unwrap();
|
||||||
|
plugin_clients
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.insert(plugin_handshake.id, stream);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use std::net::TcpStream;
|
||||||
|
|
||||||
|
pub mod loader;
|
||||||
|
|
||||||
|
pub struct Plugin(TcpStream);
|
||||||
|
|
||||||
|
impl Plugin {}
|
||||||
+19
-3
@@ -1,12 +1,15 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
|
fs,
|
||||||
net::{TcpListener, TcpStream},
|
net::{TcpListener, TcpStream},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
logger, types,
|
logger,
|
||||||
|
plugin::loader::PluginLoader,
|
||||||
|
types,
|
||||||
utils::{self, client::Client},
|
utils::{self, client::Client},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -25,6 +28,7 @@ pub struct Server {
|
|||||||
pub config: ServerConfig,
|
pub config: ServerConfig,
|
||||||
pub clients: Mutex<HashSet<Client>>,
|
pub clients: Mutex<HashSet<Client>>,
|
||||||
pub db: utils::database::Database,
|
pub db: utils::database::Database,
|
||||||
|
pub plugin_loader: PluginLoader,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ServerConfig {
|
impl Default for ServerConfig {
|
||||||
@@ -32,8 +36,8 @@ impl Default for ServerConfig {
|
|||||||
Self {
|
Self {
|
||||||
port: 7080,
|
port: 7080,
|
||||||
server_name: format!("Server Name"),
|
server_name: format!("Server Name"),
|
||||||
server_id: format!("offline-server"),
|
server_id: format!("important"),
|
||||||
server_key: format!(""),
|
server_key: format!("important"),
|
||||||
channels: Vec::new(),
|
channels: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,13 +62,25 @@ impl Server {
|
|||||||
root: root.to_path_buf(),
|
root: root.to_path_buf(),
|
||||||
config,
|
config,
|
||||||
clients: Mutex::new(HashSet::new()),
|
clients: Mutex::new(HashSet::new()),
|
||||||
|
plugin_loader: PluginLoader::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(self: &Arc<Self>) -> crate::Result<()> {
|
pub fn run(self: &Arc<Self>) -> crate::Result<()> {
|
||||||
// Load plugins
|
// Load plugins
|
||||||
|
Self::LOGGER.info("Loading plugins");
|
||||||
|
for entry in fs::read_dir(self.root.join("plugins"))? {
|
||||||
|
let entry = entry?;
|
||||||
|
let path = entry.path();
|
||||||
|
|
||||||
|
if path.extension().and_then(|s| s.to_str()) == Some("json") {
|
||||||
|
self.plugin_loader.load(&path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::LOGGER.info("Plugins loaded");
|
||||||
|
|
||||||
// Initialize plugins
|
// Initialize plugins
|
||||||
|
Self::LOGGER.info("Initializing plugins");
|
||||||
|
|
||||||
// Start server
|
// Start server
|
||||||
let listener = TcpListener::bind(format!("0.0.0.0:{}", self.config.port))?;
|
let listener = TcpListener::bind(format!("0.0.0.0:{}", self.config.port))?;
|
||||||
|
|||||||
Reference in New Issue
Block a user