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) { m := 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 { m["actor"] = e.Actor } if e.Auth != nil { m["auth"] = e.Auth } if e.Payload != nil { m["payload"] = e.Payload } if e.Meta != nil { m["meta"] = e.Meta } if e.Error != nil { errMap := map[string]any{ "code": e.Error.Code, "message": e.Error.Message, "retryable": e.Error.Retryable, } if e.Error.Details != nil { errMap["details"] = e.Error.Details } m["error"] = errMap } return structpb.NewStruct(m) } func EnvelopeFromStruct(s *structpb.Struct) (Envelope, error) { var env Envelope if s == nil { return env, fmt.Errorf("nil struct") } m := s.AsMap() if v, ok := m["protocol_version"].(string); ok { env.ProtocolVersion = v } if v, ok := m["id"].(string); ok { env.ID = v } if v, ok := m["correlation_id"].(string); ok { env.CorrelationID = v } if v, ok := m["type"].(string); ok { env.Type = v } if v, ok := m["channel"].(string); ok { env.Channel = v } if v, ok := m["action"].(string); ok { env.Action = v } if v, ok := m["actor"].(map[string]any); ok { env.Actor = v } if v, ok := m["auth"].(map[string]any); ok { env.Auth = v } if v, ok := m["payload"].(map[string]any); ok { env.Payload = v } if v, ok := m["meta"].(map[string]any); ok { env.Meta = v } if errVal, ok := m["error"].(map[string]any); ok { var envErr EnvelopeError if code, ok := errVal["code"].(string); ok { envErr.Code = code } if msg, ok := errVal["message"].(string); ok { envErr.Message = msg } if ret, ok := errVal["retryable"].(bool); ok { envErr.Retryable = ret } if details, ok := errVal["details"].(map[string]any); ok { envErr.Details = details } env.Error = &envErr } return env, nil }