From a1c13457197e73150d77363394ba78e25ab74f19 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Fri, 16 Dec 2022 18:56:36 +0100 Subject: [PATCH] Server-side support for protocol 2. The "time" field of messages is now a string in RFC 3339 format, and there is a new "error" field in messages. --- group/group.go | 18 +++--------------- group/group_test.go | 18 +----------------- rtpconn/webclient.go | 26 +++++++++++++++----------- 3 files changed, 19 insertions(+), 43 deletions(-) diff --git a/group/group.go b/group/group.go index 6ce7438..74f168f 100644 --- a/group/group.go +++ b/group/group.go @@ -60,7 +60,7 @@ func (err ProtocolError) Error() string { type ChatHistoryEntry struct { Id string User string - Time int64 + Time time.Time Kind string Value interface{} } @@ -760,18 +760,6 @@ func (g *Group) WallOps(message string) { } } -func FromJSTime(tm int64) time.Time { - if tm == 0 { - return time.Time{} - } - return time.Unix(int64(tm)/1000, (int64(tm)%1000)*1000000) -} - -func ToJSTime(tm time.Time) int64 { - return int64((tm.Sub(time.Unix(0, 0)) + time.Millisecond/2) / - time.Millisecond) -} - const maxChatHistory = 50 func (g *Group) ClearChatHistory() { @@ -780,7 +768,7 @@ func (g *Group) ClearChatHistory() { g.history = nil } -func (g *Group) AddToChatHistory(id, user string, time int64, kind string, value interface{}) { +func (g *Group) AddToChatHistory(id, user string, time time.Time, kind string, value interface{}) { g.mu.Lock() defer g.mu.Unlock() @@ -796,7 +784,7 @@ func (g *Group) AddToChatHistory(id, user string, time int64, kind string, value func discardObsoleteHistory(h []ChatHistoryEntry, duration time.Duration) []ChatHistoryEntry { i := 0 for i < len(h) { - if time.Since(FromJSTime(h[i].Time)) <= duration { + if time.Since(h[i].Time) <= duration { break } i++ diff --git a/group/group_test.go b/group/group_test.go index 0b80608..f7c794b 100644 --- a/group/group_test.go +++ b/group/group_test.go @@ -47,28 +47,12 @@ func TestGroup(t *testing.T) { } } -func TestJSTime(t *testing.T) { - tm := time.Now() - js := ToJSTime(tm) - tm2 := FromJSTime(js) - js2 := ToJSTime(tm2) - - if js != js2 { - t.Errorf("%v != %v", js, js2) - } - - delta := tm.Sub(tm2) - if delta < -time.Millisecond/2 || delta > time.Millisecond/2 { - t.Errorf("Delta %v, %v, %v", delta, tm, tm2) - } -} - func TestChatHistory(t *testing.T) { g := Group{ description: &Description{}, } for i := 0; i < 2*maxChatHistory; i++ { - g.AddToChatHistory("id", "user", ToJSTime(time.Now()), "", + g.AddToChatHistory("id", "user", time.Now(), "", fmt.Sprintf("%v", i), ) } diff --git a/rtpconn/webclient.go b/rtpconn/webclient.go index bcbf94a..ddbd80e 100644 --- a/rtpconn/webclient.go +++ b/rtpconn/webclient.go @@ -112,6 +112,7 @@ type clientMessage struct { Type string `json:"type"` Version []string `json:"version"` Kind string `json:"kind,omitempty"` + Error string `json:"error,omitempty"` Id string `json:"id,omitempty"` Replace string `json:"replace,omitempty"` Source string `json:"source,omitempty"` @@ -126,7 +127,7 @@ type clientMessage struct { Group string `json:"group,omitempty"` Value interface{} `json:"value,omitempty"` NoEcho bool `json:"noecho,omitempty"` - Time int64 `json:"time,omitempty"` + Time string `json:"time,omitempty"` SDP string `json:"sdp,omitempty"` Candidate *webrtc.ICECandidateInit `json:"candidate,omitempty"` Label string `json:"label,omitempty"` @@ -834,6 +835,8 @@ func readMessage(conn *websocket.Conn, m *clientMessage) error { return conn.ReadJSON(&m) } +const protocolVersion = "2" + func StartClient(conn *websocket.Conn) (err error) { var m clientMessage @@ -858,7 +861,7 @@ func StartClient(conn *websocket.Conn) (err error) { versionError := true if m.Version != nil { for _, v := range m.Version { - if v == "1" { + if v == protocolVersion { versionError = false } } @@ -973,7 +976,7 @@ func clientLoop(c *webClient, ws *websocket.Conn, versionError bool) error { err := c.write(clientMessage{ Type: "handshake", - Version: []string{"1"}, + Version: []string{protocolVersion}, }) if err != nil { return err @@ -1203,7 +1206,7 @@ func handleAction(c *webClient, a interface{}) error { Type: "chathistory", Source: m.Id, Username: m.User, - Time: m.Time, + Time: m.Time.Format(time.RFC3339), Value: m.Value, Kind: m.Kind, }) @@ -1418,7 +1421,7 @@ func handleClientMessage(c *webClient, m clientMessage) error { }, ) if err != nil { - var s string + var e, s string if os.IsNotExist(err) { s = "group does not exist" } else if err == group.ErrNotAuthorised { @@ -1426,8 +1429,8 @@ func handleClientMessage(c *webClient, m clientMessage) error { time.Sleep(200 * time.Millisecond) } else if err == group.ErrAnonymousNotAuthorised { s = "please choose a username" - } else if e, ok := err.(group.UserError); ok { - s = string(e) + } else if err, ok := err.(group.UserError); ok { + s = err.Error() } else { s = "internal server error" log.Printf("Join group: %v", err) @@ -1435,6 +1438,7 @@ func handleClientMessage(c *webClient, m clientMessage) error { return c.write(clientMessage{ Type: "joined", Kind: "fail", + Error: e, Group: m.Group, Username: c.username, Value: s, @@ -1559,12 +1563,12 @@ func handleClientMessage(c *webClient, m clientMessage) error { return c.error(group.UserError("join a group first")) } - tm := group.ToJSTime(time.Now()) + now := time.Now() if m.Type == "chat" { if m.Dest == "" { g.AddToChatHistory( - m.Source, m.Username, tm, m.Kind, m.Value, + m.Source, m.Username, now, m.Kind, m.Value, ) } } @@ -1574,7 +1578,7 @@ func handleClientMessage(c *webClient, m clientMessage) error { Dest: m.Dest, Username: m.Username, Privileged: member("op", c.permissions), - Time: tm, + Time: now.Format(time.RFC3339), Kind: m.Kind, NoEcho: m.NoEcho, Value: m.Value, @@ -1677,7 +1681,7 @@ func handleClientMessage(c *webClient, m clientMessage) error { Type: "chat", Dest: c.id, Username: "Server", - Time: group.ToJSTime(time.Now()), + Time: time.Now().Format(time.RFC3339), Value: s, }) case "setdata":