package controller import ( "context" "encoding/json" "fmt" "hash-of-wisdom/internal/pow/challenge" "hash-of-wisdom/internal/protocol" "hash-of-wisdom/internal/quotes" ) // WisdomService defines the interface for the wisdom service type WisdomService interface { GenerateChallenge(ctx context.Context, resource string) (*challenge.Challenge, error) VerifySolution(ctx context.Context, solution *challenge.Solution) error GetQuote(ctx context.Context) (*quotes.Quote, error) } // WisdomController handles the Word of Wisdom protocol flow type WisdomController struct { wisdomService WisdomService codec *protocol.Codec } // NewWisdomController creates a new wisdom protocol controller func NewWisdomController(wisdomService WisdomService) *WisdomController { return &WisdomController{ wisdomService: wisdomService, codec: protocol.NewCodec(), } } // HandleMessage processes a protocol message and returns a response func (c *WisdomController) HandleMessage(ctx context.Context, msg *protocol.Message) (*protocol.Message, error) { switch msg.Type { case protocol.ChallengeRequest: return c.handleChallengeRequest(ctx, msg) case protocol.SolutionRequest: return c.handleSolutionRequest(ctx, msg) default: return c.createErrorResponse(protocol.ErrMalformedMessage, fmt.Sprintf("unsupported message type: 0x%02x", msg.Type)) } } // handleChallengeRequest processes challenge requests func (c *WisdomController) handleChallengeRequest(ctx context.Context, _ *protocol.Message) (*protocol.Message, error) { challenge, err := c.wisdomService.GenerateChallenge(ctx, "quotes") if err != nil { return c.createErrorResponse(protocol.ErrServerError, "failed to generate challenge") } // Protocol requires direct challenge JSON (not wrapped) payload := (*protocol.ChallengeResponsePayload)(challenge) jsonData, err := json.Marshal(payload) if err != nil { return c.createErrorResponse(protocol.ErrServerError, "failed to marshal challenge") } return &protocol.Message{ Type: protocol.ChallengeResponse, Payload: jsonData, }, nil } // handleSolutionRequest processes solution requests func (c *WisdomController) handleSolutionRequest(ctx context.Context, msg *protocol.Message) (*protocol.Message, error) { // Parse solution request var solutionReq protocol.SolutionRequestPayload if err := json.Unmarshal(msg.Payload, &solutionReq); err != nil { return c.createErrorResponse(protocol.ErrMalformedMessage, "invalid solution format") } // Create solution object solution := &challenge.Solution{ Challenge: solutionReq.Challenge, Nonce: solutionReq.Nonce, } // Verify solution if err := c.wisdomService.VerifySolution(ctx, solution); err != nil { return c.createErrorResponse(protocol.ErrInvalidSolution, "solution verification failed") } // Get quote quote, err := c.wisdomService.GetQuote(ctx) if err != nil { return c.createErrorResponse(protocol.ErrServerError, "failed to get quote") } // Protocol requires direct quote JSON (not wrapped) payload := (*protocol.QuoteResponsePayload)(quote) jsonData, err := json.Marshal(payload) if err != nil { return c.createErrorResponse(protocol.ErrServerError, "failed to marshal quote") } return &protocol.Message{ Type: protocol.QuoteResponse, Payload: jsonData, }, nil } // createErrorResponse creates a protocol error response func (c *WisdomController) createErrorResponse(code, message string) (*protocol.Message, error) { errorPayload := &protocol.ErrorResponsePayload{ Code: code, Message: message, } jsonData, err := json.Marshal(errorPayload) if err != nil { return nil, fmt.Errorf("failed to marshal error: %w", err) } return &protocol.Message{ Type: protocol.ErrorResponse, Payload: jsonData, }, nil }