{"id":17760871,"url":"https://github.com/backendstack21/realtime-pubsub-client-go","last_synced_at":"2025-04-01T13:18:09.997Z","repository":{"id":258530689,"uuid":"875140748","full_name":"BackendStack21/realtime-pubsub-client-go","owner":"BackendStack21","description":"The official Realtime Pub/Sub client for Go","archived":false,"fork":false,"pushed_at":"2024-12-17T16:30:05.000Z","size":31,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-01T13:18:06.346Z","etag":null,"topics":["client","golang","messaging","publish-subscribe","realtime","websocket"],"latest_commit_sha":null,"homepage":"https://realtime.21no.de","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BackendStack21.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-19T07:44:45.000Z","updated_at":"2024-12-17T16:30:09.000Z","dependencies_parsed_at":"2024-10-19T12:42:37.210Z","dependency_job_id":"ad03aaec-8cee-46d1-b8b4-c531a02d0681","html_url":"https://github.com/BackendStack21/realtime-pubsub-client-go","commit_stats":null,"previous_names":["backendstack21/realtime-pubsub-client-go"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BackendStack21%2Frealtime-pubsub-client-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BackendStack21%2Frealtime-pubsub-client-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BackendStack21%2Frealtime-pubsub-client-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BackendStack21%2Frealtime-pubsub-client-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BackendStack21","download_url":"https://codeload.github.com/BackendStack21/realtime-pubsub-client-go/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246644097,"owners_count":20810687,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["client","golang","messaging","publish-subscribe","realtime","websocket"],"created_at":"2024-10-26T19:13:56.045Z","updated_at":"2025-04-01T13:18:09.977Z","avatar_url":"https://github.com/BackendStack21.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Realtime Pub/Sub Client for Go\n\nThe `realtime-pubsub-client-go` is a Go client library for interacting with [Realtime Pub/Sub](https://realtime.21no.de)\napplications. It enables developers to manage real-time WebSocket connections, handle subscriptions, and process\nmessages efficiently. The library provides a simple and flexible API to interact with realtime applications, supporting\nfeatures like publishing/sending messages, subscribing to topics, handling acknowledgements, and waiting for replies\nwith timeout support.\n\n## Features\n\n- **WebSocket Connection Management**: Seamlessly connect and disconnect from the Realtime Pub/Sub service with\n  automatic reconnection support.\n- **Topic Subscription**: Subscribe and unsubscribe to topics for receiving messages.\n- **Topic Publishing**: Publish messages to specific topics with optional message types and compression.\n- **Message Sending**: Send messages to backend applications with optional message types and compression.\n- **Event Handling**: Handle incoming messages with custom event listeners.\n- **Acknowledgements and Replies**: Wait for gateway acknowledgements or replies to messages with timeout support.\n- **Error Handling**: Robust error handling and logging capabilities.\n- **Concurrency Support**: Safe for use in concurrent environments with thread-safe operations.\n\n## Installation\n\nInstall the `realtime-pubsub-client-go` library using `go get`:\n\n```bash\ngo get github.com/backendstack21/realtime-pubsub-client-go\n```\n\nOr, if you're using Go modules, simply import the package in your project, and Go will handle the installation.\n\n## Getting Started\n\nThis guide will help you set up and use the `realtime-pubsub-client-go` library in your Go project.\n\n### Prerequisites\n\n- Go 1.16 or later\n- A Realtime Pub/Sub account and an application set up at [Realtime Pub/Sub](https://realtime.21no.de)\n- Access token for authentication with sufficient permissions, see: [Subscribers](https://realtime.21no.de/documentation/#subscribers)\n  and [Publishers](https://realtime.21no.de/documentation/#publishers)\n\n### Working Examples\n\nThe following are working examples demonstrating how to use the `realtime-pubsub-client-go` library:\n\n* [basic.go](main/basic.go) \n* [rpc/client](main/rpc/client.go)\n* [rpc/server](main/rpc/server.go)\n\n### Subscribing to Incoming Messages\n\nYou can handle messages for specific topics and message types by registering event listeners.\nIn this example we handle `text-message` messages under the `chat` topic:\n\n```go\nclient.On(\"chat.text-message\", func (args ...interface{}) {\n  // Extract message and reply function\n  message, _ := args[0].(realtime_pubsub.IncomingMessage)\n  replyFunc, _ := args[1].(realtime_pubsub.ReplyFunc)\n  \n  log.Printf(\"Received message: %v\", message)\n  \n  // Reply to the message\n  if err := replyFunc(\"Got it!\", \"ok\"); err != nil {\n  log.Printf(\"Failed to reply to message: %v\", err)\n  }\n})\n\n```\n\n#### Wildcard Subscriptions\n\nWildcard subscriptions are also supported, allowing you to handle multiple message types under a topic:\n\n```go\nclient.On(\"chat.*\", func (args ...interface{}) {\n  // Extract message and reply function\n  message, _ := args[0].(realtime_pubsub.IncomingMessage)\n  replyFunc, _ := args[1].(realtime_pubsub.ReplyFunc)\n  \n  //...\n})\n```\n\n### Publishing Messages\n\nPublish messages to a topic using the `Publish` method:\n\n```go\ntopic:= \"chat\"\npayload := \"Hello, World!\"\nmessageType := \"text-message\"\n\nwaitFor, err := client.Publish(topic, payload,\n  realtime_pubsub.WithPublishMessageType(messageType),\n  realtime_pubsub.WithPublishCompress(true),\n)\nif err != nil {\n  log.Fatalf(\"Failed to publish message: %v\", err)\n}\n\n// Wait for acknowledgment\nif _, err := waitFor.WaitForAck(100 * time.Millisecond); err != nil {\n  log.Printf(\"Failed to receive acknowledgment: %v\", err)\n}\n\n// Wait for a reply\nreply, err := waitFor.WaitForReply(500 * time.Millisecond)\nif err != nil {\n  log.Printf(\"Failed to receive reply: %v\", err)\n} else {\n  log.Printf(\"Received reply: %v\", reply[\"data\"])\n}\n```\n\n### Sending Messages\n\nSend messages to the server using the `Send` method:\n\n```go\nwaitFor, err := client.Send(map[string]interface{}{\n  \"action\": \"create\",\n  \"data\": map[string]interface{}{\n    \"name\": \"John Doe\",\n  },\n}, realtime_pubsub.WithSendMessageType(\"create-user\"))\nif err != nil {\n  log.Fatalf(\"Failed to send message: %v\", err)\n}\n\n// Wait for acknowledgment\nif _, err := waitFor.WaitForAck(100 * time.Millisecond); err != nil {\n  log.Printf(\"Failed to receive acknowledgment: %v\", err)\n}\n\n// Wait for a reply\nreply, err := waitFor.WaitForReply(500 * time.Millisecond)\nif err != nil {\n  log.Printf(\"Failed to receive reply: %v\", err)\n} else {\n  log.Printf(\"Received reply: %v\", reply.Data())\n}\n```\n\n### Handling Replies\n\nSet up event listeners to handle incoming replies, use the ReplyFunc param to send replies to messages:\n\n```go\nclient.On(\"chat.text-message\", func (args ...interface{}) {\n  // Extract message and reply function\n  message, _ := args[0].(realtime_pubsub.IncomingMessage)\n  replyFunc, _ := args[1].(realtime_pubsub.ReplyFunc)\n  \n  log.Printf(\"Received message: %v\", message)\n  \n  // Reply to the message\n  replyPayload := \"Got it!\"\n  replyStatus := \"ok\"\n  if err := replyFunc(replyPayload, replyStatus); err != nil {\n    log.Printf(\"Failed to reply to message: %v\", err)\n  }\n})\n```\n\n### Waiting for Acknowledgements and Replies\n\n- **Wait for Acknowledgement**: Use `WaitForAck` to wait for a gateway acknowledgement after publishing or sending a\n  message.\n\n  ```go\n  if _, err := waitFor.WaitForAck(500 * time.Millisecond); err != nil {\n    log.Printf(\"Failed to receive acknowledgment: %v\", err)\n  }\n  ```\n\n- **Wait for Reply**: Use `WaitForReply` to wait for a reply to your message with a specified timeout.\n\n  ```go\n  reply, err := waitFor.WaitForReply(500 * time.Millisecond)\n  if err != nil {\n    log.Printf(\"Failed to receive reply: %v\", err)\n  } else {\n    log.Printf(\"Received reply: %v\", reply.Data())\n  }\n  ```\n\n### Error Handling\n\nHandle errors and disconnections gracefully:\n\n```go\nclient.On(\"error\", func (args ...interface{}) {\n  log.Printf(\"Received error: %v\", args)\n})\n\nclient.On(\"close\", func (args ...interface{}) {\n  log.Printf(\"Connection closed: %v\", args)\n})\n```\n\n## API Reference\n\n### RealtimeClient\n\n#### Constructor\n\n```go\nfunc NewClient(config Config) *Client\n```\n\nCreates a new `Client` instance.\n\n- **config**: Configuration options for the client.\n\n#### Methods\n\n- **Connect()**\n\n  ```go\n  func (c *Client) Connect()\n  ```\n\n  Establishes a connection to the WebSocket server.\n\n- **Disconnect() error**\n\n  ```go\n  func (c *Client) Disconnect() error\n  ```\n\n  Terminates the WebSocket connection gracefully.\n\n- **On(event string, listener ListenerFunc)**\n\n  ```go\n  func (c *Client) On(event string, listener ListenerFunc)\n  ```\n\n  Registers a listener for a specific event. Supports wildcard patterns.\n\n- **Off(event string, id int)**\n\n  ```go\n  func (c *Client) Off(event string, id int)\n  ```\n\n  Removes a listener for a specific event using the listener ID.\n\n- **Once(event string, listener ListenerFunc) int**\n\n  ```go\n  func (c *Client) Once(event string, listener ListenerFunc) int\n  ```\n\n  Registers a listener that will be called at most once for the specified event.\n\n- **SubscribeRemoteTopic(topic string) error**\n\n  ```go\n  func (c *Client) SubscribeRemoteTopic(topic string) error\n  ```\n\n  Subscribes the client to a remote topic to receive messages.\n\n- **UnsubscribeRemoteTopic(topic string) error**\n\n  ```go\n  func (c *Client) UnsubscribeRemoteTopic(topic string) error\n  ```\n\n  Unsubscribes the client from a remote topic.\n\n- **Publish(topic string, payload interface{}, opts ...PublishOption) (\\*WaitFor, error)**\n\n  ```go\n  func (c *Client) Publish(topic string, payload interface{}, opts ...PublishOption) (*WaitFor, error)\n  ```\n\n  Publishes a message to a specified topic with optional configurations.\n\n- **Send(payload interface{}, opts ...SendOption) (\\*WaitFor, error)**\n\n  ```go\n  func (c *Client) Send(payload interface{}, opts ...SendOption) (*WaitFor, error)\n  ```\n\n  Sends a message to the server with optional configurations.\n\n- **WaitFor(event string, timeout time.Duration) (interface{}, error)**\n\n  ```go\n  func (c *Client) WaitFor(event string, timeout time.Duration) (interface{}, error)\n  ```\n\n  Waits for a specific event to occur within the given timeout.\n\n#### Events\n\n- **'session.started'**\n\n  Emitted when the session starts.\n\n  ```go\n  client.On(\"session.started\", func(args ...interface{}) {\n    info := args[0].(realtime_pubsub.ConnectionInfo)\n    //...\n  })\n  ```\n\n- **'error'**\n\n  Emitted on WebSocket errors.\n\n  ```go\n  client.On(\"error\", func(args ...interface{}) {\n    // Handle error\n  })\n  ```\n\n- **'close'**\n\n  Emitted when the WebSocket connection closes.\n\n  ```go\n  client.On(\"close\", func(args ...interface{}) {\n    // Handle close event\n  })\n  ```\n\n- **Custom Events**\n\n  Handle custom events based on topic and message type.\n\n  ```go\n  client.On(\"topic1.action1\", func(args ...interface{}) {\n    // Handle specific message\n  })\n  ```\n\n  **Wildcard Subscriptions**\n\n  ```go\n  client.On(\"topic1.*\", func(args ...interface{}) {\n    // Handle any message under topic1\n  })\n  ```\n\n## Type Definitions\n\n### IncomingMessage\n\nRepresents a message received from the server.\n\n```go\ntype IncomingMessage map[string]interface{}\n```\n\n#### Methods\n\n- **Topic() string**\n\n  Extracts the \"topic\" from the message.\n\n  ```go\n  func (m IncomingMessage) Topic() string\n  ```\n\n- **Data() interface{}**\n\n  Extracts the \"data\" from the message.\n\n  ```go\n  func (m IncomingMessage) Data() interface{}\n  ```\n\n- **MessageType() string**\n\n  Extracts the \"messageType\" from the message.\n\n  ```go\n  func (m IncomingMessage) MessageType() string\n  ```\n\n- **Compression() bool**\n\n  Extracts the \"compression\" flag from the message.\n\n  ```go\n  func (m IncomingMessage) Compression() bool\n  ```\n  \n- **DataAsMap() map[string]interface{}**\n\n  Extracts the \"data\" as a map from the message.\n\n  ```go\n  func (m IncomingMessage) DataAsMap() map[string]interface{}\n  ```\n\n- **DataAsPresenceMessage() PresenceMessage** \n\n  Extracts the \"data\" as a PresenceMessage from the message.\n\n  ```go\n  func (m IncomingMessage) DataAsPresenceMessage() PresenceMessage\n  ```\n  \n### ResponseMessage\n\nRepresents a message sent by a client in response to an incoming message.\n\n```go\ntype ResponseMessage map[string]interface{}\n```\n\n#### Methods\n\n- **Id() string**\n\n  Extracts the \"id\" from the response.\n\n  ```go\n  func (m ResponseMessage) Id() string\n  ```\n\n- **Data() interface{}**\n\n  Extracts the \"data\" from the response.\n\n  ```go\n  func (m ResponseMessage) Data() interface{}\n  ```\n\n- **Status() string**\n\n  Extracts the \"status\" from the response.\n\n  ```go\n  func (m ResponseMessage) Status() string\n  ```\n  \n- **DataAsMap() map[string]interface{}**\n\n  Extracts the \"data\" as a map from the response.\n\n  ```go\n  func (m ResponseMessage) DataAsMap() map[string]interface{}\n  ```\n\n### ReplyFunc\n\nDefines the signature for reply functions used in event listeners.\n\n```go\ntype ReplyFunc func (data interface{}, status string, opts ...ReplyOption) error\n```\n\n## Configuration Options\n\n### Config\n\nConfiguration options for initializing the client.\n\n```go\ntype Config struct {\n  Logger           *logrus.Logger\n  WebSocketOptions WebSocketOptions\n}\n```\n\n- **Logger**: Optional. Pass a custom logger implementing the `logrus.Logger` interface for logging purposes. If not\n  provided, the client uses the standard logger.\n- **WebSocketOptions**: Configuration options for the WebSocket connection.\n\n### WebSocketOptions\n\nOptions for configuring the WebSocket connection.\n\n```go\ntype WebSocketOptions struct {\n  URLProvider func () (string, error)\n}\n```\n\n- **URLProvider**: A function that returns the WebSocket URL for connecting to the Realtime Pub/Sub server. It can\n  include dynamic parameters like access tokens.\n\n## API Components\n\n### WaitFor\n\nRepresents a mechanism to wait for acknowledgements or replies to messages.\n\n```go\ntype WaitFor struct {\n  // Internal fields\n}\n```\n\n#### Methods\n\n- **WaitForAck(timeout time.Duration) (interface{}, error)**\n\n  Waits for an acknowledgement of the published or sent message within the specified timeout.\n\n  ```go\n  func (w *WaitFor) WaitForAck(timeout time.Duration) (interface{}, error)\n  ```\n\n- **WaitForReply(timeout time.Duration) (map[string]interface{}, error)**\n\n  Waits for a reply to the published or sent message within the specified timeout.\n\n  ```go\n  func (w *WaitFor) WaitForReply(timeout time.Duration) (map[string]interface{}, error)\n  ```\n\n## License\n\nThis library is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.\n\n---\n\nFor more detailed examples and advanced configurations, please refer to\nthe [documentation](https://realtime.21no.de/docs).\n\n## Notes\n\n- **Environment Setup**: Ensure that you have an account and an app set up\n  with [Realtime Pub/Sub](https://realtime.21no.de).\n- **Authentication**: Customize the `urlProvider` function to retrieve the access token for connecting to your realtime\n  application.\n- **Logging**: Use the `Logger` option to integrate with your application's logging system.\n- **Error Handling**: Handle errors and disconnections gracefully to improve the robustness of your application.\n- **Timeouts**: Handle timeouts when waiting for replies to avoid hanging operations.\n- **Concurrency**: The client is designed to be safe for use in concurrent environments, with thread-safe operations on\n  its internal data structures. However, keep in mind that listeners are executed sequentially by default within the\n  event loop. If your application requires concurrent handling of events, you can spawn goroutines within your listeners\n  or implement custom thread pools for parallel processing. Additionally, if your listeners modify shared state, ensure\n  that you manage synchronization (e.g., using mutexes or channels) to avoid race conditions or data corruption.\n- **Wildcard Subscriptions**: Utilize wildcard subscriptions (`*` and `**`) to handle multiple message types under a\n  single topic efficiently.\n\n---\n\nFeel free to contribute to this project by submitting issues or pull requests\non [GitHub](https://github.com/BackendStack21/realtime-pubsub-client-go).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbackendstack21%2Frealtime-pubsub-client-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbackendstack21%2Frealtime-pubsub-client-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbackendstack21%2Frealtime-pubsub-client-go/lists"}