Commit cb3afd7b authored by Andrei Mihu's avatar Andrei Mihu
Browse files

Add realtime envelope and dispatch presence events. (#143)

parent e02f8e40
Loading
Loading
Loading
Loading
+15 −3
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import (
	"net/url"

	_ "github.com/lib/pq"
	"github.com/golang/protobuf/jsonpb"
)

var (
@@ -69,12 +70,23 @@ func main() {
	// Check migration status and log if the schema has diverged.
	cmd.MigrationStartupCheck(multiLogger, db)

	// Shared utility components.
	jsonpbMarshaler := &jsonpb.Marshaler{
		EnumsAsInts:  true,
		EmitDefaults: false,
		Indent:       "",
		OrigName:     false,
	}
	jsonpbUnmarshaler := &jsonpb.Unmarshaler{
		AllowUnknownFields: false,
	}

	// Start up server components.
	registry := server.NewSessionRegistry()
	tracker := server.StartLocalTracker(jsonLogger, registry, config.GetName())
	router := server.NewLocalMessageRouter(registry, tracker)
	tracker := server.StartLocalTracker(jsonLogger, registry, jsonpbMarshaler, config.GetName())
	router := server.NewLocalMessageRouter(registry, tracker, jsonpbMarshaler)
	pipeline := server.NewPipeline(config, db, tracker, router, registry)
	apiServer := server.StartApiServer(jsonLogger, db, config, tracker, registry, pipeline)
	apiServer := server.StartApiServer(jsonLogger, db, config, tracker, registry, pipeline, jsonpbMarshaler, jsonpbUnmarshaler)

	// Respect OS stop signals.
	c := make(chan os.Signal, 2)
+0 −1
Original line number Diff line number Diff line
@@ -37,7 +37,6 @@ CREATE TABLE IF NOT EXISTS users (
    edge_count     INT           DEFAULT 0 CHECK (edge_count >= 0) NOT NULL,
    created_at     BIGINT        CHECK (created_at > 0) NOT NULL,
    updated_at     BIGINT        CHECK (updated_at > 0) NOT NULL,
    verified_at    BIGINT        CHECK (verified_at >= 0) DEFAULT 0 NOT NULL,
    disabled_at    BIGINT        CHECK (disabled_at >= 0) DEFAULT 0 NOT NULL
);

+2 −2
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ func (fi bindataFileInfo) Sys() interface{} {
	return nil
}

var __20180103142000_initial_schemaSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x56\x51\x73\xda\x38\x17\x7d\xe7\x57\xdc\xc9\xc3\x57\xdc\x8f\x00\xa1\xed\x6e\xa7\xd9\xed\x8c\x03\x4e\xeb\x29\x35\x5d\xdb\xb4\x9b\x27\x46\x48\x17\x5b\x13\x5b\xf2\x4a\x32\x94\xdd\xd9\xff\xbe\x23\xdb\x38\x40\x08\xe9\xec\xf2\x94\xd8\x47\xe7\x9e\x7b\x75\x74\xe4\xc1\xcb\x0e\xbc\x84\xb1\x2c\xb6\x8a\x27\xa9\x81\xd1\xf0\xea\x2d\xc4\x29\x42\x40\xee\x49\x4e\xc0\x2d\x4d\x2a\x95\xee\x40\x85\x9b\x72\x8a\x42\x23\x83\x52\x30\x54\x60\x52\x04\xb7\x20\x34\xc5\xdd\x9b\x1e\x7c\x45\xa5\xb9\x14\x30\xea\x0f\xa1\x6b\x01\x17\xcd\xab\x0b\xe7\xda\x52\x6c\x65\x09\x39\xd9\x82\x90\x06\x4a\x8d\x60\x52\xae\x61\xc5\x33\x04\xfc\x4e\xb1\x30\xc0\x05\x50\x99\x17\x19\x27\x82\x22\x6c\xb8\x49\xab\x3a\x0d\x4b\xdf\x72\xdc\x35\x1c\x72\x69\x08\x17\x40\x80\xca\x62\x0b\x72\xb5\x0f\x04\x62\x1a\xd1\xa9\x31\xc5\xbb\xc1\x60\xb3\xd9\xf4\x49\x25\xb6\x2f\x55\x32\xc8\x6a\x98\x1e\x4c\xfd\xb1\x17\x44\xde\xe5\xa8\x3f\x6c\x16\xcc\x45\x86\x5a\x83\xc2\x3f\x4a\xae\x90\xc1\x72\x0b\xa4\x28\x32\x4e\xc9\x32\x43\xc8\xc8\x06\xa4\x02\x92\x28\x44\x06\x46\x5a\xc1\x1b\xc5\x0d\x17\x49\x0f\xb4\x5c\x99\x0d\x51\x68\x69\x18\xd7\x46\xf1\x65\x69\x0e\xe6\xb5\x93\xc7\xf5\x01\x40\x0a\x20\x02\x2e\xdc\x08\xfc\xe8\x02\x6e\xdc\xc8\x8f\x7a\x96\xe4\x9b\x1f\x7f\x9c\xcd\x63\xf8\xe6\x86\xa1\x1b\xc4\xbe\x17\xc1\x2c\x84\xf1\x2c\x98\xf8\xb1\x3f\x0b\x22\x98\xdd\x82\x1b\xdc\xc1\x27\x3f\x98\xf4\x00\xb9\x49\x51\x01\x7e\x2f\x94\xed\x40\x2a\xe0\x76\x92\xc8\xaa\xb1\x45\x88\x07\x12\x56\xb2\x96\xa4\x0b\xa4\x7c\xc5\x29\x64\x44\x24\x25\x49\x10\x12\xb9\x46\x25\xb8\x48\xa0\x40\x95\x73\x6d\x77\x54\x03\x11\xcc\xd2\x64\x3c\xe7\x86\x98\xea\xd1\xa3\xbe\x6c\xa1\x41\xa7\x73\x79\x09\xff\xcf\x79\xa2\x88\x41\x98\x17\x9d\x71\xe8\xb9\xb1\x07\xb1\x7b\x33\xf5\xc0\xbf\x85\x60\x16\x83\xf7\xbb\x1f\xc5\x91\xf5\x80\xd2\xd0\xed\x00\x00\x7c\x09\xfd\xcf\x6e\x78\x07\x9f\xbc\x3b\xe8\x72\xe6\xf4\xaa\xa7\x9c\xc1\xfe\x6f\x3e\xf7\x27\x0f\xff\x59\xa6\x60\x3e\x9d\xd6\x50\x4b\x26\x48\x8e\xcd\xcb\xaf\x6e\x38\xfe\xe8\x86\xdd\xab\xd1\x5b\x07\xec\xd0\xa2\x38\x74\xfd\x20\xae\x8b\x2e\x76\xe8\xc5\x3d\x6e\x61\x1e\xf8\xbf\xcd\xbd\x23\xbe\x55\x99\x65\x27\xf8\x46\x6f\xde\x34\xda\xc8\x9a\x18\xa2\x16\xa5\xca\x9e\x00\x5c\x5e\x56\xfe\xd3\xef\x06\x03\x23\x65\xa6\xfb\x1c\xcd\xaa\x32\x60\x6a\xf2\x6c\xb0\xa4\xc5\xeb\x9f\x2b\xa0\x9d\xfd\x5e\x97\xad\x74\xab\x1c\x26\xde\xad\x3b\x9f\xc6\xf0\x02\xc5\x8b\x23\x89\x99\xa4\xd5\x5e\x9c\x92\x68\xab\x63\x3f\xe9\xc3\x45\x44\x04\xdc\x2a\x22\x28\xd7\x54\xf6\x60\xec\x5e\x54\x8b\x0d\xcf\xf1\x4f\x29\x4e\xf6\xf7\xb0\xf8\x0b\xa9\xed\x11\xf3\x1c\xa1\x3b\x8f\xe0\x7f\x30\x26\x82\x30\xe2\xd4\x2c\xa5\xa1\x0b\xb9\x5a\x69\x34\x8b\x5c\x03\x44\x9f\xdd\xe9\xd4\x4e\xb9\xfa\xed\xa4\x0f\x8f\x74\xe7\x68\x08\x23\x86\x34\xa5\x6f\xee\x62\xcf\x6d\xbb\x6f\xfb\xfd\xeb\xef\x17\x30\xfe\xe8\x8d\x3f\x41\x37\x43\x91\x98\xb4\xbb\x5b\xe7\xc0\x2f\x70\xf5\xd3\x70\x38\x74\x8e\x88\x31\x27\x3c\x7b\x3c\x48\xdb\x13\x34\xbb\x5c\x03\x0b\xa2\xf5\x46\x2a\x76\x52\xc1\x61\xd1\x1d\xd4\x16\x7d\x35\xb2\x45\x1b\x7f\x10\x8a\x4b\x29\xef\x17\xb5\x47\x0f\xfd\xb6\x5f\x2b\x91\x32\xc9\x70\xb1\xb3\xf2\x19\x20\xc9\x91\xa2\x30\xa8\x2a\xf0\xd3\x40\x6d\x90\xe4\x2d\xe1\x19\x20\x2d\xb5\x91\xf9\x0f\x94\x46\x96\xe0\x82\xca\x52\x98\x0a\xd8\xee\xe0\xd1\x36\x36\x93\xd9\x43\xbf\xff\x15\x1e\xed\x02\x55\x48\x0c\xb2\x05\xa9\xc9\x6e\xfc\x0f\x7b\x7c\x0d\xc5\x1e\xe6\xfd\x63\x86\xb2\x60\xcf\x32\xec\x61\x4e\x30\xac\x51\xf1\x15\x6f\x29\x4e\x32\xec\x63\xea\x3e\x9e\x32\x2c\xe3\xda\xe6\xff\x59\xb6\x7d\xcc\x53\x6c\x1d\xe7\xba\xca\xc7\xd8\x5e\x7c\xa6\xba\x52\x74\x2a\xcb\x8c\xc1\x12\x41\x61\x91\x11\x8a\xac\xbe\xf7\x88\x00\xa2\x14\xd9\x02\x95\x59\x99\x0b\x7b\xd3\xd8\xa8\xad\x23\xb3\x5a\x6a\x89\xa4\xbd\x27\xa9\xa4\xf7\x4a\x12\x9a\xb2\x25\x10\xc6\x34\xe8\xb2\x28\xa4\x32\x55\xc8\xd7\x24\x66\x5b\xa0\x7e\x2e\x8a\x17\x0c\xd7\x9c\xe2\xd9\x40\xbe\x9d\x85\x9e\xff\x21\xa8\x9f\x56\x8b\x38\x73\x20\xf4\x6e\xbd\xd0\x0b\xc6\x5e\x93\xe9\x15\xde\x86\x48\x3c\x9b\xcc\xde\xc1\x2c\x80\x89\x37\xf5\x62\x0f\xc6\x6e\x34\x76\x27\xde\x61\xb8\x1f\xd8\xf2\x71\xa8\x5b\xfb\x1e\x04\xff\xc1\x34\x9f\xeb\xc9\x7a\xf5\x54\x47\x5a\x96\x8a\xda\x53\xd9\x03\x6d\x88\xc1\x1e\x14\x52\x73\x9b\xa6\xa7\x3a\x6d\xd1\xff\xb6\xd7\x03\x36\x86\xda\x70\x51\x45\xf7\x7f\xa0\x6c\x35\xd5\x53\x69\x47\x74\x38\xc1\x5d\x57\xbb\xa4\xdb\x59\xb7\x45\xd9\x3a\x73\xfb\x5d\x67\xdd\xa2\xad\x6d\xa4\xb2\x17\xbb\x14\xa0\xe4\x46\x9f\x3d\x8f\x3f\x74\x14\x0f\xbb\x7d\x4a\x67\xb5\x09\x0f\x99\xd3\x5e\x24\x27\x8e\xa4\x55\xbc\x52\x1c\x05\xeb\x0e\x9d\x1e\x70\xb1\xe6\x06\xbb\x57\xed\x9f\xac\x3b\x72\x7a\xb0\xcc\x24\xbd\x47\xd6\x7d\xe5\xf4\x80\x61\x86\xf6\xf9\x6b\xa7\x07\x44\xd1\x94\xaf\x91\x75\xdf\x38\x9d\xaa\x72\x73\xfb\xef\x3b\xe2\x68\x83\x76\xc7\xb6\xfd\xac\x99\xc8\x8d\xe8\x4c\xc2\xd9\x97\x07\xdf\x1d\x7b\xee\xfa\xcc\xfb\xfa\x9c\x9d\x41\xe8\xeb\xce\x3f\x01\x00\x00\xff\xff\x0d\xac\x17\xbe\x9d\x0b\x00\x00")
var __20180103142000_initial_schemaSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x56\x5f\x93\x9b\xb6\x17\x7d\xf7\xa7\xb8\xb3\x0f\xbf\x40\x7e\xac\xed\x38\xc9\x34\x93\x6d\x33\xc3\x62\x9c\x30\x71\x70\x0a\x38\xe9\x3e\x79\x64\x74\x0d\x9a\x05\x89\x4a\x62\x1d\xb7\xd3\xef\xde\x11\x60\xaf\xff\xad\x93\xb6\x3c\xd9\xd2\xd1\xb9\xe7\xde\x7b\xb8\x62\xf0\xbc\x07\xcf\xc1\x13\xd5\x46\xb2\x2c\xd7\x30\x1a\xbe\x78\x03\x49\x8e\x10\x92\x7b\x52\x12\x70\x6b\x9d\x0b\xa9\x7a\xd0\xe0\xa6\x2c\x45\xae\x90\x42\xcd\x29\x4a\xd0\x39\x82\x5b\x91\x34\xc7\xed\x8e\x03\x5f\x50\x2a\x26\x38\x8c\xfa\x43\xb0\x0c\xe0\xaa\xdb\xba\xb2\x6f\x0c\xc5\x46\xd4\x50\x92\x0d\x70\xa1\xa1\x56\x08\x3a\x67\x0a\x56\xac\x40\xc0\x6f\x29\x56\x1a\x18\x87\x54\x94\x55\xc1\x08\x4f\x11\xd6\x4c\xe7\x4d\x9c\x8e\xa5\x6f\x38\xee\x3a\x0e\xb1\xd4\x84\x71\x20\x90\x8a\x6a\x03\x62\xb5\x0f\x04\xa2\x3b\xd1\xb9\xd6\xd5\xdb\xc1\x60\xbd\x5e\xf7\x49\x23\xb6\x2f\x64\x36\x28\x5a\x98\x1a\x4c\x03\xcf\x0f\x63\xff\x7a\xd4\x1f\x76\x07\xe6\xbc\x40\xa5\x40\xe2\xef\x35\x93\x48\x61\xb9\x01\x52\x55\x05\x4b\xc9\xb2\x40\x28\xc8\x1a\x84\x04\x92\x49\x44\x0a\x5a\x18\xc1\x6b\xc9\x34\xe3\x99\x03\x4a\xac\xf4\x9a\x48\x34\x34\x94\x29\x2d\xd9\xb2\xd6\x07\xf5\xda\xca\x63\xea\x00\x20\x38\x10\x0e\x57\x6e\x0c\x41\x7c\x05\xb7\x6e\x1c\xc4\x8e\x21\xf9\x1a\x24\x1f\x66\xf3\x04\xbe\xba\x51\xe4\x86\x49\xe0\xc7\x30\x8b\xc0\x9b\x85\xe3\x20\x09\x66\x61\x0c\xb3\x09\xb8\xe1\x1d\x7c\x0c\xc2\xb1\x03\xc8\x74\x8e\x12\xf0\x5b\x25\x4d\x06\x42\x02\x33\x95\x44\xda\x94\x2d\x46\x3c\x90\xb0\x12\xad\x24\x55\x61\xca\x56\x2c\x85\x82\xf0\xac\x26\x19\x42\x26\x1e\x50\x72\xc6\x33\xa8\x50\x96\x4c\x99\x8e\x2a\x20\x9c\x1a\x9a\x82\x95\x4c\x13\xdd\x2c\x9d\xe4\x65\x02\x0d\x7a\xbd\xeb\x6b\xf8\x7f\xc9\x32\x49\x34\xc2\xbc\xea\x79\x91\xef\x26\x3e\x24\xee\xed\xd4\x87\x60\x02\xe1\x2c\x01\xff\xb7\x20\x4e\x62\xe3\x01\xa9\xc0\xea\x01\x00\x7c\x8e\x82\x4f\x6e\x74\x07\x1f\xfd\x3b\xb0\x18\xb5\x9d\x66\x95\x51\xd8\x7f\xe6\xf3\x60\xfc\xf8\xcf\x30\x85\xf3\xe9\xb4\x85\x1a\x32\x4e\x4a\xec\x36\xbf\xb8\x91\xf7\xc1\x8d\xac\x17\xa3\x37\x36\x98\xa2\xc5\x49\xe4\x06\x61\xd2\x06\x5d\x6c\xd1\x8b\x7b\xdc\xc0\x3c\x0c\x7e\x9d\xfb\x47\x7c\xab\xba\x28\xce\xf0\x8d\x5e\xbf\xee\xb4\x91\x07\xa2\x89\x5c\xd4\xb2\x78\x02\x70\x7d\xdd\xf8\x4f\xbd\x1d\x0c\xb4\x10\x85\xea\x33\xd4\xab\xc6\x80\xb9\x2e\x8b\xc1\x32\xad\x5e\xfd\xd4\x00\x4d\xed\xf7\xb2\xdc\x49\x37\xca\x61\xec\x4f\xdc\xf9\x34\x81\x67\xc8\x9f\x1d\x49\x2c\x44\xda\xf4\xe2\x9c\x44\x13\x1d\xfb\x59\x1f\xae\x62\xc2\x61\x22\x09\x4f\x99\x4a\x85\x03\x9e\x7b\xd5\x1c\xd6\xac\xc4\x3f\x04\x3f\x9b\xdf\xe3\xe1\xcf\xa4\xb5\x47\xc2\x4a\x04\x6b\x1e\xc3\xff\xc0\x23\x9c\x50\x62\xb7\x2c\xb5\x4e\x17\x62\xb5\x52\xa8\x17\xa5\x02\x88\x3f\xb9\xd3\xa9\xa9\x72\xf3\x6c\xa5\x0f\x8f\x74\x97\xa8\x09\x25\x9a\x74\xa1\x6f\xef\x12\xdf\xdd\x65\xbf\xcb\xf7\xcf\xbf\x9e\x81\xf7\xc1\xf7\x3e\x82\x55\x20\xcf\x74\x6e\x6d\xcf\xd9\xf0\x33\xbc\x1c\x0d\x87\x43\xfb\x88\x18\x4b\xc2\x8a\xd3\x42\x9a\x9c\xa0\xeb\x72\x0b\xac\x88\x52\x6b\x21\xe9\x59\x05\x87\x41\xb7\xd0\xc7\xa0\x9d\x3f\x48\x8a\x4b\x21\xee\x17\xad\x47\x0f\xfd\xb6\x1f\x2b\x13\x22\x2b\x70\xb1\xb5\xf2\x05\x20\x29\x31\x45\xae\x51\x36\xe0\xa7\x81\x4a\x23\x29\x77\x84\x17\x80\x69\xad\xb4\x28\x7f\x20\x34\xd2\x0c\x17\xa9\xa8\xb9\x6e\x80\xbb\x0e\x1e\xb5\xb1\xab\xcc\x1e\xfa\xdd\x2f\x70\xd2\x85\x54\x22\xd1\x48\x17\xa4\x25\xbb\x0d\xde\xef\xf1\x75\x14\x7b\x98\x77\xa7\x0c\x75\x45\xbf\xcb\xb0\x87\x39\xc3\x40\x99\x32\x13\x7b\x4b\x71\x96\x61\x1f\xd3\xe6\x71\x6a\xd8\x9e\x7d\xd3\xfb\xde\x08\x5b\x50\x7c\x60\x29\x5e\x1c\x64\x93\x59\xe4\x07\xef\xc3\x76\xb5\x39\xc4\xa8\x0d\x91\x3f\xf1\x23\x3f\xf4\xfc\x6e\x16\x36\x78\xf3\xf2\x25\xb3\xf1\xec\x2d\xcc\x42\x18\xfb\x53\x3f\xf1\xc1\x73\x63\xcf\x1d\xfb\x87\x43\xf1\xa0\x9d\xa7\xc3\xd0\xb4\xfd\x60\x60\xfe\xa3\x9c\x4c\x8f\xcf\x65\xa4\x44\x2d\x53\xe3\x66\x07\x94\x26\x1a\x1d\xa8\x84\x62\x66\x0a\x9d\xcb\x74\x87\xfe\xb7\xb9\x1e\xb0\x51\x54\x9a\xf1\x66\xe4\xfd\x07\xca\x9d\xa6\xb6\x2a\xbb\x12\x1d\x56\x70\x9b\xd5\x76\x42\x6c\x0d\xb4\x43\x99\x38\x73\xf3\x3d\x64\xae\x52\x25\xa4\x06\x21\xcd\x85\x28\x38\x48\xb1\x56\x17\x7d\xfc\x63\x16\x3e\xc8\xf6\x29\x9d\x4d\x13\x1e\xdf\xd5\xdd\x00\x3e\x33\x7b\x8d\xe2\x95\x64\xc8\xa9\x35\xb4\x1d\x60\xfc\x81\x69\xb4\x5e\xec\x7e\x52\x6b\x64\x3b\xb0\x2c\x44\x7a\x8f\xd4\x7a\x69\x3b\x40\xb1\x40\xb3\xfe\xca\x76\x80\xc8\x34\x67\x0f\x48\xad\xd7\x76\xaf\x89\xdc\xdd\x9a\xfb\x8e\x38\x6a\x50\x63\xb4\xfd\xcf\x81\xb1\x58\xf3\xde\x38\x9a\x7d\x7e\xf4\xdd\xb1\xe7\x6e\x2e\xec\xb7\xef\xd9\x05\x84\xba\xe9\xfd\x1d\x00\x00\xff\xff\x4b\x0e\x1b\x05\xd5\x0a\x00\x00")

func _20180103142000_initial_schemaSqlBytes() ([]byte, error) {
	return bindataRead(
@@ -83,7 +83,7 @@ func _20180103142000_initial_schemaSql() (*asset, error) {
		return nil, err
	}

	info := bindataFileInfo{name: "20180103142000_initial_schema.sql", size: 2973, mode: os.FileMode(420), modTime: time.Unix(1515235772, 0)}
	info := bindataFileInfo{name: "20180103142000_initial_schema.sql", size: 2773, mode: os.FileMode(420), modTime: time.Unix(1517419637, 0)}
	a := &asset{bytes: bytes, info: info}
	return a, nil
}
+321 −50

File changed.

Preview size limit exceeded, changes collapsed.

+62 −3
Original line number Diff line number Diff line
@@ -35,11 +35,16 @@ option objc_class_prefix = "NKPB";
 * An envelope for a realtime message.
 */
message Envelope {
  string cid = 1;
  oneof message {
    // Describes an error which occurred on the server.
    Error error = 1;

    nakama.api.ChannelId channel_id = 2; // TODO(zyro): replace with real imported message.
    Error error = 2;
    // RPC call or response.
    api.Rpc rpc = 3;
    // A data message delivered over a stream.
    StreamData stream_data = 4;
    // Represents a presence update for a particular stream.
    StreamPresenceEvent stream_presence_event = 5;
  }
}

@@ -72,3 +77,57 @@ message Error {
  // Additional error details which may be different for each response.
  map<string, string> context = 3;
}

/**
 * Represents identifying information for a stream.
 */
message Stream {
  // Mode identifies the type of stream.
  int32 mode = 1;
  // Subject is the primary identifier, if any.
  string subject = 2;
  // Descriptor is a secondary identifier, if any.
  string descriptor = 3;
  // The label is an arbitrary identifying string, if the stream has one.
  string label = 4;
}

/**
 * A data message delivered over a stream.
 */
message StreamData {
  // The stream this data message relates to.
  Stream stream = 1;
  // The sender, if any.
  StreamPresence sender = 2;
  // Arbitrary contents of the data message.
  string data = 3;
}

/**
 * A user session associated to a stream, usually through a list operation or a join/leave event.
 */
message StreamPresence {
  // The user this presence belongs to.
  string user_id = 1;
  // A unique session ID identifying the particular connection, because the user may have many.
  string session_id = 2;
  // The username for display purposes.
  string username = 3;
  // Whether this presence generates persistent data/messages, if applicable for the stream type.
  bool persistence = 4;
  // A user-set status message for this stream, if applicable.
  string status = 5;
}

/**
 * A set of joins and leaves on a particular stream.
 */
message StreamPresenceEvent {
  // The stream this event relates to.
  Stream stream = 1;
  // Presences joining the stream as part of this event, if any.
  repeated StreamPresence joins = 2;
  // Presences leaving the stream as part of this event, if any.
  repeated StreamPresence leaves = 3;
}
Loading