package node import ( "fmt" ) // if pe, ok := err.(*ProtocolError); ok { log(pe.Code, pe.Message) } type ProtocolError struct { Code int Message string } func (e *ProtocolError) Error() string { return fmt.Sprintf("remote error (%d): %s", e.Code, e.Message) } // handler := &ResponseHandler{} // if err := handler.ValidateResponse(resp, MsgPong); err != nil { return 0, err } type ResponseHandler struct{} // if err := handler.ValidateResponse(resp, MsgPong); err != nil { return 0, err } func (h *ResponseHandler) ValidateResponse(resp *Message, expectedType MessageType) error { if resp == nil { return fmt.Errorf("nil response") } // Check for error response if resp.Type == MsgError { var errPayload ErrorPayload if err := resp.ParsePayload(&errPayload); err != nil { return &ProtocolError{Code: ErrCodeUnknown, Message: "unable to parse error response"} } return &ProtocolError{Code: errPayload.Code, Message: errPayload.Message} } // Check expected type if resp.Type != expectedType { return fmt.Errorf("unexpected response type: expected %s, got %s", expectedType, resp.Type) } return nil } // ParseResponse validates the response and parses the payload into the target. // This combines ValidateResponse and ParsePayload into a single call. func (h *ResponseHandler) ParseResponse(resp *Message, expectedType MessageType, target interface{}) error { if err := h.ValidateResponse(resp, expectedType); err != nil { return err } if target != nil { if err := resp.ParsePayload(target); err != nil { return fmt.Errorf("failed to parse %s payload: %w", expectedType, err) } } return nil } // DefaultResponseHandler is the default response handler instance. var DefaultResponseHandler = &ResponseHandler{} // ValidateResponse is a convenience function using the default handler. func ValidateResponse(resp *Message, expectedType MessageType) error { return DefaultResponseHandler.ValidateResponse(resp, expectedType) } // ParseResponse is a convenience function using the default handler. func ParseResponse(resp *Message, expectedType MessageType, target interface{}) error { return DefaultResponseHandler.ParseResponse(resp, expectedType, target) } // IsProtocolError returns true if the error is a ProtocolError. func IsProtocolError(err error) bool { _, ok := err.(*ProtocolError) return ok } // GetProtocolErrorCode returns the error code if err is a ProtocolError, otherwise returns 0. func GetProtocolErrorCode(err error) int { if pe, ok := err.(*ProtocolError); ok { return pe.Code } return 0 }