ptth/crates/ptth_server_gui/src/main.rs

204 lines
4.6 KiB
Rust

use std::{
collections::*,
path::PathBuf,
};
use fltk::{
app,
button::Button,
enums::CallbackTrigger,
frame::Frame,
input::*,
prelude::*,
window::Window
};
use tokio::{
sync::oneshot,
};
struct ServerInstance {
task: tokio::task::JoinHandle <()>,
shutdown_tx: oneshot::Sender <()>,
}
#[derive (Clone, Copy)]
enum Message {
RunServer,
StopServer,
}
fn main ()
{
let rt = tokio::runtime::Runtime::new ().unwrap ();
tracing_subscriber::fmt::init ();
let mut server_instance = None;
// let shutdown_rx = ptth_core::graceful_shutdown::init ();
let (fltk_tx, fltk_rx) = app::channel::<Message> ();
let app = app::App::default();
let mut wind = Window::new (100, 100, 500, 180, "PTTH server");
let config_file_opt = ptth_server::load_toml::load::<ConfigFile, _> ("./config/ptth_server.toml").ok ();
let mut gui = Gui::new (fltk_tx, config_file_opt.as_ref ());
gui.set_server_running (false);
wind.end ();
wind.show ();
while app.wait () {
match fltk_rx.recv () {
Some (Message::RunServer) => {
let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel ();
let config_file = ptth_server::ConfigFile {
name: gui.input_name.value ().to_string (),
api_key: gui.input_api_key.value ().to_string (),
relay_url: gui.input_relay_url.value ().to_string (),
file_server_root: PathBuf::from (gui.input_file_server_root.value ()),
file_server_roots: config_file_opt.as_ref ()
.map (|cf| cf.file_server_roots.clone ())
.unwrap_or_else (|| Default::default ()),
throttle_upload: false,
client_keys: Default::default (),
allow_any_client: true,
};
let task = rt.spawn (async {
if let Err (e) = ptth_server::run_server (
config_file,
shutdown_rx,
None,
None
).await
{
tracing::error! ("ptth_server crashed: {}", e);
}
});
server_instance.replace (Some (ServerInstance {
task,
shutdown_tx,
}));
gui.set_server_running (true);
},
Some (Message::StopServer) => {
server_instance.replace (None);
gui.set_server_running (false);
},
None => (),
}
}
}
struct Gui {
frame: Frame,
but_run: Button,
but_stop: Button,
input_name: Input,
input_relay_url: Input,
input_file_server_root: Input,
input_api_key: SecretInput,
}
#[derive (Default, serde::Deserialize)]
pub struct ConfigFile {
pub name: Option <String>,
pub api_key: String,
pub relay_url: Option <String>,
pub file_server_root: Option <PathBuf>,
pub file_server_roots: BTreeMap <String, PathBuf>,
}
impl Gui {
fn new (
fltk_tx: app::Sender <Message>,
config_file_opt: Option <&ConfigFile>,
)
-> Self
{
let mut input_name = Input::new (200, 10, 290, 20, "name");
input_name.set_value ("my_ptth_server");
let mut input_relay_url = Input::new (200, 40, 290, 20, "relay_url");
input_relay_url.set_value ("http://127.0.0.1:4000/7ZSFUKGV");
let mut input_file_server_root = Input::new (200, 70, 290, 20, "file_server_root");
input_file_server_root.set_value ("/home/user");
let mut input_api_key = SecretInput::new (200, 100, 290, 20, "api_key");
input_api_key.set_value ("");
let mut but_run = Button::new (10, 130, 90, 40, "Run");
but_run.set_trigger (CallbackTrigger::Changed);
but_run.emit (fltk_tx, Message::RunServer);
let frame = Frame::new (110, 130, 280, 40, "");
let mut but_stop = Button::new (400, 130, 90, 40, "Stop");
but_stop.set_trigger (CallbackTrigger::Changed);
but_stop.emit (fltk_tx, Message::StopServer);
if let Some (config_file) = config_file_opt
{
if let Some (v) = config_file.name.as_ref () {
input_name.set_value (v);
}
input_api_key.set_value (&config_file.api_key);
if let Some (v) = config_file.relay_url.as_ref () {
input_relay_url.set_value (v);
}
if let Some (v) = config_file.file_server_root.as_ref () {
if let Some (v) = v.to_str () {
input_file_server_root.set_value (v);
}
}
}
Self {
frame,
but_run,
but_stop,
input_name,
input_relay_url,
input_file_server_root,
input_api_key,
}
}
fn set_server_running (&mut self, b: bool) {
self.frame.set_label (if b {
"Running"
}
else {
"Stopped"
});
set_active (&mut self.but_run, ! b);
set_active (&mut self.but_stop, b);
self.but_run.set (b);
self.but_stop.set (! b);
set_active (&mut self.input_name, ! b);
set_active (&mut self.input_relay_url, ! b);
set_active (&mut self.input_file_server_root, ! b);
set_active (&mut self.input_api_key, ! b);
}
}
fn set_active <W: WidgetExt> (w: &mut W, b: bool) {
if b {
w.activate ();
}
else {
w.deactivate ();
}
}