mirror of
https://github.com/Astatin3/unshell.git
synced 2026-06-08 22:38:01 -06:00
Make unshell-lib, and module system with components.
This commit is contained in:
Generated
+136
@@ -0,0 +1,136 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
|
||||
dependencies = [
|
||||
"bincode_derive",
|
||||
"serde",
|
||||
"unty",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode_derive"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09"
|
||||
dependencies = [
|
||||
"virtue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "unshell-lib"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"libloading",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unty"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
|
||||
|
||||
[[package]]
|
||||
name = "virtue"
|
||||
version = "0.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "unshell-lib"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
libloading = {version = "0.8.9"}
|
||||
bincode = "2.0.1"
|
||||
log = "0.4.28"
|
||||
# unshell-modules = {path = "../unshell-modules"}
|
||||
@@ -0,0 +1,22 @@
|
||||
use bincode::{Decode, Encode};
|
||||
|
||||
#[derive(Debug, Encode, Decode)]
|
||||
pub enum Announcement {
|
||||
TestAnnouncement(String),
|
||||
}
|
||||
|
||||
const BINCODE_CONFIG: bincode::config::Configuration = bincode::config::standard();
|
||||
|
||||
impl Announcement {
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
bincode::encode_to_vec(self, BINCODE_CONFIG).unwrap()
|
||||
}
|
||||
|
||||
pub fn decode(bytes: &[u8]) -> Option<Self> {
|
||||
if let Ok((decoded, _)) = bincode::decode_from_slice(&bytes[..], BINCODE_CONFIG) {
|
||||
Some(decoded)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
use std::{
|
||||
io::Read,
|
||||
net::TcpStream,
|
||||
sync::{
|
||||
Arc, Mutex,
|
||||
atomic::{AtomicBool, Ordering},
|
||||
},
|
||||
thread::{self, JoinHandle},
|
||||
};
|
||||
|
||||
// use unshell_modules::{Manager, ModuleRuntime};
|
||||
|
||||
use crate::{Announcement, ModuleRuntime, module::Manager};
|
||||
|
||||
pub struct RuntimeTest {
|
||||
thread_handle: JoinHandle<()>,
|
||||
join_signal: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl RuntimeTest {
|
||||
pub fn new(_manager: Arc<Mutex<Manager>>) -> RuntimeTest {
|
||||
let join_signal = Arc::new(AtomicBool::new(false));
|
||||
let join_clone = join_signal.clone();
|
||||
|
||||
Self {
|
||||
thread_handle: thread::spawn(move || {
|
||||
info!("Connecting to server...");
|
||||
let mut stream = TcpStream::connect("localhost:1234").unwrap();
|
||||
info!("Connectied");
|
||||
// let reader = BufReader::new(stream.try_clone().unwrap());
|
||||
// let mut writer = BufWriter::new(stream.try_clone().unwrap());
|
||||
|
||||
// let (a, b) = crossbeam_channel::unbounded();
|
||||
|
||||
// a.
|
||||
|
||||
// if join_receiver.len() == 0 {
|
||||
// join_receiver.recv().unwrap();
|
||||
// }
|
||||
|
||||
while !join_clone.load(Ordering::Relaxed) {
|
||||
let mut size_buf = [0u8; 4];
|
||||
stream.read_exact(&mut size_buf).unwrap();
|
||||
let size = u32::from_be_bytes(size_buf);
|
||||
|
||||
let mut buf = vec![0u8; size as usize];
|
||||
|
||||
stream.read_exact(&mut buf).unwrap();
|
||||
|
||||
let a = Announcement::decode(&buf).unwrap();
|
||||
|
||||
match a {
|
||||
Announcement::TestAnnouncement(s) => {
|
||||
info!("Received test announcement: {}", s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
join_signal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleRuntime for RuntimeTest {
|
||||
// fn init(&mut self) {}
|
||||
|
||||
fn is_running(&self) -> bool {
|
||||
// println!("Checking if running");
|
||||
!self.thread_handle.is_finished()
|
||||
}
|
||||
|
||||
fn kill(self: Box<Self>) {
|
||||
if !self.thread_handle.is_finished() {
|
||||
self.join_signal.store(true, Ordering::Relaxed);
|
||||
let _ = self.thread_handle.join();
|
||||
}
|
||||
// drop(self);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
mod client_runtime;
|
||||
|
||||
// use crate::module::Interface;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
pub const MODULE_NAME: &'static str = "client";
|
||||
|
||||
// pub use unshell_modules::setup_logger;
|
||||
|
||||
// use unshell_modules::{Manager, ModuleRuntime, module_interface};
|
||||
|
||||
use crate::{
|
||||
Component,
|
||||
ModuleRuntime,
|
||||
client::client_runtime::RuntimeTest,
|
||||
module::{Interface, Manager},
|
||||
module_interface,
|
||||
// module_interface,
|
||||
};
|
||||
|
||||
pub extern "C" fn test1() {
|
||||
warn!("Test1 called xxxxxxxxxxx");
|
||||
}
|
||||
pub extern "C" fn test2() {
|
||||
warn!("Test2 called");
|
||||
}
|
||||
pub extern "C" fn test3() {
|
||||
warn!("Test3 called");
|
||||
}
|
||||
|
||||
module_interface! {
|
||||
ClientInterface {
|
||||
fn test1();
|
||||
fn test2();
|
||||
fn test3();
|
||||
}
|
||||
}
|
||||
|
||||
// #[unsafe(no_mangle)]
|
||||
// pub fn interface() -> Interface {
|
||||
// Interface::from_raw(test1, test2, test3)
|
||||
// }
|
||||
|
||||
// #[unsafe(no_mangle)]
|
||||
// pub fn init(manager: Arc<Mutex<Manager>>) -> Box<dyn ModuleRuntime> {
|
||||
// info!("Initializing client module");
|
||||
// }
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ClientComponent;
|
||||
|
||||
impl ClientComponent {
|
||||
pub fn new() -> Self {
|
||||
ClientComponent
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for ClientComponent {
|
||||
fn name(&self) -> &'static str {
|
||||
MODULE_NAME
|
||||
}
|
||||
|
||||
fn start_runtime(&self, manager: Arc<Mutex<Manager>>) -> Option<Box<dyn ModuleRuntime>> {
|
||||
Some(Box::new(RuntimeTest::new(manager)))
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn Component> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn get_interface(&self) -> Box<dyn Interface> {
|
||||
Box::new(ClientInterface::from_raw(test1, test2, test3))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#![no_main]
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
pub mod client;
|
||||
pub mod module;
|
||||
pub mod server;
|
||||
|
||||
mod announcement;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
pub use announcement::Announcement;
|
||||
|
||||
use crate::module::{Interface, Manager};
|
||||
|
||||
///Generic error type for module-related operations.
|
||||
#[derive(Debug)]
|
||||
pub enum ModuleError {
|
||||
LibLoadingError(libloading::Error),
|
||||
LogError(log::SetLoggerError),
|
||||
LinkError(String),
|
||||
Error(String),
|
||||
}
|
||||
|
||||
/// Trait for defining modules that have a runtime.
|
||||
pub trait ModuleRuntime: Send {
|
||||
/// Returns true if the module is running.
|
||||
/// After returning false, the module will be dropped.
|
||||
fn is_running(&self) -> bool;
|
||||
/// Consumes the module, implementation should kill whatever is running.
|
||||
fn kill(self: Box<Self>);
|
||||
}
|
||||
|
||||
pub trait Component {
|
||||
fn name(&self) -> &'static str;
|
||||
fn start_runtime(&self, manager: Arc<Mutex<Manager>>) -> Option<Box<dyn ModuleRuntime>>;
|
||||
fn get_interface(&self) -> Box<dyn Interface>;
|
||||
fn clone_box(&self) -> Box<dyn Component>;
|
||||
}
|
||||
|
||||
impl Clone for Box<dyn Component> {
|
||||
fn clone(&self) -> Box<dyn Component> {
|
||||
self.clone_box()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#![allow(improper_ctypes_definitions)]
|
||||
|
||||
use log::{LevelFilter, Log, SetLoggerError};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub type SetupLogger =
|
||||
extern "C" fn(logger: &'static dyn Log, level: LevelFilter) -> Result<(), SetLoggerError>;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn setup_logger(
|
||||
logger: &'static dyn log::Log,
|
||||
level: log::LevelFilter,
|
||||
) -> Result<(), log::SetLoggerError> {
|
||||
log::set_max_level(level);
|
||||
log::set_logger(logger)
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, Mutex},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use crate::{Component, ModuleRuntime, module::Module};
|
||||
|
||||
pub struct Manager {
|
||||
modules: Vec<Module>,
|
||||
components: HashMap<&'static str, Box<dyn Component>>,
|
||||
}
|
||||
|
||||
// static mut MANAGER_RUNTIME: Option<Arc<Mutex<Manager>>> = None;
|
||||
|
||||
impl Manager {
|
||||
/// Create Manager, and run initilization for each Module
|
||||
#[allow(static_mut_refs)]
|
||||
pub fn run<'a>(modules: Vec<Module>) {
|
||||
let this: Self = Self::load_modules(modules);
|
||||
let components = this.components.clone();
|
||||
|
||||
let this = Arc::new(Mutex::new(this));
|
||||
|
||||
let mut runtimes: Vec<Box<dyn ModuleRuntime>> = Vec::new();
|
||||
|
||||
for (name, component) in components {
|
||||
let module_runtime = component.start_runtime(this.clone());
|
||||
if let Some(module_runtime) = module_runtime {
|
||||
info!("Initialized {}", name);
|
||||
runtimes.push(module_runtime);
|
||||
}
|
||||
}
|
||||
|
||||
Self::join(&mut runtimes);
|
||||
}
|
||||
|
||||
pub fn load_modules<'a>(modules: Vec<Module>) -> Self {
|
||||
let module_count = modules.len();
|
||||
let mut this = Self {
|
||||
modules,
|
||||
components: HashMap::new(),
|
||||
};
|
||||
|
||||
// let mut runtimes = Vec::new();
|
||||
|
||||
for i in 0..module_count {
|
||||
info!("Importing module {}", i);
|
||||
// let this_lock = .unwrap();
|
||||
let component_func = if let Ok(component_func) = this.modules[i]
|
||||
.get_symbol::<fn() -> HashMap<&'static str, Box<dyn Component>>>(b"get_components")
|
||||
{
|
||||
component_func
|
||||
} else {
|
||||
warn!("get_components function not found");
|
||||
continue;
|
||||
};
|
||||
|
||||
let components = component_func();
|
||||
|
||||
info!("[{i}] Loaded {} components", components.len());
|
||||
|
||||
this.components.extend(components);
|
||||
}
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
/// Iterateratively loop through all runtimes, until all are finished executing
|
||||
pub fn join(runtimes: &mut Vec<Box<dyn ModuleRuntime>>) {
|
||||
// let mut len = runtimes.len().clone();
|
||||
while runtimes.len() > 0 {
|
||||
runtimes.retain(|runtime| runtime.is_running());
|
||||
|
||||
thread::sleep(Duration::from_micros(100));
|
||||
}
|
||||
}
|
||||
|
||||
// pub extern "C" fn test1234(&self, float: f32) {
|
||||
// info!("Manager Test Sucsessfull! {}", float.powf(2.));
|
||||
// }
|
||||
|
||||
// #[allow(static_mut_refs, improper_ctypes_definitions)]
|
||||
// pub extern "C" fn get_manager() -> Arc<Mutex<Manager>> {
|
||||
// unsafe { MANAGER_RUNTIME.clone().unwrap() }
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
mod logger;
|
||||
mod manager;
|
||||
mod module;
|
||||
|
||||
// use std::any::Any;
|
||||
|
||||
pub use logger::setup_logger;
|
||||
pub use manager::Manager;
|
||||
pub use module::Module;
|
||||
|
||||
pub trait Interface {
|
||||
fn as_any(self: Box<Self>) -> Box<dyn std::any::Any>;
|
||||
}
|
||||
|
||||
/// "Module Interface" helper macro that creates a struct with function pointers
|
||||
/// Useful for defining and requiring modules' functions accross FFI boundry.
|
||||
#[macro_export]
|
||||
macro_rules! module_interface {
|
||||
($(#[$struct_meta:meta])* $interface_name:ident { $($(#[$fn_meta:meta])* fn $fn_name:ident $(<$($gen:ident),+ $(,)?>)?($($arg:ident : $ty:ty),* $(,)?) $(-> $ret:ty)? $(where $($where_clause:tt)*)?);* $(;)? }) => {
|
||||
|
||||
#[repr(C)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, Copy)]
|
||||
#[allow(improper_ctypes_definitions)]
|
||||
$(#[$struct_meta])*
|
||||
pub struct $interface_name {
|
||||
$(
|
||||
// This line will FAIL TO COMPILE if you use generics in the macro input.
|
||||
// You MUST use concrete types like *mut c_void for "generic" data.
|
||||
$fn_name: extern "C" fn($($ty),*) $(-> $ret)?,
|
||||
)*
|
||||
}
|
||||
|
||||
impl $interface_name {
|
||||
$(
|
||||
#[inline(always)]
|
||||
$(#[$fn_meta])* // Propagate function attributes
|
||||
// This is the fix for the `impl` block.
|
||||
// It adds the captured generics and where-clause to the wrapper function.
|
||||
pub fn $fn_name $(<$($gen),+>)? (&self, $($arg: $ty),*) $(-> $ret)?
|
||||
$(where $($where_clause)*)?
|
||||
{
|
||||
(self.$fn_name)($($arg),*)
|
||||
}
|
||||
)*
|
||||
|
||||
/// Create from raw function pointers
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure all function pointers are valid and have
|
||||
/// the correct signatures
|
||||
pub fn from_raw(
|
||||
$($fn_name: extern "C" fn($($ty),*) $(-> $ret)?),*
|
||||
) -> Self {
|
||||
Self {
|
||||
$($fn_name),*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::module::Interface for $interface_name {
|
||||
fn as_any(self: Box<Self>) -> Box<dyn std::any::Any> {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
use libloading::{Library, Symbol};
|
||||
|
||||
use crate::{ModuleError, module::logger::SetupLogger};
|
||||
|
||||
pub struct Module {
|
||||
// name: String,
|
||||
lib: Library,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
pub fn new(path: &str) -> Result<Self, ModuleError> {
|
||||
let lib = unsafe { Library::new(&path) }.map_err(|e| ModuleError::LibLoadingError(e))?;
|
||||
|
||||
let this = Self {
|
||||
// name: path.to_owned(),
|
||||
lib,
|
||||
};
|
||||
|
||||
if let Ok(setup_logger) = this.get_symbol::<SetupLogger>(b"setup_logger") {
|
||||
setup_logger(log::logger(), log::max_level()).map_err(|e| ModuleError::LogError(e))?;
|
||||
} else {
|
||||
warn!("setup_logger not found");
|
||||
}
|
||||
|
||||
Ok(this)
|
||||
}
|
||||
pub fn get_symbol<T>(&self, symbol: &[u8]) -> Result<Symbol<'_, T>, ModuleError> {
|
||||
let symbol = unsafe { self.lib.get::<T>(symbol) }
|
||||
.map_err(|e| ModuleError::LinkError(format!("Failed to load symbol: {}", e)))?;
|
||||
|
||||
Ok(symbol)
|
||||
}
|
||||
// pub fn get_interface<T>(&self) -> Result<T, ModuleError> {
|
||||
// if let Ok(interface_function) = self.get_symbol::<fn() -> T>(b"interface") {
|
||||
// Ok(interface_function())
|
||||
// } else {
|
||||
// Err(ModuleError::LinkError(format!(
|
||||
// "Interface function not found!"
|
||||
// )))
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// extern "C" fn test1234() {
|
||||
// info!("Test1234!");
|
||||
// }
|
||||
@@ -0,0 +1,3 @@
|
||||
mod server_runtime;
|
||||
|
||||
pub use server_runtime::ListenerRuntime;
|
||||
@@ -0,0 +1,77 @@
|
||||
use std::{
|
||||
io::Write,
|
||||
net::{TcpListener, TcpStream},
|
||||
sync::{Arc, Mutex},
|
||||
thread::{self, JoinHandle},
|
||||
};
|
||||
|
||||
use crate::ModuleRuntime;
|
||||
|
||||
use crate::Announcement;
|
||||
|
||||
pub struct ListenerRuntime {
|
||||
thread_handle: JoinHandle<()>,
|
||||
// listener: TcpListener,
|
||||
streams: Arc<Mutex<Vec<TcpStream>>>,
|
||||
// reader: BufReader<TcpListener>,
|
||||
// writer: BufWriter<TcpListener>,
|
||||
}
|
||||
|
||||
impl ListenerRuntime {
|
||||
pub fn new() -> ListenerRuntime {
|
||||
info!("Starting listener runtime on 127.0.0.1:1234");
|
||||
let listener = TcpListener::bind("127.0.0.1:1234").unwrap();
|
||||
let streams = Arc::new(Mutex::new(Vec::new()));
|
||||
|
||||
let streams_clone = streams.clone();
|
||||
|
||||
let thread_handle = thread::spawn(move || {
|
||||
let streams = streams_clone.clone();
|
||||
for stream in listener.incoming() {
|
||||
let stream = stream.unwrap();
|
||||
println!("New connection from {}", stream.peer_addr().unwrap());
|
||||
streams.lock().unwrap().push(stream);
|
||||
}
|
||||
});
|
||||
Self {
|
||||
thread_handle,
|
||||
streams,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&mut self, announcement: &Announcement) -> Result<(), std::io::Error> {
|
||||
let bytes = announcement.encode();
|
||||
|
||||
let mut streams = self.streams.lock().unwrap();
|
||||
|
||||
for stream in streams.iter_mut() {
|
||||
stream.write_all(&u32::to_be_bytes(bytes.len() as u32))?;
|
||||
stream.write_all(&bytes)?;
|
||||
stream.flush()?;
|
||||
}
|
||||
|
||||
println!("Announcement {:?} sent", announcement);
|
||||
|
||||
Ok(())
|
||||
|
||||
// self.stream
|
||||
// .write_all(&u32::to_be_bytes(bytes.len() as u32))?;
|
||||
// self.stream.write_all(&bytes)?;
|
||||
// self.stream.flush()?;
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleRuntime for ListenerRuntime {
|
||||
// fn init(&mut self) {}
|
||||
|
||||
fn is_running(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn kill(self: Box<Self>) {
|
||||
if !self.thread_handle.is_finished() {
|
||||
let _ = self.thread_handle.join();
|
||||
}
|
||||
// drop(self);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user