diff --git a/static/js/services/buddydata.js b/static/js/services/buddydata.js index fc0e110e..212b898d 100644 --- a/static/js/services/buddydata.js +++ b/static/js/services/buddydata.js @@ -67,9 +67,20 @@ define(['underscore'], function(underscore) { } else if (!createInParent && pushed.hasOwnProperty(id)) { return pushed[id].scope; } else { + var scope; + if (userid && scopes.hasOwnProperty(userid)) { + scope = scopes[userid]; + if (createInParent) { + scopes[id] = scope; + } + return scope; + } if (createInParent) { // If we have a parent we can create a new scope. - var scope = scopes[id] = createInParent.$new(); + scope = scopes[id] = createInParent.$new(); + if (userid) { + scopes[userid] = scope; + } scope.buddyIndex = ++count; if (userid) { scope.contact = contactData.get(userid); @@ -107,12 +118,17 @@ define(['underscore'], function(underscore) { var scope = scopes[id]; if (scope) { scope.$destroy(); - brain[id] = scope; + if (!hard) { + brain[id] = scope; + } delete scopes[id]; return scope; } else { return null; } + }, + set: function(id, scope) { + scopes[id] = scope; } }; return buddyData; diff --git a/static/js/services/buddylist.js b/static/js/services/buddylist.js index d2d20718..d4d9dd56 100644 --- a/static/js/services/buddylist.js +++ b/static/js/services/buddylist.js @@ -116,7 +116,7 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text! }; // buddyList - return ["$window", "$compile", "playSound", "buddyData", "fastScroll", "mediaStream", function($window, $compile, playSound, buddyData, fastScroll, mediaStream) { + return ["$window", "$compile", "playSound", "buddyData", "buddySession", "fastScroll", "mediaStream", function($window, $compile, playSound, buddyData, buddySession, fastScroll, mediaStream) { var requestAnimationFrame = $window.requestAnimationFrame; @@ -196,7 +196,7 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text! }; - Buddylist.prototype.onBuddyScope = function(scope) { + Buddylist.prototype.onBuddyScopeCreated = function(scope) { scope.element = null; scope.doDefault = function() { @@ -217,6 +217,28 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text! }; + Buddylist.prototype.onBuddySessionUserid = function(scope, sourceSession) { + + var targetScope = buddyData.get(sourceSession.Userid); + if (targetScope === scope) { + // No action. + return; + } + // Merge sessions. + targetScope.session.merge(sourceSession); + // Cleanup old from tree and DOM. + var id = sourceSession.Id; + this.tree.remove(id); + if (scope.element) { + this.lefts[id] = scope.element; + scope.element = null; + } + scope.$destroy(); + buddyData.set(id, targetScope); + delete this.actionElements[id]; + + }; + Buddylist.prototype.soundLoop = function() { if (this.playSoundLeft) { @@ -354,22 +376,21 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text! //console.log("onStatus", data); var id = data.Id; - var scope = buddyData.get(id, this.$scope, _.bind(this.onBuddyScope, this), data.Userid); + var scope = buddyData.get(id, this.$scope, _.bind(function(scope) { + this.onBuddyScopeCreated(scope); + scope.session = buddySession.create(data); + }, this), data.Userid); // Update session. - if (scope.session.Userid !== data.Userid) { - scope.session.Userid = data.Userid; - console.log("onStatus session is now userid", id, data.Userid); - } - // Update status. - if (true) { - if (data.Rev) { - scope.session.Rev = data.Rev; - } - scope.status = data.Status; - this.updateBuddyPicture(scope.status); + var sessionData = scope.session.update(id, data, _.bind(function(session) { + //console.log("Session is now authenticated", session); + this.onBuddySessionUserid(scope, session); + }, this)); + if (sessionData) { + // onStatus for main session. + scope.status = sessionData.Status; var displayName = scope.displayName; - if (scope.status.displayName) { - scope.displayName = scope.status.displayName; + if (sessionData.Status.displayName) { + scope.displayName = sessionData.Status.displayName; } else { scope.displayName = null; } @@ -377,8 +398,9 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text! var before = this.tree.update(id, scope); this.queue.push(["status", id, before]); } - scope.$apply(); + this.updateBuddyPicture(sessionData.Status); } + scope.$apply(); }; @@ -386,31 +408,24 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text! //console.log("Joined", data); var id = data.Id; - var scope = buddyData.get(id, this.$scope, _.bind(this.onBuddyScope, this), data.Userid); - // Create session. - scope.session = { - Id: data.Id, - Userid: data.Userid, - Ua: data.Ua, - Rev: 0 - }; - // Add status. + var scope = buddyData.get(id, this.$scope, _.bind(function(scope) { + this.onBuddyScopeCreated(scope); + scope.session = buddySession.create(data); + }, this), data.Userid); + // Update session. buddyCount++; - if (data.Status) { - if (true) { - if (data.Rev) { - scope.session.Rev = data.Rev; - } - scope.status = data.Status; - scope.displayName = scope.status.displayName; - this.updateBuddyPicture(scope.status); + var sessionData = scope.session.update(id, data); + if (sessionData && sessionData.Status) { + scope.status = sessionData.Status; + scope.displayName = sessionData.Status.displayName; + this.updateBuddyPicture(sessionData.Status); + if (!scope.element) { + var before = this.tree.add(id, scope); + this.queue.push(["joined", id, before]); + this.playSoundJoined = true; } - } - //console.log("Joined scope", scope, scope.element); - if (!scope.element) { - var before = this.tree.add(id, scope); - this.queue.push(["joined", id, before]); - this.playSoundJoined = true; + } else { + scope.$apply(); } }; @@ -438,9 +453,8 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text! Buddylist.prototype.onLeft = function(data) { - //console.log("Left", session); + //console.log("Left", data); var id = data.Id; - this.tree.remove(id); var scope = buddyData.get(id); if (!scope) { //console.warn("Trying to remove buddy with no registered scope", session); @@ -449,12 +463,21 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text! if (buddyCount > 0) { buddyCount--; } - if (scope.element) { - this.lefts[id] = scope.element; - this.playSoundLeft = true; + if (scope.session.remove(id)) { + // No session left. Cleanup. + this.tree.remove(id); + if (scope.element) { + this.lefts[id] = scope.element; + this.playSoundLeft = true; + } + buddyData.del(id); + if (scope.session.Userid) { + buddyData.del(scope.session.Userid); + } + delete this.actionElements[id]; + } else { + scope.$apply(); } - buddyData.del(id); - delete this.actionElements[id]; }; diff --git a/static/js/services/buddysession.js b/static/js/services/buddysession.js new file mode 100644 index 00000000..cd240f57 --- /dev/null +++ b/static/js/services/buddysession.js @@ -0,0 +1,140 @@ +/* + * Spreed WebRTC. + * Copyright (C) 2013-2014 struktur AG + * + * This file is part of Spreed WebRTC. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +define(["underscore"], function(_) { + + // buddySession + return [function() { + + var BuddySession = function(data) { + this.sessions = {}; + this.count = 0; + if (data.Id) { + this.add(data.Id, data); + this.use(data); + this.Userid = data.Userid || null; + } else { + this.set({}); + } + }; + + BuddySession.prototype.add = function(id, data) { + this.sessions[id] = data; + this.count++; + return data; + }; + + BuddySession.prototype.rm = function(id) { + delete this.sessions[id]; + this.count--; + }; + + BuddySession.prototype.get = function(id) { + if (!id) { + id = this.Id; + } + return this.sessions[id]; + }; + + BuddySession.prototype.use = function(data) { + this.Id = data.Id || null; + this.Ua = data.Ua || ""; + }; + + BuddySession.prototype.remove = function(id, onEmptyCallback) { + + this.rm(id); + if (id === this.Id) { + var sessions = this.sessions; + var sessionData; + for (var sd in sessions) { + if (sessions.hasOwnProperty(sd)) { + sessionData = sessions[sd]; + break; + } + } + if (sessionData) { + //console.log("remove session", sessionData); + this.use(sessionData); + } else { + console.log("Last session removed", sessions); + return true; + } + } + return false; + + }; + + BuddySession.prototype.update = function(id, data, onUseridCallback) { + + var sessionData = this.sessions[id]; + if (!sessionData) { + sessionData = this.add(id, data); + } + + if (data.Userid && !this.Userid) { + this.Userid = data.Userid; + console.log("Session now has a user id", this.Id, data.Userid); + if (onUseridCallback) { + onUseridCallback(this); + } + } + if (data.Rev) { + sessionData.Rev = data.Rev; + } + if (data.Status) { + sessionData.Status = data.Status; + } + + if (id === this.Id) { + return sessionData; + } else { + return null; + } + + }; + + BuddySession.prototype.merge = function(otherSession) { + if (!this.Userid) { + console.error("Refusing to merge into session as we have no userid", this, otherSession); + return; + } + if (otherSession.Userid !== this.Userid) { + console.error("Refusing to merge other session with different userid", otherSession, this); + return; + } + _.each(otherSession.sessions, _.bind(function(s, id) { + if (this.sessions.hasOwnProperty(id)) { + return; + } + this.add(id, s); + }, this)); + console.log("Merged sessions", this, otherSession); + }; + + return { + create: function(data) { + return new BuddySession(data); + } + }; + + }]; + +}); diff --git a/static/js/services/services.js b/static/js/services/services.js index a15f3dba..12f340b3 100644 --- a/static/js/services/services.js +++ b/static/js/services/services.js @@ -45,7 +45,8 @@ define([ 'services/videowaiter', 'services/videolayout', 'services/contactdata', - 'services/contacts'], function(_, + 'services/contacts', + 'services/buddysession'], function(_, desktopNotify, playSound, safeApply, @@ -70,7 +71,8 @@ fastScroll, videoWaiter, videoLayout, contactData, -contacts) { +contacts, +buddySession) { var services = { desktopNotify: desktopNotify, @@ -97,7 +99,8 @@ contacts) { videoWaiter: videoWaiter, videoLayout: videoLayout, contactData: contactData, - contacts: contacts + contacts: contacts, + buddySession: buddySession }; var initialize = function(angModule) { diff --git a/static/partials/buddy.html b/static/partials/buddy.html index 26b59bdd..9ba70952 100644 --- a/static/partials/buddy.html +++ b/static/partials/buddy.html @@ -1,5 +1,5 @@
{{session.Id|displayName}}
-
{{session.Ua}}
+
({{session.count}}) {{session.Ua}}