Merge pull request #163 from matrix-org/markjh/presence_list_cache
Add a cache for the presence list
This commit is contained in:
commit
d9f60e8dc8
|
@ -521,20 +521,26 @@ class PresenceHandler(BaseHandler):
|
||||||
if not self.hs.is_mine(observer_user):
|
if not self.hs.is_mine(observer_user):
|
||||||
raise SynapseError(400, "User is not hosted on this Home Server")
|
raise SynapseError(400, "User is not hosted on this Home Server")
|
||||||
|
|
||||||
presence = yield self.store.get_presence_list(
|
presence_list = yield self.store.get_presence_list(
|
||||||
observer_user.localpart, accepted=accepted
|
observer_user.localpart, accepted=accepted
|
||||||
)
|
)
|
||||||
|
|
||||||
for p in presence:
|
results = []
|
||||||
observed_user = UserID.from_string(p.pop("observed_user_id"))
|
for row in presence_list:
|
||||||
p["observed_user"] = observed_user
|
observed_user = UserID.from_string(row["observed_user_id"])
|
||||||
p.update(self._get_or_offline_usercache(observed_user).get_state())
|
result = {
|
||||||
if "last_active" in p:
|
"observed_user": observed_user, "accepted": row["accepted"]
|
||||||
p["last_active_ago"] = int(
|
}
|
||||||
self.clock.time_msec() - p.pop("last_active")
|
result.update(
|
||||||
|
self._get_or_offline_usercache(observed_user).get_state()
|
||||||
|
)
|
||||||
|
if "last_active" in result:
|
||||||
|
result["last_active_ago"] = int(
|
||||||
|
self.clock.time_msec() - result.pop("last_active")
|
||||||
)
|
)
|
||||||
|
results.append(result)
|
||||||
|
|
||||||
defer.returnValue(presence)
|
defer.returnValue(results)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
@log_function
|
@log_function
|
||||||
|
|
|
@ -13,7 +13,9 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from ._base import SQLBaseStore
|
from ._base import SQLBaseStore, cached
|
||||||
|
|
||||||
|
from twisted.internet import defer
|
||||||
|
|
||||||
|
|
||||||
class PresenceStore(SQLBaseStore):
|
class PresenceStore(SQLBaseStore):
|
||||||
|
@ -87,31 +89,48 @@ class PresenceStore(SQLBaseStore):
|
||||||
desc="add_presence_list_pending",
|
desc="add_presence_list_pending",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
def set_presence_list_accepted(self, observer_localpart, observed_userid):
|
def set_presence_list_accepted(self, observer_localpart, observed_userid):
|
||||||
return self._simple_update_one(
|
result = yield self._simple_update_one(
|
||||||
table="presence_list",
|
table="presence_list",
|
||||||
keyvalues={"user_id": observer_localpart,
|
keyvalues={"user_id": observer_localpart,
|
||||||
"observed_user_id": observed_userid},
|
"observed_user_id": observed_userid},
|
||||||
updatevalues={"accepted": True},
|
updatevalues={"accepted": True},
|
||||||
desc="set_presence_list_accepted",
|
desc="set_presence_list_accepted",
|
||||||
)
|
)
|
||||||
|
self.get_presence_list_accepted.invalidate(observer_localpart)
|
||||||
|
defer.returnValue(result)
|
||||||
|
|
||||||
def get_presence_list(self, observer_localpart, accepted=None):
|
def get_presence_list(self, observer_localpart, accepted=None):
|
||||||
keyvalues = {"user_id": observer_localpart}
|
if accepted:
|
||||||
if accepted is not None:
|
return self.get_presence_list_accepted(observer_localpart)
|
||||||
keyvalues["accepted"] = accepted
|
else:
|
||||||
|
keyvalues = {"user_id": observer_localpart}
|
||||||
|
if accepted is not None:
|
||||||
|
keyvalues["accepted"] = accepted
|
||||||
|
|
||||||
|
return self._simple_select_list(
|
||||||
|
table="presence_list",
|
||||||
|
keyvalues=keyvalues,
|
||||||
|
retcols=["observed_user_id", "accepted"],
|
||||||
|
desc="get_presence_list",
|
||||||
|
)
|
||||||
|
|
||||||
|
@cached()
|
||||||
|
def get_presence_list_accepted(self, observer_localpart):
|
||||||
return self._simple_select_list(
|
return self._simple_select_list(
|
||||||
table="presence_list",
|
table="presence_list",
|
||||||
keyvalues=keyvalues,
|
keyvalues={"user_id": observer_localpart, "accepted": True},
|
||||||
retcols=["observed_user_id", "accepted"],
|
retcols=["observed_user_id", "accepted"],
|
||||||
desc="get_presence_list",
|
desc="get_presence_list_accepted",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
def del_presence_list(self, observer_localpart, observed_userid):
|
def del_presence_list(self, observer_localpart, observed_userid):
|
||||||
return self._simple_delete_one(
|
yield self._simple_delete_one(
|
||||||
table="presence_list",
|
table="presence_list",
|
||||||
keyvalues={"user_id": observer_localpart,
|
keyvalues={"user_id": observer_localpart,
|
||||||
"observed_user_id": observed_userid},
|
"observed_user_id": observed_userid},
|
||||||
desc="del_presence_list",
|
desc="del_presence_list",
|
||||||
)
|
)
|
||||||
|
self.get_presence_list_accepted.invalidate(observer_localpart)
|
||||||
|
|
|
@ -233,7 +233,7 @@ class MockedDatastorePresenceTestCase(PresenceTestCase):
|
||||||
if not user_localpart in self.PRESENCE_LIST:
|
if not user_localpart in self.PRESENCE_LIST:
|
||||||
return defer.succeed([])
|
return defer.succeed([])
|
||||||
return defer.succeed([
|
return defer.succeed([
|
||||||
{"observed_user_id": u} for u in
|
{"observed_user_id": u, "accepted": accepted} for u in
|
||||||
self.PRESENCE_LIST[user_localpart]])
|
self.PRESENCE_LIST[user_localpart]])
|
||||||
datastore.get_presence_list = get_presence_list
|
datastore.get_presence_list = get_presence_list
|
||||||
|
|
||||||
|
@ -735,9 +735,11 @@ class PresencePushTestCase(MockedDatastorePresenceTestCase):
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
[
|
[
|
||||||
{"observed_user": self.u_banana,
|
{"observed_user": self.u_banana,
|
||||||
"presence": OFFLINE},
|
"presence": OFFLINE,
|
||||||
|
"accepted": True},
|
||||||
{"observed_user": self.u_clementine,
|
{"observed_user": self.u_clementine,
|
||||||
"presence": OFFLINE},
|
"presence": OFFLINE,
|
||||||
|
"accepted": True},
|
||||||
],
|
],
|
||||||
presence
|
presence
|
||||||
)
|
)
|
||||||
|
@ -758,9 +760,11 @@ class PresencePushTestCase(MockedDatastorePresenceTestCase):
|
||||||
self.assertEquals([
|
self.assertEquals([
|
||||||
{"observed_user": self.u_banana,
|
{"observed_user": self.u_banana,
|
||||||
"presence": ONLINE,
|
"presence": ONLINE,
|
||||||
"last_active_ago": 2000},
|
"last_active_ago": 2000,
|
||||||
|
"accepted": True},
|
||||||
{"observed_user": self.u_clementine,
|
{"observed_user": self.u_clementine,
|
||||||
"presence": OFFLINE},
|
"presence": OFFLINE,
|
||||||
|
"accepted": True},
|
||||||
], presence)
|
], presence)
|
||||||
|
|
||||||
(events, _) = yield self.event_source.get_new_events_for_user(
|
(events, _) = yield self.event_source.get_new_events_for_user(
|
||||||
|
|
|
@ -101,8 +101,8 @@ class PresenceProfilelikeDataTestCase(unittest.TestCase):
|
||||||
self.datastore.get_profile_avatar_url = get_profile_avatar_url
|
self.datastore.get_profile_avatar_url = get_profile_avatar_url
|
||||||
|
|
||||||
self.presence_list = [
|
self.presence_list = [
|
||||||
{"observed_user_id": "@banana:test"},
|
{"observed_user_id": "@banana:test", "accepted": True},
|
||||||
{"observed_user_id": "@clementine:test"},
|
{"observed_user_id": "@clementine:test", "accepted": True},
|
||||||
]
|
]
|
||||||
def get_presence_list(user_localpart, accepted=None):
|
def get_presence_list(user_localpart, accepted=None):
|
||||||
return defer.succeed(self.presence_list)
|
return defer.succeed(self.presence_list)
|
||||||
|
@ -144,8 +144,8 @@ class PresenceProfilelikeDataTestCase(unittest.TestCase):
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def test_set_my_state(self):
|
def test_set_my_state(self):
|
||||||
self.presence_list = [
|
self.presence_list = [
|
||||||
{"observed_user_id": "@banana:test"},
|
{"observed_user_id": "@banana:test", "accepted": True},
|
||||||
{"observed_user_id": "@clementine:test"},
|
{"observed_user_id": "@clementine:test", "accepted": True},
|
||||||
]
|
]
|
||||||
|
|
||||||
mocked_set = self.datastore.set_presence_state
|
mocked_set = self.datastore.set_presence_state
|
||||||
|
@ -167,8 +167,8 @@ class PresenceProfilelikeDataTestCase(unittest.TestCase):
|
||||||
self.mock_get_joined.side_effect = get_joined
|
self.mock_get_joined.side_effect = get_joined
|
||||||
|
|
||||||
self.presence_list = [
|
self.presence_list = [
|
||||||
{"observed_user_id": "@banana:test"},
|
{"observed_user_id": "@banana:test", "accepted": True},
|
||||||
{"observed_user_id": "@clementine:test"},
|
{"observed_user_id": "@clementine:test", "accepted": True},
|
||||||
]
|
]
|
||||||
|
|
||||||
self.datastore.set_presence_state.return_value = defer.succeed(
|
self.datastore.set_presence_state.return_value = defer.succeed(
|
||||||
|
@ -203,9 +203,11 @@ class PresenceProfilelikeDataTestCase(unittest.TestCase):
|
||||||
"presence": ONLINE,
|
"presence": ONLINE,
|
||||||
"last_active_ago": 0,
|
"last_active_ago": 0,
|
||||||
"displayname": "Frank",
|
"displayname": "Frank",
|
||||||
"avatar_url": "http://foo"},
|
"avatar_url": "http://foo",
|
||||||
|
"accepted": True},
|
||||||
{"observed_user": self.u_clementine,
|
{"observed_user": self.u_clementine,
|
||||||
"presence": OFFLINE}
|
"presence": OFFLINE,
|
||||||
|
"accepted": True}
|
||||||
], presence)
|
], presence)
|
||||||
|
|
||||||
self.mock_update_client.assert_has_calls([
|
self.mock_update_client.assert_has_calls([
|
||||||
|
@ -233,7 +235,7 @@ class PresenceProfilelikeDataTestCase(unittest.TestCase):
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def test_push_remote(self):
|
def test_push_remote(self):
|
||||||
self.presence_list = [
|
self.presence_list = [
|
||||||
{"observed_user_id": "@potato:remote"},
|
{"observed_user_id": "@potato:remote", "accepted": True},
|
||||||
]
|
]
|
||||||
|
|
||||||
self.datastore.set_presence_state.return_value = defer.succeed(
|
self.datastore.set_presence_state.return_value = defer.succeed(
|
||||||
|
|
|
@ -183,7 +183,7 @@ class PresenceListTestCase(unittest.TestCase):
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def test_get_my_list(self):
|
def test_get_my_list(self):
|
||||||
self.datastore.get_presence_list.return_value = defer.succeed(
|
self.datastore.get_presence_list.return_value = defer.succeed(
|
||||||
[{"observed_user_id": "@banana:test"}],
|
[{"observed_user_id": "@banana:test", "accepted": True}],
|
||||||
)
|
)
|
||||||
|
|
||||||
(code, response) = yield self.mock_resource.trigger("GET",
|
(code, response) = yield self.mock_resource.trigger("GET",
|
||||||
|
@ -191,7 +191,7 @@ class PresenceListTestCase(unittest.TestCase):
|
||||||
|
|
||||||
self.assertEquals(200, code)
|
self.assertEquals(200, code)
|
||||||
self.assertEquals([
|
self.assertEquals([
|
||||||
{"user_id": "@banana:test", "presence": OFFLINE},
|
{"user_id": "@banana:test", "presence": OFFLINE, "accepted": True},
|
||||||
], response)
|
], response)
|
||||||
|
|
||||||
self.datastore.get_presence_list.assert_called_with(
|
self.datastore.get_presence_list.assert_called_with(
|
||||||
|
|
Loading…
Reference in New Issue