package protocol import ( "encoding/binary" "encoding/json" "fmt" "io" "hash-of-wisdom/internal/pow/challenge" "hash-of-wisdom/internal/quotes" ) // writeHeader writes the message type and payload length to the writer func writeHeader(w io.Writer, msgType MessageType, payloadLength uint32) error { // Write message type (1 byte) if err := binary.Write(w, binary.BigEndian, msgType); err != nil { return fmt.Errorf("failed to write message type: %w", err) } // Write payload length (4 bytes, big-endian) if err := binary.Write(w, binary.BigEndian, payloadLength); err != nil { return fmt.Errorf("failed to write payload length: %w", err) } return nil } // encodeResponse is a helper function that encodes any response with the given message type func encodeResponse(w io.Writer, msgType MessageType, payload interface{}) error { // Marshal to get exact payload size payloadBytes, err := json.Marshal(payload) if err != nil { return fmt.Errorf("failed to encode payload: %w", err) } // Write header if err := writeHeader(w, msgType, uint32(len(payloadBytes))); err != nil { return err } // Write JSON payload directly to stream if len(payloadBytes) > 0 { if _, err := w.Write(payloadBytes); err != nil { return fmt.Errorf("failed to write payload: %w", err) } } return nil } // ChallengeResponse represents a challenge response type ChallengeResponse struct { Challenge *challenge.Challenge } // SolutionResponse represents a successful solution response (contains quote) type SolutionResponse struct { Quote *quotes.Quote } // ErrorResponse represents an error response type ErrorResponse struct { Code string `json:"code"` Message string `json:"message"` RetryAfter int `json:"retry_after,omitempty"` Details map[string]string `json:"details,omitempty"` } // Encode writes the challenge response to the writer func (r *ChallengeResponse) Encode(w io.Writer) error { return encodeResponse(w, ChallengeResponseType, r.Challenge) } // Encode writes the solution response to the writer func (r *SolutionResponse) Encode(w io.Writer) error { return encodeResponse(w, QuoteResponseType, r.Quote) } // Encode writes the error response to the writer func (r *ErrorResponse) Encode(w io.Writer) error { return encodeResponse(w, ErrorResponseType, r) }