From 7470fbfa66896a521ec218306af11e5b6e85f3b9 Mon Sep 17 00:00:00 2001 From: Savely Krendelhoff Date: Fri, 22 Aug 2025 21:32:46 +0700 Subject: [PATCH] Implement controller --- internal/controller/controller.go | 121 ++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 internal/controller/controller.go diff --git a/internal/controller/controller.go b/internal/controller/controller.go new file mode 100644 index 0000000..e3b3023 --- /dev/null +++ b/internal/controller/controller.go @@ -0,0 +1,121 @@ +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 +}