package afdata
import (
"encoding/json"
"fmt"
"strings"
)
type DecodedEvent interface {
isDecodedEvent()
}
type DecodedResult struct {
Result any
Trace map[string]any
}
type DecodedError struct {
Code string
Message string
Retryable bool
Hint string
Fields map[string]any
Trace map[string]any
}
type DecodedProgress struct {
Progress any
Trace map[string]any
}
type DecodedLog struct {
Log any
Trace map[string]any
}
func (*DecodedResult) isDecodedEvent() {}
func (*DecodedError) isDecodedEvent() {}
func (*DecodedProgress) isDecodedEvent() {}
func (*DecodedLog) isDecodedEvent() {}
type EventDecodeError struct {
msg string
}
func (e *EventDecodeError) Error() string { return e.msg }
func DecodeProtocolEvent(text string) (DecodedEvent, error) {
var value any
dec := json.NewDecoder(strings.NewReader(text))
dec.UseNumber()
if err := dec.Decode(&value); err != nil {
return nil, &EventDecodeError{msg: fmt.Sprintf("invalid JSON: %v", err)}
}
if err := ValidateProtocolEvent(value, true); err != nil {
return nil, &EventDecodeError{msg: err.Error()}
}
obj := value.(map[string]any)
trace, _ := obj["trace"].(map[string]any)
switch obj["kind"].(string) {
case "result":
return &DecodedResult{Result: obj["result"], Trace: trace}, nil
case "error":
errorPayload := obj["error"].(map[string]any)
hint, _ := errorPayload["hint"].(string)
fields := make(map[string]any, len(errorPayload))
for k, v := range errorPayload {
if k != "code" && k != "message" && k != "retryable" && k != "hint" {
fields[k] = v
}
}
return &DecodedError{
Code: errorPayload["code"].(string),
Message: errorPayload["message"].(string),
Retryable: errorPayload["retryable"].(bool),
Hint: hint,
Fields: fields,
Trace: trace,
}, nil
case "progress":
return &DecodedProgress{
Progress: obj["progress"],
Trace: trace,
}, nil
case "log":
return &DecodedLog{
Log: obj["log"],
Trace: trace,
}, nil
default:
return nil, &EventDecodeError{msg: fmt.Sprintf("unsupported event kind %q", obj["kind"])}
}
}