-
Notifications
You must be signed in to change notification settings - Fork 31
Create GUI #240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
sermuns
wants to merge
30
commits into
ifd3f:main
Choose a base branch
from
sermuns:gui
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Create GUI #240
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
232e127
start creating mock GUI with egui
sermuns e9ffd22
only use glow backend, add rfd
sermuns 50743d0
simplify structure, add input file pick
sermuns c547dd2
start adding hashing, overall app state
sermuns c0b79ba
create `sections.rs`, create functions per section. add (shitty) targ…
sermuns 95bb4d0
start creating "begin write" section
sermuns 9ad3e08
REMOVEME: remove all CI
sermuns 05c9644
Revert "REMOVEME: remove all CI"
sermuns b97c443
WIP: use local flavor of tokio runtime (PROBABLY NOT THE SOLUTION) an…
sermuns 149f799
go back to multithreaded tokio runtime
sermuns 2da6c03
somewhat working PoC, but insanely hacky. Spawning a thread just for …
sermuns aac7fff
revert changes to other code
sermuns c351ee3
WIP: rework using syncified code. remove `sections.rs`, just have the…
sermuns c479b7d
rename methods, simplify
sermuns 90d673c
WIP: using orchestrator in main thread. THIS WONT WORK actually, need…
sermuns 32a9573
rename Orchestrator to Facade
ifd3f 737253b
Split Facade into multiple traits
ifd3f 108a108
Move write_verify and hash into submodule of facade
ifd3f c3da6d7
now split Orchestrator into workflow-specific traits
ifd3f e766ab7
split into workflow and worker error
ifd3f 531c636
fix all the errors
ifd3f 60012b0
Rename and document stuff
ifd3f a137cac
Merge branch 'refactor/facade-split' into gui
ifd3f 9daebf8
export `ui::simple_ui::facade_ext::FacadeExt` publicly
sermuns a755a0f
WIP: try to correctly implement worker thread
sermuns 8f4bc95
remove generics, simplifying impl blocks
sermuns cb020bc
somewhat working, need to clean this shit code up
sermuns ce7f480
very shitty but working abort worker threada
sermuns 47fa7eb
add TODO
sermuns d86aa2c
move sections into own module (again). add back confirm write button
sermuns File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| //! Exposes the [`CaligulaFacade`], which is a facade that orchestrates all | ||
| //! "high-level" work and tracks the state of worker tasks. | ||
|
|
||
| use std::path::PathBuf; | ||
|
|
||
| pub use self::{ | ||
| disks::DiskList, | ||
| legacy_facade::{DaemonError, StartWriterError}, | ||
| workflow::{ | ||
| Orchestrator, OrchestratorExt, | ||
| write_verify::{WVState, WriteVerifyWorkflow, WriteVerifyWorkflowError}, | ||
| }, | ||
| }; | ||
| use crate::{ | ||
| escalation::EscalationMethod, | ||
| facade::{analyze_input::FileAnalysis, workflow::hash::HashWorkflow}, | ||
| }; | ||
|
|
||
| mod analyze_input; | ||
| mod disks; | ||
| mod legacy_facade; | ||
| mod real; | ||
| pub mod watch; | ||
| pub mod workflow; | ||
|
|
||
| /// Main facade for UI implementations to interact with the rest of the | ||
| /// program's logic. | ||
| /// | ||
| /// This trait is split up into several subtraits, each representing a different | ||
| /// kind of action the UI can take. | ||
| /// | ||
| /// The API for this can be considered "mostly" stable. I'll be changing out the | ||
| /// error types, but in general, the overall shape of this API can be used for | ||
| /// new UI developments. | ||
| pub trait CaligulaFacade: | ||
| Sync | ||
| + Send | ||
| + DiskWatcher | ||
| + FileAnalyzer | ||
| + Escalator | ||
| + Orchestrator<WriteVerifyWorkflow> | ||
| + Orchestrator<HashWorkflow> | ||
| + 'static | ||
| { | ||
| } | ||
|
|
||
| impl<F> CaligulaFacade for F where | ||
| F: Sync | ||
| + Send | ||
| + DiskWatcher | ||
| + FileAnalyzer | ||
| + Escalator | ||
| + Orchestrator<WriteVerifyWorkflow> | ||
| + Orchestrator<HashWorkflow> | ||
| + 'static | ||
| { | ||
| } | ||
|
|
||
| /// Represents an interface to the disk querying subsystem. | ||
| pub trait DiskWatcher { | ||
| /// Get a handle for watching the list of disks available. This may update | ||
| /// as disks are added and removed to the system. | ||
| /// | ||
| /// Although this returns a handle immediately, the initial results may take | ||
| /// a while to load. | ||
| #[expect(unused, reason = "Stub interface created for later use.")] | ||
| fn watch_disks(&self) -> watch::Watch<DiskList>; | ||
| } | ||
|
|
||
| /// Represents an interface to the file analysis subsystem. | ||
| pub trait FileAnalyzer { | ||
| /// Analyze a file to guess how we should handle it. | ||
| /// | ||
| /// This is a fairly fast operation, expected to take 1-3 seconds to run. | ||
| /// | ||
| /// Returns the results of the analysis, or an error if the file could not | ||
| /// be read. This method is fault-tolerant, so the only errors that can | ||
| /// cause this operation to fail are I/O errors. | ||
| /// | ||
| /// The intended workflow is that you call it once, to fill up your UI's | ||
| /// wizard with data, and then ask the user for more information if | ||
| /// there's anything that's not certain. | ||
| #[expect(unused, reason = "Stub interface created for later use.")] | ||
| async fn analyze_file(&self, input: PathBuf) -> std::io::Result<FileAnalysis>; | ||
| } | ||
|
|
||
| /// Represents an interface to the privilege escalation subsystem. | ||
| pub trait Escalator { | ||
| /// Attempt to spawn a child process as root using the provided escalation | ||
| /// method (or [`None`] to automatically guess which one to use). | ||
| /// | ||
| /// Returns [`Ok`] if we successfully managed to escalate, or an error if we | ||
| /// failed. If we were already escalated before this was called, returns | ||
| /// [`Ok`]. | ||
| /// | ||
| /// Once this is called, all future workflows will be routed through the | ||
| /// escalated child process rather than executing at the parent's | ||
| /// permission level! | ||
| /// | ||
| /// If your requested method involves the terminal, you should switch back | ||
| /// to the non-alternate screen before calling this. | ||
| async fn escalate(&self, method: Option<EscalationMethod>) -> Result<(), DaemonError>; | ||
|
|
||
| /// Returns whether or not we have a child process running as root. | ||
| #[expect(unused, reason = "Stub interface created for later use.")] | ||
| fn is_escalated(&self) -> bool; | ||
| } | ||
|
|
||
| /// Make the actual prod-used CaligulaFacade implementation. | ||
| pub fn make_real_facade(log_path: &str) -> impl CaligulaFacade { | ||
| self::real::FacadeImpl::new(legacy_facade::make_legacy_facade_impl(log_path)) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| use std::{path::PathBuf, sync::Arc, time::Instant}; | ||
|
|
||
| use futures::StreamExt; | ||
|
|
||
| use super::legacy_facade::{DaemonError, LegacyFacade}; | ||
| use crate::{ | ||
| escalation::EscalationMethod, | ||
| facade::{ | ||
| DiskList, DiskWatcher, Escalator, FileAnalyzer, Orchestrator, WVState, WriteVerifyWorkflow, | ||
| analyze_input::FileAnalysis, | ||
| watch::Watch, | ||
| workflow::hash::{HashWorkflow, HashingState}, | ||
| }, | ||
| }; | ||
|
|
||
| /// Actual CaligulaFacade implementation used by Caligula. | ||
| pub struct FacadeImpl<H> { | ||
| inner: tokio::sync::Mutex<Inner<H>>, | ||
| } | ||
|
|
||
| struct Inner<H> { | ||
| // TODO: get rid of the entire herder facade thing altogether. just assimilate the good parts | ||
| // into CaligulaFacade. | ||
| h: H, | ||
| escalation: Option<Option<EscalationMethod>>, | ||
| } | ||
|
|
||
| impl<H> FacadeImpl<H> { | ||
| pub fn new(h: H) -> Self { | ||
| Self { | ||
| inner: Inner { | ||
| h, | ||
| escalation: None, | ||
| } | ||
| .into(), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl<H: LegacyFacade + Send + 'static> Orchestrator<WriteVerifyWorkflow> for FacadeImpl<H> { | ||
| async fn start_workflow(&self, params: WriteVerifyWorkflow) -> Watch<WVState> { | ||
| tracing::info!("Requesting herder to start"); | ||
|
|
||
| // request the herder to start the action | ||
| let mut inner = self.inner.lock().await; | ||
| let esc = inner.escalation.is_some(); | ||
| let handle: crate::facade::legacy_facade::HerdHandle< | ||
| crate::herder_api::write_verify::WriteVerifyEvent, | ||
| > = match inner.h.start_herd(params.make_child_config(), esc).await { | ||
| Ok(handle) => handle, | ||
| Err(e) => { | ||
| // oh god what a shitshow | ||
| // TODO: refactor the shit out of this thing | ||
| return Watch { | ||
| rx: tokio::sync::watch::channel(WVState::error( | ||
| Instant::now(), | ||
| match e { | ||
| crate::facade::StartWriterError::UnexpectedFirstStatus(s) => { | ||
| crate::facade::WriteVerifyWorkflowError::Unexpected(s) | ||
| } | ||
| crate::facade::StartWriterError::Failed(f) => { | ||
| crate::facade::WriteVerifyWorkflowError::Worker(f) | ||
| } | ||
| crate::facade::StartWriterError::DaemonError(daemon_error) => { | ||
| crate::facade::WriteVerifyWorkflowError::Daemon(Arc::new( | ||
| daemon_error, | ||
| )) | ||
| } | ||
| }, | ||
| )) | ||
| .1, | ||
| }; | ||
| } | ||
| }; | ||
| drop(inner); | ||
|
|
||
| // create state reduction task | ||
| let (tx_state, rx_state) = tokio::sync::watch::channel(WVState::initial( | ||
| Instant::now(), | ||
| !params.compression.is_identity(), | ||
| handle.initial_info.input_file_bytes, | ||
| )); | ||
| let mut events = handle.events; | ||
| let _jh = tokio::spawn(async move { | ||
| while !tx_state.borrow().is_finished() && !tx_state.is_closed() { | ||
| let event = events.next().await; | ||
| tx_state.send_modify(move |state| { | ||
| *state = std::mem::take(state).on_status(Instant::now(), event); | ||
| }); | ||
| } | ||
| }); | ||
| super::watch::Watch { rx: rx_state } | ||
| } | ||
| } | ||
|
|
||
| impl<H: LegacyFacade + Send + 'static> Orchestrator<HashWorkflow> for FacadeImpl<H> { | ||
| async fn start_workflow(&self, _workflow: HashWorkflow) -> Watch<HashingState> { | ||
| unimplemented!( | ||
| "Until this is implemented, for testing purposes, you may replace this with test values." | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| impl<H: LegacyFacade> Escalator for FacadeImpl<H> { | ||
| async fn escalate(&self, method: Option<EscalationMethod>) -> Result<(), DaemonError> { | ||
| let mut inner = self.inner.lock().await; | ||
| inner.escalation = Some(method); | ||
| inner.h.ensure_escalated_daemon().await?; | ||
| Ok(()) | ||
| } | ||
|
|
||
| fn is_escalated(&self) -> bool { | ||
| // TODO: this is badly implemented but it's good enough for writing new UIs | ||
| // against. It will be improved when we get rid of herder facade. | ||
| let Ok(lock) = self.inner.try_lock() else { | ||
| return false; | ||
| }; | ||
| lock.escalation.is_some() | ||
| } | ||
| } | ||
|
|
||
| impl<H> DiskWatcher for FacadeImpl<H> { | ||
| fn watch_disks(&self) -> Watch<DiskList> { | ||
| unimplemented!( | ||
| "Until this is implemented, for testing purposes, you may replace this with test values." | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| impl<H> FileAnalyzer for FacadeImpl<H> { | ||
| async fn analyze_file(&self, _input: PathBuf) -> std::io::Result<FileAnalysis> { | ||
| unimplemented!( | ||
| "Until this is implemented, for testing purposes, you may replace this with test values." | ||
| ) | ||
| } | ||
| } |
File renamed without changes.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is one chunky boi