Composed gui, data and network

This commit is contained in:
Andrew Golovashevich 2026-03-10 22:33:04 +03:00
parent 93ab48db81
commit f2271c1037
9 changed files with 262 additions and 44 deletions

View File

@ -8,7 +8,8 @@ workspace = true
[dependencies] [dependencies]
bgtu-networks-2-network-abstract = { path = "../network/abstract" } bgtu-networks-2-network-abstract = { path = "../network/abstract" }
bgtu-networks-2-gui-abstract = { path = "../gui/abstract" } bgtu-networks-2-gui-egui = { path = "../gui/egui" }
bgtu-networks-2-data = { path = "../data" }
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
bgtu-networks-2-network-windows = { path = "../network/windows" } bgtu-networks-2-network-windows = { path = "../network/windows" }

View File

@ -1,8 +1,9 @@
use bgtu_networks_2_network_abstract::{Address, NetworkContext, NetworkScope, ServersContext}; use bgtu_networks_2_data::SynchronizedServersStorage;
use bgtu_networks_2_network_abstract::{NetworkContext, NetworkScope};
use bgtu_networks_2_network_windows::winsocks_scope_2_2; use bgtu_networks_2_network_windows::winsocks_scope_2_2;
use bgtu_networks_2_gui_abstract::ServersStorage; use std::sync::Arc;
use std::thread;
// mod data; use bgtu_networks_2_gui_egui::run_eframe_gui;
fn main() { fn main() {
winsocks_scope_2_2(NetworkMain {}); winsocks_scope_2_2(NetworkMain {});
@ -14,34 +15,16 @@ impl NetworkScope for NetworkMain {
type R = (); type R = ();
fn run<Ctx: NetworkContext>(self, network: &mut Ctx) -> Self::R { fn run<Ctx: NetworkContext>(self, network: &mut Ctx) -> Self::R {
let mut servers = Servers2NetworkCtxTestImpl { let mut storage = Arc::new(SynchronizedServersStorage::<Ctx::Address>::new(10));
loopback: Ctx::Address::parse("127.0.0.1").unwrap(),
ros_com_nadzor: Ctx::Address::parse("ya.ru").unwrap(), thread::scope(|s| {
}; s.spawn(|| {
Ctx::run_ping_eventloop(&mut storage.as_ref().new_network_ctx());
});
run_eframe_gui(&mut storage.new_gui_ctx());
});
Ctx::run_ping_eventloop(&mut servers)
} }
} }
struct Servers2NetworkCtxTestImpl<A: Address> {
loopback: A,
ros_com_nadzor: A,
}
impl<A: Address> ServersContext<A> for Servers2NetworkCtxTestImpl<A> {
fn start_measuring(&mut self) -> (u64, impl Iterator<Item = A>) {
return (
0,
[self.loopback.clone(), self.ros_com_nadzor.clone()].into_iter(),
);
}
fn report_ping(&mut self, addr: A, id: u64, ping_ms: u128) {
println!("{} {ping_ms} ms", addr.to_string())
}
fn report_error(&mut self, addr: A, id: u64) {
println!("{} err", addr.to_string())
}
}

View File

@ -1,2 +1,6 @@
mod cycled_buffer; mod cycled_buffer;
mod unprotected; mod unprotected;
mod synchronized;
pub use unprotected::ServersStorage;
pub use synchronized::SynchronizedServersStorage;

View File

@ -0,0 +1,28 @@
use super::rw_lock::LockReadGuard;
pub(super) struct SyncedIterator<'g, It: Iterator> {
it: Option<(It, LockReadGuard<'g>)>,
}
impl<'g, It: Iterator> SyncedIterator<'g, It> {
pub fn wrap(it: It, guard: LockReadGuard<'g>) -> Self {
return Self {
it: Some((it, guard)),
};
}
}
impl<It: Iterator> Iterator for SyncedIterator<'_, It> {
type Item = It::Item;
fn next(&mut self) -> Option<Self::Item> {
match &mut self.it {
None => return None,
Some((it, s)) => match it.next() {
Some(e) => return Some(e),
None => {
self.it = None;
return None;
}
},
}
}
}

View File

