mirror of
https://mau.dev/maunium/synapse.git
synced 2024-09-07 10:25:40 +02:00
Merge branch 'develop' into server2server_tls
This commit is contained in:
commit
46dcb0d890
8 changed files with 125 additions and 24 deletions
|
@ -391,22 +391,101 @@ If all members in a room leave, that room becomes eligible for deletion.
|
||||||
|
|
||||||
Events in a room
|
Events in a room
|
||||||
----------------
|
----------------
|
||||||
- Split into state and non-state data
|
Room events can be split into two categories:
|
||||||
- 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
|
:State Events:
|
||||||
--------------
|
These are events which replace events that came before it, depending on a set of unique keys.
|
||||||
- Single room initial sync. ``rooms/<room id>/initialSync`` API to hit. Why it might be used (lazy loading)
|
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.
|
||||||
|
|
||||||
Getting grouped state events
|
:Non-state events:
|
||||||
----------------------------
|
These are events which cannot be overwritten after sending. The list of events continues
|
||||||
- ``/members`` and ``/messages`` and the events they return.
|
to grow as more events are sent. As this list grows, it becomes necessary to
|
||||||
- ``/state`` and it returns ALL THE THINGS.
|
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 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
|
Room Events
|
||||||
===========
|
===========
|
||||||
|
|
|
@ -76,6 +76,10 @@ class MessageHandler(BaseRoomHandler):
|
||||||
Raises:
|
Raises:
|
||||||
SynapseError if something went wrong.
|
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:
|
if stamp_event:
|
||||||
event.content["hsob_ts"] = int(self.clock.time_msec())
|
event.content["hsob_ts"] = int(self.clock.time_msec())
|
||||||
|
|
||||||
|
@ -86,6 +90,10 @@ class MessageHandler(BaseRoomHandler):
|
||||||
|
|
||||||
yield self._on_new_room_event(event, snapshot)
|
yield self._on_new_room_event(event, snapshot)
|
||||||
|
|
||||||
|
self.hs.get_handlers().presence_handler.bump_presence_active_time(
|
||||||
|
user
|
||||||
|
)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def get_messages(self, user_id=None, room_id=None, pagin_config=None,
|
def get_messages(self, user_id=None, room_id=None, pagin_config=None,
|
||||||
feedback=False):
|
feedback=False):
|
||||||
|
|
|
@ -266,6 +266,12 @@ class PresenceHandler(BaseHandler):
|
||||||
# we don't have to do this all the time
|
# we don't have to do this all the time
|
||||||
self.changed_presencelike_data(target_user, state)
|
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):
|
def changed_presencelike_data(self, user, state):
|
||||||
statuscache = self._get_or_make_usercache(user)
|
statuscache = self._get_or_make_usercache(user)
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ class RoomPermissionsTestCase(RestTestCase):
|
||||||
persistence_service.get_latest_pdus_in_context.return_value = []
|
persistence_service.get_latest_pdus_in_context.return_value = []
|
||||||
|
|
||||||
hs = HomeServer(
|
hs = HomeServer(
|
||||||
"test",
|
"red",
|
||||||
db_pool=None,
|
db_pool=None,
|
||||||
http_client=None,
|
http_client=None,
|
||||||
datastore=MemoryDataStore(),
|
datastore=MemoryDataStore(),
|
||||||
|
@ -398,7 +398,7 @@ class RoomsMemberListTestCase(RestTestCase):
|
||||||
persistence_service.get_latest_pdus_in_context.return_value = []
|
persistence_service.get_latest_pdus_in_context.return_value = []
|
||||||
|
|
||||||
hs = HomeServer(
|
hs = HomeServer(
|
||||||
"test",
|
"red",
|
||||||
db_pool=None,
|
db_pool=None,
|
||||||
http_client=None,
|
http_client=None,
|
||||||
datastore=MemoryDataStore(),
|
datastore=MemoryDataStore(),
|
||||||
|
@ -476,7 +476,7 @@ class RoomsCreateTestCase(RestTestCase):
|
||||||
persistence_service.get_latest_pdus_in_context.return_value = []
|
persistence_service.get_latest_pdus_in_context.return_value = []
|
||||||
|
|
||||||
hs = HomeServer(
|
hs = HomeServer(
|
||||||
"test",
|
"red",
|
||||||
db_pool=None,
|
db_pool=None,
|
||||||
http_client=None,
|
http_client=None,
|
||||||
datastore=MemoryDataStore(),
|
datastore=MemoryDataStore(),
|
||||||
|
@ -566,7 +566,7 @@ class RoomTopicTestCase(RestTestCase):
|
||||||
persistence_service.get_latest_pdus_in_context.return_value = []
|
persistence_service.get_latest_pdus_in_context.return_value = []
|
||||||
|
|
||||||
hs = HomeServer(
|
hs = HomeServer(
|
||||||
"test",
|
"red",
|
||||||
db_pool=None,
|
db_pool=None,
|
||||||
http_client=None,
|
http_client=None,
|
||||||
datastore=MemoryDataStore(),
|
datastore=MemoryDataStore(),
|
||||||
|
@ -669,7 +669,7 @@ class RoomMemberStateTestCase(RestTestCase):
|
||||||
persistence_service.get_latest_pdus_in_context.return_value = []
|
persistence_service.get_latest_pdus_in_context.return_value = []
|
||||||
|
|
||||||
hs = HomeServer(
|
hs = HomeServer(
|
||||||
"test",
|
"red",
|
||||||
db_pool=None,
|
db_pool=None,
|
||||||
http_client=None,
|
http_client=None,
|
||||||
datastore=MemoryDataStore(),
|
datastore=MemoryDataStore(),
|
||||||
|
@ -794,7 +794,7 @@ class RoomMessagesTestCase(RestTestCase):
|
||||||
persistence_service.get_latest_pdus_in_context.return_value = []
|
persistence_service.get_latest_pdus_in_context.return_value = []
|
||||||
|
|
||||||
hs = HomeServer(
|
hs = HomeServer(
|
||||||
"test",
|
"red",
|
||||||
db_pool=None,
|
db_pool=None,
|
||||||
http_client=None,
|
http_client=None,
|
||||||
datastore=MemoryDataStore(),
|
datastore=MemoryDataStore(),
|
||||||
|
|
|
@ -188,8 +188,9 @@ class MemoryDataStore(object):
|
||||||
|
|
||||||
def get_rooms_for_user_where_membership_is(self, user_id, membership_list):
|
def get_rooms_for_user_where_membership_is(self, user_id, membership_list):
|
||||||
return [
|
return [
|
||||||
r for r in self.members
|
self.members[r].get(user_id) for r in self.members
|
||||||
if self.members[r].get(user_id).membership in membership_list
|
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,
|
def get_room_events_stream(self, user_id=None, from_key=None, to_key=None,
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
|
|
||||||
<div id="footer" ng-hide="location.indexOf('/room') == 0">
|
<div id="footer" ng-hide="location.indexOf('/room') == 0">
|
||||||
<div id="footerContent">
|
<div id="footerContent">
|
||||||
© 2014 Matrix.org
|
© 2014 Matrix.org
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -43,6 +43,11 @@ angular.module('RecentsController', ['matrixService', 'eventHandlerService'])
|
||||||
$scope.rooms[event.room_id].lastMsg = event;
|
$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;
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-switch-default>
|
<div ng-switch-default>
|
||||||
{{ room.lastMsg }}
|
<div ng-if="room.lastMsg.type.indexOf('m.call.') == 0">
|
||||||
|
Call
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
Loading…
Reference in a new issue