Implement Witness-Refinery protocol handlers (gt-m5w4g.2)
Add internal/protocol/ package with handlers for: - MERGE_READY (witness→refinery): worker done, branch ready - MERGED (refinery→witness): merge succeeded, cleanup ok - MERGE_FAILED (refinery→witness): merge failed, needs rework - REWORK_REQUEST (refinery→witness): rebase needed due to conflicts Package structure: - types.go: Protocol message types and payload structs - messages.go: Message builders and body parsers - handlers.go: Handler interface and registry for dispatch - witness_handlers.go: DefaultWitnessHandler implementation - refinery_handlers.go: DefaultRefineryHandler implementation - protocol_test.go: Comprehensive test coverage Also updated docs/mail-protocol.md with: - MERGE_FAILED and REWORK_REQUEST message type documentation - Merge failure and rebase required flow diagrams - Reference to internal/protocol/ package 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
124
internal/protocol/handlers.go
Normal file
124
internal/protocol/handlers.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/steveyegge/gastown/internal/mail"
|
||||
)
|
||||
|
||||
// Handler processes a protocol message and returns an error if processing failed.
|
||||
type Handler func(msg *mail.Message) error
|
||||
|
||||
// HandlerRegistry maps message types to their handlers.
|
||||
type HandlerRegistry struct {
|
||||
handlers map[MessageType]Handler
|
||||
}
|
||||
|
||||
// NewHandlerRegistry creates a new handler registry.
|
||||
func NewHandlerRegistry() *HandlerRegistry {
|
||||
return &HandlerRegistry{
|
||||
handlers: make(map[MessageType]Handler),
|
||||
}
|
||||
}
|
||||
|
||||
// Register adds a handler for a specific message type.
|
||||
func (r *HandlerRegistry) Register(msgType MessageType, handler Handler) {
|
||||
r.handlers[msgType] = handler
|
||||
}
|
||||
|
||||
// Handle dispatches a message to the appropriate handler.
|
||||
// Returns an error if no handler is registered for the message type.
|
||||
func (r *HandlerRegistry) Handle(msg *mail.Message) error {
|
||||
msgType := ParseMessageType(msg.Subject)
|
||||
if msgType == "" {
|
||||
return fmt.Errorf("unknown message type for subject: %s", msg.Subject)
|
||||
}
|
||||
|
||||
handler, ok := r.handlers[msgType]
|
||||
if !ok {
|
||||
return fmt.Errorf("no handler registered for message type: %s", msgType)
|
||||
}
|
||||
|
||||
return handler(msg)
|
||||
}
|
||||
|
||||
// CanHandle returns true if a handler is registered for the message's type.
|
||||
func (r *HandlerRegistry) CanHandle(msg *mail.Message) bool {
|
||||
msgType := ParseMessageType(msg.Subject)
|
||||
if msgType == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
_, ok := r.handlers[msgType]
|
||||
return ok
|
||||
}
|
||||
|
||||
// WitnessHandler defines the interface for Witness protocol handlers.
|
||||
// The Witness receives messages from Refinery about merge status.
|
||||
type WitnessHandler interface {
|
||||
// HandleMerged is called when a branch was successfully merged.
|
||||
HandleMerged(payload *MergedPayload) error
|
||||
|
||||
// HandleMergeFailed is called when a merge attempt failed.
|
||||
HandleMergeFailed(payload *MergeFailedPayload) error
|
||||
|
||||
// HandleReworkRequest is called when a branch needs rebasing.
|
||||
HandleReworkRequest(payload *ReworkRequestPayload) error
|
||||
}
|
||||
|
||||
// RefineryHandler defines the interface for Refinery protocol handlers.
|
||||
// The Refinery receives messages from Witness about ready branches.
|
||||
type RefineryHandler interface {
|
||||
// HandleMergeReady is called when a polecat's work is verified and ready.
|
||||
HandleMergeReady(payload *MergeReadyPayload) error
|
||||
}
|
||||
|
||||
// WrapWitnessHandlers creates mail handlers from a WitnessHandler.
|
||||
func WrapWitnessHandlers(h WitnessHandler) *HandlerRegistry {
|
||||
registry := NewHandlerRegistry()
|
||||
|
||||
registry.Register(TypeMerged, func(msg *mail.Message) error {
|
||||
payload := ParseMergedPayload(msg.Body)
|
||||
return h.HandleMerged(payload)
|
||||
})
|
||||
|
||||
registry.Register(TypeMergeFailed, func(msg *mail.Message) error {
|
||||
payload := ParseMergeFailedPayload(msg.Body)
|
||||
return h.HandleMergeFailed(payload)
|
||||
})
|
||||
|
||||
registry.Register(TypeReworkRequest, func(msg *mail.Message) error {
|
||||
payload := ParseReworkRequestPayload(msg.Body)
|
||||
return h.HandleReworkRequest(payload)
|
||||
})
|
||||
|
||||
return registry
|
||||
}
|
||||
|
||||
// WrapRefineryHandlers creates mail handlers from a RefineryHandler.
|
||||
func WrapRefineryHandlers(h RefineryHandler) *HandlerRegistry {
|
||||
registry := NewHandlerRegistry()
|
||||
|
||||
registry.Register(TypeMergeReady, func(msg *mail.Message) error {
|
||||
payload := ParseMergeReadyPayload(msg.Body)
|
||||
return h.HandleMergeReady(payload)
|
||||
})
|
||||
|
||||
return registry
|
||||
}
|
||||
|
||||
// ProcessProtocolMessage processes a protocol message using the registry.
|
||||
// It returns (true, nil) if the message was handled successfully,
|
||||
// (true, error) if handling failed, or (false, nil) if not a protocol message.
|
||||
func (r *HandlerRegistry) ProcessProtocolMessage(msg *mail.Message) (bool, error) {
|
||||
if !IsProtocolMessage(msg.Subject) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if !r.CanHandle(msg) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
err := r.Handle(msg)
|
||||
return true, err
|
||||
}
|
||||
Reference in New Issue
Block a user