async_client/event_emitter: add tests for invited and left rooms
parent
0e538a7c67
commit
7c7aaee22e
|
@ -621,6 +621,7 @@ impl AsyncClient {
|
||||||
///
|
///
|
||||||
/// * `sync_settings` - Settings for the sync call.
|
/// * `sync_settings` - Settings for the sync call.
|
||||||
#[instrument]
|
#[instrument]
|
||||||
|
#[allow(clippy::useless_let_if_seq)]
|
||||||
pub async fn sync(&self, mut sync_settings: SyncSettings) -> Result<sync_events::Response> {
|
pub async fn sync(&self, mut sync_settings: SyncSettings) -> Result<sync_events::Response> {
|
||||||
{
|
{
|
||||||
// if the client has been synced from the state store don't sync again
|
// if the client has been synced from the state store don't sync again
|
||||||
|
@ -647,9 +648,11 @@ impl AsyncClient {
|
||||||
|
|
||||||
// when events change state updated signals to state store to update database
|
// when events change state updated signals to state store to update database
|
||||||
let mut updated = self.iter_joined_rooms(&mut response).await?;
|
let mut updated = self.iter_joined_rooms(&mut response).await?;
|
||||||
if self.iter_invited_rooms(&mut response).await? {
|
|
||||||
|
if self.iter_invited_rooms(&response).await? {
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.iter_left_rooms(&mut response).await? {
|
if self.iter_left_rooms(&mut response).await? {
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
|
@ -660,6 +663,7 @@ impl AsyncClient {
|
||||||
Ok(response)
|
Ok(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
async fn iter_joined_rooms(&self, response: &mut sync_events::Response) -> Result<bool> {
|
async fn iter_joined_rooms(&self, response: &mut sync_events::Response) -> Result<bool> {
|
||||||
let mut updated = false;
|
let mut updated = false;
|
||||||
for (room_id, room) in &mut response.rooms.join {
|
for (room_id, room) in &mut response.rooms.join {
|
||||||
|
@ -764,35 +768,32 @@ impl AsyncClient {
|
||||||
Ok(updated)
|
Ok(updated)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
async fn iter_left_rooms(&self, response: &mut sync_events::Response) -> Result<bool> {
|
async fn iter_left_rooms(&self, response: &mut sync_events::Response) -> Result<bool> {
|
||||||
let mut updated = false;
|
let mut updated = false;
|
||||||
for (room_id, left_room) in &mut response.rooms.leave {
|
for (room_id, left_room) in &mut response.rooms.leave {
|
||||||
let matrix_room = {
|
for mut event in &mut left_room.timeline.events {
|
||||||
let mut client = self.base_client.write().await;
|
let decrypted_event = {
|
||||||
for mut event in &mut left_room.timeline.events {
|
let mut client = self.base_client.write().await;
|
||||||
let decrypted_event = {
|
|
||||||
let mut client = self.base_client.write().await;
|
let (decrypt_ev, timeline_update) = client
|
||||||
let (decrypt_ev, timeline_update) = client
|
.receive_joined_timeline_event(room_id, &mut event)
|
||||||
.receive_joined_timeline_event(room_id, &mut event)
|
.await;
|
||||||
.await;
|
if timeline_update {
|
||||||
if timeline_update {
|
updated = true;
|
||||||
updated = true;
|
|
||||||
};
|
|
||||||
decrypt_ev
|
|
||||||
};
|
};
|
||||||
|
decrypt_ev
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(e) = decrypted_event {
|
if let Some(e) = decrypted_event {
|
||||||
*event = e;
|
*event = e;
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(e) = event.deserialize() {
|
|
||||||
let client = self.base_client.read().await;
|
|
||||||
client.emit_timeline_event(&room_id, &e).await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client.get_or_create_room(&room_id).clone()
|
if let Ok(e) = event.deserialize() {
|
||||||
};
|
let client = self.base_client.read().await;
|
||||||
|
client.emit_timeline_event(&room_id, &e).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// re looping is not ideal here
|
// re looping is not ideal here
|
||||||
for event in &mut left_room.state.events {
|
for event in &mut left_room.state.events {
|
||||||
|
@ -804,19 +805,19 @@ impl AsyncClient {
|
||||||
|
|
||||||
if updated {
|
if updated {
|
||||||
if let Some(store) = self.base_client.read().await.state_store.as_ref() {
|
if let Some(store) = self.base_client.read().await.state_store.as_ref() {
|
||||||
store
|
let mut client = self.base_client.write().await;
|
||||||
.store_room_state(matrix_room.read().await.deref())
|
let room = client.get_or_create_room(&room_id).clone();
|
||||||
.await?;
|
store.store_room_state(room.read().await.deref()).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(updated)
|
Ok(updated)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn iter_invited_rooms(&self, response: &mut sync_events::Response) -> Result<bool> {
|
#[inline]
|
||||||
|
async fn iter_invited_rooms(&self, response: &sync_events::Response) -> Result<bool> {
|
||||||
let mut updated = false;
|
let mut updated = false;
|
||||||
// INVITED ROOMS
|
for (room_id, invited_room) in &response.rooms.invite {
|
||||||
for (room_id, invited_room) in &mut response.rooms.invite {
|
|
||||||
let matrix_room = {
|
let matrix_room = {
|
||||||
let mut client = self.base_client.write().await;
|
let mut client = self.base_client.write().await;
|
||||||
for event in &invited_room.invite_state.events {
|
for event in &invited_room.invite_state.events {
|
||||||
|
@ -831,7 +832,7 @@ impl AsyncClient {
|
||||||
};
|
};
|
||||||
|
|
||||||
// re looping is not ideal here
|
// re looping is not ideal here
|
||||||
for event in &mut invited_room.invite_state.events {
|
for event in &invited_room.invite_state.events {
|
||||||
if let Ok(e) = event.deserialize() {
|
if let Ok(e) = event.deserialize() {
|
||||||
let client = self.base_client.read().await;
|
let client = self.base_client.read().await;
|
||||||
client.emit_stripped_state_event(&room_id, &e).await;
|
client.emit_stripped_state_event(&room_id, &e).await;
|
||||||
|
|
|
@ -129,29 +129,29 @@ pub trait EventEmitter: Send + Sync {
|
||||||
async fn on_state_join_rules(&self, _: Arc<RwLock<Room>>, _: &JoinRulesEvent) {}
|
async fn on_state_join_rules(&self, _: Arc<RwLock<Room>>, _: &JoinRulesEvent) {}
|
||||||
|
|
||||||
// `AnyStrippedStateEvent`s
|
// `AnyStrippedStateEvent`s
|
||||||
/// Fires when `AsyncClient` receives a `StateEvent::RoomMember` event.
|
/// Fires when `AsyncClient` receives a `AnyStrippedStateEvent::StrippedRoomMember` event.
|
||||||
async fn on_stripped_state_member(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomMember) {}
|
async fn on_stripped_state_member(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomMember) {}
|
||||||
/// Fires when `AsyncClient` receives a `StateEvent::RoomName` event.
|
/// Fires when `AsyncClient` receives a `AnyStrippedStateEvent::StrippedRoomName` event.
|
||||||
async fn on_stripped_state_name(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomName) {}
|
async fn on_stripped_state_name(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomName) {}
|
||||||
/// Fires when `AsyncClient` receives a `StateEvent::RoomCanonicalAlias` event.
|
/// Fires when `AsyncClient` receives a `AnyStrippedStateEvent::StrippedRoomCanonicalAlias` event.
|
||||||
async fn on_stripped_state_canonical_alias(
|
async fn on_stripped_state_canonical_alias(
|
||||||
&self,
|
&self,
|
||||||
_: Arc<RwLock<Room>>,
|
_: Arc<RwLock<Room>>,
|
||||||
_: &StrippedRoomCanonicalAlias,
|
_: &StrippedRoomCanonicalAlias,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
/// Fires when `AsyncClient` receives a `StateEvent::RoomAliases` event.
|
/// Fires when `AsyncClient` receives a `AnyStrippedStateEvent::StrippedRoomAliases` event.
|
||||||
async fn on_stripped_state_aliases(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomAliases) {}
|
async fn on_stripped_state_aliases(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomAliases) {}
|
||||||
/// Fires when `AsyncClient` receives a `StateEvent::RoomAvatar` event.
|
/// Fires when `AsyncClient` receives a `AnyStrippedStateEvent::StrippedRoomAvatar` event.
|
||||||
async fn on_stripped_state_avatar(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomAvatar) {}
|
async fn on_stripped_state_avatar(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomAvatar) {}
|
||||||
/// Fires when `AsyncClient` receives a `StateEvent::RoomPowerLevels` event.
|
/// Fires when `AsyncClient` receives a `AnyStrippedStateEvent::StrippedRoomPowerLevels` event.
|
||||||
async fn on_stripped_state_power_levels(
|
async fn on_stripped_state_power_levels(
|
||||||
&self,
|
&self,
|
||||||
_: Arc<RwLock<Room>>,
|
_: Arc<RwLock<Room>>,
|
||||||
_: &StrippedRoomPowerLevels,
|
_: &StrippedRoomPowerLevels,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
/// Fires when `AsyncClient` receives a `StateEvent::RoomJoinRules` event.
|
/// Fires when `AsyncClient` receives a `AnyStrippedStateEvent::StrippedRoomJoinRules` event.
|
||||||
async fn on_stripped_state_join_rules(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomJoinRules) {}
|
async fn on_stripped_state_join_rules(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomJoinRules) {}
|
||||||
|
|
||||||
// `NonRoomEvent` (this is a type alias from ruma_events) from `IncomingAccountData`
|
// `NonRoomEvent` (this is a type alias from ruma_events) from `IncomingAccountData`
|
||||||
|
@ -232,6 +232,52 @@ mod test {
|
||||||
self.0.lock().await.push("state rules".to_string())
|
self.0.lock().await.push("state rules".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn on_stripped_state_member(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomMember) {
|
||||||
|
self.0
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.push("stripped state member".to_string())
|
||||||
|
}
|
||||||
|
async fn on_stripped_state_name(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomName) {
|
||||||
|
self.0.lock().await.push("stripped state name".to_string())
|
||||||
|
}
|
||||||
|
async fn on_stripped_state_canonical_alias(
|
||||||
|
&self,
|
||||||
|
_: Arc<RwLock<Room>>,
|
||||||
|
_: &StrippedRoomCanonicalAlias,
|
||||||
|
) {
|
||||||
|
self.0
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.push("stripped state canonical".to_string())
|
||||||
|
}
|
||||||
|
async fn on_stripped_state_aliases(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomAliases) {
|
||||||
|
self.0
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.push("stripped state aliases".to_string())
|
||||||
|
}
|
||||||
|
async fn on_stripped_state_avatar(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomAvatar) {
|
||||||
|
self.0
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.push("stripped state avatar".to_string())
|
||||||
|
}
|
||||||
|
async fn on_stripped_state_power_levels(
|
||||||
|
&self,
|
||||||
|
_: Arc<RwLock<Room>>,
|
||||||
|
_: &StrippedRoomPowerLevels,
|
||||||
|
) {
|
||||||
|
self.0.lock().await.push("stripped state power".to_string())
|
||||||
|
}
|
||||||
|
async fn on_stripped_state_join_rules(
|
||||||
|
&self,
|
||||||
|
_: Arc<RwLock<Room>>,
|
||||||
|
_: &StrippedRoomJoinRules,
|
||||||
|
) {
|
||||||
|
self.0.lock().await.push("stripped state rules".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
async fn on_account_presence(&self, _: Arc<RwLock<Room>>, _: &PresenceEvent) {
|
async fn on_account_presence(&self, _: Arc<RwLock<Room>>, _: &PresenceEvent) {
|
||||||
self.0.lock().await.push("account presence".to_string())
|
self.0.lock().await.push("account presence".to_string())
|
||||||
}
|
}
|
||||||
|
@ -260,7 +306,7 @@ mod test {
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn event_emitter() {
|
async fn event_emitter_sync() {
|
||||||
let homeserver = Url::from_str(&mockito::server_url()).unwrap();
|
let homeserver = Url::from_str(&mockito::server_url()).unwrap();
|
||||||
|
|
||||||
let session = Session {
|
let session = Session {
|
||||||
|
@ -279,7 +325,7 @@ mod test {
|
||||||
|
|
||||||
let vec = Arc::new(Mutex::new(Vec::new()));
|
let vec = Arc::new(Mutex::new(Vec::new()));
|
||||||
let test_vec = Arc::clone(&vec);
|
let test_vec = Arc::clone(&vec);
|
||||||
let emitter = Box::new(EvEmitterTest(vec)) as Box<(dyn EventEmitter)>;
|
let emitter = Box::new(EvEmitterTest(vec));
|
||||||
let mut client = AsyncClient::new(homeserver, Some(session)).unwrap();
|
let mut client = AsyncClient::new(homeserver, Some(session)).unwrap();
|
||||||
client.add_event_emitter(emitter).await;
|
client.add_event_emitter(emitter).await;
|
||||||
|
|
||||||
|
@ -304,4 +350,81 @@ mod test {
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn event_emitter_invite() {
|
||||||
|
let homeserver = Url::from_str(&mockito::server_url()).unwrap();
|
||||||
|
|
||||||
|
let session = Session {
|
||||||
|
access_token: "1234".to_owned(),
|
||||||
|
user_id: UserId::try_from("@example:example.com").unwrap(),
|
||||||
|
device_id: "DEVICEID".to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _m = mock(
|
||||||
|
"GET",
|
||||||
|
Matcher::Regex(r"^/_matrix/client/r0/sync\?.*$".to_string()),
|
||||||
|
)
|
||||||
|
.with_status(200)
|
||||||
|
.with_body_from_file("../test_data/invite_sync.json")
|
||||||
|
.create();
|
||||||
|
|
||||||
|
let vec = Arc::new(Mutex::new(Vec::new()));
|
||||||
|
let test_vec = Arc::clone(&vec);
|
||||||
|
let emitter = Box::new(EvEmitterTest(vec));
|
||||||
|
let mut client = AsyncClient::new(homeserver, Some(session)).unwrap();
|
||||||
|
client.add_event_emitter(emitter).await;
|
||||||
|
|
||||||
|
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||||
|
let _response = client.sync(sync_settings).await.unwrap();
|
||||||
|
|
||||||
|
let v = test_vec.lock().await;
|
||||||
|
assert_eq!(
|
||||||
|
v.as_slice(),
|
||||||
|
["stripped state name", "stripped state member"],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn event_emitter_leave() {
|
||||||
|
let homeserver = Url::from_str(&mockito::server_url()).unwrap();
|
||||||
|
|
||||||
|
let session = Session {
|
||||||
|
access_token: "1234".to_owned(),
|
||||||
|
user_id: UserId::try_from("@example:example.com").unwrap(),
|
||||||
|
device_id: "DEVICEID".to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _m = mock(
|
||||||
|
"GET",
|
||||||
|
Matcher::Regex(r"^/_matrix/client/r0/sync\?.*$".to_string()),
|
||||||
|
)
|
||||||
|
.with_status(200)
|
||||||
|
.with_body_from_file("../test_data/leave_sync.json")
|
||||||
|
.create();
|
||||||
|
|
||||||
|
let vec = Arc::new(Mutex::new(Vec::new()));
|
||||||
|
let test_vec = Arc::clone(&vec);
|
||||||
|
let emitter = Box::new(EvEmitterTest(vec));
|
||||||
|
let mut client = AsyncClient::new(homeserver, Some(session)).unwrap();
|
||||||
|
client.add_event_emitter(emitter).await;
|
||||||
|
|
||||||
|
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||||
|
let _response = client.sync(sync_settings).await.unwrap();
|
||||||
|
|
||||||
|
let v = test_vec.lock().await;
|
||||||
|
assert_eq!(
|
||||||
|
v.as_slice(),
|
||||||
|
[
|
||||||
|
"message",
|
||||||
|
"state rules",
|
||||||
|
"state member",
|
||||||
|
"state aliases",
|
||||||
|
"state power",
|
||||||
|
"state canonical",
|
||||||
|
"state member",
|
||||||
|
"state member"
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
{
|
||||||
|
"device_one_time_keys_count": {},
|
||||||
|
"next_batch": "s526_47314_0_7_1_1_1_11444_1",
|
||||||
|
"device_lists": {
|
||||||
|
"changed": [
|
||||||
|
"@example:example.org"
|
||||||
|
],
|
||||||
|
"left": []
|
||||||
|
},
|
||||||
|
"rooms": {
|
||||||
|
"invite": {
|
||||||
|
"!696r7674:example.com": {
|
||||||
|
"invite_state": {
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"sender": "@alice:example.com",
|
||||||
|
"type": "m.room.name",
|
||||||
|
"state_key": "",
|
||||||
|
"content": {
|
||||||
|
"name": "My Room Name"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sender": "@alice:example.com",
|
||||||
|
"type": "m.room.member",
|
||||||
|
"state_key": "@bob:example.com",
|
||||||
|
"content": {
|
||||||
|
"membership": "invite"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"join": {},
|
||||||
|
"leave": {}
|
||||||
|
},
|
||||||
|
"to_device": {
|
||||||
|
"events": []
|
||||||
|
},
|
||||||
|
"presence": {
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"avatar_url": "mxc://localhost:wefuiwegh8742w",
|
||||||
|
"currently_active": false,
|
||||||
|
"last_active_ago": 1,
|
||||||
|
"presence": "online",
|
||||||
|
"status_msg": "Making cupcakes"
|
||||||
|
},
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"type": "m.presence"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,277 @@
|
||||||
|
{
|
||||||
|
"device_one_time_keys_count": {},
|
||||||
|
"next_batch": "s526_47314_0_7_1_1_1_11444_1",
|
||||||
|
"device_lists": {
|
||||||
|
"changed": [
|
||||||
|
"@example:example.org"
|
||||||
|
],
|
||||||
|
"left": []
|
||||||
|
},
|
||||||
|
"rooms": {
|
||||||
|
"invite": {},
|
||||||
|
"join": {},
|
||||||
|
"leave": {
|
||||||
|
"!SVkFJHzfwvuaIEawgC:localhost": {
|
||||||
|
"summary": {},
|
||||||
|
"account_data": {
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"event_id": "$someplace:example.org"
|
||||||
|
},
|
||||||
|
"room_id": "!roomid:room.com",
|
||||||
|
"type": "m.fully_read"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"ignored_users": {
|
||||||
|
"@someone:example.org": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "m.ignored_user_list"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ephemeral": {
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"$151680659217152dPKjd:localhost": {
|
||||||
|
"m.read": {
|
||||||
|
"@example:localhost": {
|
||||||
|
"ts": 1516809890615
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "m.receipt"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"join_rule": "public"
|
||||||
|
},
|
||||||
|
"event_id": "$15139375514WsgmR:localhost",
|
||||||
|
"origin_server_ts": 1513937551539,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.join_rules",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 7034220355
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"avatar_url": null,
|
||||||
|
"displayname": "example",
|
||||||
|
"membership": "join"
|
||||||
|
},
|
||||||
|
"event_id": "$151800140517rfvjc:localhost",
|
||||||
|
"membership": "join",
|
||||||
|
"origin_server_ts": 1518001405556,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "@example:localhost",
|
||||||
|
"type": "m.room.member",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 2970366338,
|
||||||
|
"replaces_state": "$151800111315tsynI:localhost"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"history_visibility": "shared"
|
||||||
|
},
|
||||||
|
"event_id": "$15139375515VaJEY:localhost",
|
||||||
|
"origin_server_ts": 1513937551613,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.history_visibility",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 7034220281
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"creator": "@example:localhost"
|
||||||
|
},
|
||||||
|
"event_id": "$15139375510KUZHi:localhost",
|
||||||
|
"origin_server_ts": 1513937551203,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.create",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 7034220691
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"aliases": [
|
||||||
|
"#tutorial:localhost"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"event_id": "$15139375516NUgtD:localhost",
|
||||||
|
"origin_server_ts": 1513937551720,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "localhost",
|
||||||
|
"type": "m.room.aliases",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 7034220174
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"topic": "\ud83d\ude00"
|
||||||
|
},
|
||||||
|
"event_id": "$151957878228ssqrJ:localhost",
|
||||||
|
"origin_server_ts": 1519578782185,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.topic",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1392989709,
|
||||||
|
"prev_content": {
|
||||||
|
"topic": "test"
|
||||||
|
},
|
||||||
|
"prev_sender": "@example:localhost",
|
||||||
|
"replaces_state": "$151957069225EVYKm:localhost"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"ban": 50,
|
||||||
|
"events": {
|
||||||
|
"m.room.avatar": 50,
|
||||||
|
"m.room.canonical_alias": 50,
|
||||||
|
"m.room.history_visibility": 100,
|
||||||
|
"m.room.name": 50,
|
||||||
|
"m.room.power_levels": 100
|
||||||
|
},
|
||||||
|
"events_default": 0,
|
||||||
|
"invite": 0,
|
||||||
|
"kick": 50,
|
||||||
|
"redact": 50,
|
||||||
|
"state_default": 50,
|
||||||
|
"users": {
|
||||||
|
"@example:localhost": 100
|
||||||
|
},
|
||||||
|
"users_default": 0
|
||||||
|
},
|
||||||
|
"event_id": "$15139375512JaHAW:localhost",
|
||||||
|
"origin_server_ts": 1513937551359,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.power_levels",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 7034220535
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"alias": "#tutorial:localhost"
|
||||||
|
},
|
||||||
|
"event_id": "$15139375513VdeRF:localhost",
|
||||||
|
"origin_server_ts": 1513937551461,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.canonical_alias",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 7034220433
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"avatar_url": null,
|
||||||
|
"displayname": "example2",
|
||||||
|
"membership": "join"
|
||||||
|
},
|
||||||
|
"event_id": "$152034824468gOeNB:localhost",
|
||||||
|
"membership": "join",
|
||||||
|
"origin_server_ts": 1520348244605,
|
||||||
|
"sender": "@example2:localhost",
|
||||||
|
"state_key": "@example2:localhost",
|
||||||
|
"type": "m.room.member",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 623527289,
|
||||||
|
"prev_content": {
|
||||||
|
"membership": "leave"
|
||||||
|
},
|
||||||
|
"prev_sender": "@example:localhost",
|
||||||
|
"replaces_state": "$152034819067QWJxM:localhost"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"membership": "leave",
|
||||||
|
"reason": "offline",
|
||||||
|
"avatar_url": "avatar.com",
|
||||||
|
"displayname": "example"
|
||||||
|
},
|
||||||
|
"event_id": "$1585345508297748AIUBh:matrix.org",
|
||||||
|
"origin_server_ts": 1585345508223,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "@example:localhost",
|
||||||
|
"type": "m.room.member",
|
||||||
|
"unsigned": {
|
||||||
|
"replaces_state": "$1585345354296486IGZfp:localhost",
|
||||||
|
"prev_content": {
|
||||||
|
"avatar_url": "avatar.com",
|
||||||
|
"displayname": "example",
|
||||||
|
"membership": "join"
|
||||||
|
},
|
||||||
|
"prev_sender": "@example2:localhost",
|
||||||
|
"age": 6992
|
||||||
|
},
|
||||||
|
"room_id": "!roomid:room.com"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"timeline": {
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "baba",
|
||||||
|
"format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "<strong>baba</strong>",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$152037280074GZeOm:localhost",
|
||||||
|
"origin_server_ts": 1520372800469,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 598971425
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"limited": true,
|
||||||
|
"prev_batch": "t392-516_47314_0_7_1_1_1_11444_1"
|
||||||
|
},
|
||||||
|
"unread_notifications": {
|
||||||
|
"highlight_count": 0,
|
||||||
|
"notification_count": 11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"to_device": {
|
||||||
|
"events": []
|
||||||
|
},
|
||||||
|
"presence": {
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"avatar_url": "mxc://localhost:wefuiwegh8742w",
|
||||||
|
"currently_active": false,
|
||||||
|
"last_active_ago": 1,
|
||||||
|
"presence": "online",
|
||||||
|
"status_msg": "Making cupcakes"
|
||||||
|
},
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"type": "m.presence"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue