package protosocket import ( "fmt" "google.golang.org/protobuf/types/known/structpb" ) const ProtocolVersion = "nomadcode.proto-socket.v1" type Envelope struct { ProtocolVersion string `json:"protocol_version"` ID string `json:"id"` CorrelationID string `json:"correlation_id"` Type string `json:"type"` Channel string `json:"channel"` Action string `json:"action"` Actor map[string]any `json:"actor,omitempty"` Auth map[string]any `json:"auth,omitempty"` Payload map[string]any `json:"payload,omitempty"` Error *EnvelopeError `json:"error,omitempty"` Meta map[string]any `json:"meta,omitempty"` } type EnvelopeError struct { Code string `json:"code"` Message string `json:"message"` Retryable bool `json:"retryable"` Details map[string]any `json:"details,omitempty"` } func (e Envelope) ToStruct() (*structpb.Struct, error) { value := map[string]any{ "protocol_version": e.ProtocolVersion, "id": e.ID, "correlation_id": e.CorrelationID, "type": e.Type, "channel": e.Channel, "action": e.Action, } if e.Actor != nil { value["actor"] = e.Actor } if e.Auth != nil { value["auth"] = e.Auth } if e.Payload != nil { value["payload"] = e.Payload } if e.Meta != nil { value["meta"] = e.Meta } if e.Error != nil { errValue := map[string]any{ "code": e.Error.Code, "message": e.Error.Message, "retryable": e.Error.Retryable, } if e.Error.Details != nil { errValue["details"] = e.Error.Details } value["error"] = errValue } return structpb.NewStruct(value) } func EnvelopeFromStruct(value *structpb.Struct) (Envelope, error) { var env Envelope if value == nil { return env, fmt.Errorf("nil struct") } raw := value.AsMap() if v, ok := raw["protocol_version"].(string); ok { env.ProtocolVersion = v } if v, ok := raw["id"].(string); ok { env.ID = v } if v, ok := raw["correlation_id"].(string); ok { env.CorrelationID = v } if v, ok := raw["type"].(string); ok { env.Type = v } if v, ok := raw["channel"].(string); ok { env.Channel = v } if v, ok := raw["action"].(string); ok { env.Action = v } if v, ok := raw["actor"].(map[string]any); ok { env.Actor = v } if v, ok := raw["auth"].(map[string]any); ok { env.Auth = v } if v, ok := raw["payload"].(map[string]any); ok { env.Payload = v } if v, ok := raw["meta"].(map[string]any); ok { env.Meta = v } if errValue, ok := raw["error"].(map[string]any); ok { envErr := EnvelopeError{} if v, ok := errValue["code"].(string); ok { envErr.Code = v } if v, ok := errValue["message"].(string); ok { envErr.Message = v } if v, ok := errValue["retryable"].(bool); ok { envErr.Retryable = v } if v, ok := errValue["details"].(map[string]any); ok { envErr.Details = v } env.Error = &envErr } return env, nil }