diff options
author | Mark Haines <mark.haines@matrix.org> | 2014-09-01 16:31:09 +0100 |
---|---|---|
committer | Mark Haines <mark.haines@matrix.org> | 2014-09-01 16:31:09 +0100 |
commit | 46dcb0d8902c531e3b187453435913fc6e2344a9 (patch) | |
tree | 1bfb42952b976731888fb06a49e253d1037fa827 | |
parent | Listen using SSL (diff) | |
parent | missing semicolon (diff) | |
download | synapse-46dcb0d8902c531e3b187453435913fc6e2344a9.tar.xz |
Merge branch 'develop' into server2server_tls
-rw-r--r-- | docs/specification.rst | 109 | ||||
-rw-r--r-- | synapse/handlers/message.py | 8 | ||||
-rw-r--r-- | synapse/handlers/presence.py | 6 | ||||
-rw-r--r-- | tests/rest/test_rooms.py | 12 | ||||
-rw-r--r-- | tests/utils.py | 5 | ||||
-rw-r--r-- | webclient/index.html | 2 | ||||
-rw-r--r-- | webclient/recents/recents-controller.js | 5 | ||||
-rw-r--r-- | webclient/recents/recents.html | 4 |
8 files changed, 126 insertions, 25 deletions
diff --git a/docs/specification.rst b/docs/specification.rst index d47705ca0f..9a494a4c0f 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -391,22 +391,101 @@ If all members in a room leave, that room becomes eligible for deletion. Events in a room ---------------- -- Split into state and non-state data -- Explain what they are, semantics, give examples of clobbering / not, use cases (msgs vs room names). - Not too much detail on the actual event contents. -- API to hit. -- Extensibility provided by the API for custom events. Examples. -- How this hooks into ``initialSync``. -- See the "Room Events" section for actual spec on each type. - -Syncing a room --------------- -- Single room initial sync. ``rooms/<room id>/initialSync`` API to hit. Why it might be used (lazy loading) +Room events can be split into two categories: + +:State Events: + These are events which replace events that came before it, depending on a set of unique keys. + These keys are the event ``type`` and a ``state_key``. Events with the same set of keys will + be overwritten. Typically, state events are used to store state, hence their name. + +:Non-state events: + These are events which cannot be overwritten after sending. The list of events continues + to grow as more events are sent. As this list grows, it becomes necessary to + provide a mechanism for navigating this list. Pagination APIs are used to view the list + of historical non-state events. Typically, non-state events are used to send messages. + +This specification outlines several events, all with the event type prefix ``m.``. However, +applications may wish to add their own type of event, and this can be achieved using the +REST API detailed in the following sections. If new events are added, the event ``type`` +key SHOULD follow the Java package naming convention, e.g. ``com.example.myapp.event``. +This ensures event types are suitably namespaced for each application and reduces the +risk of clashes. + +State events +------------ +State events can be sent by ``PUT`` ing to ``/rooms/<room id>/state/<event type>/<state key>``. +These events will be overwritten if ``<room id>``, ``<event type>`` and ``<state key>`` all match. +If the state event has no ``state_key``, it can be omitted from the path. These requests +**cannot use transaction IDs** like other ``PUT`` paths because they cannot be differentiated +from the ``state key``. Furthermore, ``POST`` is unsupported on state paths. Valid requests +look like:: + + PUT /rooms/!roomid:domain/state/m.example.event + { "key" : "without a state key" } + + PUT /rooms/!roomid:domain/state/m.another.example.event/foo + { "key" : "with 'foo' as the state key" } + +In contrast, these requests are invalid:: + + POST /rooms/!roomid:domain/state/m.example.event/ + { "key" : "cannot use POST here" } + + PUT /rooms/!roomid:domain/state/m.another.example.event/foo/11 + { "key" : "txnIds are not supported" } + +Care should be taken to avoid setting the wrong ``state key``:: + + PUT /rooms/!roomid:domain/state/m.another.example.event/11 + { "key" : "with '11' as the state key, but was probably intended to be a txnId" } + +The ``state_key`` is often used to store state about individual users, by using the user ID as the +value. For example:: + + PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Adomain.com + { "animal" : "cat", "reason": "fluffy" } + +In some cases, there may be no need for a ``state_key``, so it can be omitted:: + + PUT /rooms/!roomid:domain/state/m.room.bgd.color + { "color": "red", "hex": "#ff0000" } + +See "Room Events" for the ``m.`` event specification. + +Non-state events +---------------- +Non-state events can be sent by sending a request to ``/rooms/<room id>/send/<event type>``. +These requests *can* use transaction IDs and ``PUT``/``POST`` methods. Non-state events +allow access to historical events and pagination, making it best suited for sending messages. +For example:: + + POST /rooms/!roomid:domain/send/m.custom.example.message + { "text": "Hello world!" } + + PUT /rooms/!roomid:domain/send/m.custom.example.message/11 + { "text": "Goodbye world!" } + +See "Room Events" for the ``m.`` event specification. + +Syncing rooms +------------- +When a client logs in, they may have a list of rooms which they have already joined. These rooms +may also have a list of events associated with them. The purpose of 'syncing' is to present the +current room and event information in a convenient, compact manner. There are two APIs provided: + + - ``/initialSync`` : A global sync which will present room and event information for all rooms + the user has joined. + + - ``/rooms/<room id>/initialSync`` : A sync scoped to a single room. Presents room and event + information for this room only. + +- TODO: JSON response format for both types +- TODO: when would you use global? when would you use scoped? -Getting grouped state events ----------------------------- -- ``/members`` and ``/messages`` and the events they return. -- ``/state`` and it returns ALL THE THINGS. +Getting grouped state events for a room +--------------------------------------- +- ``/members`` and ``/messages`` and the event types they return. Spec JSON response format. +- ``/state`` and it returns ALL THE THINGS. Room Events =========== diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py index c8ff34e5f5..4c74ce3eff 100644 --- a/synapse/handlers/message.py +++ b/synapse/handlers/message.py @@ -76,6 +76,10 @@ class MessageHandler(BaseRoomHandler): Raises: SynapseError if something went wrong. """ + # TODO(paul): Why does 'event' not have a 'user' object? + user = self.hs.parse_userid(event.user_id) + assert(user.is_mine) + if stamp_event: event.content["hsob_ts"] = int(self.clock.time_msec()) @@ -86,6 +90,10 @@ class MessageHandler(BaseRoomHandler): yield self._on_new_room_event(event, snapshot) + self.hs.get_handlers().presence_handler.bump_presence_active_time( + user + ) + @defer.inlineCallbacks def get_messages(self, user_id=None, room_id=None, pagin_config=None, feedback=False): diff --git a/synapse/handlers/presence.py b/synapse/handlers/presence.py index c1af07133f..f55bea58a5 100644 --- a/synapse/handlers/presence.py +++ b/synapse/handlers/presence.py @@ -266,6 +266,12 @@ class PresenceHandler(BaseHandler): # we don't have to do this all the time self.changed_presencelike_data(target_user, state) + def bump_presence_active_time(self, user, now=None): + if now is None: + now = self.clock.time_msec() + + self.changed_presencelike_data(user, {"last_active": now}) + def changed_presencelike_data(self, user, state): statuscache = self._get_or_make_usercache(user) diff --git a/tests/rest/test_rooms.py b/tests/rest/test_rooms.py index b432cf254e..cdaf948a3b 100644 --- a/tests/rest/test_rooms.py +++ b/tests/rest/test_rooms.py @@ -51,7 +51,7 @@ class RoomPermissionsTestCase(RestTestCase): persistence_service.get_latest_pdus_in_context.return_value = [] hs = HomeServer( - "test", + "red", db_pool=None, http_client=None, datastore=MemoryDataStore(), @@ -398,7 +398,7 @@ class RoomsMemberListTestCase(RestTestCase): persistence_service.get_latest_pdus_in_context.return_value = [] hs = HomeServer( - "test", + "red", db_pool=None, http_client=None, datastore=MemoryDataStore(), @@ -476,7 +476,7 @@ class RoomsCreateTestCase(RestTestCase): persistence_service.get_latest_pdus_in_context.return_value = [] hs = HomeServer( - "test", + "red", db_pool=None, http_client=None, datastore=MemoryDataStore(), @@ -566,7 +566,7 @@ class RoomTopicTestCase(RestTestCase): persistence_service.get_latest_pdus_in_context.return_value = [] hs = HomeServer( - "test", + "red", db_pool=None, http_client=None, datastore=MemoryDataStore(), @@ -669,7 +669,7 @@ class RoomMemberStateTestCase(RestTestCase): persistence_service.get_latest_pdus_in_context.return_value = [] hs = HomeServer( - "test", + "red", db_pool=None, http_client=None, datastore=MemoryDataStore(), @@ -794,7 +794,7 @@ class RoomMessagesTestCase(RestTestCase): persistence_service.get_latest_pdus_in_context.return_value = [] hs = HomeServer( - "test", + "red", db_pool=None, http_client=None, datastore=MemoryDataStore(), diff --git a/tests/utils.py b/tests/utils.py index 37b759febc..ea7d6893c6 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -188,8 +188,9 @@ class MemoryDataStore(object): def get_rooms_for_user_where_membership_is(self, user_id, membership_list): return [ - r for r in self.members - if self.members[r].get(user_id).membership in membership_list + self.members[r].get(user_id) for r in self.members + if user_id in self.members[r] and + self.members[r][user_id].membership in membership_list ] def get_room_events_stream(self, user_id=None, from_key=None, to_key=None, diff --git a/webclient/index.html b/webclient/index.html index 3c31a8a051..bf24e392ac 100644 --- a/webclient/index.html +++ b/webclient/index.html @@ -56,7 +56,7 @@ <div id="footer" ng-hide="location.indexOf('/room') == 0"> <div id="footerContent"> - © 2014 Matrix.org + © 2014 Matrix.org </div> </div> </body> diff --git a/webclient/recents/recents-controller.js b/webclient/recents/recents-controller.js index d33d41a922..c9fd022d7f 100644 --- a/webclient/recents/recents-controller.js +++ b/webclient/recents/recents-controller.js @@ -43,6 +43,11 @@ angular.module('RecentsController', ['matrixService', 'eventHandlerService']) $scope.rooms[event.room_id].lastMsg = event; } }); + $scope.$on(eventHandlerService.CALL_EVENT, function(ngEvent, event, isLive) { + if (isLive) { + $scope.rooms[event.room_id].lastMsg = event; + } + }); }; diff --git a/webclient/recents/recents.html b/webclient/recents/recents.html index 3f025a98d8..56fb38b02a 100644 --- a/webclient/recents/recents.html +++ b/webclient/recents/recents.html @@ -51,7 +51,9 @@ </div> <div ng-switch-default> - {{ room.lastMsg }} + <div ng-if="room.lastMsg.type.indexOf('m.call.') == 0"> + Call + </div> </div> </div> </td> |