diff --git a/debian/changelog b/debian/changelog index 89ce5c22..41f4b257 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +spreed-webrtc-server (0.23.8) precise; urgency=low + + * Session subscriptions now notify close both ways. + * Reenable chat rooms on certain conditions related to peer connectivity. + * Fixed an issue where replaced sessions cannot receive data from contacts in other rooms. + + -- Simon Eisenmann Wed, 08 Apr 2015 17:24:59 +0200 + spreed-webrtc-server (0.23.7) precise; urgency=low * Updated SCSS to match coding style. diff --git a/src/app/spreed-webrtc-server/client.go b/src/app/spreed-webrtc-server/client.go index c9f3bb41..b858176b 100644 --- a/src/app/spreed-webrtc-server/client.go +++ b/src/app/spreed-webrtc-server/client.go @@ -43,7 +43,7 @@ type Client interface { Session() *Session Index() uint64 Close() - ReplaceAndClose() + ReplaceAndClose(Client) } type client struct { @@ -87,9 +87,15 @@ func (client *client) Session() *Session { return client.session } -func (client *client) ReplaceAndClose() { - client.session.Close() - if client.Connection != nil { - client.Connection.Close() - } +func (client *client) ReplaceAndClose(oldClient Client) { + oldSession := oldClient.Session() + client.session.Replace(oldSession) + go func() { + // Close old session and client in another go routine, + // to avoid blocking the new client if the old one hangs or + // whatever. + log.Printf("Closing obsolete client %d (replaced with %d) with id %s\n", oldClient.Index(), client.Index(), oldSession.Id) + oldSession.Close() + oldClient.Close() + }() } diff --git a/src/app/spreed-webrtc-server/hub.go b/src/app/spreed-webrtc-server/hub.go index 963c74b9..6a7dcd26 100644 --- a/src/app/spreed-webrtc-server/hub.go +++ b/src/app/spreed-webrtc-server/hub.go @@ -154,12 +154,8 @@ func (h *hub) OnConnect(client Client, session *Session) { log.Printf("Created client %d with id %s\n", client.Index(), session.Id) // Register connection or replace existing one. if ec, ok := h.clients[session.Id]; ok { - // Clean up old client at the end and make sure to run this in another go routine, - // to avoid blocking the new client if the old one hangs or whatever. - go func() { - log.Printf("Closing obsolete client %d (replaced with %d) with id %s\n", ec.Index(), client.Index(), session.Id) - ec.ReplaceAndClose() - }() + // Clean up old client at the end outside the hub lock. + defer client.ReplaceAndClose(ec) } h.clients[session.Id] = client h.mutex.Unlock() diff --git a/src/app/spreed-webrtc-server/session.go b/src/app/spreed-webrtc-server/session.go index 2adcc0e2..c226e6c0 100644 --- a/src/app/spreed-webrtc-server/session.go +++ b/src/app/spreed-webrtc-server/session.go @@ -56,6 +56,7 @@ type Session struct { subscriptions map[string]*Session subscribers map[string]*Session disconnected bool + replaced bool } func NewSession(manager SessionManager, unicaster Unicaster, broadcaster Broadcaster, rooms RoomStatusManager, buddyImages ImageCache, attestations *securecookie.SecureCookie, id, sid string) *Session { @@ -85,16 +86,13 @@ func (s *Session) authenticated() (authenticated bool) { } func (s *Session) Subscribe(session *Session) { - s.mutex.Lock() s.subscriptions[session.Id] = session s.mutex.Unlock() session.AddSubscriber(s) - } func (s *Session) Unsubscribe(id string) { - s.mutex.Lock() if session, ok := s.subscriptions[id]; ok { delete(s.subscriptions, id) @@ -103,7 +101,6 @@ func (s *Session) Unsubscribe(id string) { } else { s.mutex.Unlock() } - } func (s *Session) AddSubscriber(session *Session) { @@ -209,33 +206,39 @@ func (s *Session) Close() { return } - outgoing := &DataOutgoing{ - From: s.Id, - A: s.attestation.Token(), - Data: &DataSession{ - Type: "Left", - Id: s.Id, - Status: "hard", - }, - } + // TODO(longsleep): Verify that it is ok to not do all this when replaced is true. + if !s.replaced { - if s.Hello { - // NOTE(lcooper): If we don't check for Hello here, we could deadlock - // when implicitly creating a room while a user is reconnecting. - s.Broadcaster.Broadcast(s.Id, s.Roomid, outgoing) - s.RoomStatusManager.LeaveRoom(s.Roomid, s.Id) - } + outgoing := &DataOutgoing{ + From: s.Id, + A: s.attestation.Token(), + Data: &DataSession{ + Type: "Left", + Id: s.Id, + Status: "hard", + }, + } - for _, session := range s.subscribers { - s.Unicaster.Unicast(session.Id, outgoing) - } + if s.Hello { + // NOTE(lcooper): If we don't check for Hello here, we could deadlock + // when implicitly creating a room while a user is reconnecting. + s.Broadcaster.Broadcast(s.Id, s.Roomid, outgoing) + s.RoomStatusManager.LeaveRoom(s.Roomid, s.Id) + } - for _, session := range s.subscriptions { - session.RemoveSubscriber(s.Id) - } + for _, session := range s.subscribers { + s.Unicaster.Unicast(session.Id, outgoing) + } + + for _, session := range s.subscriptions { + session.RemoveSubscriber(s.Id) + s.Unicaster.Unicast(session.Id, outgoing) + } - s.SessionManager.DestroySession(s.Id, s.userid) - s.buddyImages.Delete(s.Id) + s.SessionManager.DestroySession(s.Id, s.userid) + s.buddyImages.Delete(s.Id) + + } s.subscriptions = make(map[string]*Session) s.subscribers = make(map[string]*Session) @@ -244,6 +247,27 @@ func (s *Session) Close() { s.mutex.Unlock() } +func (s *Session) Replace(oldSession *Session) { + + oldSession.mutex.Lock() + if oldSession.disconnected { + oldSession.mutex.Unlock() + return + } + + s.mutex.Lock() + + s.subscriptions = oldSession.subscriptions + s.subscribers = oldSession.subscribers + + s.mutex.Unlock() + + // Mark old session as replaced. + oldSession.replaced = true + oldSession.mutex.Unlock() + +} + func (s *Session) Update(update *SessionUpdate) uint64 { s.mutex.Lock() defer s.mutex.Unlock() diff --git a/static/js/directives/chat.js b/static/js/directives/chat.js index 75f06755..1980d409 100644 --- a/static/js/directives/chat.js +++ b/static/js/directives/chat.js @@ -78,7 +78,7 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro if (!with_message) { return; } - // No room with this id, get one with the from id + // No room with this id, get one with the from id. $scope.$emit("startchat", from, { restore: with_message }); @@ -90,14 +90,19 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro room.peerIsTyping = "no"; room.p2p( !! p2p); if (room.firstmessage) { + // Auto show when this is the first message. $scope.showRoom(room.id, null, { restore: with_message }); } + if (!room.enabled) { + // Reenable chat room when receiving messages again. + room.enabled = true; + } } - room.$broadcast("received", from, data); safeApply(room); + room.$broadcast("received", from, data); }); @@ -108,10 +113,6 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro case "Left": if (data.Status !== "soft") { room.enabled = false; - room.$broadcast("received", data.Id, { - Type: "LeftOrJoined", - "LeftOrJoined": "left" - }); safeApply(room); } break; @@ -119,10 +120,6 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro if (!room.enabled) { room.enabled = true; _.delay(function() { - room.$broadcast("received", data.Id, { - Type: "LeftOrJoined", - "LeftOrJoined": "joined" - }); safeApply(room); }, 1000); } @@ -398,6 +395,22 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro } } }); + subscope.$watch("enabled", function(enabled, old) { + if (enabled === old) { + return; + } + //console.log("enabled", enabled, old); + var value; + if (enabled) { + value = "resumed"; + } else { + value = "left"; + } + subscope.$broadcast("received", subscope.id, { + Type: "LeftOrJoined", + "LeftOrJoined": value + }); + }); chat(subscope, function(clonedElement, $scope) { pane.append(clonedElement); @@ -445,6 +458,9 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro subscope.index = index; subscope.visible = true; } + if (!subscope.enabled) { + subscope.enabled = true; + } } if (options.autofocus && subscope.visible) { subscope.$broadcast("focus");