Composed gui, data and network
This commit is contained in:
parent
93ab48db81
commit
f2271c1037
@ -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" }
|
||||||
@ -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())
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,2 +1,6 @@
|
|||||||
mod cycled_buffer;
|
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> {
|
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()
|
||||||
|
|||||||
@ -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>>)>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user