Skip to main content
Markdown

A server in Go

An app server in Go on WordPlus Cloud, written from these pages alone, with no package of ours: its own rules, the routes the browser SDK asks, sending sealed events through the HTTP API, the webhook, calls, group calls and live streams. Take it as it is, or as the map for a server in your own language.

It is checked as the packages are: its test runs it against the test values, and the end-to-end checks of the SDK run the browser SDK in real browsers against it and a realtime server, on every route it answers and every request it sends.

The files​

File
go.modthe module: Go 1.23, with golang.org/x/crypto for XChaCha20-Poly1305
wordplus/wordplus.gothe protocol: signing, the HTTP API, keys and sealing, every token, and the webhook
wordplus/wordplus_test.goits test against the test values
main.gothe example app: its rules and its routes
go test ./wordplus/
WORDPLUS_SITE=… WORDPLUS_SECRET=… WORDPLUS_LOCAL_KEY=… go run .

The package​

App{ Site, Secret, LocalKey, API }your app
Request( method, path, body )a signed request to the HTTP API, its JSON answer, or a Refusal with its status and code
Signature( timestamp, method, path, body )the signature of a request (signing requests)
Emit( room, event, data, sealed, history ), EmitToUser( user, event, data )send, sealed with the key of the room or of the user
Key( label ), Entry( label ), Seal( text, label, nonce ), SealJSON( value, label ), Open( value )sealing
RoomGrant( user, rooms, denied ), PublicGrant( patterns )what the auth route answers, and the public grants (room tokens)
Keys( user, profile ), Identity( user, profile, hidden )what the keys route answers with nothing asked (keys and identity)
Line( user ), CallSide( call, id, role, type, me, other, info ), GroupCall( … )what the calls route answers (calls)
StreamGrant( Stream{ … } )a live stream grant (live streams)
Webhook( header, path, body )a webhook checked, its events with their data opened (webhooks)

The example app​

main.go has rules as an app would:

order:{id}a sealed room only its customer joins, keeping its last 10 events
chat:{a}:{b}a sealed presence room for its two people, where pages send message, typing and read, and the webhook gets message
product:{id}a public room anyone joins, with a live count, from the public grant
support:{a}:{b}calls between its two people
meeting:{id}a group call for anyone signed in, encrypted end to end
show:{id}a live stream user 42 hosts, and everyone else watches, a visitor too

Its routes answer the browser at /api/realtime/: config (the settings, which a page passes to connect()), auth, keys, calls and webhook.

The auth route, as the rules decide it:

func auth(w http.ResponseWriter, r *http.Request, user string) {
var body struct {
Rooms []string `json:"rooms"`
}
if json.NewDecoder(r.Body).Decode(&body) != nil || body.Rooms == nil {
w.WriteHeader(400)
reply(w, map[string]string{"code": "bad_request"})
return
}
allowed, denied := map[string]wordplus.Room{}, map[string]string{}
for _, room := range body.Rooms {
if rule, refusal := roomRule(room, user); rule != nil {
allowed[room] = *rule
} else {
denied[room] = refusal
}
}
reply(w, app.RoomGrant(user, allowed, denied))
}

Sending, sealed with the key of the room, kept for pages that reconnect:

ids, err := app.Emit("order:42", "updated", map[string]any{"status": "shipped"}, true, 10)

The webhook:

func webhook(w http.ResponseWriter, r *http.Request) {
raw, _ := io.ReadAll(r.Body)
events, err := app.Webhook(r.Header, r.URL.RequestURI(), raw)
if err != nil {
w.WriteHeader(401)
reply(w, map[string]string{"code": err.Error()})
return
}
heardMu.Lock()
heard = append(heard, events...)
heardMu.Unlock()
w.WriteHeader(204)
}

The example takes the user from an X-User header, so it runs on its own. A real app takes them from its session.

In another language​

Port wordplus.go: it is about 600 lines, with the standard HMAC-SHA256, SHA-256, base64url and JSON of any language, and XChaCha20-Poly1305 from libsodium or its like. Check it against the test values first, then against WordPlus Cloud.