Documentation
¶
Overview ¶
Package tyomq provides a Socket.IO v4 client for the tyo-mq message broker.
Protocol: Engine.IO v4 over WebSocket, then Socket.IO v4 events. Wire format: `42["event_name",{...payload...}]`
Index ¶
- Constants
- func ConsumeEventName(producer, event, scope string) string
- func NewAuthDecideReq(adminToken, requestID string, approved bool, role, reason string) map[string]interface{}
- func NewAuthNextReq(adminToken, realmFilter string) map[string]interface{}
- type AckReq
- type AdminProof
- type AuthFail
- type AuthOK
- type AuthenticationReq
- type AuthorizationApproved
- type AuthorizationDecideResult
- type AuthorizationNextResult
- type AuthorizationRejected
- type AuthorizationRequest
- type AuthorizationRequestOK
- type Client
- func (c *Client) Ack(msgID string) error
- func (c *Client) Authenticate(ctx context.Context, token string) error
- func (c *Client) Close()
- func (c *Client) Connect(ctx context.Context, ready chan<- struct{}) error
- func (c *Client) Emit(event string, payload interface{}) error
- func (c *Client) On(event string, h Handler)
- func (c *Client) Produce(from, event string, message interface{}) error
- func (c *Client) RegisterConsumer(name string) error
- func (c *Client) RegisterProducer(name string) error
- func (c *Client) Subscribe(req SubscribeReq, handler func(ConsumedMessage)) error
- func (c *Client) WaitFor(event string) <-chan json.RawMessage
- type ConsumedMessage
- type Handler
- type PendingAuthRequest
- type ProduceReq
- type RegisterConsumer
- type RegisterProducer
- type RetryPolicy
- type ServerError
- type SubscribeReq
Constants ¶
const ( DefaultPort = 17352 // AllProducers subscribes to an event (or topic pattern) from any producer. AllProducers = "TYO-MQ-ALL" // EventAll is the suffix used when subscribing to all events of a producer. EventAll = "TM-ALL" )
Well-known tyo-mq protocol constants.
Variables ¶
This section is empty.
Functions ¶
func ConsumeEventName ¶
ConsumeEventName returns the Socket.IO event name that tyo-mq emits when delivering a message from the given producer with the given event name.
scope="" (default) → "CONSUME-<lower(producer-event)>" scope="all" → "CONSUME-<lower(producer)>-TM-ALL"
func NewAuthDecideReq ¶
func NewAuthDecideReq(adminToken, requestID string, approved bool, role, reason string) map[string]interface{}
NewAuthDecideReq builds the signed payload for AUTHORIZATION_DECIDE.
func NewAuthNextReq ¶
NewAuthNextReq builds the signed payload for AUTHORIZATION_NEXT. Pass realmFilter="" to get the next request across all realms.
Types ¶
type AckReq ¶
type AckReq struct {
MsgID string `json:"msgId"`
}
AckReq is emitted as "ACK" to acknowledge one delivered message.
type AdminProof ¶
type AdminProof struct {
Timestamp int64 `json:"timestamp"`
Nonce string `json:"nonce"`
Signature string `json:"signature"`
}
AdminProof is the HMAC-SHA256 signed proof required for manager actions. Build one with CreateAdminProof.
func CreateAdminProof ¶
func CreateAdminProof(adminToken, action string, body interface{}) AdminProof
CreateAdminProof creates an HMAC-SHA256 signed proof for a tyo-mq manager action. Matches the JS adminSignature.createAdminProof implementation exactly.
type AuthenticationReq ¶
type AuthenticationReq struct {
Token string `json:"token"`
}
AuthenticationReq is emitted as "AUTHENTICATION" when the server has auth enabled. The server answers with "AUTH_OK" or "AUTH_FAIL".
type AuthorizationApproved ¶
type AuthorizationDecideResult ¶
type AuthorizationDecideResult struct {
OK bool `json:"ok"`
Request *PendingAuthRequest `json:"request"`
}
AuthorizationDecideResult is the server response to "AUTHORIZATION_DECIDE".
type AuthorizationNextResult ¶
type AuthorizationNextResult struct {
OK bool `json:"ok"`
Request *PendingAuthRequest `json:"request"` // nil when the queue is empty
}
AuthorizationNextResult is the server response to "AUTHORIZATION_NEXT".
type AuthorizationRejected ¶
type AuthorizationRequest ¶
type AuthorizationRequest struct {
Realm string `json:"realm"`
Role string `json:"role"`
ClientID string `json:"client_id"`
ClientName string `json:"client_name"`
ClientToken string `json:"client_token"`
ChallengeResponse interface{} `json:"challenge_response,omitempty"`
}
AuthorizationRequest is emitted as "AUTHORIZATION_REQUEST" by a new client asking to be admitted to a realm. The client generates its own ClientToken; once an operator approves the request, that token authenticates normally.
type AuthorizationRequestOK ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a Socket.IO v4 client for tyo-mq.
Usage:
c := tyomq.NewClient("http://localhost:17352", logger)
c.On("AUTH_OK", func(p json.RawMessage) { ... })
ready := make(chan struct{})
go c.Connect(ctx, ready)
<-ready // wait for namespace "/" to be joined
c.Emit("AUTHENTICATION", tyomq.AuthenticationReq{Token: "..."})
func NewClientNS ¶
NewClientNS returns an unconnected client for a specific Socket.IO namespace (e.g. "/remote"). Call Connect to establish the connection.
func (*Client) Authenticate ¶
Authenticate sends the AUTHENTICATION message and waits for AUTH_OK or AUTH_FAIL. Call it right after Connect signals ready, before registering as a producer or consumer. Not needed when the server runs with auth disabled.
func (*Client) Close ¶
func (c *Client) Close()
Close sends a WebSocket close frame and tears down the connection.
func (*Client) Connect ¶
Connect dials the server, performs the Engine.IO + Socket.IO handshake, and runs the read loop until ctx is cancelled or the connection drops.
ready is closed exactly once when namespace "/" is joined and the client is ready to Emit. The caller must create ready before starting this goroutine:
ready := make(chan struct{})
go client.Connect(ctx, ready)
<-ready
func (*Client) Emit ¶
Emit sends a Socket.IO event to the server. Returns an error if the client is not currently connected (caller should wait for Connected() first, or retry).
func (*Client) On ¶
On registers a handler for the given Socket.IO event name. Safe to call concurrently. Multiple handlers for one event run in order.
func (*Client) Produce ¶
Produce publishes one fire-and-forget message. For durable/broadcast/TTL options emit a full ProduceReq: c.Emit("PRODUCE", tyomq.ProduceReq{...}).
func (*Client) RegisterConsumer ¶
RegisterConsumer announces this connection as a consumer named name. The name doubles as the durable consumer identity: reconnect with the same name to replay queued messages of a durable subscription.
func (*Client) RegisterProducer ¶
RegisterProducer announces this connection as a producer named name.
func (*Client) Subscribe ¶
func (c *Client) Subscribe(req SubscribeReq, handler func(ConsumedMessage)) error
Subscribe sends a SUBSCRIBE request and dispatches matching deliveries to handler. req.Consumer defaults to the name passed to RegisterConsumer being required — set it explicitly. For topic-pattern subscriptions set Mode: "topic"; req.Producer then defaults to AllProducers.
When req.Ack is true and req.ManualAck is false, Subscribe acknowledges each delivery automatically after handler returns. With ManualAck, call c.Ack(msg.MsgID) yourself once the work has truly succeeded.
func (*Client) WaitFor ¶
func (c *Client) WaitFor(event string) <-chan json.RawMessage
WaitFor registers a one-shot handler for event and returns a channel that receives its first payload. Useful for handshake-style events:
ok := c.WaitFor("AUTH_OK")
c.Emit("AUTHENTICATION", tyomq.AuthenticationReq{Token: token})
select { case <-ok: ... case <-ctx.Done(): ... }
type ConsumedMessage ¶
type ConsumedMessage struct {
Event string `json:"event"`
Message json.RawMessage `json:"message"`
From string `json:"from"`
MsgID string `json:"msgId"`
}
ConsumedMessage is the payload of a "CONSUME-…" event. MsgID is present only on ACK-enabled deliveries; send AckReq with it (or use Subscribe, which can do so automatically).
type Handler ¶
type Handler func(payload json.RawMessage)
Handler is called when a matching Socket.IO event is received.
type PendingAuthRequest ¶
type PendingAuthRequest struct {
RequestID string `json:"request_id"`
Status string `json:"status"`
Realm string `json:"realm"`
Role string `json:"role"`
ClientID string `json:"client_id"`
ClientName string `json:"client_name"`
CreatedAt string `json:"created_at"`
DecisionReason string `json:"decision_reason,omitempty"`
}
PendingAuthRequest is a pending authorization request returned by "AUTHORIZATION_NEXT_RESULT".
type ProduceReq ¶
type ProduceReq struct {
Event string `json:"event"`
Message interface{} `json:"message"`
From string `json:"from"`
Guaranteed bool `json:"guaranteed,omitempty"` // persist until consumed
TTL interface{} `json:"ttl,omitempty"` // e.g. "1h" or ms
Method string `json:"method,omitempty"` // "broadcast" when broadcasting
Broadcast string `json:"broadcast,omitempty"` // "realm" | "group"
Group string `json:"group,omitempty"`
}
ProduceReq is emitted as "PRODUCE".
Broadcast "realm" delivers one copy to every connected member of the producer's realm; "group" (with Group set) delivers one copy to every member of that consumer group. TTL bounds how long a durable copy may wait.
type RegisterConsumer ¶
type RegisterConsumer struct {
Name string `json:"name"`
ID string `json:"id,omitempty"`
ConsumerID string `json:"consumer_id,omitempty"`
}
RegisterConsumer is emitted as "CONSUMER" after connecting.
type RegisterProducer ¶
type RegisterProducer struct {
Name string `json:"name"`
}
RegisterProducer is emitted as "PRODUCER" after connecting.
type RetryPolicy ¶
type RetryPolicy struct {
MaxAttempts int `json:"max_attempts,omitempty"`
Delay string `json:"delay,omitempty"`
Backoff string `json:"backoff,omitempty"` // "" | "exponential"
}
RetryPolicy configures server-side re-delivery for ACK-enabled durable subscriptions. Delay accepts duration strings like "5s", "200ms".
type ServerError ¶
type SubscribeReq ¶
type SubscribeReq struct {
Event string `json:"event"`
Producer string `json:"producer"`
Consumer string `json:"consumer"`
Scope string `json:"scope,omitempty"` // "all" or "" (default)
Durable bool `json:"durable,omitempty"`
Ack bool `json:"ack,omitempty"`
ManualAck bool `json:"manual_ack,omitempty"`
AckTimeout string `json:"ack_timeout,omitempty"` // e.g. "30s"
Retry *RetryPolicy `json:"retry,omitempty"`
Mode string `json:"mode,omitempty"` // "" | "topic"
Group string `json:"group,omitempty"`
ConsumerID string `json:"consumer_id,omitempty"`
}
SubscribeReq is emitted as "SUBSCRIBE".
The zero value of the optional fields gives plain fire-and-forget delivery. Durable + Ack turn on guaranteed delivery: the server queues messages while the consumer is offline, waits for "ACK" per message, retries on the RetryPolicy schedule, and dead-letters messages that exhaust their attempts. Mode "topic" treats Event as an MQTT-style pattern ("orders/+/status", "factory/#") matched against events from any producer. Group makes the subscription part of a consumer group that load-balances deliveries.