In our crux app we quickly got the need for the shell to know when an Event is finished, and potentially get an output from it.
A typical example would be the shell sending a SyncWithRemote event which the core process by doing a bunch of database and http calls.
The core could build a state machine in the view model to expose the progress with a value like sync: Pending/Done but it doesn't scale well and view models can get pretty complex.
So we built a system similar to the following:
pub enum Event {
Init,
SyncWithRemote,
DoSomething
}
pub struct TrackedEvent {
pub event: Event,
pub id: Option<String>
}
the App::Event is actually TrackedEvent.
We added a Track capability, able to notify the shell with the following operations:
// Status of a tracked event
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, facet::Facet)]
#[repr(C)]
pub enum OperationStatus {
/// The event was started by the core
Started,
/// The event was successful
Success,
/// The event failed -- error message
Error(String),
}
/// Notify the shell of the status of a tracked event
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, facet::Facet)]
#[repr(C)]
pub struct TrackOperation {
/// Identifier of the tracked event
pub id: String,
/// New status of that event
pub status: OperationStatus,
}
The simplified logic is that if the shell specifies an TrackEvent::id we are going to wrap the associated Command with some tracking
Command::new(|ctx| {
ctx.notify_shell(TrackOperation { id, status: OperatioStatus::Started });
let result = {
// The actual event processing return a `Result`
}.await;
match result {
Ok(()) -> ctx.notify_shell(TrackOperation { id, status: OperationStatus::Success }),
Err(e) -> ctx.notify_shell(TrackOperation { id, status: OperationStatus::Error(e.to_string()) })
}
}
This way the shell is notified when:
- The core actually starts polling the associated
Command
- The core finishes processing and gives a status
Concretely it allows many things for the shell:
- Display loading screens
- Show sucess toasts
- Given context (The original user instruction) to failures instead of a simple error capability.
This works well as long as the shell has to specify unique ids itself based on an Event + some entropy to avoid duplicates but we can go even further by adding data to the Success variant.
Doing so unlocks some cool features:
- Being able to query the core without having to be based on the view model
- Returning relevant data
An example could be that for a calendar app the Event::CreateCalendarItem could return the actual new calendar item unique id and avoid for the shell the necessity to do some comparisons between the previous view model and the new one to find the "new" item that was created
This goes even further if we are in a workspace environment with potentially multiple new calendar items popping up. The shell is often confused on what is a result of an instruction it sent and what is coming from something else
I think crux could benefit from having a tracking mechanism built-in, would that make sense ? If so I could work on an RFC for that
In our crux app we quickly got the need for the shell to know when an
Eventis finished, and potentially get an output from it.A typical example would be the shell sending a
SyncWithRemoteevent which the core process by doing a bunch of database and http calls.The core could build a state machine in the view model to expose the progress with a value like
sync: Pending/Donebut it doesn't scale well and view models can get pretty complex.So we built a system similar to the following:
the
App::Eventis actuallyTrackedEvent.We added a
Trackcapability, able to notify the shell with the following operations:The simplified logic is that if the shell specifies an
TrackEvent::idwe are going to wrap the associatedCommandwith some trackingThis way the shell is notified when:
CommandConcretely it allows many things for the shell:
This works well as long as the shell has to specify unique ids itself based on an Event + some entropy to avoid duplicates but we can go even further by adding data to the
Successvariant.Doing so unlocks some cool features:
I think crux could benefit from having a tracking mechanism built-in, would that make sense ? If so I could work on an RFC for that