refactor: extract Undo dispatch into type-specific handlers #14

Open
opened 2026-05-30 01:32:44 +00:00 by GKaszewski · 0 comments
Owner

Problem

activities/undo.rs contains a 94-line match statement in receive() that dispatches based on object["type"] string matching:

match obj_type {
    "Follow" => { ... },
    "Add" => { ... },
    "Like" => { ... },
    "Announce" => { ... },
    "Block" => { ... },
    other => { tracing::debug!("ignoring Undo of unknown type"); }
}

Each branch duplicates the pattern: parse object → call handler → log. Adding a new undo-able type requires editing undo.rs. No type safety — obj_type is a runtime string.

Proposal

Option A — Registry pattern: Each activity type registers its own undo handler:

trait UndoHandler {
    fn activity_type(&self) -> &str;
    async fn undo(&self, actor: &Url, object: &Value, data: &Data<FederationData>) -> Result<()>;
}

Option B — Co-locate with activity: Each activity module defines its own undo() function, and undo.rs just does lookup + delegation.

Option C — Trait method: Add fn undo() to the activity handler trait from #10, so undo logic lives next to receive logic.

Files

  • src/activities/undo.rs (primary)
  • src/activities/mod.rs (if registry-based)

Trade-offs

  • Registry adds indirection but is extensible
  • Co-location keeps related logic together but still needs a dispatcher
  • Trait method is cleanest but depends on #10 landing first

Dependency

Best done after #10 (activity dispatcher middleware).

## Problem `activities/undo.rs` contains a 94-line match statement in `receive()` that dispatches based on `object["type"]` string matching: ```rust match obj_type { "Follow" => { ... }, "Add" => { ... }, "Like" => { ... }, "Announce" => { ... }, "Block" => { ... }, other => { tracing::debug!("ignoring Undo of unknown type"); } } ``` Each branch duplicates the pattern: parse object → call handler → log. Adding a new undo-able type requires editing `undo.rs`. No type safety — `obj_type` is a runtime string. ## Proposal Option A — **Registry pattern**: Each activity type registers its own undo handler: ```rust trait UndoHandler { fn activity_type(&self) -> &str; async fn undo(&self, actor: &Url, object: &Value, data: &Data<FederationData>) -> Result<()>; } ``` Option B — **Co-locate with activity**: Each activity module defines its own `undo()` function, and `undo.rs` just does lookup + delegation. Option C — **Trait method**: Add `fn undo()` to the activity handler trait from #10, so undo logic lives next to receive logic. ## Files - `src/activities/undo.rs` (primary) - `src/activities/mod.rs` (if registry-based) ## Trade-offs - Registry adds indirection but is extensible - Co-location keeps related logic together but still needs a dispatcher - Trait method is cleanest but depends on #10 landing first ## Dependency Best done after #10 (activity dispatcher middleware).
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: GKaszewski/k-ap#14