@ -0,0 +1,89 @@
use crate::ServersStorage;
use crate::synchronized::iterator::SyncedIterator;
use bgtu_networks_2_gui_abstract::ServersStorage as ServersGuiCtx;
use bgtu_networks_2_network_abstract::{Address, ServersContext as ServersNetworkCtx};
use std::cell::UnsafeCell;
use std::hash::Hash;
use std::ptr::NonNull;
mod iterator;
mod rw_lock;
use rw_lock::CustomRwLock;
pub struct SynchronizedServersStorage<A: Address + Hash + Eq> {
mutex: CustomRwLock,
data: UnsafeCell<ServersStorage<A>>,
}
unsafe impl<A: Address + Hash + Eq> Sync for SynchronizedServersStorage<A> {}
impl<A: Address + Hash + Eq> SynchronizedServersStorage<A> {
pub fn new(history_capacity: usize) -> Self {
return Self {
mutex: CustomRwLock::new(),
data: UnsafeCell::new(ServersStorage::new(history_capacity)),
};
}
pub fn new_network_ctx(&self) -> impl ServersNetworkCtx<A> {
return _Impl { data: self };
}
pub fn new_gui_ctx(&self) -> impl ServersGuiCtx<Address = A> {
return _Impl { data: self };
}
}
struct _Impl<'o, A: Address + Hash + Eq> {
data: &'o SynchronizedServersStorage<A>,
}
impl<A: Address + Hash + Eq> _Impl<'_, A> {
unsafe fn get_unprotected(&self) -> &mut ServersStorage<A> {
return NonNull::new_unchecked(self.data.data.get()).as_mut();
}
}
impl<A: Address + Hash + Eq> ServersNetworkCtx<A> for _Impl<'_, A> {
fn start_measuring(&mut self) -> (u64, impl Iterator<Item = A>) {
let w_lock_scope = self.data.mutex.write();
let data = unsafe { self.get_unprotected() }.start_measuring();
let r_lock_scope = w_lock_scope.write_to_read();
return (data.0, SyncedIterator::wrap(data.1, r_lock_scope));
}
fn report_ping(&mut self, addr: A, id: u64, ping_ms: u128) {
let lock_scope = self.data.mutex.read();
unsafe { self.get_unprotected() }.report_ping(addr, id, ping_ms);
}
fn report_error(&mut self, addr: A, id: u64) {
let lock_scope = self.data.mutex.read();
unsafe { self.get_unprotected() }.report_error(addr, id);
}
}
impl<A: Address + Hash + Eq> ServersGuiCtx for _Impl<'_, A> {
type Address = A;
fn add_server(&mut self, addr: Self::Address, memo: String) {
let w_lock_scope = self.data.mutex.write();
unsafe { self.get_unprotected() }.add_server(addr, memo);
}
fn remove_server(&mut self, addr: &Self::Address) {
let w_lock_scope = self.data.mutex.write();
unsafe { self.get_unprotected() }.remove_server(addr);
}
fn iter_servers(
&self,
) -> impl Iterator<Item = (&Self::Address, &str, impl Iterator<Item = Option<u128>>)> {
let r_lock_scope = self.data.mutex.read();
return SyncedIterator::wrap(
unsafe { self.get_unprotected() }.iter_servers(),
r_lock_scope,
);
}
}

View File

@ -0,0 +1,103 @@
use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut};
use std::sync::{Condvar, Mutex};
enum RwLockState {
Free,
Write,
Read(usize),
}
pub(super) struct CustomRwLock {
counter: Mutex<RwLockState>,
condvar: Condvar,
}
impl CustomRwLock {
pub fn new() -> Self {
return Self {
counter: Mutex::new(RwLockState::Free),
condvar: Condvar::new(),
};
}
pub fn write(&self) -> LockWriteGuard<'_> {
let mut lock_scope = self.counter.lock().unwrap();
loop {
match lock_scope.deref() {
RwLockState::Free => {
*lock_scope.deref_mut() = RwLockState::Write;
return LockWriteGuard { parent: self };
}
RwLockState::Write | RwLockState::Read(_) => {
lock_scope = self.condvar.wait(lock_scope).unwrap();
continue;
}
}
}
}
pub fn read(&self) -> LockReadGuard<'_> {
let mut lock_scope = self.counter.lock().unwrap();
loop {
match lock_scope.deref() {
RwLockState::Free => {
*lock_scope.deref_mut() = RwLockState::Read(1);
return LockReadGuard { parent: self };
}
RwLockState::Read(cnt) => {
*lock_scope.deref_mut() = RwLockState::Read(*cnt + 1);
return LockReadGuard { parent: self };
}
RwLockState::Write => {
lock_scope = self.condvar.wait(lock_scope).unwrap();
continue;
}
}
}
}
}
pub(super) struct LockWriteGuard<'p> {
parent: &'p CustomRwLock,
}
impl<'p> LockWriteGuard<'p> {
pub fn write_to_read(self) -> LockReadGuard<'p> {
*self.parent.counter.lock().unwrap().deref_mut() = RwLockState::Read(1);
self.parent.condvar.notify_all();
let new_guard = LockReadGuard {
parent: self.parent,
};
let _ = ManuallyDrop::new(self);
return new_guard;
}
}
impl Drop for LockWriteGuard<'_> {
fn drop(&mut self) {
*self.parent.counter.lock().unwrap().deref_mut() = RwLockState::Free;
self.parent.condvar.notify_all();
}
}
pub(super) struct LockReadGuard<'p> {
parent: &'p CustomRwLock,
}
impl Drop for LockReadGuard<'_> {
fn drop(&mut self) {
let mut lock_scope = self.parent.counter.lock().unwrap();
match lock_scope.deref() {
RwLockState::Free | RwLockState::Write => panic!("Unexpected state"),
RwLockState::Read(cnt) => {
if *cnt - 1 == 0 {
*lock_scope.deref_mut() = RwLockState::Free;
self.parent.condvar.notify_all();
} else {
*lock_scope.deref_mut() = RwLockState::Read(*cnt - 1);
}
}
}
}
}

