Skip to content

Commit e0e9d73

Browse files
Adam GibsonAdam Gibson
Adam Gibson
authored and
Adam Gibson
committed
Add framework for starting server in background for GUI
Currently the server startup is replaced with a dummy sleep operation. Places a colored dot in the bottom right corner of the application window which indicates whether the server is stopped, started or running.
1 parent cb2ff36 commit e0e9d73

File tree

1 file changed

+86
-2
lines changed

1 file changed

+86
-2
lines changed

src/bin/gui.rs

+86-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
#![forbid(unsafe_code)]
33
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
44

5-
use eframe::egui::{self, RichText, Vec2, Window};
5+
use eframe::egui::{self, Color32, Ui, Pos2, RichText, Vec2, Window};
66
use tokio::runtime::Runtime;
77
use std::sync::{Arc, Mutex};
88
use std::thread;
9+
use tokio::time::Duration;
910
use rfd::FileDialog;
1011
use autct::autctactions::request_audit_verify;
1112
use autct::config::AutctConfig;
@@ -25,11 +26,19 @@ struct AutctVerifierApp {
2526
is_verif_loading: bool,
2627
verif_result: Arc<Mutex<Option<String>>>,
2728
verif_runtime: Arc<Runtime>,
29+
server_state: Arc<Mutex<ServerState>>,
2830
}
2931

3032
#[derive(Debug)]
3133
struct CustomError(String);
3234

35+
#[derive(PartialEq, Clone, Copy)]
36+
enum ServerState {
37+
NotStarted,
38+
Running,
39+
Ready,
40+
}
41+
3342
#[tokio::main]
3443
async fn main() -> eframe::Result {
3544
let mut myapp: AutctVerifierApp = AutctVerifierApp::default();
@@ -88,6 +97,64 @@ impl AutctVerifierApp {
8897
*result.lock().unwrap() = Some(res);
8998
});
9099
}
100+
101+
/// Starts the verification server in the background
102+
/// by calling std::process:Command
103+
fn start_server(&self) {
104+
let server_state = Arc::clone(
105+
&self.server_state);
106+
107+
// Spawn a new thread to run the process
108+
thread::spawn(move || {
109+
{
110+
let mut state = server_state.lock().unwrap();
111+
*state = ServerState::Running;
112+
}
113+
114+
// Simulate running the process
115+
// Replace this with the actual command,
116+
// `std::process::Command::new(
117+
// "./autct -k dummycontext:keysetfile -n network")`
118+
thread::sleep(Duration::from_secs(5));
119+
120+
// Need some kind of hook to trigger this independently,
121+
// because the above process is a daemon not a batch process.
122+
{
123+
let mut state = server_state.lock().unwrap();
124+
*state = ServerState::Ready;
125+
}
126+
});
127+
}
128+
129+
fn update_dot(&mut self, ctx: &egui::Context, dot_pos: &Pos2, dot_radius: f32) {
130+
// Determine the color of the dot based on the verification
131+
// server(called in the background)'s state:
132+
let process_state = *self.server_state.lock().unwrap();
133+
let dot_color = match process_state {
134+
ServerState::NotStarted => Color32::BLUE,
135+
ServerState::Running => Color32::YELLOW,
136+
ServerState::Ready => Color32::GREEN,
137+
};
138+
egui::Area::new("circle_area".into())
139+
.fixed_pos(*dot_pos)
140+
.show(ctx, |ui| {
141+
// Create an interactable area using `ui.allocate_response`
142+
let response = ui.allocate_response(
143+
Vec2::splat(dot_radius * 2.0),
144+
egui::Sense::click(),
145+
);
146+
147+
// Draw the circle
148+
let painter = ui.painter();
149+
painter.circle_filled(*dot_pos, dot_radius, dot_color);
150+
151+
// Handle click on the circle
152+
if response.clicked() && process_state == ServerState::NotStarted {
153+
println!("Circle clicked! Starting the process...");
154+
self.start_server();
155+
}
156+
});
157+
}
91158
}
92159

93160
impl Default for AutctVerifierApp {
@@ -103,6 +170,7 @@ impl Default for AutctVerifierApp {
103170
is_verif_loading: false,
104171
verif_result: Arc::new(Mutex::new(None)),
105172
verif_runtime: Arc::new(Runtime::new().unwrap()),
173+
server_state: Arc::new(Mutex::new(ServerState::NotStarted)),
106174
}
107175
}
108176
}
@@ -112,8 +180,24 @@ impl eframe::App for AutctVerifierApp {
112180
// Point of discussion: I think dark mode will work
113181
// a little better than light:
114182
//ctx.set_visuals(egui::Visuals::light());
115-
let available_height = ctx.available_rect().height();
116183

184+
// GUI does not respond to updates unless
185+
// user acts (e.g. mouse events), by default,
186+
// so force it:
187+
ctx.request_repaint();
188+
189+
// Calculate the correct center and radius
190+
// for the dot, and its reaction area:
191+
let screen_rect = ctx.screen_rect();
192+
let dot_pos = Pos2::new(screen_rect.max.x - 20.0,
193+
screen_rect.max.y - 20.0);
194+
// This is very close to the edge?:
195+
let dot_radius = 15.0;
196+
self.update_dot(ctx, &dot_pos, dot_radius);
197+
198+
// bottom section contains verification action and result.
199+
// use 25% of height:
200+
let available_height = ctx.available_rect().height();
117201
egui::TopBottomPanel::bottom("actionpanel")
118202
.min_height(available_height * 0.25)
119203
.show(ctx, |ui| {

0 commit comments

Comments
 (0)