feat(host): unify typed failure results
Represent denied, timeout, unavailable, and error host outcomes with one HostFailure result shape, update the browser adapter, and keep Workout host recovery flowing through app code before UI effects. req: host/002 req: host/005 req: local/003
This commit is contained in:
+28
-12
@@ -3,8 +3,8 @@ use hemx::{Html, IntoEffect};
|
||||
use hemx_axum::Form;
|
||||
use hemx_host::{
|
||||
browser_pwa_host_profile, native_shell_host_profile, Capability, CapabilityManifest,
|
||||
CapabilityShape, CapabilityUse, HapticPattern, HostCall, HostCallId, HostEvent,
|
||||
SharePayload as HostShareData,
|
||||
CapabilityShape, CapabilityUse, HapticPattern, HostCall, HostCallId, HostEvent, HostFailure,
|
||||
HostFailureKind, SharePayload as HostShareData,
|
||||
};
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::{Arc, Mutex};
|
||||
@@ -942,9 +942,10 @@ pub fn record_share_denied(app: AppState) -> impl IntoEffect {
|
||||
// req: host/002 req: host/005 req: local/003
|
||||
apply_host_event(
|
||||
state,
|
||||
HostEvent::PermissionDenied {
|
||||
capability: Capability::Share,
|
||||
},
|
||||
HostEvent::Failed(
|
||||
HostFailure::new(HostFailureKind::PermissionDenied, "share permission denied")
|
||||
.with_capability(Capability::Share),
|
||||
),
|
||||
);
|
||||
effects(state, "Share permission denial returned through app code")
|
||||
})
|
||||
@@ -955,10 +956,11 @@ pub fn record_host_timeout(app: AppState) -> impl IntoEffect {
|
||||
// req: host/002 req: host/005 req: local/003
|
||||
apply_host_event(
|
||||
state,
|
||||
HostEvent::Failed {
|
||||
id: Some(HostCallId::new("workout-export")),
|
||||
message: "share timed out".into(),
|
||||
},
|
||||
HostEvent::Failed(
|
||||
HostFailure::new(HostFailureKind::Timeout, "share timed out")
|
||||
.with_id(HostCallId::new("workout-export"))
|
||||
.with_capability(Capability::Share),
|
||||
),
|
||||
);
|
||||
effects(state, "Host timeout returned through app code")
|
||||
})
|
||||
@@ -999,6 +1001,15 @@ pub fn record_native_haptic_ack(app: AppState) -> impl IntoEffect {
|
||||
})
|
||||
}
|
||||
|
||||
fn host_failure_label(kind: HostFailureKind) -> &'static str {
|
||||
match kind {
|
||||
HostFailureKind::PermissionDenied => "permission denied",
|
||||
HostFailureKind::Timeout => "timeout",
|
||||
HostFailureKind::Unavailable => "unavailable",
|
||||
HostFailureKind::Error => "error",
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_host_event(state: &mut WorkoutState, event: HostEvent) {
|
||||
match event {
|
||||
HostEvent::ShareCompleted {
|
||||
@@ -1013,14 +1024,19 @@ fn apply_host_event(state: &mut WorkoutState, event: HostEvent) {
|
||||
state.host_status =
|
||||
"Share cancelled; local event log unchanged. Try Share export when ready.".into();
|
||||
}
|
||||
HostEvent::PermissionDenied { capability } if capability == Capability::Share => {
|
||||
HostEvent::Failed(failure)
|
||||
if failure.kind == HostFailureKind::PermissionDenied
|
||||
&& failure.capability == Some(Capability::Share) =>
|
||||
{
|
||||
state.host_status =
|
||||
"Share permission denied. Local export text is still ready; try again or copy it."
|
||||
.into();
|
||||
}
|
||||
HostEvent::Failed { message, .. } => {
|
||||
HostEvent::Failed(failure) => {
|
||||
state.host_status = format!(
|
||||
"Host unavailable: {message}. Keep the local export below and try Share export again."
|
||||
"Host {}: {}. Keep the local export below and try Share export again.",
|
||||
host_failure_label(failure.kind),
|
||||
failure.message
|
||||
);
|
||||
}
|
||||
HostEvent::Acknowledged { id } if id.0 == "workout-set-haptic" => {
|
||||
|
||||
Reference in New Issue
Block a user