View File

@ -11,6 +11,14 @@ pub struct ServersStorage<A: Address + Hash + Eq> {
} }
impl<A: Address + Hash + Eq> ServersStorage<A> { impl<A: Address + Hash + Eq> ServersStorage<A> {
pub fn new(history_capacity: usize) -> Self {
return Self {
history_capacity,
last_stored_req_id: 0,
map: HashMap::new(),
};
}
fn _get_offset(&self, req_id: u64) -> usize { fn _get_offset(&self, req_id: u64) -> usize {
return self.last_stored_req_id.wrapping_sub(req_id) as usize; return self.last_stored_req_id.wrapping_sub(req_id) as usize;
} }
@ -37,9 +45,9 @@ impl<A: Address + Hash + Eq> ServersNetworkCtx<A> for ServersStorage<A> {
} }
impl<A: Address + Hash + Eq> ServersGuiCtx for ServersStorage<A> { impl<A: Address + Hash + Eq> ServersGuiCtx for ServersStorage<A> {
type A = A; type Address = A;
fn add_server(&mut self, addr: Self::A, memo: String) { fn add_server(&mut self, addr: Self::Address, memo: String) {
if self.map.get(&addr).is_some() { if self.map.get(&addr).is_some() {
todo!() todo!()
}; };
@ -48,13 +56,13 @@ impl<A: Address + Hash + Eq> ServersGuiCtx for ServersStorage<A> {
.insert(addr, (memo, CycledBuffer::new(self.history_capacity))); .insert(addr, (memo, CycledBuffer::new(self.history_capacity)));
} }
fn remove_server(&mut self, addr: &Self::A) { fn remove_server(&mut self, addr: &Self::Address) {
self.map.remove(addr); self.map.remove(addr);
} }
fn iter_servers( fn iter_servers(
&self, &self,
) -> impl Iterator<Item = (&Self::A, &str, impl Iterator<Item = Option<u128>>)> { ) -> impl Iterator<Item = (&Self::Address, &str, impl Iterator<Item = Option<u128>>)> {
return self return self
.map .map
.iter() .iter()

View File

@ -1,11 +1,11 @@
use bgtu_networks_2_network_abstract::Address; use bgtu_networks_2_network_abstract::Address;
pub trait ServersStorage { pub trait ServersStorage {
type A: Address; type Address: Address;
fn add_server(&mut self, addr: Self::A, memo: String); fn add_server(&mut self, addr: Self::Address, memo: String);
fn remove_server(&mut self, addr: &Self::A); fn remove_server(&mut self, addr: &Self::Address);
// type TimeIterator: Iterator<Item = Option<u128>>; // type TimeIterator: Iterator<Item = Option<u128>>;
fn iter_servers(&self) -> impl Iterator<Item = (&Self::A, &str, impl Iterator<Item = Option<u128>>)>; fn iter_servers(&self) -> impl Iterator<Item = (&Self::Address, &str, impl Iterator<Item = Option<u128>>)>;
} }

View File

@ -1,10 +1,12 @@
pub trait Address: Sized + Clone { use std::hash::Hash;
pub trait Address: Sized + Clone + Send {
fn parse(raw: &str) -> Result<Self, String>; fn parse(raw: &str) -> Result<Self, String>;
fn to_string(&self) -> String; fn to_string(&self) -> String;
} }
pub trait NetworkContext { pub trait NetworkContext {
type Address: Address ; type Address: Address + Hash + Eq ;
fn run_ping_eventloop(ctx: &mut impl ServersContext<Self::Address>); fn run_ping_eventloop(ctx: &mut impl ServersContext<Self::Address>);
} }