1
0

Compare commits

...

4 Commits

Author SHA1 Message Date
Paul "LeoNerd" Evans 01e83c9680 Merge branch 'develop' into paul/schema_breaking_changes 2014-09-03 18:21:55 +01:00
Paul "LeoNerd" Evans 9705706a7f Merge branch 'develop' into paul/schema_breaking_changes 2014-09-03 17:40:42 +01:00
Paul "LeoNerd" Evans 801a551da1 Rename 'mtime' DB field to 'last_active', adjusted semantics 2014-09-03 17:04:58 +01:00
Paul "LeoNerd" Evans b8906b0ea8 Kill the 'state' presence key in DB, name it 'presence' instead to match the over-the-wire API 2014-09-03 16:11:34 +01:00
8 changed files with 81 additions and 45 deletions
+1 -1
View File
@@ -57,7 +57,7 @@ SCHEMAS = [
# Remember to update this number every time an incompatible change is made to # Remember to update this number every time an incompatible change is made to
# database schema files, so the users will be informed on server restarts. # database schema files, so the users will be informed on server restarts.
SCHEMA_VERSION = 2 SCHEMA_VERSION = 3
class SynapseHomeServer(HomeServer): class SynapseHomeServer(HomeServer):
+8 -14
View File
@@ -178,9 +178,6 @@ class PresenceHandler(BaseHandler):
if not visible: if not visible:
raise SynapseError(404, "Presence information not visible") raise SynapseError(404, "Presence information not visible")
state = yield self.store.get_presence_state(target_user.localpart) state = yield self.store.get_presence_state(target_user.localpart)
if "mtime" in state:
del state["mtime"]
state["presence"] = state.pop("state")
if target_user in self._user_cachemap: if target_user in self._user_cachemap:
state["last_active"] = ( state["last_active"] = (
@@ -226,13 +223,17 @@ class PresenceHandler(BaseHandler):
logger.debug("Updating presence state of %s to %s", logger.debug("Updating presence state of %s to %s",
target_user.localpart, state["presence"]) target_user.localpart, state["presence"])
state_to_store = dict(state)
state_to_store["state"] = state_to_store.pop("presence")
statuscache=self._get_or_offline_usercache(target_user) statuscache=self._get_or_offline_usercache(target_user)
was_level = self.STATE_LEVELS[statuscache.get_state()["presence"]] oldstate = statuscache.get_state()
was_level = self.STATE_LEVELS[oldstate["presence"]]
now_level = self.STATE_LEVELS[state["presence"]] now_level = self.STATE_LEVELS[state["presence"]]
if now_level > was_level:
state["last_active"] = self.clock.time_msec()
state_to_store = dict(state)
yield defer.DeferredList([ yield defer.DeferredList([
self.store.set_presence_state( self.store.set_presence_state(
target_user.localpart, state_to_store target_user.localpart, state_to_store
@@ -242,9 +243,6 @@ class PresenceHandler(BaseHandler):
), ),
]) ])
if now_level > was_level:
state["last_active"] = self.clock.time_msec()
now_online = state["presence"] != PresenceState.OFFLINE now_online = state["presence"] != PresenceState.OFFLINE
was_polling = target_user in self._user_cachemap was_polling = target_user in self._user_cachemap
@@ -595,8 +593,6 @@ class PresenceHandler(BaseHandler):
def _push_presence_remote(self, user, destination, state=None): def _push_presence_remote(self, user, destination, state=None):
if state is None: if state is None:
state = yield self.store.get_presence_state(user.localpart) state = yield self.store.get_presence_state(user.localpart)
del state["mtime"]
state["presence"] = state.pop("state")
if user in self._user_cachemap: if user in self._user_cachemap:
state["last_active"] = ( state["last_active"] = (
@@ -884,8 +880,6 @@ class UserPresenceCache(object):
self.serial = None self.serial = None
def update(self, state, serial): def update(self, state, serial):
assert("mtime_age" not in state)
self.state.update(state) self.state.update(state)
# Delete keys that are now 'None' # Delete keys that are now 'None'
for k in self.state.keys(): for k in self.state.keys():
+3 -5
View File
@@ -35,17 +35,15 @@ class PresenceStore(SQLBaseStore):
return self._simple_select_one( return self._simple_select_one(
table="presence", table="presence",
keyvalues={"user_id": user_localpart}, keyvalues={"user_id": user_localpart},
retcols=["state", "status_msg", "mtime"], retcols=["presence", "status_msg", "last_active"],
) )
def set_presence_state(self, user_localpart, new_state): def set_presence_state(self, user_localpart, new_state):
return self._simple_update_one( return self._simple_update_one(
table="presence", table="presence",
keyvalues={"user_id": user_localpart}, keyvalues={"user_id": user_localpart},
updatevalues={"state": new_state["state"], updatevalues=new_state,
"status_msg": new_state["status_msg"], retcols=["presence"],
"mtime": self._clock.time_msec()},
retcols=["state"],
) )
def allow_presence_visible(self, observed_localpart, observer_userid): def allow_presence_visible(self, observed_localpart, observer_userid):
+35
View File
@@ -0,0 +1,35 @@
/* Copyright 2014 matrix.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-- SQLite3 doesn't support renaming or dropping columns. We'll have to go the
-- long way round
CREATE TABLE NEW_presence(
user_id INTEGER NOT NULL,
presence INTEGER,
status_msg TEXT,
last_active INTEGER,
FOREIGN KEY(user_id) REFERENCES users(id)
);
-- rename the 'state' field to 'presence'; migrate the old 'mtime' field into
-- the new 'last_active' field
INSERT INTO NEW_presence (user_id, presence, status_msg, last_active)
SELECT user_id, state, status_msg, mtime FROM presence;
DROP TABLE presence;
ALTER TABLE NEW_presence RENAME TO presence;
PRAGMA user_version = 3;
+2 -2
View File
@@ -14,9 +14,9 @@
*/ */
CREATE TABLE IF NOT EXISTS presence( CREATE TABLE IF NOT EXISTS presence(
user_id INTEGER NOT NULL, user_id INTEGER NOT NULL,
state INTEGER, presence INTEGER,
status_msg TEXT, status_msg TEXT,
mtime INTEGER, -- miliseconds since last state change last_active INTEGER,
FOREIGN KEY(user_id) REFERENCES users(id) FOREIGN KEY(user_id) REFERENCES users(id)
); );
+17 -13
View File
@@ -134,7 +134,7 @@ class PresenceStateTestCase(unittest.TestCase):
def test_get_my_state(self): def test_get_my_state(self):
mocked_get = self.datastore.get_presence_state mocked_get = self.datastore.get_presence_state
mocked_get.return_value = defer.succeed( mocked_get.return_value = defer.succeed(
{"state": ONLINE, "status_msg": "Online"} {"presence": ONLINE, "status_msg": "Online"}
) )
state = yield self.handler.get_state( state = yield self.handler.get_state(
@@ -151,7 +151,7 @@ class PresenceStateTestCase(unittest.TestCase):
def test_get_allowed_state(self): def test_get_allowed_state(self):
mocked_get = self.datastore.get_presence_state mocked_get = self.datastore.get_presence_state
mocked_get.return_value = defer.succeed( mocked_get.return_value = defer.succeed(
{"state": ONLINE, "status_msg": "Online"} {"presence": ONLINE, "status_msg": "Online"}
) )
state = yield self.handler.get_state( state = yield self.handler.get_state(
@@ -168,7 +168,7 @@ class PresenceStateTestCase(unittest.TestCase):
def test_get_same_room_state(self): def test_get_same_room_state(self):
mocked_get = self.datastore.get_presence_state mocked_get = self.datastore.get_presence_state
mocked_get.return_value = defer.succeed( mocked_get.return_value = defer.succeed(
{"state": ONLINE, "status_msg": "Online"} {"presence": ONLINE, "status_msg": "Online"}
) )
self.room_members = [self.u_apple, self.u_clementine] self.room_members = [self.u_apple, self.u_clementine]
@@ -186,7 +186,7 @@ class PresenceStateTestCase(unittest.TestCase):
def test_get_disallowed_state(self): def test_get_disallowed_state(self):
mocked_get = self.datastore.get_presence_state mocked_get = self.datastore.get_presence_state
mocked_get.return_value = defer.succeed( mocked_get.return_value = defer.succeed(
{"state": ONLINE, "status_msg": "Online"} {"presence": ONLINE, "status_msg": "Online"}
) )
self.room_members = [] self.room_members = []
@@ -201,14 +201,17 @@ class PresenceStateTestCase(unittest.TestCase):
@defer.inlineCallbacks @defer.inlineCallbacks
def test_set_my_state(self): def test_set_my_state(self):
mocked_set = self.datastore.set_presence_state mocked_set = self.datastore.set_presence_state
mocked_set.return_value = defer.succeed({"state": OFFLINE}) mocked_set.return_value = defer.succeed({"presence": OFFLINE})
yield self.handler.set_state( yield self.handler.set_state(
target_user=self.u_apple, auth_user=self.u_apple, target_user=self.u_apple, auth_user=self.u_apple,
state={"presence": UNAVAILABLE, "status_msg": "Away"}) state={"presence": UNAVAILABLE, "status_msg": "Away"})
mocked_set.assert_called_with("apple", mocked_set.assert_called_with("apple",
{"state": UNAVAILABLE, "status_msg": "Away"} {"presence": UNAVAILABLE,
"status_msg": "Away",
"last_active": 1000000, # MockClock
}
) )
self.mock_start.assert_called_with(self.u_apple, self.mock_start.assert_called_with(self.u_apple,
state={ state={
@@ -624,7 +627,7 @@ class PresencePushTestCase(unittest.TestCase):
self.room_members = [self.u_apple, self.u_elderberry] self.room_members = [self.u_apple, self.u_elderberry]
self.datastore.set_presence_state.return_value = defer.succeed( self.datastore.set_presence_state.return_value = defer.succeed(
{"state": ONLINE} {"presence": ONLINE}
) )
# TODO(paul): Gut-wrenching # TODO(paul): Gut-wrenching
@@ -793,7 +796,7 @@ class PresencePushTestCase(unittest.TestCase):
self.room_members = [self.u_apple, self.u_onion] self.room_members = [self.u_apple, self.u_onion]
self.datastore.set_presence_state.return_value = defer.succeed( self.datastore.set_presence_state.return_value = defer.succeed(
{"state": ONLINE} {"presence": ONLINE}
) )
# TODO(paul): Gut-wrenching # TODO(paul): Gut-wrenching
@@ -1043,16 +1046,16 @@ class PresencePollingTestCase(unittest.TestCase):
def get_presence_state(user_localpart): def get_presence_state(user_localpart):
return defer.succeed( return defer.succeed(
{"state": self.current_user_state[user_localpart], {"presence": self.current_user_state[user_localpart],
"status_msg": None, "status_msg": None,
"mtime": 123456000} "last_active": 500000}
) )
self.datastore.get_presence_state = get_presence_state self.datastore.get_presence_state = get_presence_state
def set_presence_state(user_localpart, new_state): def set_presence_state(user_localpart, new_state):
was = self.current_user_state[user_localpart] was = self.current_user_state[user_localpart]
self.current_user_state[user_localpart] = new_state["state"] self.current_user_state[user_localpart] = new_state["presence"]
return defer.succeed({"state": was}) return defer.succeed({"presence": was})
self.datastore.set_presence_state = set_presence_state self.datastore.set_presence_state = set_presence_state
def get_presence_list(user_localpart, accepted): def get_presence_list(user_localpart, accepted):
@@ -1249,7 +1252,8 @@ class PresencePollingTestCase(unittest.TestCase):
"push": [ "push": [
{"user_id": "@banana:test", {"user_id": "@banana:test",
"presence": "offline", "presence": "offline",
"status_msg": None}, "status_msg": None,
"last_active_ago": 500000},
], ],
}, },
), ),
+6 -4
View File
@@ -144,14 +144,16 @@ class PresenceProfilelikeDataTestCase(unittest.TestCase):
] ]
mocked_set = self.datastore.set_presence_state mocked_set = self.datastore.set_presence_state
mocked_set.return_value = defer.succeed({"state": OFFLINE}) mocked_set.return_value = defer.succeed({"presence": OFFLINE})
yield self.handlers.presence_handler.set_state( yield self.handlers.presence_handler.set_state(
target_user=self.u_apple, auth_user=self.u_apple, target_user=self.u_apple, auth_user=self.u_apple,
state={"presence": UNAVAILABLE, "status_msg": "Away"}) state={"presence": UNAVAILABLE, "status_msg": "Away"})
mocked_set.assert_called_with("apple", mocked_set.assert_called_with("apple",
{"state": UNAVAILABLE, "status_msg": "Away"} {"presence": UNAVAILABLE,
"status_msg": "Away",
"last_active": 1000000}
) )
@defer.inlineCallbacks @defer.inlineCallbacks
@@ -162,7 +164,7 @@ class PresenceProfilelikeDataTestCase(unittest.TestCase):
] ]
self.datastore.set_presence_state.return_value = defer.succeed( self.datastore.set_presence_state.return_value = defer.succeed(
{"state": ONLINE} {"presence": ONLINE}
) )
# TODO(paul): Gut-wrenching # TODO(paul): Gut-wrenching
@@ -244,7 +246,7 @@ class PresenceProfilelikeDataTestCase(unittest.TestCase):
] ]
self.datastore.set_presence_state.return_value = defer.succeed( self.datastore.set_presence_state.return_value = defer.succeed(
{"state": ONLINE} {"presence": ONLINE}
) )
# TODO(paul): Gut-wrenching # TODO(paul): Gut-wrenching
+9 -6
View File
@@ -21,7 +21,7 @@ from twisted.internet import defer
from mock import Mock from mock import Mock
import logging import logging
from ..utils import MockHttpResource from ..utils import MockHttpResource, MockClock
from synapse.api.constants import PresenceState from synapse.api.constants import PresenceState
from synapse.handlers.presence import PresenceHandler from synapse.handlers.presence import PresenceHandler
@@ -51,6 +51,7 @@ class PresenceStateTestCase(unittest.TestCase):
self.mock_resource = MockHttpResource(prefix=PATH_PREFIX) self.mock_resource = MockHttpResource(prefix=PATH_PREFIX)
hs = HomeServer("test", hs = HomeServer("test",
clock=MockClock(),
db_pool=None, db_pool=None,
datastore=Mock(spec=[ datastore=Mock(spec=[
"get_presence_state", "get_presence_state",
@@ -91,7 +92,7 @@ class PresenceStateTestCase(unittest.TestCase):
def test_get_my_status(self): def test_get_my_status(self):
mocked_get = self.datastore.get_presence_state mocked_get = self.datastore.get_presence_state
mocked_get.return_value = defer.succeed( mocked_get.return_value = defer.succeed(
{"state": ONLINE, "status_msg": "Available"} {"presence": ONLINE, "status_msg": "Available"}
) )
(code, response) = yield self.mock_resource.trigger("GET", (code, response) = yield self.mock_resource.trigger("GET",
@@ -107,7 +108,7 @@ class PresenceStateTestCase(unittest.TestCase):
@defer.inlineCallbacks @defer.inlineCallbacks
def test_set_my_status(self): def test_set_my_status(self):
mocked_set = self.datastore.set_presence_state mocked_set = self.datastore.set_presence_state
mocked_set.return_value = defer.succeed({"state": OFFLINE}) mocked_set.return_value = defer.succeed({"presence": OFFLINE})
(code, response) = yield self.mock_resource.trigger("PUT", (code, response) = yield self.mock_resource.trigger("PUT",
"/presence/%s/status" % (myid), "/presence/%s/status" % (myid),
@@ -115,7 +116,9 @@ class PresenceStateTestCase(unittest.TestCase):
self.assertEquals(200, code) self.assertEquals(200, code)
mocked_set.assert_called_with("apple", mocked_set.assert_called_with("apple",
{"state": UNAVAILABLE, "status_msg": "Away"} {"presence": UNAVAILABLE,
"status_msg": "Away",
"last_active": 1000000}
) )
@@ -312,7 +315,7 @@ class PresenceEventStreamTestCase(unittest.TestCase):
self.room_members = [self.u_apple, self.u_banana] self.room_members = [self.u_apple, self.u_banana]
self.mock_datastore.set_presence_state.return_value = defer.succeed( self.mock_datastore.set_presence_state.return_value = defer.succeed(
{"state": ONLINE} {"presence": ONLINE}
) )
self.mock_datastore.get_presence_list.return_value = defer.succeed( self.mock_datastore.get_presence_list.return_value = defer.succeed(
[] []
@@ -332,7 +335,7 @@ class PresenceEventStreamTestCase(unittest.TestCase):
) )
self.mock_datastore.set_presence_state.return_value = defer.succeed( self.mock_datastore.set_presence_state.return_value = defer.succeed(
{"state": ONLINE} {"presence": ONLINE}
) )
self.mock_datastore.get_presence_list.return_value = defer.succeed( self.mock_datastore.get_presence_list.return_value = defer.succeed(
[] []