Go
Use the Go server SDK for publishing, auth, state queries, and push notifications.
Install
Install the v2 Go module. Go resolves this package through the module path and the v2.1.0 Git tag:
go get github.com/sockudo/sockudo/server-sdks/sockudo-http-go/v2Configure
package main
import sockudo "github.com/sockudo/sockudo/server-sdks/sockudo-http-go/v2"
var client = sockudo.Client{
AppID: "app-id",
Key: "app-key",
Secret: "app-secret",
Host: "127.0.0.1",
Port: "6001",
Secure: false,
}Reuse the client for the lifetime of the process. Configure a custom
http.Client to set the overall deadline and preserve connection pooling:
client.HTTPClient = &http.Client{
Timeout: 5 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 20,
IdleConnTimeout: 90 * time.Second,
},
}The default client timeout is five seconds. Set Secure: true for HTTPS in
production. ClientFromURL and ClientFromEnv("SOCKUDO_URL") are convenient,
but connection URLs contain credentials and must not be logged.
Publish
data := map[string]string{"id": "ord_123"}
key := "order-created-ord_123"
_, err := client.TriggerWithParams(
"orders",
"order.created",
data,
sockudo.TriggerParams{IdempotencyKey: &key},
)
if err != nil {
panic(err)
}Publish the same event to multiple channels with TriggerMulti, batch
independent events with TriggerBatch, and exclude an originating socket with
TriggerParams.SocketID:
socketID := "123.456"
key := "order-paid:ord_123:v3"
_, err := client.TriggerWithParams(
"orders",
"order.updated",
map[string]string{"id": "ord_123", "status": "paid"},
sockudo.TriggerParams{
SocketID: &socketID,
IdempotencyKey: &key,
},
)
if err != nil {
return err
}Use a stable idempotency key for any publish a worker or HTTP handler may retry. Do not generate a new key for each attempt.
Auth endpoint
func sockudoAuth(res http.ResponseWriter, req *http.Request) {
params, _ := io.ReadAll(req.Body)
if !currentUserCanAccess(req.Context(), requestedChannel(params)) {
http.Error(res, "forbidden", http.StatusForbidden)
return
}
response, err := client.AuthorizePrivateChannel(params)
if err != nil {
http.Error(res, "unauthorized", http.StatusUnauthorized)
return
}
fmt.Fprint(res, string(response))
}Presence auth
member := sockudo.MemberData{
UserID: "user-42",
UserInfo: map[string]string{
"name": "Ada",
},
}
response, err := client.AuthorizePresenceChannel(params, member)The SDK signs the form body; your handler still owns session authentication and
channel authorization. Populate MemberData from trusted application state.
Use AuthenticateUser for user-targeted events, then
TerminateUserConnections or ForceReconnectUser when access changes.
State and history
prefix := "presence-"
info := "user_count"
channels, err := client.Channels(sockudo.ChannelsParams{
FilterByPrefix: &prefix,
Info: &info,
})
if err != nil {
return err
}
users, err := client.GetChannelUsers("presence-lobby")
limit := 50
direction := "newest_first"
page, err := client.ChannelHistory("orders", sockudo.HistoryParams{
Limit: &limit,
Direction: &direction,
})State is an operational snapshot, not an authorization source. History cursors are opaque and must be passed to the next call unchanged.
Webhooks
Read and preserve the exact body bytes for signature validation:
body, err := io.ReadAll(req.Body)
if err != nil {
http.Error(res, "invalid body", http.StatusBadRequest)
return
}
webhook, err := client.Webhook(req.Header, body)
if err != nil {
http.Error(res, "invalid signature", http.StatusUnauthorized)
return
}
enqueueWebhookEvents(webhook.Events)
res.WriteHeader(http.StatusAccepted)Do not decode the JSON first or log the raw body and signature.
End-to-end encrypted channels
Set EncryptionMasterKeyBase64 to a base64-encoded 32-byte key and publish only
to private-encrypted-* names. The server SDK encrypts payloads and produces
the shared secret during channel auth. Keep the master key in a secret manager
and do not mix encrypted and unencrypted channels in one logical publish.
Push notifications
_, err := client.ActivateDevice(sockudo.PushDeviceDetails{
"deviceId": "android-device-1",
"clientId": "user-42",
"platform": "fcm",
"providerToken": "provider-token",
})
_, err = client.UpsertChannelPushSubscription(sockudo.PushChannelSubscription{
"deviceId": "android-device-1",
"clientId": "user-42",
"channel": "orders",
}, "")
accepted, err := client.PublishPush(sockudo.PushPublishRequest{
"recipients": []sockudo.PushRecipient{
{"type": "channel", "channel": "orders"},
},
"payload": map[string]interface{}{
"title": "Order updated",
"body": "Order ord_123 is packed",
},
"idempotency_key": "push-order-ord_123-packed",
})
_ = acceptedThe Go push helpers sign /push/* requests and force async publish behavior.
Errors and production guidance
Every network operation returns an error; check it before using the response.
Retry only transient network errors, 429, and suitable server failures with
bounded exponential backoff. Because an HTTP error can be ambiguous after the
server accepted a request, every retried publish needs an idempotency key.
- Reuse one
Clientand one tunedhttp.Client. - Set a timeout below the enclosing request or job deadline.
- Pass request-scoped cancellation through your own surrounding workflow.
- Keep credentials, signed URLs, provider tokens, and raw webhook content out of logs.
- Bound channel-history page sizes and validate all auth endpoint input.
- Test duplicate attempts, key rotation, network interruption, and graceful worker shutdown.