Compare commits
9 Commits
cffb888ac8
...
800dbcb019
Author | SHA1 | Date |
---|---|---|
Trisha | 800dbcb019 | |
Trisha | 365c878a90 | |
Trisha | fb9b0c67f5 | |
Trisha | 436adb98ef | |
Trisha | de5338f4f2 | |
Trisha | e6273209f9 | |
Trisha | 81141e2faf | |
Trisha | 8c4e7d484c | |
Trisha | 1d9ef8f510 |
|
@ -246,6 +246,26 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-channel"
|
||||||
|
version = "0.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ct-logs"
|
name = "ct-logs"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
@ -345,20 +365,22 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fltk"
|
name = "fltk"
|
||||||
version = "1.2.8"
|
version = "1.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "889d9b2176b88c6f8f90ba64b0b030e52807ed1d6e416df0c15611225b40cc1d"
|
checksum = "14c92a8adbc0189c9cade37f90bb50b3023cdef1c0c4de7eb5c36238dfdd2a23"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
"crossbeam-channel",
|
||||||
"fltk-sys",
|
"fltk-sys",
|
||||||
"paste",
|
"paste",
|
||||||
|
"ttf-parser",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fltk-sys"
|
name = "fltk-sys"
|
||||||
version = "1.2.8"
|
version = "1.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e38b2f3fb23b4bd46fc492d5d8d099b0bf766a7ab5d18b8424d93089ae934a48"
|
checksum = "cbc9366cd150615afd138f261903e0029f40db720bceabe8e81bc7dac8f9cc11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cmake",
|
"cmake",
|
||||||
]
|
]
|
||||||
|
@ -2155,6 +2177,12 @@ version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
|
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ttf-parser"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c74c96594835e10fa545e2a51e8709f30b173a092bfd6036ef2cec53376244f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.14.0"
|
version = "1.14.0"
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp::min,
|
cmp::min,
|
||||||
collections::HashMap,
|
collections::*,
|
||||||
convert::{Infallible, TryFrom},
|
convert::{Infallible, TryFrom},
|
||||||
io::SeekFrom,
|
io::SeekFrom,
|
||||||
path::{
|
path::{
|
||||||
|
@ -56,6 +56,7 @@ use errors::FileServerError;
|
||||||
#[derive (Default)]
|
#[derive (Default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub file_server_root: PathBuf,
|
pub file_server_root: PathBuf,
|
||||||
|
pub file_server_roots: BTreeMap <String, PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FileServer {
|
pub struct FileServer {
|
||||||
|
@ -68,7 +69,7 @@ pub struct FileServer {
|
||||||
|
|
||||||
impl FileServer {
|
impl FileServer {
|
||||||
pub fn new (
|
pub fn new (
|
||||||
file_server_root: PathBuf,
|
config: Config,
|
||||||
asset_root: &Path,
|
asset_root: &Path,
|
||||||
name: String,
|
name: String,
|
||||||
metrics_interval: Arc <ArcSwap <Option <metrics::Interval>>>,
|
metrics_interval: Arc <ArcSwap <Option <metrics::Interval>>>,
|
||||||
|
@ -76,9 +77,7 @@ impl FileServer {
|
||||||
) -> Result <Self, FileServerError>
|
) -> Result <Self, FileServerError>
|
||||||
{
|
{
|
||||||
Ok (Self {
|
Ok (Self {
|
||||||
config: Config {
|
config,
|
||||||
file_server_root,
|
|
||||||
},
|
|
||||||
handlebars: load_templates (asset_root)?,
|
handlebars: load_templates (asset_root)?,
|
||||||
metrics_startup: metrics::Startup::new (name),
|
metrics_startup: metrics::Startup::new (name),
|
||||||
metrics_interval,
|
metrics_interval,
|
||||||
|
@ -374,9 +373,12 @@ impl FileServer {
|
||||||
resp
|
resp
|
||||||
}
|
}
|
||||||
|
|
||||||
let root: &std::path::Path = &self.config.file_server_root;
|
let roots = internal::FileRoots {
|
||||||
|
files: &self.config.file_server_root,
|
||||||
|
dirs: &self.config.file_server_roots,
|
||||||
|
};
|
||||||
|
|
||||||
Ok (match internal::serve_all (root, method, uri, headers, self.hidden_path.as_deref ()).await? {
|
Ok (match internal::serve_all (roots, method, uri, headers, self.hidden_path.as_deref ()).await? {
|
||||||
Favicon => serve_error (StatusCode::NotFound, "Not found\n"),
|
Favicon => serve_error (StatusCode::NotFound, "Not found\n"),
|
||||||
Forbidden => serve_error (StatusCode::Forbidden, "403 Forbidden\n"),
|
Forbidden => serve_error (StatusCode::Forbidden, "403 Forbidden\n"),
|
||||||
MethodNotAllowed => serve_error (StatusCode::MethodNotAllowed, "Unsupported method\n"),
|
MethodNotAllowed => serve_error (StatusCode::MethodNotAllowed, "Unsupported method\n"),
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
// human-readable HTML
|
// human-readable HTML
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::*,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -244,11 +244,59 @@ async fn serve_api (
|
||||||
Ok (NotFound)
|
Ok (NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive (Clone, Copy)]
|
||||||
|
pub struct FileRoots <'a> {
|
||||||
|
pub files: &'a Path,
|
||||||
|
pub dirs: &'a BTreeMap <String, PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RoutedPath <'a> {
|
||||||
|
root: &'a Path,
|
||||||
|
path_s: std::borrow::Cow <'a, str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a> FileRoots <'a> {
|
||||||
|
fn route (self, input: &'a str) -> Result <Option <RoutedPath>, FileServerError> {
|
||||||
|
// TODO: There is totally a dir traversal attack in here somewhere
|
||||||
|
|
||||||
|
if let Some (path) = input.strip_prefix ("/dirs/") {
|
||||||
|
if let Some ((dir, path)) = path.split_once ('/') {
|
||||||
|
let root = match self.dirs.get (dir) {
|
||||||
|
None => return Ok (None),
|
||||||
|
Some (x) => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
let path_s = percent_decode (path.as_bytes ()).decode_utf8 ().map_err (FileServerError::PathNotUtf8)?;
|
||||||
|
|
||||||
|
return Ok (Some (RoutedPath {
|
||||||
|
root,
|
||||||
|
path_s,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Ok (None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some (path) = input.strip_prefix ("/files/") {
|
||||||
|
let encoded_path = &path [0..];
|
||||||
|
|
||||||
|
let path_s = percent_decode (encoded_path.as_bytes ()).decode_utf8 ().map_err (FileServerError::PathNotUtf8)?;
|
||||||
|
|
||||||
|
return Ok (Some (RoutedPath {
|
||||||
|
root: self.files,
|
||||||
|
path_s,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok (None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle the requests internally without knowing anything about PTTH or
|
// Handle the requests internally without knowing anything about PTTH or
|
||||||
// HTML / handlebars
|
// HTML / handlebars
|
||||||
|
|
||||||
pub async fn serve_all (
|
pub async fn serve_all (
|
||||||
root: &Path,
|
roots: FileRoots <'_>,
|
||||||
method: Method,
|
method: Method,
|
||||||
uri: &str,
|
uri: &str,
|
||||||
headers: &HashMap <String, Vec <u8>>,
|
headers: &HashMap <String, Vec <u8>>,
|
||||||
|
@ -283,19 +331,17 @@ pub async fn serve_all (
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some (path) = path.strip_prefix ("/api") {
|
if let Some (path) = path.strip_prefix ("/api") {
|
||||||
return serve_api (root, &uri, hidden_path, path).await;
|
return serve_api (roots.files, &uri, hidden_path, path).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = match path.strip_prefix ("/files/") {
|
let RoutedPath {
|
||||||
Some (x) => x,
|
root,
|
||||||
|
path_s,
|
||||||
|
} = match roots.route (path)? {
|
||||||
None => return Ok (NotFound),
|
None => return Ok (NotFound),
|
||||||
|
Some (x) => x,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: There is totally a dir traversal attack in here somewhere
|
|
||||||
|
|
||||||
let encoded_path = &path [0..];
|
|
||||||
|
|
||||||
let path_s = percent_decode (encoded_path.as_bytes ()).decode_utf8 ().map_err (FileServerError::PathNotUtf8)?;
|
|
||||||
let path = Path::new (&*path_s);
|
let path = Path::new (&*path_s);
|
||||||
|
|
||||||
let full_path = root.join (path);
|
let full_path = root.join (path);
|
||||||
|
|
|
@ -207,9 +207,14 @@ pub struct ConfigFile {
|
||||||
pub relay_url: String,
|
pub relay_url: String,
|
||||||
|
|
||||||
/// Directory that the file server module will expose to clients
|
/// Directory that the file server module will expose to clients
|
||||||
/// over the relay. If None, the current working dir is used.
|
/// over the relay, under `/files`. If None, the current working dir is used.
|
||||||
pub file_server_root: PathBuf,
|
pub file_server_root: PathBuf,
|
||||||
|
|
||||||
|
/// The file server module will expose these directories to clients under
|
||||||
|
/// `/dirs`. If symlinks can't be used (like on Windows), this allows PTTH
|
||||||
|
/// to serve multiple directories easily.
|
||||||
|
pub file_server_roots: BTreeMap <String, PathBuf>,
|
||||||
|
|
||||||
/// For debugging.
|
/// For debugging.
|
||||||
pub throttle_upload: bool,
|
pub throttle_upload: bool,
|
||||||
|
|
||||||
|
@ -226,6 +231,7 @@ impl ConfigFile {
|
||||||
api_key,
|
api_key,
|
||||||
relay_url,
|
relay_url,
|
||||||
file_server_root: PathBuf::from ("."),
|
file_server_root: PathBuf::from ("."),
|
||||||
|
file_server_roots: Default::default (),
|
||||||
throttle_upload: false,
|
throttle_upload: false,
|
||||||
client_keys: Default::default (),
|
client_keys: Default::default (),
|
||||||
allow_any_client: true,
|
allow_any_client: true,
|
||||||
|
@ -268,6 +274,7 @@ impl Builder {
|
||||||
api_key: ptth_core::gen_key (),
|
api_key: ptth_core::gen_key (),
|
||||||
relay_url,
|
relay_url,
|
||||||
file_server_root: PathBuf::from ("."),
|
file_server_root: PathBuf::from ("."),
|
||||||
|
file_server_roots: Default::default (),
|
||||||
throttle_upload: false,
|
throttle_upload: false,
|
||||||
client_keys: Default::default (),
|
client_keys: Default::default (),
|
||||||
allow_any_client: true,
|
allow_any_client: true,
|
||||||
|
@ -301,7 +308,8 @@ pub async fn run_server (
|
||||||
config_file: ConfigFile,
|
config_file: ConfigFile,
|
||||||
shutdown_oneshot: oneshot::Receiver <()>,
|
shutdown_oneshot: oneshot::Receiver <()>,
|
||||||
hidden_path: Option <PathBuf>,
|
hidden_path: Option <PathBuf>,
|
||||||
asset_root: Option <PathBuf>
|
asset_root: Option <PathBuf>,
|
||||||
|
hit_counter: Option <mpsc::Sender <()>>,
|
||||||
)
|
)
|
||||||
-> Result <(), ServerError>
|
-> Result <(), ServerError>
|
||||||
{
|
{
|
||||||
|
@ -312,7 +320,10 @@ pub async fn run_server (
|
||||||
});
|
});
|
||||||
|
|
||||||
let file_server = file_server::FileServer::new (
|
let file_server = file_server::FileServer::new (
|
||||||
config_file.file_server_root.clone (),
|
file_server::Config {
|
||||||
|
file_server_root: config_file.file_server_root.clone (),
|
||||||
|
file_server_roots: config_file.file_server_roots.clone (),
|
||||||
|
},
|
||||||
&asset_root.clone ().unwrap_or_else (|| PathBuf::from (".")),
|
&asset_root.clone ().unwrap_or_else (|| PathBuf::from (".")),
|
||||||
config_file.name.clone (),
|
config_file.name.clone (),
|
||||||
metrics_interval,
|
metrics_interval,
|
||||||
|
@ -330,8 +341,13 @@ pub async fn run_server (
|
||||||
|
|
||||||
let mut spawn_handler = || {
|
let mut spawn_handler = || {
|
||||||
let file_server = Arc::clone (&file_server);
|
let file_server = Arc::clone (&file_server);
|
||||||
|
let hit_counter = hit_counter.clone ();
|
||||||
|
|
||||||
|req: http_serde::RequestParts| async move {
|
|req: http_serde::RequestParts| async move {
|
||||||
|
if let Some (hit_tx) = &hit_counter {
|
||||||
|
eprintln! ("hit_tx.send");
|
||||||
|
hit_tx.send (()).await;
|
||||||
|
}
|
||||||
Ok (file_server.serve_all (req.method, &req.uri, &req.headers).await?)
|
Ok (file_server.serve_all (req.method, &req.uri, &req.headers).await?)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -529,6 +545,12 @@ pub mod executable {
|
||||||
api_key: config_file.api_key,
|
api_key: config_file.api_key,
|
||||||
relay_url: opt.relay_url.or (config_file.relay_url).ok_or (anyhow::anyhow! ("`--relay-url` must be provided in command line or `relay_url` in config file"))?,
|
relay_url: opt.relay_url.or (config_file.relay_url).ok_or (anyhow::anyhow! ("`--relay-url` must be provided in command line or `relay_url` in config file"))?,
|
||||||
file_server_root: opt.file_server_root.or (config_file.file_server_root).unwrap_or_else (PathBuf::new),
|
file_server_root: opt.file_server_root.or (config_file.file_server_root).unwrap_or_else (PathBuf::new),
|
||||||
|
file_server_roots: vec! [
|
||||||
|
("c", "C:/"),
|
||||||
|
("d", "D:/"),
|
||||||
|
].into_iter ()
|
||||||
|
.map (|(k, v)| (String::from (k), PathBuf::from (v)))
|
||||||
|
.collect (),
|
||||||
throttle_upload: opt.throttle_upload,
|
throttle_upload: opt.throttle_upload,
|
||||||
allow_any_client: true,
|
allow_any_client: true,
|
||||||
client_keys: Default::default (),
|
client_keys: Default::default (),
|
||||||
|
@ -544,7 +566,8 @@ pub mod executable {
|
||||||
config_file,
|
config_file,
|
||||||
ptth_core::graceful_shutdown::init (),
|
ptth_core::graceful_shutdown::init (),
|
||||||
Some (path),
|
Some (path),
|
||||||
asset_root
|
asset_root,
|
||||||
|
None,
|
||||||
).await?;
|
).await?;
|
||||||
|
|
||||||
Ok (())
|
Ok (())
|
||||||
|
|
|
@ -6,7 +6,7 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.38"
|
anyhow = "1.0.38"
|
||||||
fltk = "1.1.0"
|
fltk = "1.3.1"
|
||||||
serde = {version = "1.0.117", features = ["derive"]}
|
serde = {version = "1.0.117", features = ["derive"]}
|
||||||
tokio = "1.4.0"
|
tokio = "1.4.0"
|
||||||
tracing = "0.1.25"
|
tracing = "0.1.25"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::*,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,7 +14,10 @@ use fltk::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use tokio::{
|
use tokio::{
|
||||||
sync::oneshot,
|
sync::{
|
||||||
|
mpsc,
|
||||||
|
oneshot,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ServerInstance {
|
struct ServerInstance {
|
||||||
|
@ -23,6 +27,7 @@ struct ServerInstance {
|
||||||
|
|
||||||
#[derive (Clone, Copy)]
|
#[derive (Clone, Copy)]
|
||||||
enum Message {
|
enum Message {
|
||||||
|
Hit,
|
||||||
RunServer,
|
RunServer,
|
||||||
StopServer,
|
StopServer,
|
||||||
}
|
}
|
||||||
|
@ -42,7 +47,22 @@ fn main ()
|
||||||
let app = app::App::default();
|
let app = app::App::default();
|
||||||
let mut wind = Window::new (100, 100, 500, 180, "PTTH server");
|
let mut wind = Window::new (100, 100, 500, 180, "PTTH server");
|
||||||
|
|
||||||
let mut gui = Gui::new (fltk_tx);
|
let config_file_opt = ptth_server::load_toml::load::<ConfigFile, _> ("./config/ptth_server.toml").ok ();
|
||||||
|
|
||||||
|
let (hit_tx, mut hit_rx) = mpsc::channel (1);
|
||||||
|
{
|
||||||
|
let fltk_tx = fltk_tx.clone ();
|
||||||
|
|
||||||
|
rt.spawn (async move {
|
||||||
|
eprintln! ("Entering channel task");
|
||||||
|
while let Some (_) = hit_rx.recv ().await {
|
||||||
|
eprintln! ("fltk_tx");
|
||||||
|
fltk_tx.send (Message::Hit);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut gui = Gui::new (fltk_tx, config_file_opt.as_ref ());
|
||||||
gui.set_server_running (false);
|
gui.set_server_running (false);
|
||||||
|
|
||||||
wind.end ();
|
wind.end ();
|
||||||
|
@ -50,25 +70,40 @@ fn main ()
|
||||||
|
|
||||||
while app.wait () {
|
while app.wait () {
|
||||||
match fltk_rx.recv () {
|
match fltk_rx.recv () {
|
||||||
|
Some (Message::Hit) => {
|
||||||
|
gui.hits += 1;
|
||||||
|
gui.refresh_label ();
|
||||||
|
},
|
||||||
Some (Message::RunServer) => {
|
Some (Message::RunServer) => {
|
||||||
let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel ();
|
let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel ();
|
||||||
|
|
||||||
|
let roots = match &config_file_opt {
|
||||||
|
None => Default::default (),
|
||||||
|
Some (cf) => match &cf.file_server_roots {
|
||||||
|
None => Default::default (),
|
||||||
|
Some (x) => x.clone (),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let config_file = ptth_server::ConfigFile {
|
let config_file = ptth_server::ConfigFile {
|
||||||
name: gui.input_name.value ().to_string (),
|
name: gui.input_name.value ().to_string (),
|
||||||
api_key: gui.input_api_key.value ().to_string (),
|
api_key: gui.input_api_key.value ().to_string (),
|
||||||
relay_url: gui.input_relay_url.value ().to_string (),
|
relay_url: gui.input_relay_url.value ().to_string (),
|
||||||
file_server_root: std::path::PathBuf::from (gui.input_file_server_root.value ()),
|
file_server_root: PathBuf::from (gui.input_file_server_root.value ()),
|
||||||
|
file_server_roots: roots,
|
||||||
throttle_upload: false,
|
throttle_upload: false,
|
||||||
client_keys: Default::default (),
|
client_keys: Default::default (),
|
||||||
allow_any_client: true,
|
allow_any_client: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let hit_tx = hit_tx.clone ();
|
||||||
let task = rt.spawn (async {
|
let task = rt.spawn (async {
|
||||||
if let Err (e) = ptth_server::run_server (
|
if let Err (e) = ptth_server::run_server (
|
||||||
config_file,
|
config_file,
|
||||||
shutdown_rx,
|
shutdown_rx,
|
||||||
None,
|
None,
|
||||||
None
|
None,
|
||||||
|
Some (hit_tx),
|
||||||
).await
|
).await
|
||||||
{
|
{
|
||||||
tracing::error! ("ptth_server crashed: {}", e);
|
tracing::error! ("ptth_server crashed: {}", e);
|
||||||
|
@ -100,6 +135,9 @@ struct Gui {
|
||||||
input_relay_url: Input,
|
input_relay_url: Input,
|
||||||
input_file_server_root: Input,
|
input_file_server_root: Input,
|
||||||
input_api_key: SecretInput,
|
input_api_key: SecretInput,
|
||||||
|
|
||||||
|
server_is_running: bool,
|
||||||
|
hits: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive (Default, serde::Deserialize)]
|
#[derive (Default, serde::Deserialize)]
|
||||||
|
@ -108,10 +146,16 @@ pub struct ConfigFile {
|
||||||
pub api_key: String,
|
pub api_key: String,
|
||||||
pub relay_url: Option <String>,
|
pub relay_url: Option <String>,
|
||||||
pub file_server_root: Option <PathBuf>,
|
pub file_server_root: Option <PathBuf>,
|
||||||
|
pub file_server_roots: Option <BTreeMap <String, PathBuf>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gui {
|
impl Gui {
|
||||||
fn new (fltk_tx: app::Sender <Message>) -> Self {
|
fn new (
|
||||||
|
fltk_tx: app::Sender <Message>,
|
||||||
|
config_file_opt: Option <&ConfigFile>,
|
||||||
|
)
|
||||||
|
-> Self
|
||||||
|
{
|
||||||
let mut input_name = Input::new (200, 10, 290, 20, "name");
|
let mut input_name = Input::new (200, 10, 290, 20, "name");
|
||||||
input_name.set_value ("my_ptth_server");
|
input_name.set_value ("my_ptth_server");
|
||||||
|
|
||||||
|
@ -134,7 +178,7 @@ impl Gui {
|
||||||
but_stop.set_trigger (CallbackTrigger::Changed);
|
but_stop.set_trigger (CallbackTrigger::Changed);
|
||||||
but_stop.emit (fltk_tx, Message::StopServer);
|
but_stop.emit (fltk_tx, Message::StopServer);
|
||||||
|
|
||||||
if let Ok (config_file) = ptth_server::load_toml::load::<ConfigFile, _> ("./config/ptth_server.toml")
|
if let Some (config_file) = config_file_opt
|
||||||
{
|
{
|
||||||
if let Some (v) = config_file.name.as_ref () {
|
if let Some (v) = config_file.name.as_ref () {
|
||||||
input_name.set_value (v);
|
input_name.set_value (v);
|
||||||
|
@ -158,16 +202,16 @@ impl Gui {
|
||||||
input_relay_url,
|
input_relay_url,
|
||||||
input_file_server_root,
|
input_file_server_root,
|
||||||
input_api_key,
|
input_api_key,
|
||||||
|
|
||||||
|
server_is_running: false,
|
||||||
|
hits: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_server_running (&mut self, b: bool) {
|
fn set_server_running (&mut self, b: bool) {
|
||||||
self.frame.set_label (if b {
|
self.server_is_running = b;
|
||||||
"Running"
|
|
||||||
}
|
self.refresh_label ();
|
||||||
else {
|
|
||||||
"Stopped"
|
|
||||||
});
|
|
||||||
|
|
||||||
set_active (&mut self.but_run, ! b);
|
set_active (&mut self.but_run, ! b);
|
||||||
set_active (&mut self.but_stop, b);
|
set_active (&mut self.but_stop, b);
|
||||||
|
@ -179,6 +223,18 @@ impl Gui {
|
||||||
set_active (&mut self.input_file_server_root, ! b);
|
set_active (&mut self.input_file_server_root, ! b);
|
||||||
set_active (&mut self.input_api_key, ! b);
|
set_active (&mut self.input_api_key, ! b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn refresh_label (&mut self) {
|
||||||
|
let s =
|
||||||
|
if self.server_is_running {
|
||||||
|
format! ("Running. Requests: {}", self.hits)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
"Stopped".to_string ()
|
||||||
|
};
|
||||||
|
|
||||||
|
self.frame.set_label (&s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_active <W: WidgetExt> (w: &mut W, b: bool) {
|
fn set_active <W: WidgetExt> (w: &mut W, b: bool) {
|
||||||
|
|
Loading…
Reference in New Issue