Composed gui, data and network
This commit is contained in:
parent
93ab48db81
commit
f2271c1037
@ -8,7 +8,8 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
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]
|
||||
bgtu-networks-2-network-windows = { path = "../network/windows" }
|
||||
@ -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_gui_abstract::ServersStorage;
|
||||
|
||||
// mod data;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use bgtu_networks_2_gui_egui::run_eframe_gui;
|
||||
|
||||
fn main() {
|
||||
winsocks_scope_2_2(NetworkMain {});
|
||||
@ -14,34 +15,16 @@ impl NetworkScope for NetworkMain {
|
||||
type R = ();
|
||||
|
||||
fn run<Ctx: NetworkContext>(self, network: &mut Ctx) -> Self::R {
|
||||
let mut servers = Servers2NetworkCtxTestImpl {
|
||||
loopback: Ctx::Address::parse("127.0.0.1").unwrap(),
|
||||
ros_com_nadzor: Ctx::Address::parse("ya.ru").unwrap(),
|
||||
};
|
||||
let mut storage = Arc::new(SynchronizedServersStorage::<Ctx::Address>::new(10));
|
||||
|
||||
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())
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,2 +1,6 @@
|
||||
mod cycled_buffer;
|
||||
mod unprotected;
|
||||
mod unprotected;
|
||||
mod synchronized;
|
||||
|
||||
pub use unprotected::ServersStorage;
|
||||
pub use synchronized::SynchronizedServersStorage;
|
||||
28
data/src/synchronized/iterator.rs
Normal file
28
data/src/synchronized/iterator.rs
Normal 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;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
89
data/src/synchronized/mod.rs
Normal file
89
data/src/synchronized/mod.rs
Normal 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
103
data/src/synchronized/rw_lock.rs
Normal file
103
data/src/synchronized/rw_lock.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -11,6 +11,14 @@ pub struct ServersStorage<A: Address + Hash + Eq> {
|
||||
}
|
||||
|
||||
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 {
|
||||
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> {
|
||||
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() {
|
||||
todo!()
|
||||
};
|
||||
@ -48,13 +56,13 @@ impl<A: Address + Hash + Eq> ServersGuiCtx for ServersStorage<A> {
|
||||
.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);
|
||||
}
|
||||
|
||||
fn iter_servers(
|
||||
&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
|
||||
.map
|
||||
.iter()
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
use bgtu_networks_2_network_abstract::Address;
|
||||
|
||||
pub trait ServersStorage {
|
||||
type A: Address;
|
||||
type Address: Address;
|
||||
|
||||
fn add_server(&mut self, addr: Self::A, memo: String);
|
||||
fn remove_server(&mut self, addr: &Self::A);
|
||||
fn add_server(&mut self, addr: Self::Address, memo: String);
|
||||
fn remove_server(&mut self, addr: &Self::Address);
|
||||
|
||||
// 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>>)>;
|
||||
}
|
||||
|
||||
@ -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 to_string(&self) -> String;
|
||||
}
|
||||
|
||||
pub trait NetworkContext {
|
||||
type Address: Address ;
|
||||
type Address: Address + Hash + Eq ;
|
||||
|
||||
fn run_ping_eventloop(ctx: &mut impl ServersContext<Self::Address>);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user