325 lines
8.1 KiB
Go
325 lines
8.1 KiB
Go
package envelope
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"git.wisehodl.dev/jay/go-roots-ws/errors"
|
|
)
|
|
|
|
// CheckArrayLength is a helper function that ensures the JSON array has at
|
|
// least the minimum length required
|
|
func CheckArrayLength(arr []json.RawMessage, minLen int) error {
|
|
if len(arr) < minLen {
|
|
return fmt.Errorf("%w: expected %d elements, got %d", errors.InvalidEnvelope, minLen, len(arr))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CheckLabel is a helper function that verifies that the envelope label
|
|
// matches the expected one
|
|
func CheckLabel(got, want string) error {
|
|
if got != want {
|
|
return fmt.Errorf("%w: expected %s, got %s", errors.WrongEnvelopeLabel, want, got)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ParseElement is a helper function that unmarshals an array element into the
|
|
// provided value
|
|
func ParseElement(element json.RawMessage, value interface{}, position string) error {
|
|
if err := json.Unmarshal(element, value); err != nil {
|
|
return fmt.Errorf("%w: %s is not the expected type", errors.WrongFieldType, position)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// FindEvent extracts an event from an EVENT envelope with no subscription ID.
|
|
// Expected Format: ["EVENT", event]
|
|
func FindEvent(env Envelope) ([]byte, error) {
|
|
var arr []json.RawMessage
|
|
if err := json.Unmarshal(env, &arr); err != nil {
|
|
return nil, fmt.Errorf("%w: %v", errors.InvalidJSON, err)
|
|
}
|
|
|
|
if err := CheckArrayLength(arr, 2); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var label string
|
|
if err := ParseElement(arr[0], &label, "envelope label"); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := CheckLabel(label, "EVENT"); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return arr[1], nil
|
|
}
|
|
|
|
// FindSubscriptionEvent extracts an event and subscription ID from an EVENT envelope.
|
|
// Expected Format: ["EVENT", subID, event]
|
|
func FindSubscriptionEvent(env Envelope) (subID string, event []byte, err error) {
|
|
var arr []json.RawMessage
|
|
if err = json.Unmarshal(env, &arr); err != nil {
|
|
return "", nil, fmt.Errorf("%w: %v", errors.InvalidJSON, err)
|
|
}
|
|
|
|
if err = CheckArrayLength(arr, 3); err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
var label string
|
|
if err := ParseElement(arr[0], &label, "envelope label"); err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
if err = CheckLabel(label, "EVENT"); err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
if err = ParseElement(arr[1], &subID, "subscription ID"); err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
return subID, arr[2], nil
|
|
}
|
|
|
|
// FindOK extracts eventID, status, and message from an OK envelope.
|
|
// Expected Format: ["OK", eventID, status, message]
|
|
func FindOK(env Envelope) (eventID string, status bool, message string, err error) {
|
|
var arr []json.RawMessage
|
|
if err = json.Unmarshal(env, &arr); err != nil {
|
|
return "", false, "", fmt.Errorf("%w: %v", errors.InvalidJSON, err)
|
|
}
|
|
|
|
if err = CheckArrayLength(arr, 4); err != nil {
|
|
return "", false, "", err
|
|
}
|
|
|
|
var label string
|
|
if err := ParseElement(arr[0], &label, "envelope label"); err != nil {
|
|
return "", false, "", err
|
|
}
|
|
|
|
if err = CheckLabel(label, "OK"); err != nil {
|
|
return "", false, "", err
|
|
}
|
|
|
|
if err = ParseElement(arr[1], &eventID, "event ID"); err != nil {
|
|
return "", false, "", err
|
|
}
|
|
|
|
if err = ParseElement(arr[2], &status, "status"); err != nil {
|
|
return "", false, "", err
|
|
}
|
|
|
|
if err = ParseElement(arr[3], &message, "message"); err != nil {
|
|
return "", false, "", err
|
|
}
|
|
|
|
return eventID, status, message, nil
|
|
}
|
|
|
|
// FindReq extracts subscription ID and filters from a REQ envelope.
|
|
// Expected Format: ["REQ", subID, filter1, filter2, ...]
|
|
func FindReq(env Envelope) (subID string, filters [][]byte, err error) {
|
|
var arr []json.RawMessage
|
|
if err = json.Unmarshal(env, &arr); err != nil {
|
|
return "", nil, fmt.Errorf("%w: %v", errors.InvalidJSON, err)
|
|
}
|
|
|
|
if err = CheckArrayLength(arr, 2); err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
var label string
|
|
if err := ParseElement(arr[0], &label, "envelope label"); err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
if err = CheckLabel(label, "REQ"); err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
if err = ParseElement(arr[1], &subID, "subscription ID"); err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
filters = make([][]byte, 0, len(arr)-2)
|
|
for i := 2; i < len(arr); i++ {
|
|
filters = append(filters, arr[i])
|
|
}
|
|
|
|
return subID, filters, nil
|
|
}
|
|
|
|
// FindEOSE extracts subscription ID from an EOSE envelope.
|
|
// Expected Format: ["EOSE", subID]
|
|
func FindEOSE(env Envelope) (subID string, err error) {
|
|
var arr []json.RawMessage
|
|
if err = json.Unmarshal(env, &arr); err != nil {
|
|
return "", fmt.Errorf("%w: %v", errors.InvalidJSON, err)
|
|
}
|
|
|
|
if err = CheckArrayLength(arr, 2); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
var label string
|
|
if err := ParseElement(arr[0], &label, "envelope label"); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err = CheckLabel(label, "EOSE"); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err = ParseElement(arr[1], &subID, "subscription ID"); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return subID, nil
|
|
}
|
|
|
|
// FindClose extracts subscription ID from a CLOSE envelope.
|
|
// Expected Format: ["CLOSE", subID]
|
|
func FindClose(env Envelope) (subID string, err error) {
|
|
var arr []json.RawMessage
|
|
if err = json.Unmarshal(env, &arr); err != nil {
|
|
return "", fmt.Errorf("%w: %v", errors.InvalidJSON, err)
|
|
}
|
|
|
|
if err = CheckArrayLength(arr, 2); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
var label string
|
|
if err := ParseElement(arr[0], &label, "envelope label"); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err = CheckLabel(label, "CLOSE"); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err = ParseElement(arr[1], &subID, "subscription ID"); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return subID, nil
|
|
}
|
|
|
|
// FindClosed extracts subscription ID and message from a CLOSED envelope.
|
|
// Expected Format: ["CLOSED", subID, message]
|
|
func FindClosed(env Envelope) (subID string, message string, err error) {
|
|
var arr []json.RawMessage
|
|
if err = json.Unmarshal(env, &arr); err != nil {
|
|
return "", "", fmt.Errorf("%w: %v", errors.InvalidJSON, err)
|
|
}
|
|
|
|
if err = CheckArrayLength(arr, 3); err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
var label string
|
|
if err := ParseElement(arr[0], &label, "envelope label"); err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
if err = CheckLabel(label, "CLOSED"); err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
if err = ParseElement(arr[1], &subID, "subscription ID"); err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
if err = ParseElement(arr[2], &message, "message"); err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
return subID, message, nil
|
|
}
|
|
|
|
// FindNotice extracts message from a NOTICE envelope.
|
|
// Expected Format: ["NOTICE", message]
|
|
func FindNotice(env Envelope) (message string, err error) {
|
|
var arr []json.RawMessage
|
|
if err = json.Unmarshal(env, &arr); err != nil {
|
|
return "", fmt.Errorf("%w: %v", errors.InvalidJSON, err)
|
|
}
|
|
|
|
if err = CheckArrayLength(arr, 2); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
var label string
|
|
if err := ParseElement(arr[0], &label, "envelope label"); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err = CheckLabel(label, "NOTICE"); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err = ParseElement(arr[1], &message, "message"); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return message, nil
|
|
}
|
|
|
|
// FindAuthChallenge extracts challenge from an AUTH challenge envelope.
|
|
// Expected Format: ["AUTH", challenge]
|
|
func FindAuthChallenge(env Envelope) (challenge string, err error) {
|
|
var arr []json.RawMessage
|
|
if err = json.Unmarshal(env, &arr); err != nil {
|
|
return "", fmt.Errorf("%w: %v", errors.InvalidJSON, err)
|
|
}
|
|
|
|
if err = CheckArrayLength(arr, 2); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
var label string
|
|
if err := ParseElement(arr[0], &label, "envelope label"); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err = CheckLabel(label, "AUTH"); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Check if the second element is a string (AUTH challenge)
|
|
if err = ParseElement(arr[1], &challenge, "challenge"); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return challenge, nil
|
|
}
|
|
|
|
// FindAuthResponse extracts event from an AUTH response envelope.
|
|
// Expected Format: ["AUTH", event]
|
|
func FindAuthResponse(env Envelope) (event []byte, err error) {
|
|
var arr []json.RawMessage
|
|
if err = json.Unmarshal(env, &arr); err != nil {
|
|
return nil, fmt.Errorf("%w: %v", errors.InvalidJSON, err)
|
|
}
|
|
|
|
if err = CheckArrayLength(arr, 2); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var label string
|
|
if err := ParseElement(arr[0], &label, "envelope label"); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err = CheckLabel(label, "AUTH"); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return arr[1], nil
|
|
}
|