diff --git a/CHANGES b/CHANGES index c7d91ed..2ce1969 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,8 @@ -Galene 0.5.6 (unreleased): +Galene 0.6 (unreleased): + * Version the protocol: the handshake message now contains a version + number, and the server will warn if it is incorrect. This will become + a hard error in the future. * Rework the peer-to-peer file transfer protocol. It now lives in protocol.js, which makes it easy to use by third-party clients. * Extend the authorization protocol to allow the authorization server to diff --git a/README.PROTOCOL b/README.PROTOCOL index 2328b60..2fe9b5c 100644 --- a/README.PROTOCOL +++ b/README.PROTOCOL @@ -81,12 +81,15 @@ start pipelining messages to the server. ```javascript { type: 'handshake', + version: ["1"], id: id } ``` -If the field `id` is absent, then the peer doesn't originate streams (it -is a server). +The version field contains an array of supported protocol versions; the +client may announce multiple versions, but the server will always reply +with a singleton. If the field `id` is absent, then the peer doesn't +originate streams. A peer may, at any time, send a `ping` message. diff --git a/rtpconn/webclient.go b/rtpconn/webclient.go index 2fea510..18268d7 100644 --- a/rtpconn/webclient.go +++ b/rtpconn/webclient.go @@ -110,6 +110,7 @@ func (c *webClient) PushClient(group, kind, id, username string, perms []string, type clientMessage struct { Type string `json:"type"` + Version []string `json:"version"` Kind string `json:"kind,omitempty"` Id string `json:"id,omitempty"` Replace string `json:"replace,omitempty"` @@ -854,6 +855,15 @@ func StartClient(conn *websocket.Conn) (err error) { return } + versionError := true + if m.Version != nil { + for _, v := range m.Version { + if v == "1" { + versionError = false + } + } + } + c := &webClient{ id: m.Id, actionCh: make(chan struct{}, 1), @@ -878,7 +888,7 @@ func StartClient(conn *websocket.Conn) (err error) { c.close(e) }() - return clientLoop(c, conn) + return clientLoop(c, conn, versionError) } type pushConnAction struct { @@ -950,7 +960,7 @@ func addnew(v string, l []string) []string { return l } -func clientLoop(c *webClient, ws *websocket.Conn) error { +func clientLoop(c *webClient, ws *websocket.Conn, versionError bool) error { read := make(chan interface{}, 1) go clientReader(ws, read, c.done) @@ -962,12 +972,25 @@ func clientLoop(c *webClient, ws *websocket.Conn) error { defer ticker.Stop() err := c.write(clientMessage{ - Type: "handshake", + Type: "handshake", + Version: []string{"1"}, }) if err != nil { return err } + if versionError { + c.write(clientMessage{ + Type: "usermessage", + Kind: "warning", + Dest: c.id, + Privileged: true, + Value: "This client is using an unknown protocol version.\n" + + "Perhaps it needs upgrading?\n" + + "Trying to continue, things may break.", + }) + } + for { select { case m, ok := <-read: @@ -1384,22 +1407,22 @@ func handleClientMessage(c *webClient, m clientMessage) error { log.Printf("Join group: %v", err) } return c.write(clientMessage{ - Type: "joined", - Kind: "fail", - Group: m.Group, - Username: c.username, - Value: s, + Type: "joined", + Kind: "fail", + Group: m.Group, + Username: c.username, + Value: s, }) } if redirect := g.Description().Redirect; redirect != "" { // We normally redirect at the HTTP level, but the group // description could have been edited in the meantime. return c.write(clientMessage{ - Type: "joined", - Kind: "redirect", - Group: m.Group, - Username: c.username, - Value: redirect, + Type: "joined", + Kind: "redirect", + Group: m.Group, + Username: c.username, + Value: redirect, }) } c.group = g diff --git a/static/protocol.js b/static/protocol.js index 222a2e0..d9e6127 100644 --- a/static/protocol.js +++ b/static/protocol.js @@ -223,6 +223,7 @@ function ServerConnection() { /** * @typedef {Object} message * @property {string} type + * @property {Array} [version] * @property {string} [kind] * @property {string} [id] * @property {string} [replace] @@ -289,6 +290,7 @@ ServerConnection.prototype.connect = async function(url) { this.socket.onopen = function(e) { sc.send({ type: 'handshake', + version: ["1"], id: sc.id, }); if(sc.onconnected) @@ -322,6 +324,8 @@ ServerConnection.prototype.connect = async function(url) { let m = JSON.parse(e.data); switch(m.type) { case 'handshake': + if(!m.version || !m.version.includes('1')) + console.warn(`Unexpected protocol version ${m.version}.`); break; case 'offer': sc.gotOffer(m.id, m.label, m.source, m.username,