Skip to content

Commit

Permalink
refactor(gtk): Separate state and event handling into their own modules
Browse files Browse the repository at this point in the history
  • Loading branch information
mmstick committed Nov 11, 2019
1 parent 29273d7 commit 9b8ee5b
Show file tree
Hide file tree
Showing 8 changed files with 1,005 additions and 853 deletions.
77 changes: 0 additions & 77 deletions gtk/src/events.rs

This file was deleted.

159 changes: 159 additions & 0 deletions gtk/src/events/background/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
mod recovery;
mod release;
mod scan;

use crate::{errors::UnderlyingError, events::*, reboot};

use self::scan::scan;

use num_traits::cast::FromPrimitive;
use pop_upgrade::{
client::{Client, ReleaseInfo, Status},
daemon::DaemonStatus,
release::RefreshOp,
};

use std::sync::mpsc::{self, SyncSender};

/// Events sent to this widget's background thread.
#[derive(Debug)]
pub enum BackgroundEvent {
DownloadUpgrade(ReleaseInfo),
Finalize,
GetStatus(DaemonStatus),
IsActive(SyncSender<bool>),
DismissNotification(bool),
RefreshOS,
RepoModify(Vec<Box<str>>, Vec<bool>),
Reset,
Scan,
Shutdown,
}

pub fn run(
receiver: mpsc::Receiver<BackgroundEvent>,
send: impl Fn(UiEvent) + Send + Sync + 'static,
) {
let send: &dyn Fn(UiEvent) = &send;
if let Ok(ref client) = Client::new() {
while let Ok(event) = receiver.recv() {
trace!("received BackgroundEvent: {:?}", event);
match event {
BackgroundEvent::DismissNotification(dismiss) => {
let event = match client.dismiss_notification(dismiss) {
Ok(dismissed) => UiEvent::Dismissed(dismissed),
Err(why) => {
UiEvent::Error(UiError::Dismiss(dismiss, UnderlyingError::Client(why)))
}
};

send(event)
}

BackgroundEvent::DownloadUpgrade(info) => {
self::release::download(client, send, info);
}

BackgroundEvent::Finalize => match client.release_upgrade_finalize() {
Ok(()) => reboot(),
Err(why) => send(UiEvent::Error(UiError::Finalize(why))),
},

BackgroundEvent::GetStatus(from) => {
get_status(client, send, from);
}

BackgroundEvent::IsActive(tx) => {
let _ = tx.send(client.status().is_ok());
}

BackgroundEvent::RefreshOS => {
refresh_os(client, send);
}

BackgroundEvent::RepoModify(failures, answers) => {
repo_modify(client, send, failures, answers);
}

BackgroundEvent::Reset => {
send(match client.reset() {
Ok(()) => UiEvent::CancelledUpgrade,
Err(why) => UiEvent::Error(UiError::Cancel(why)),
});
}

BackgroundEvent::Scan => scan(client, send),

BackgroundEvent::Shutdown => {
send(UiEvent::Shutdown);
break;
}
}
}
}
}

fn get_status(client: &Client, send: &dyn Fn(UiEvent), from: DaemonStatus) {
match from {
DaemonStatus::RecoveryUpgrade => {
let event = match client.recovery_upgrade_release_status() {
Ok(status) => {
if status.status == 0 {
UiEvent::Completed(CompletedEvent::Recovery)
} else {
UiEvent::Error(UiError::Recovery(status.why.into()))
}
}
Err(why) => UiEvent::Error(UiError::Recovery(why.into())),
};

send(event);
}
DaemonStatus::ReleaseUpgrade => {
let event = match client.release_upgrade_status() {
Ok(status) => {
if status.status == 0 {
UiEvent::Completed(CompletedEvent::Download)
} else {
UiEvent::Error(UiError::Upgrade(status.why.into()))
}
}
Err(why) => UiEvent::Error(UiError::Upgrade(why.into())),
};

send(event);
}
_ => (),
}
}

fn refresh_os(client: &Client, send: &dyn Fn(UiEvent)) {
send(UiEvent::Initiated(InitiatedEvent::Refresh));

if let Err(why) = client.refresh_os(RefreshOp::Enable) {
send(UiEvent::Error(UiError::Refresh(why.into())));
return;
}

send(UiEvent::Completed(CompletedEvent::Refresh));
}

fn repo_modify(
client: &Client,
send: &dyn Fn(UiEvent),
failures: Vec<Box<str>>,
answers: Vec<bool>,
) {
let input = failures.into_iter().zip(answers.into_iter());
if let Err(why) = client.repo_modify(input) {
send(UiEvent::Error(UiError::Repos(why.into())));
return;
}

send(UiEvent::UpgradeClicked);
}

fn status_changed(send: &dyn Fn(UiEvent), new_status: Status, expected: DaemonStatus) {
let status = DaemonStatus::from_u8(new_status.status).expect("unknown daemon status value");
send(UiEvent::StatusChanged(expected, status, new_status.why));
}
60 changes: 60 additions & 0 deletions gtk/src/events/background/recovery.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use crate::{
errors::UiError,
events::{CompletedEvent, InitiatedEvent, ProgressEvent, UiEvent},
};

use super::status_changed;

use pop_upgrade::{
client::{self, Client, Signal},
daemon::DaemonStatus,
recovery::ReleaseFlags,
};

pub fn upgrade(client: &Client, send: &dyn Fn(UiEvent), version: &str) -> bool {
send(UiEvent::Initiated(InitiatedEvent::Recovery));

let arch = "nvidia";
let flags = ReleaseFlags::empty();

if let Err(why) = client.recovery_upgrade_release(version, arch, flags) {
send(UiEvent::Error(UiError::Recovery(why.into())));
return false;
}

let error = &mut None;

let _ = client.event_listen(
DaemonStatus::RecoveryUpgrade,
Client::recovery_upgrade_release_status,
|status| status_changed(send, status, DaemonStatus::RecoveryUpgrade),
|_client, signal| {
match signal {
Signal::RecoveryDownloadProgress(progress) => {
send(UiEvent::Progress(ProgressEvent::Recovery(
progress.progress,
progress.total,
)));
}
Signal::RecoveryResult(status) => {
if status.status != 0 {
*error = Some(status.why);
}

return Ok(client::Continue(false));
}
_ => (),
}

Ok(client::Continue(true))
},
);

if let Some(why) = error.take() {
send(UiEvent::Error(UiError::Recovery(why.into())));
return false;
}

send(UiEvent::Completed(CompletedEvent::Recovery));
true
}
Loading

0 comments on commit 9b8ee5b

Please sign in to comment.