Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c886d3fa6 | ||
|
|
2dcbb78b40 |
2 changed files with 80 additions and 35 deletions
|
|
@ -585,7 +585,10 @@ async fn serve_loop<S: Surface>(
|
||||||
}
|
}
|
||||||
} {
|
} {
|
||||||
RecvOutcome::Message(first) => first,
|
RecvOutcome::Message(first) => first,
|
||||||
RecvOutcome::LocalTodo => synthetic_todo_message(),
|
RecvOutcome::LocalTodo => {
|
||||||
|
tracing::debug!("todo wake consumed, sending synthetic todo message");
|
||||||
|
synthetic_todo_message()
|
||||||
|
}
|
||||||
RecvOutcome::Empty => {
|
RecvOutcome::Empty => {
|
||||||
// Idle: no message this poll. Service a queued operator
|
// Idle: no message this poll. Service a queued operator
|
||||||
// `/compact` here so it runs even when no turn is driving
|
// `/compact` here so it runs even when no turn is driving
|
||||||
|
|
|
||||||
|
|
@ -170,44 +170,21 @@ fn dispatch(
|
||||||
key,
|
key,
|
||||||
summary,
|
summary,
|
||||||
source,
|
source,
|
||||||
} => match store.upsert(&subsystem, key.as_deref(), &summary, source.as_deref()) {
|
} => upsert_todo(
|
||||||
Ok((_, changed)) => {
|
store,
|
||||||
if changed {
|
wake,
|
||||||
wake.notify_one();
|
&subsystem,
|
||||||
}
|
key.as_deref(),
|
||||||
Response::Ok
|
&summary,
|
||||||
}
|
source.as_deref(),
|
||||||
Err(e) => err(&e),
|
),
|
||||||
},
|
|
||||||
Request::ClearTodo {
|
Request::ClearTodo {
|
||||||
subsystem,
|
subsystem,
|
||||||
key,
|
key,
|
||||||
all,
|
all,
|
||||||
} => {
|
} => clear_todo(store, &subsystem, key.as_deref(), all),
|
||||||
let result = if all {
|
Request::ListTodos { subsystem } => list_todos(store, subsystem.as_deref()),
|
||||||
store.clear_subsystem(&subsystem)
|
Request::MarkTodoDone { id } => mark_todo_done(store, id),
|
||||||
} else {
|
|
||||||
store.clear(&subsystem, key.as_deref())
|
|
||||||
};
|
|
||||||
match result {
|
|
||||||
Ok(count) => Response::Acked {
|
|
||||||
count: u64::try_from(count).unwrap_or(0),
|
|
||||||
},
|
|
||||||
Err(e) => err(&e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Request::ListTodos { subsystem } => match store.list(subsystem.as_deref()) {
|
|
||||||
Ok(todos) => Response::LooseEnds {
|
|
||||||
loose_ends: todos.into_iter().map(to_loose_end).collect(),
|
|
||||||
},
|
|
||||||
Err(e) => err(&e),
|
|
||||||
},
|
|
||||||
Request::MarkTodoDone { id } => match store.mark_done(id) {
|
|
||||||
Ok(count) => Response::Acked {
|
|
||||||
count: u64::try_from(count).unwrap_or(0),
|
|
||||||
},
|
|
||||||
Err(e) => err(&e),
|
|
||||||
},
|
|
||||||
Request::StoreReminder {
|
Request::StoreReminder {
|
||||||
message,
|
message,
|
||||||
timing,
|
timing,
|
||||||
|
|
@ -260,6 +237,71 @@ fn dispatch(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `UpsertTodo` handler: writes/refreshes a todo row, logs the outcome, and
|
||||||
|
/// fires `wake` on a new-or-changed upsert so the serve loop runs a turn.
|
||||||
|
fn upsert_todo(
|
||||||
|
store: &Todos,
|
||||||
|
wake: &Notify,
|
||||||
|
subsystem: &str,
|
||||||
|
key: Option<&str>,
|
||||||
|
summary: &str,
|
||||||
|
source: Option<&str>,
|
||||||
|
) -> Response {
|
||||||
|
match store.upsert(subsystem, key, summary, source) {
|
||||||
|
Ok((id, changed)) => {
|
||||||
|
tracing::debug!(%subsystem, ?key, id, changed, "todo upsert");
|
||||||
|
if changed {
|
||||||
|
wake.notify_one();
|
||||||
|
}
|
||||||
|
Response::Ok
|
||||||
|
}
|
||||||
|
Err(e) => err(&e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `ClearTodo` handler: drops one keyed todo, or every todo in `subsystem`
|
||||||
|
/// when `all` is set.
|
||||||
|
fn clear_todo(store: &Todos, subsystem: &str, key: Option<&str>, all: bool) -> Response {
|
||||||
|
let result = if all {
|
||||||
|
store.clear_subsystem(subsystem)
|
||||||
|
} else {
|
||||||
|
store.clear(subsystem, key)
|
||||||
|
};
|
||||||
|
match result {
|
||||||
|
Ok(count) => {
|
||||||
|
tracing::debug!(%subsystem, ?key, all, count, "todo clear");
|
||||||
|
Response::Acked {
|
||||||
|
count: u64::try_from(count).unwrap_or(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => err(&e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `ListTodos` handler: read-only, so no debug logging — not relevant to
|
||||||
|
/// diagnosing wake behaviour.
|
||||||
|
fn list_todos(store: &Todos, subsystem: Option<&str>) -> Response {
|
||||||
|
match store.list(subsystem) {
|
||||||
|
Ok(todos) => Response::LooseEnds {
|
||||||
|
loose_ends: todos.into_iter().map(to_loose_end).collect(),
|
||||||
|
},
|
||||||
|
Err(e) => err(&e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `MarkTodoDone` handler: marks a single todo done by id.
|
||||||
|
fn mark_todo_done(store: &Todos, id: i64) -> Response {
|
||||||
|
match store.mark_done(id) {
|
||||||
|
Ok(count) => {
|
||||||
|
tracing::debug!(id, count, "todo mark-done");
|
||||||
|
Response::Acked {
|
||||||
|
count: u64::try_from(count).unwrap_or(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => err(&e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// `Request::Compact` handler: gate on context usage, then queue the same
|
/// `Request::Compact` handler: gate on context usage, then queue the same
|
||||||
/// deferred `compact_pending` flag the operator's `/compact` button sets.
|
/// deferred `compact_pending` flag the operator's `/compact` button sets.
|
||||||
/// Mirrors `hive-agent::web_ui::actions::post_compact` but reachable from
|
/// Mirrors `hive-agent::web_ui::actions::post_compact` but reachable from
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue