Skip to content

Commit

Permalink
Merge pull request #241 from Berrysoft/remove-callback
Browse files Browse the repository at this point in the history
Remove callback
  • Loading branch information
Berrysoft authored Mar 10, 2024
2 parents 676d2bc + 25467cc commit aa1f57a
Show file tree
Hide file tree
Showing 18 changed files with 277 additions and 285 deletions.
141 changes: 63 additions & 78 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ chrono = { version = "0.4", default-features = false, features = [
clap = { version = "4", features = ["derive"] }
dirs = "5"
log = "0.4"
base64 = "0.21"
base64 = "0.22"

futures-core = "0.3"
futures-util = "0.3"
Expand All @@ -70,6 +70,5 @@ objc = "0.2"
core-foundation = "0.9"
system-configuration = "0.6"

windows = "0.53"
windows = "0.54"
winresource = "0.1"

4 changes: 2 additions & 2 deletions macbundle/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
<string>tunet-gui</string>

<key>CFBundleVersion</key>
<string>0.9.2</string>
<string>0.9.3</string>
<key>CFBundleShortVersionString</key>
<string>0.9.2</string>
<string>0.9.3</string>

<key>LSMinimumSystemVersion</key>
<string>11.7</string>
Expand Down
2 changes: 1 addition & 1 deletion tunet-cui/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tunet-cui"
version = "0.9.2"
version = "0.9.3"
description = "Tsinghua University network CUI"
edition.workspace = true
authors.workspace = true
Expand Down
85 changes: 27 additions & 58 deletions tunet-cui/src/event.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
use anyhow::Result;
pub use crossterm::event::Event as TerminalEvent;
use crossterm::event::{KeyCode, MouseButton, MouseEventKind};
use futures_util::{pin_mut, Stream, StreamExt};
use crossterm::event::{EventStream, KeyCode, MouseButton, MouseEventKind};
use futures_util::StreamExt;
use ratatui::layout::Rect;
use std::{
pin::Pin,
task::{Context, Poll},
};
use tokio::sync::mpsc::*;
use tunet_model::*;

Expand All @@ -19,23 +15,21 @@ pub enum EventType {

pub struct Event {
pub model: Model,
tx: Sender<Result<EventType>>,
rx: Receiver<Result<EventType>>,
event: EventStream,
mrx: Receiver<Action>,
urx: Receiver<UpdateMsg>,
}

impl Event {
pub fn new() -> Result<Self> {
let (tx, rx) = channel(32);
let (mtx, mrx) = channel(32);
let mut e = Self {
model: Model::new(mtx)?,
tx,
rx,
};
e.attach_callback();
e.spawn_terminal_event();
e.spawn_model_action(mrx);
Ok(e)
let (utx, urx) = channel(32);
Ok(Self {
model: Model::new(mtx, utx)?,
event: EventStream::new(),
mrx,
urx,
})
}

pub fn start(&self) {
Expand All @@ -45,39 +39,22 @@ impl Event {
self.spawn_details();
}

#[allow(clippy::single_match)]
fn attach_callback(&mut self) {
let tx = self.tx.clone();
self.model.update = Some(Box::new(move |_model, msg| match msg {
UpdateMsg::State => {
let tx = tx.clone();
tokio::spawn(async move { tx.send(Ok(EventType::UpdateState)).await.ok() });
}
_ => {}
}));
}

fn spawn_terminal_event(&self) {
let tx = self.tx.clone();
tokio::spawn(async move {
let stream = crossterm::event::EventStream::new();
pin_mut!(stream);
while let Some(e) = stream.next().await {
tx.send(e.map(EventType::TerminalEvent).map_err(anyhow::Error::from))
.await?;
}
Ok::<_, anyhow::Error>(())
});
}

fn spawn_model_action(&self, mut mrx: Receiver<Action>) {
let tx = self.tx.clone();
tokio::spawn(async move {
while let Some(a) = mrx.recv().await {
tx.send(Ok(EventType::ModelAction(a))).await?;
pub async fn next_event(&mut self) -> Result<Option<EventType>> {
loop {
tokio::select! {
e = self.event.next() => break if let Some(e) = e {
Ok(Some(EventType::TerminalEvent(e?)))
} else {
Ok(None)
},
a = self.mrx.recv() => break Ok(a.map(EventType::ModelAction)),
u = self.urx.recv() => match u {
None => break Ok(None),
Some(UpdateMsg::State) => break Ok(Some(EventType::UpdateState)),
_ => {}
},
}
Ok::<_, anyhow::Error>(())
});
}
}

fn spawn_watch_status(&self) {
Expand Down Expand Up @@ -153,11 +130,3 @@ impl Event {
true
}
}

impl Stream for Event {
type Item = Result<EventType>;

fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.rx.poll_recv(cx)
}
}
3 changes: 1 addition & 2 deletions tunet-cui/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use crossterm::{
execute,
terminal::*,
};
use futures_util::TryStreamExt;
use ratatui::{
backend::{Backend, CrosstermBackend},
layout::*,
Expand Down Expand Up @@ -87,7 +86,7 @@ async fn main_loop<B: Backend>(
_ = interval.tick() => {
terminal.draw(|f| view::draw(&event.model, f))?;
}
e = event.try_next() => {
e = event.next_event() => {
if let Some(e) = e? {
if !event.handle(e, terminal.size()?) {
break;
Expand Down
2 changes: 1 addition & 1 deletion tunet-flutter/lib/runtime.dart
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class ManagedRuntime extends NotifyPropertyChanged {
} else {
await RustLib.init();
}
final runtime = await Runtime.newRuntime();
final runtime = Runtime();
return ManagedRuntime(runtime: runtime);
}

Expand Down
2 changes: 1 addition & 1 deletion tunet-flutter/native/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ anyhow = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread"] }
log = { workspace = true }
chrono = { workspace = true }
flutter_rust_bridge = { version = "=2.0.0-dev.26", features = ["chrono"] }
flutter_rust_bridge = { version = "=2.0.0-dev.27", features = ["chrono"] }

[target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.13"
Expand Down
132 changes: 76 additions & 56 deletions tunet-flutter/native/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,14 @@ pub struct RuntimeStartConfig {
}

pub struct Runtime {
pub rx: RustOpaque<Mutex<Option<mpsc::Receiver<Action>>>>,
pub arx: RustOpaque<Mutex<Option<mpsc::Receiver<Action>>>>,
pub urx: RustOpaque<Mutex<Option<mpsc::Receiver<UpdateMsg>>>>,
pub model: RustOpaque<Mutex<Model>>,
pub handle: RustOpaque<Mutex<Option<Handle>>>,
}

impl Runtime {
#[frb(sync)]
pub fn new() -> Result<Runtime> {
#[cfg(target_os = "android")]
android_logger::init_once(
Expand All @@ -144,18 +146,21 @@ impl Runtime {
.level_filter(log::LevelFilter::Trace)
.init()?;

let (tx, rx) = mpsc::channel(32);
let model = Model::new(tx)?;
let (atx, arx) = mpsc::channel(32);
let (utx, urx) = mpsc::channel(32);
let model = Model::new(atx, utx)?;
Ok(Self {
rx: RustOpaque::new(Mutex::new(Some(rx))),
arx: RustOpaque::new(Mutex::new(Some(arx))),
urx: RustOpaque::new(Mutex::new(Some(urx))),
model: RustOpaque::new(Mutex::new(model)),
handle: RustOpaque::new(Mutex::new(None)),
})
}

pub fn start(&self, sink: StreamSink<UpdateMsgWrap>, config: RuntimeStartConfig) {
let model = self.model.clone();
let mut rx = self.rx.lock().unwrap().take().unwrap();
let mut arx = self.arx.lock().unwrap().take().unwrap();
let mut urx = self.urx.lock().unwrap().take().unwrap();
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(1)
.enable_all()
Expand All @@ -166,66 +171,81 @@ impl Runtime {
std::thread::spawn(move || {
runtime.block_on(async {
{
let mut model = model.lock().unwrap();
model.update = Some(Box::new(move |model, msg| {
let msg = match msg {
UpdateMsg::Credential => {
UpdateMsgWrap::Credential(model.username.clone())
}
UpdateMsg::State => UpdateMsgWrap::State(model.state),
UpdateMsg::Status => UpdateMsgWrap::Status(model.status.to_string()),
UpdateMsg::Log => UpdateMsgWrap::Log(model.log.to_string()),
UpdateMsg::Flux => UpdateMsgWrap::Flux(model.flux.clone()),
UpdateMsg::Online => UpdateMsgWrap::Online(
model
.users
.iter()
.map(|u| NetUserWrap {
address: u.address.into(),
address_v6: u.address_v6.into(),
login_time: u.login_time,
mac_address: u
.mac_address
.map(|addr| addr.to_string())
.unwrap_or_default(),
flux: u.flux,
is_local: model
.mac_addrs
let model = model.clone();
tokio::spawn(async move {
while let Some(msg) = urx.recv().await {
let msg = {
let model = model.lock().unwrap();
match msg {
UpdateMsg::Credential => {
UpdateMsgWrap::Credential(model.username.clone())
}
UpdateMsg::State => UpdateMsgWrap::State(model.state),
UpdateMsg::Status => {
UpdateMsgWrap::Status(model.status.to_string())
}
UpdateMsg::Log => UpdateMsgWrap::Log(model.log.to_string()),
UpdateMsg::Flux => UpdateMsgWrap::Flux(model.flux.clone()),
UpdateMsg::Online => UpdateMsgWrap::Online(
model
.users
.iter()
.any(|it| Some(it) == u.mac_address.as_ref()),
})
.collect(),
),
UpdateMsg::Details => UpdateMsgWrap::Details(model.details.clone(), {
let data = DetailDaily::new(&model.details);
DetailDailyWrap {
details: data
.details
.into_iter()
.map(|(date, flux)| DetailDailyPoint {
day: date.day(),
flux,
.map(|u| NetUserWrap {
address: u.address.into(),
address_v6: u.address_v6.into(),
login_time: u.login_time,
mac_address: u
.mac_address
.map(|addr| addr.to_string())
.unwrap_or_default(),
flux: u.flux,
is_local: model
.mac_addrs
.iter()
.any(|it| Some(it) == u.mac_address.as_ref()),
})
.collect(),
),
UpdateMsg::Details => {
UpdateMsgWrap::Details(model.details.clone(), {
let data = DetailDaily::new(&model.details);
DetailDailyWrap {
details: data
.details
.into_iter()
.map(|(date, flux)| DetailDailyPoint {
day: date.day(),
flux,
})
.collect(),
now_month: data.now.month(),
now_day: data.now.day(),
max_flux: data.max_flux,
}
})
.collect(),
now_month: data.now.month(),
now_day: data.now.day(),
max_flux: data.max_flux,
}
UpdateMsg::LogBusy => UpdateMsgWrap::LogBusy(model.log_busy()),
UpdateMsg::OnlineBusy => {
UpdateMsgWrap::OnlineBusy(model.online_busy())
}
UpdateMsg::DetailBusy => {
UpdateMsgWrap::DetailBusy(model.detail_busy())
}
}
}),
UpdateMsg::LogBusy => UpdateMsgWrap::LogBusy(model.log_busy()),
UpdateMsg::OnlineBusy => UpdateMsgWrap::OnlineBusy(model.online_busy()),
UpdateMsg::DetailBusy => UpdateMsgWrap::DetailBusy(model.detail_busy()),
};
sink.add(msg).unwrap();
}));

};
sink.add(msg).unwrap();
}
});
}
{
let model = model.lock().unwrap();
if (!config.username.is_empty()) && (!config.password.is_empty()) {
model.queue(Action::Credential(config.username, config.password));
}
model.queue(Action::Status(Some(config.status)));
model.queue(Action::Timer);
}
while let Some(action) = rx.recv().await {
while let Some(action) = arx.recv().await {
log::debug!("received action: {:?}", action);
model.lock().unwrap().handle(action);
}
Expand Down
4 changes: 2 additions & 2 deletions tunet-flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 0.9.2+1
version: 0.9.3+1

environment:
sdk: ">=3.0.0 <4.0.0"
Expand All @@ -31,7 +31,7 @@ dependencies:
sdk: flutter

ffi: ^2.1.0
flutter_rust_bridge: 2.0.0-dev.26
flutter_rust_bridge: 2.0.0-dev.27
meta: ^1.9.1
uuid: ^4.1.0
freezed_annotation: ^2.2.0
Expand Down
2 changes: 1 addition & 1 deletion tunet-gui/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tunet-gui"
version = "0.9.2"
version = "0.9.3"
description = "Tsinghua University network GUI"
edition.workspace = true
authors.workspace = true
Expand Down
Loading

0 comments on commit aa1f57a

Please sign in to comment.