feat: implement WebSocket binary protocol and NOT_IMPLEMENTED error code
Add CodeNotImplemented error constant (HTTP 501) for planned but unavailable features. Refactor WebSocket packet handling from JSON to binary protocol for improved efficiency: New packet structure: - PacketTypeSuccess (0x00): [type:1][json_data:var] - PacketTypeError (0x01): [type:1][code_len:1][code:var][msg_len:2][msg:var][details_len:2][details:var] - PacketTypeData (0x02): Reserved for future use Update SendErrorPacket: - Build binary error packets with length-prefixed fields - Use WriteMessage with websocket.BinaryMessage Update SendSuccessPacket: - Marshal data to JSON then wrap in binary packet - Eliminates "success" wrapper field for cleaner protocol Add helper functions: - NewNotImplemented(feature) - Standard 501 error - NewNotImplementedWithIssue(feature, issueURL) - 501 with GitHub reference
This commit is contained in:
parent
8a30acf661
commit
96dd604789
1 changed files with 58 additions and 10 deletions
|
|
@ -34,6 +34,7 @@ const (
|
|||
CodeBadRequest = "BAD_REQUEST"
|
||||
CodeForbidden = "FORBIDDEN"
|
||||
CodeNotFound = "NOT_FOUND"
|
||||
CodeNotImplemented = "NOT_IMPLEMENTED"
|
||||
)
|
||||
|
||||
// ErrorResponse represents a standardized error response
|
||||
|
|
@ -79,21 +80,39 @@ func WriteHTTPErrorFromError(w http.ResponseWriter, statusCode int, err error) {
|
|||
WriteHTTPError(w, statusCode, CodeUnknownError, err.Error(), "")
|
||||
}
|
||||
|
||||
// SendErrorPacket sends an error packet over WebSocket
|
||||
// Packet types for binary WebSocket protocol
|
||||
const (
|
||||
PacketTypeSuccess = 0x00
|
||||
PacketTypeError = 0x01
|
||||
PacketTypeData = 0x02
|
||||
)
|
||||
|
||||
// SendErrorPacket sends an error packet over WebSocket using binary protocol
|
||||
func SendErrorPacket(conn *websocket.Conn, code, message, details string) error {
|
||||
resp := NewErrorResponse(code, message, details)
|
||||
return conn.WriteJSON(resp)
|
||||
// Build binary error packet: [type:1][code_len:1][code:var][msg_len:2][msg:var][details_len:2][details:var]
|
||||
buf := make([]byte, 0, 1+1+len(code)+2+len(message)+2+len(details))
|
||||
buf = append(buf, PacketTypeError)
|
||||
buf = append(buf, byte(len(code)))
|
||||
buf = append(buf, []byte(code)...)
|
||||
buf = append(buf, byte(len(message)>>8), byte(len(message)))
|
||||
buf = append(buf, []byte(message)...)
|
||||
buf = append(buf, byte(len(details)>>8), byte(len(details)))
|
||||
buf = append(buf, []byte(details)...)
|
||||
return conn.WriteMessage(websocket.BinaryMessage, buf)
|
||||
}
|
||||
|
||||
// SendSuccessPacket sends a success packet over WebSocket
|
||||
// Automatically adds "success": true to the response
|
||||
// SendSuccessPacket sends a success packet over WebSocket using binary protocol
|
||||
// The data is serialized as JSON within the binary packet
|
||||
func SendSuccessPacket(conn *websocket.Conn, data map[string]any) error {
|
||||
response := make(map[string]any, len(data)+1)
|
||||
response["success"] = true
|
||||
for k, v := range data {
|
||||
response[k] = v
|
||||
// Build binary success packet: [type:1][json_data:var]
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return conn.WriteJSON(response)
|
||||
buf := make([]byte, 0, 1+len(jsonData))
|
||||
buf = append(buf, PacketTypeSuccess)
|
||||
buf = append(buf, jsonData...)
|
||||
return conn.WriteMessage(websocket.BinaryMessage, buf)
|
||||
}
|
||||
|
||||
// Common error responses as typed errors for use with errors.Is/errors.As
|
||||
|
|
@ -104,8 +123,35 @@ var (
|
|||
ErrInvalidRequest = NewErrorResponse(CodeInvalidRequest, "invalid request", "")
|
||||
ErrServiceUnavailable = NewErrorResponse(CodeServiceUnavailable, "service unavailable", "")
|
||||
ErrServerOverloaded = NewErrorResponse(CodeServerOverloaded, "server overloaded", "")
|
||||
ErrNotImplemented = NewErrorResponse(CodeNotImplemented, "feature not implemented", "")
|
||||
)
|
||||
|
||||
// NewNotImplemented creates a not implemented error with feature name
|
||||
func NewNotImplemented(feature string) ErrorResponse {
|
||||
return NewErrorResponse(
|
||||
CodeNotImplemented,
|
||||
fmt.Sprintf("%s is not yet implemented", feature),
|
||||
"This feature is planned but not yet available. See documentation for alternatives.",
|
||||
)
|
||||
}
|
||||
|
||||
// NewNotImplementedWithIssue creates a not implemented error with GitHub issue reference
|
||||
func NewNotImplementedWithIssue(feature string, issueURL string) ErrorResponse {
|
||||
return NewErrorResponse(
|
||||
CodeNotImplemented,
|
||||
fmt.Sprintf("%s is not yet implemented", feature),
|
||||
fmt.Sprintf("Track progress at: %s", issueURL),
|
||||
)
|
||||
}
|
||||
|
||||
// IsNotImplemented checks if error is a not implemented error
|
||||
func IsNotImplemented(err error) bool {
|
||||
if errResp, ok := err.(ErrorResponse); ok {
|
||||
return errResp.Code == CodeNotImplemented
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// HTTPStatusFromCode maps error codes to HTTP status codes
|
||||
func HTTPStatusFromCode(code string) int {
|
||||
switch code {
|
||||
|
|
@ -123,6 +169,8 @@ func HTTPStatusFromCode(code string) int {
|
|||
return http.StatusServiceUnavailable
|
||||
case CodeTimeout:
|
||||
return http.StatusRequestTimeout
|
||||
case CodeNotImplemented:
|
||||
return http.StatusNotImplemented
|
||||
default:
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue