mod download_wrapper; mod mes_service; use std::any::Any; use crossbeam::channel; use std::sync::{Arc, Mutex, LazyLock}; use crossbeam::channel::Sender; use iced::widget::{button, checkbox, column, container, radio, row, text_editor, text_input}; use iced::{event, window, Element, Event, Length, Subscription, Task, time}; use iced::application::Title; use iced::widget::text_editor::Action::Scroll; use iced::widget::text_editor::Edit; use download_wrapper::DownloadType; use crate::mes_service::MesService; pub fn main() -> iced::Result { iced::application("WisunDownload V0.1", MainWindow::update, MainWindow::view) .subscription(MainWindow::subscription) .exit_on_close_request(false) .window_size((830.0, 600.0)) .run() } static logs: LazyLock>>> = LazyLock::new(|| { Arc::new(Mutex::new(Vec::new())) }); struct MainWindow { is_online: bool, mysql_config: MysqlConfig, selection: Option, label: String, log_content: text_editor::Content, sender: Sender, receiver: crossbeam::channel::Receiver, } impl Default for MainWindow { fn default() -> Self { let (sender, receiver) = crossbeam::channel::unbounded(); Self { is_online: true, mysql_config: MysqlConfig::default(), selection: None, label: String::new(), log_content: text_editor::Content::default(), sender, receiver } } } #[derive(Debug, Clone, Default)] struct MysqlConfig { ip: String, port: String, username: String, password: String, database: String, work_order: String, } #[derive(Debug, Clone)] enum Message { Start(), IpChanged(String), PortChanged(String), UsernameChanged(String), PasswordChanged(String), DatabaseChanged(String), WorkOrderChanged(String), LabelChanged(String), TypeSelected(DownloadType), OnlineChecked(bool), AddLog(String), LogContentChanged(text_editor::Action), SaveConfig, DownloadEnd(bool), WindowEvent(Event), Tick, } pub fn add_log<'a>(msg: String) { let time_now = chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string(); let really_msg = format!("{time_now} [Info]: {msg}"); logs.lock().unwrap().push(really_msg); } impl MainWindow { fn update(&mut self, message: Message) -> Task { match message { Message::Start() => { self.start(self.sender.clone()); Task::none() } Message::IpChanged(ip) => { self.mysql_config.ip = ip; Task::none() } Message::PortChanged(port) => { self.mysql_config.port = port; Task::none() } Message::UsernameChanged(username) => { self.mysql_config.username = username; Task::none() } Message::PasswordChanged(password) => { self.mysql_config.password = password; Task::none() } Message::DatabaseChanged(database) => { self.mysql_config.database = database; Task::none() } Message::WorkOrderChanged(work_order) => { self.mysql_config.work_order = work_order; Task::none() } Message::TypeSelected(download_type) => { self.selection = Some(download_type); Task::none() } Message::LabelChanged(label) => { self.label = label; Task::none() } Message::OnlineChecked(is_online) => { self.is_online = is_online; Task::none() } Message::AddLog(log) => { for c in log.chars() { self.log_content.perform(text_editor::Action::Edit(Edit::Insert(c))) } self.log_content.perform(text_editor::Action::Edit(Edit::Enter)); let line_size = self.log_content.lines().count(); self.log_content.perform(Scroll { lines: line_size as i32 }); Task::none() } Message::Tick => { for log in logs.lock().unwrap().iter() { for c in log.chars() { self.log_content.perform(text_editor::Action::Edit(Edit::Insert(c))) } self.log_content.perform(text_editor::Action::Edit(Edit::Enter)); let line_size = self.log_content.lines().count(); self.log_content.perform(Scroll { lines: line_size as i32 }); } logs.lock().unwrap().clear(); match self.receiver.try_recv() { Ok(res) => { self.update(Message::DownloadEnd(res)); } Err(channel::TryRecvError::Empty) => { } Err(channel::TryRecvError::Disconnected) => { println!("Disconnected"); } }; Task::none() } Message::LogContentChanged(action) => { match action{ Scroll { lines } => { self.log_content.perform(Scroll { lines }); Task::none() } _=>{ Task::none() } } } Message::DownloadEnd(res)=>{ if res{ add_log("下载成功 By Ui Thread".to_string()); }else{ add_log("下载失败 By Ui Thread".to_string()); } Task::none() } Message::WindowEvent(event) => { //println!("{:?}", event); if let Event::Window(window::Event::CloseRequested) = event { println!("Request Close"); return window::get_latest().and_then(window::close); }; Task::none() } _ => { Task::none() } } } fn view(&self) -> Element { let ip_input = text_input( "IP Address", &self.mysql_config.ip, ).on_input(Message::IpChanged); let port_input = text_input( "Port", &self.mysql_config.port, ).on_input(Message::PortChanged); let username_input = text_input( "Username", &self.mysql_config.username, ).on_input(Message::UsernameChanged); let password_input = text_input( "Password", &self.mysql_config.password, ).on_input(Message::PasswordChanged); let database_input = text_input( "Database", &self.mysql_config.database, ).on_input(Message::DatabaseChanged); let work_order_input = text_input( "WorkOrder", &self.mysql_config.work_order, ).on_input(Message::WorkOrderChanged); let label_input = text_input( "label", &self.label, ).on_input(Message::LabelChanged).on_submit(Message::Start()).width(Length::Fill); let content = column![ row![ip_input, port_input].spacing(5), row![username_input, password_input].spacing(5), row![database_input, work_order_input].spacing(5), row![ radio("BootLoader", DownloadType::Bootloader,self.selection,Message::TypeSelected), radio("App", DownloadType::App,self.selection,Message::TypeSelected), radio("Cal", DownloadType::Rail,self.selection,Message::TypeSelected), checkbox("online", self.is_online).on_toggle(Message::OnlineChecked) ].spacing(10), row![label_input,button("Start").on_press(Message::Start())].spacing(10), text_editor(&self.log_content).on_action(Message::LogContentChanged).height(Length::Fill) ].spacing(10).padding(5); let container = container(content).padding(20); container.into() } fn subscription(&self) -> Subscription { Subscription::batch(vec![ event::listen().map(Message::WindowEvent), time::every(time::Duration::from_millis(50)) .map(|_| Message::Tick) ]) } fn start(&mut self, sender: Sender) -> (){ let mes_config = self.mysql_config.clone(); let label = self.label.clone(); let download_type: DownloadType = self.selection.unwrap(); let online = self.is_online.clone(); std::thread::spawn(move || { let mut download_wrapper = download_wrapper::DownloadWrapper::new(); let mut mes_service: MesService; if online { add_log("当前为在线模式, 正在连接数据库".to_string()); mes_service = MesService::new(mes_config.ip.clone(), mes_config.port.clone(), mes_config.username.clone(), mes_config.password.clone(), mes_config.database.clone()); add_log("连接成功".to_string()); add_log("正在过站检测".to_string()); let check_result = mes_service.check_station(mes_config.work_order.clone(), label.clone(), download_type); if let Err(res) = check_result { add_log(format!("过站检测失败: {:?}", res)); sender.send(false).unwrap(); } else if let Ok(res) = check_result { if !res { add_log("过站检测失败".to_string()); sender.send(false).unwrap(); } add_log("过站检测成功".to_string()); } } add_log("正在检查JLink连接".to_string()); if let Err(e) = download_wrapper.check_jlink() { add_log("JLink检查失败, 请检查是否安装驱动或连接是否异常".to_string()); sender.send(false).unwrap(); } add_log("JLink检查成功".to_string()); add_log("正在检查设备连接".to_string()); if let Err(e) = download_wrapper.check_device() { add_log("设备检查失败, 请检查设备是否连接".to_string()); sender.send(false).unwrap(); } add_log("设备检查成功".to_string()); match download_type { DownloadType::Bootloader =>{ add_log("正在擦除Flash".to_string()); if let Err(e) = download_wrapper.erase(){ add_log("擦除失败".to_string()); sender.send(false).unwrap(); } add_log("擦除成功".to_string()); add_log("正在下载BootLoader".to_string()); if let Err(e) = download_wrapper.download(download_type){ add_log("下载BootLoader失败".to_string()); sender.send(false).unwrap(); } add_log("下载成功".to_string()); } DownloadType::App =>{ add_log("正在下载App".to_string()); if let Err(e) = download_wrapper.download(download_type){ add_log("下载App失败".to_string()); sender.send(false).unwrap(); } add_log("下载成功".to_string()); } DownloadType::Rail=>{ add_log("正在下载Rail".to_string()); if let Err(e) = download_wrapper.download(download_type){ add_log("下载Rail失败".to_string()); sender.send(false).unwrap(); } add_log("下载成功".to_string()); } } return if online { mes_service = MesService::new(mes_config.ip, mes_config.port, mes_config.username, mes_config.password, mes_config.database); add_log("正在上传数据".to_string()); let update_result = mes_service.update_station(mes_config.work_order, label, download_type); if let Err(e) = update_result { add_log(format!("上传失败: {:?}", e)); sender.send(false).unwrap(); } sender.send(true).unwrap(); } else { add_log("当前为离线模式".to_string()); sender.send(true).unwrap(); } }); } }