[polari/wip/raresv/finalRebase: 3/18] userTracker: Add global tracking



commit 66590362c0dde557af1326942ba36a21fd301d0d
Author: raresv <rares visalom gmail com>
Date:   Tue Aug 2 00:46:26 2016 +0300

    userTracker: Add global tracking
    
    This reverts commit 2d9f3605d4ef77a9dc0d8973002e2a939f6e11d9.
    
    userTracker: *fixed rebase halfway split patch* UserTracker now extends GObject and emits detailed sinal 
status-changed::basenick. Add getBestMatchingContact.
    
    userTracker: patch based on the userTracker patch that introduced the global tracking of nicks. this is 
more or less the *final* second patch for the userTracker.
    
    userTracker: add the UserStatusMonitor class in order to handle all the trackers and fix conflicts in the 
UserTracker class.

 src/userTracker.js |  214 +++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 185 insertions(+), 29 deletions(-)
---
diff --git a/src/userTracker.js b/src/userTracker.js
index 5f9ca55..a9d0db2 100644
--- a/src/userTracker.js
+++ b/src/userTracker.js
@@ -7,6 +7,52 @@ const Utils = imports.utils;
 const Gio = imports.gi.Gio;
 const GLib = imports.gi.GLib;
 
+const AccountsMonitor = imports.accountsMonitor;
+const ChatroomManager = imports.chatroomManager;
+
+let _singleton = null;
+
+function getUserStatusMonitor() {
+    if (_singleton == null)
+        _singleton = new UserStatusMonitor();
+    return _singleton;
+}
+
+const UserStatusMonitor = new Lang.Class({
+    Name: 'UserStatusMonitor',
+
+    _init: function() {
+        this._userTrackers = new Map();
+        this._accountsMonitor = AccountsMonitor.getDefault();
+
+        this._accountsMonitor.connect('account-added', Lang.bind(this, this._onAccountAdded));
+        this._accountsMonitor.connect('account-removed', Lang.bind(this, this._onAccountRemoved));
+
+        this._accountsMonitor.dupAccounts().forEach(a => { this._onAccountAdded(this._accountsMonitor, a); 
});
+    },
+
+    _onAccountAdded: function(accountsMonitor, account) {
+        if (this._userTrackers.has(account))
+            return;
+
+        this._userTrackers.set(account, new UserTracker(account));
+    },
+
+    _onAccountRemoved: function(accountsMonitor, account) {
+        if (!this._userTrackers.has(account))
+            return;
+
+        this._userTrackers.delete(account);
+    },
+
+    getUserTrackerForAccount: function(account) {
+        if (this._userTrackers.has(account))
+            return this._userTrackers.get(account);
+        return null;
+    }
+});
+
+
 const UserTracker = new Lang.Class({
     Name: 'UserTracker',
     Extends: GObject.Object,
@@ -15,21 +61,45 @@ const UserTracker = new Lang.Class({
         'status-changed': {
             flags: GObject.SignalFlags.DETAILED,
             param_types: [GObject.TYPE_STRING, GObject.TYPE_INT]
+        },
+        'contacts-changed': {
+            flags: GObject.SignalFlags.DETAILED,
+            param_types: [GObject.TYPE_STRING]
         }
     },
 
-    _init: function(room) {
+    _init: function(account) {
         this.parent();
 
+        this._account = account;
+
         this._baseNickContacts = new Map();
+        this._roomData = new Map();
+        this._handlerCounter = 0;
 
-        this._room = room;
+        this._chatroomManager = ChatroomManager.getDefault();
+        this._chatroomManager.connect('room-added', Lang.bind(this, this._onRoomAdded));
+        this._chatroomManager.connect('room-removed', Lang.bind(this, this._onRoomRemoved));
+    },
+
+    _getRoomContacts: function(room) {
+        return this._roomData.get(room).contactMapping;
+    },
+
+    _getRoomHandlers: function(room) {
+        return this._roomData.get(room).handlerMapping;
+    },
 
-        this._onRoomAdded(this._room);
-        this._onChannelChanged(this._room);
+    _getRoomSignals: function(room) {
+        return this._roomData.get(room).roomSignals;
     },
 
-    _onRoomAdded: function(room) {
+    _onRoomAdded: function(roomManager, room) {
+        if (room.account != this._account)
+            return;
+
+        this._ensureRoomMappingForRoom(room);
+
         let roomSignals = [
             { name: 'notify::channel',
               handler: Lang.bind(this, this._onChannelChanged) },
@@ -47,14 +117,24 @@ const UserTracker = new Lang.Class({
               handler: Lang.bind(this, this._onMemberLeft) }
         ];
 
-        roomSignals.forEach(Lang.bind(this, function(signal) {
-            room.connect(signal.name, signal.handler);
-        }));
-    }
+        let signalIds = this._getRoomSignals(room);
+        roomSignals.forEach(signal => {
+            signalIds.push(room.connect(signal.name, signal.handler));
+        });
+    },
+
+    _onRoomRemoved: function(roomManager, room) {
+        if (!this._roomData.has(room))
+            return;
+
+        this._getRoomSignals(room).forEach(id => { room.disconnect(id); });
+        this._clearUsersFromRoom(room);
+        this._roomData.delete(room);
+    },
 
     _onChannelChanged: function(room) {
         if (!room.channel) {
-            this._clearUsers();
+            this._clearUsersFromRoom(room);
             return;
         }
 
@@ -64,44 +144,70 @@ const UserTracker = new Lang.Class({
         else
             members = [room.channel.connection.self_contact, room.channel.target_contact];
 
-        members.forEach(m => { this._trackMember(m); });
+        /*keep track of initial members in the room, both locally and
+        globally*/
+        members.forEach(m => { this._trackMember(m, room); });
     },
 
-    _clearUsers: function() {
-        for ([baseNick, contacts] of this._baseNickContacts)
-            contacts.slice().forEach((m) => { this._untrackMember(m); });
+    _clearUsersFromRoom: function(room) {
+        let map = this._getRoomContacts(room);
+        for ([baseNick, contacts] of map)
+            contacts.slice().forEach((m) => { this._untrackMember(m, room); });
+    },
+
+    _ensureRoomMappingForRoom: function(room) {
+        if (this._roomData.has(room))
+            return;
+        this._roomData.set(room, { contactMapping: new Map(),
+                                   handlerMapping: new Map(),
+                                   roomSignals: [] });
     },
 
     _onMemberRenamed: function(room, oldMember, newMember) {
-        this._untrackMember(oldMember);
-        this._trackMember(newMember);
+        this._untrackMember(oldMember, room);
+        this._trackMember(newMember, room);
     },
 
     _onMemberJoined: function(room, member) {
-        this._trackMember(member);
+        this._trackMember(member, room);
     },
 
     _onMemberLeft: function(room, member) {
-        this._untrackMember(member);
+        this._untrackMember(member, room);
     },
 
-    _pushMember: function(baseNick, member) {
-        if (!this._baseNickContacts.has(baseNick))
-            this._baseNickContacts.set(baseNick, []);
-        let contacts = this._baseNickContacts.get(baseNick);
+    _runHandlers: function(room, member, status) {
+        let baseNick = Polari.util_get_basenick(member.alias);
+        let roomHandlers = this._getRoomHandlers(room);
+        for ([id, info] of roomHandlers)
+            if (!info.nickName || info.nickName == baseNick)
+                info.handler(baseNick, status);
+    },
+
+    _pushMember: function(map, baseNick, member) {
+        if (!map.has(baseNick))
+            map.set(baseNick, []);
+        let contacts = map.get(baseNick);
         return contacts.push(member);
     },
 
-    _trackMember: function(member) {
+    _trackMember: function(member, room) {
         let baseNick = Polari.util_get_basenick(member.alias);
         let status = Tp.ConnectionPresenceType.AVAILABLE;
 
-        if (this._pushMember(baseNick, member) == 1)
+        let map = this._baseNickContacts;
+        if (this._pushMember(map, baseNick, member) == 1)
             this.emit("status-changed::" + baseNick, baseNick, status);
+
+        let roomMap = this._getRoomContacts(room);
+        if (this._pushMember(roomMap, baseNick, member) == 1)
+            this._runHandlers(room, member, status);
+
+        this.emit("contacts-changed::" + baseNick, member.alias);
     },
 
-    _popMember: function(baseNick, member) {
-        let contacts = this._baseNickContacts.get(baseNick) || [];
+    _popMember: function(map, baseNick, member) {
+        let contacts = map.get(baseNick) || [];
         let index = contacts.map(c => c.alias).indexOf(member.alias);
         if (index < 0)
             return [false, contacts.length];
@@ -109,14 +215,22 @@ const UserTracker = new Lang.Class({
         return [true, contacts.length];
     },
 
-    _untrackMember: function(member) {
+    _untrackMember: function(member, room) {
         let baseNick = Polari.util_get_basenick(member.alias);
         let status = Tp.ConnectionPresenceType.OFFLINE;
 
-        let [found, nContacts] = this._popMember(baseNick, member);
-        if (found)
+        let map = this._baseNickContacts;
+        let [found, nContacts] = this._popMember(map, baseNick, member);
+        if (found) {
             if (nContacts == 0)
                 this.emit("status-changed::" + baseNick, member.alias, status);
+            this.emit("contacts-changed::" + baseNick, member.alias);
+        }
+
+        let roomMap = this._getRoomContacts(room);
+        [found, nContacts] = this._popMember(roomMap, baseNick, member);
+        if (found && nContacts == 0)
+            this._runHandlers(room, member, status);
     },
 
     getNickStatus: function(nickName) {
@@ -125,5 +239,47 @@ const UserTracker = new Lang.Class({
         let contacts = this._baseNickContacts.get(baseNick) || [];
         return contacts.length == 0 ? Tp.ConnectionPresenceType.OFFLINE
                                     : Tp.ConnectionPresenceType.AVAILABLE;
+    },
+
+    getNickRoomStatus: function(nickName, room) {
+        let baseNick = Polari.util_get_basenick(nickName);
+
+        this._ensureRoomMappingForRoom(room);
+
+        let contacts = this._getRoomContacts(room).get(baseNick) || [];
+        return contacts.length == 0 ? Tp.ConnectionPresenceType.OFFLINE
+                                    : Tp.ConnectionPresenceType.AVAILABLE;
+    },
+
+    lookupContact: function(nickName) {
+        let baseNick = Polari.util_get_basenick(nickName);
+
+        let contacts = this._baseNickContacts.get(baseNick) || [];
+
+        if (contacts.length == 0)
+            return null;
+
+        for (let i = 0; i < contacts.length; i++)
+            if (contacts[i].alias == nickName)
+                return contacts[i];
+
+        return contacts[0];
+    },
+
+    watchRoomStatus: function(room, baseNick, callback) {
+        this._ensureRoomMappingForRoom(room);
+
+        this._getRoomHandlers(room).set(++this._handlerCounter, {
+            nickName: baseNick,
+            handler: callback
+        });
+
+        return this._handlerCounter;
+    },
+
+    unwatchRoomStatus: function(room, handlerID) {
+        if (!this._roomData.has(room))
+            return;
+        this._getRoomHandlers(room).delete(handlerID);
     }
 });


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]