ftphack/src/main.rs
2025-09-02 22:01:08 +08:00

107 lines
3.4 KiB
Rust

mod server;
mod ui;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::rc::Rc;
use std::cell::RefCell;
use gtk::prelude::*;
fn main() {
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.expect("Failed to create Tokio runtime");
// Create UI
let ui = ui::FtpUi::new();
// Create server instance
let server = Rc::new(RefCell::new(None::<server::FtpServer>));
// Connect signals
let ui_clone = ui.clone();
let server_clone = server.clone();
let rt_clone = rt.handle().clone();
ui.start_button.connect_clicked(move |_| {
// Get settings from UI
let ip = ui_clone.ip_entry.text();
let port: u16 = ui_clone.port_entry.text().parse().unwrap_or(2121);
let dir = ui_clone.dir_entry.text();
// Validate directory
let dir_path = PathBuf::from(&dir);
if !dir_path.exists() {
ui_clone.status_label.set_text("Error: Directory does not exist");
return;
}
// Update server address
let addr: SocketAddr = format!("{}:{}", ip, port).parse().unwrap();
// Create and start server
match server::FtpServer::new(addr, dir_path) {
Ok(mut srv) => {
// First start the server (initialize it)
if let Err(e) = srv.start() {
ui_clone.status_label.set_text(&format!("Error: {}", e));
return;
}
// Then run the server in the Tokio runtime
let handle = rt_clone.clone();
match handle.block_on(async { srv.run() }) {
Ok(()) => {
server_clone.borrow_mut().replace(srv);
ui_clone.status_label.set_text("Status: Running");
ui_clone.start_button.set_sensitive(false);
ui_clone.stop_button.set_sensitive(true);
}
Err(e) => {
ui_clone.status_label.set_text(&format!("Error: {}", e));
}
}
}
Err(e) => {
ui_clone.status_label.set_text(&format!("Error: {}", e));
}
}
});
let ui_clone = ui.clone();
let server_clone2 = server.clone();
ui.stop_button.connect_clicked(move |_| {
let mut server_ref = server_clone2.borrow_mut();
if let Some(mut srv) = server_ref.take() {
srv.stop();
}
ui_clone.status_label.set_text("Status: Stopped");
ui_clone.start_button.set_sensitive(true);
ui_clone.stop_button.set_sensitive(false);
});
// Directory browse button
let ui_clone = ui.clone();
ui.dir_button.connect_clicked(move |_| {
let dialog = gtk::FileChooserDialog::with_buttons(
Some("选择目录"),
Some(&ui_clone.window),
gtk::FileChooserAction::SelectFolder,
&[("取消", gtk::ResponseType::Cancel), ("确定", gtk::ResponseType::Accept)]
);
if dialog.run() == gtk::ResponseType::Accept {
if let Some(filename) = dialog.filename() {
ui_clone.dir_entry.set_text(&filename.to_string_lossy());
}
}
dialog.close();
});
// Show window
ui.window.show_all();
// Start GTK main loop
gtk::main();
}