Web PubSub

Azure Web PubSub: a REST management surface plus WebSocket client connections using the json.webpubsub.azure.v1 subprotocol, served at https://127.0.0.1:10004 and compatible with the azwebpubsub SDK. Hub state is in-memory. See Configuration to change the listen address.

localaz serves Web PubSub (REST and the WebSocket upgrade) over TLS like every other HTTP API. Trust the self-signed certificate it writes to <data>/tls/localaz.crt:

export SSL_CERT_FILE=./localaz-data/tls/localaz.crt

Supported operations

OperationSurface
Client connectGET /client/hubs/{hub} (WebSocket upgrade)
Send to allPOST /api/hubs/{hub}/:send
Send to groupPOST /api/hubs/{hub}/groups/{group}/:send
Send to userPOST /api/hubs/{hub}/users/{user}/:send
Send to connectionPOST /api/hubs/{hub}/connections/{conn}/:send
Add / remove from groupPUT / DELETE /api/hubs/{hub}/groups/{group}/connections/{conn}
Close connectionDELETE /api/hubs/{hub}/connections/{conn}

Client access URLs are signed locally; group join/leave and acks over the WebSocket are supported.

Not implemented: the MQTT subprotocol, event handlers / webhooks, and connection authentication.

Azure CLI

az webpubsub resolves its endpoint from ARM with no local override, so the data plane is SDK-only — use the Go example below.

Go SDK

Trust localaz’s certificate:

export SSL_CERT_FILE=./localaz-data/tls/localaz.crt
package main

import (
	"bytes"
	"context"
	"encoding/json"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming"
	"github.com/Azure/azure-sdk-for-go/sdk/messaging/azwebpubsub"
)

func main() {
	ctx := context.Background()
	client, err := azwebpubsub.NewClientFromConnectionString(
		"Endpoint=https://127.0.0.1:10004;AccessKey=localaz-test-key;", nil)
	if err != nil {
		panic(err)
	}

	body, _ := json.Marshal(map[string]string{"text": "hello room"})
	client.SendToGroup(ctx, "chat", "room1", azwebpubsub.ContentTypeApplicationJSON,
		streaming.NopCloser(bytes.NewReader(body)), nil)

	client.SendToAll(ctx, "chat", azwebpubsub.ContentTypeApplicationJSON,
		streaming.NopCloser(bytes.NewReader(body)), nil)
}