1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-07-31 15:24:23 +03:00

Sync room state when joining via client.joinRoom

Does not currently sync state when another device joins.
Update node example app to refresh room list.
This commit is contained in:
Kegan Dougal
2015-06-22 17:50:49 +01:00
parent ad70b3d434
commit bc0e2ad504
4 changed files with 126 additions and 44 deletions

View File

@ -28,7 +28,9 @@ rl.on('line', function(line) {
viewingRoom = roomList[roomIndex]; viewingRoom = roomList[roomIndex];
if (viewingRoom.getMember(myUserId).membership === "invite") { if (viewingRoom.getMember(myUserId).membership === "invite") {
// join the room first // join the room first
matrixClient.joinRoom(viewingRoom.roomId).done(function() { matrixClient.joinRoom(viewingRoom.roomId).done(function(room) {
roomList = matrixClient.getRooms();
viewingRoom = room;
printMessages(); printMessages();
}, function(err) { }, function(err) {
console.log("Error: %s", err); console.log("Error: %s", err);
@ -69,6 +71,13 @@ matrixClient.on("syncComplete", function() {
printHelp(); printHelp();
}); });
matrixClient.on("Room", function() {
roomList = matrixClient.getRooms();
if (!viewingRoom) {
printRoomList();
}
});
// print incoming messages. // print incoming messages.
matrixClient.on("Room.timeline", function(event, room, toStartOfTimeline) { matrixClient.on("Room.timeline", function(event, room, toStartOfTimeline) {
if (toStartOfTimeline) { if (toStartOfTimeline) {

View File

@ -121,12 +121,26 @@ MatrixClient.prototype.createRoom = function(options, callback) {
* Join a room. * Join a room.
* @param {string} roomIdOrAlias The room ID or room alias to join. * @param {string} roomIdOrAlias The room ID or room alias to join.
* @param {module:client.callback} callback Optional. * @param {module:client.callback} callback Optional.
* @return {module:client.Promise} Resolves: <code>{room_id: {string}}</code> * @return {module:client.Promise} Resolves: Room object.
* @return {module:http-api.MatrixError} Rejects: with an error response. * @return {module:http-api.MatrixError} Rejects: with an error response.
*/ */
MatrixClient.prototype.joinRoom = function(roomIdOrAlias, callback) { MatrixClient.prototype.joinRoom = function(roomIdOrAlias, callback) {
var path = utils.encodeUri("/join/$roomid", { $roomid: roomIdOrAlias}); var path = utils.encodeUri("/join/$roomid", { $roomid: roomIdOrAlias});
return this._http.authedRequest(callback, "POST", path, undefined, {}); var defer = q.defer();
var self = this;
this._http.authedRequest(undefined, "POST", path, undefined, {}).then(
function(res) {
var roomId = res.room_id;
var room = createNewRoom(self, roomId);
return _syncRoom(self, room);
}, function(err) {
_reject(callback, defer, err);
}).done(function(room) {
_resolve(callback, defer, room);
}, function(err) {
_reject(callback, defer, err);
});
return defer.promise;
}; };
/** /**
@ -915,10 +929,6 @@ MatrixClient.prototype.isLoggedIn = function() {
}; };
// Higher level APIs // Higher level APIs
// ================= // =================
@ -959,10 +969,8 @@ MatrixClient.prototype.startClient = function(historyLen) {
var i, j; var i, j;
// intercept the results and put them into our store // intercept the results and put them into our store
if (self.store) { if (self.store) {
var eventMapper = function(event) { utils.forEach(utils.map(data.presence, _PojoToMatrixEventMapper),
return new MatrixEvent(event); function(e) {
};
utils.forEach(utils.map(data.presence, eventMapper), function(e) {
var user = createNewUser(self, e.getContent().user_id); var user = createNewUser(self, e.getContent().user_id);
user.setPresenceEvent(e); user.setPresenceEvent(e);
self.store.storeUser(user); self.store.storeUser(user);
@ -986,27 +994,8 @@ MatrixClient.prototype.startClient = function(historyLen) {
}); });
} }
// "old" and "current" state are the same initially; they _processRoomEvents(
// start diverging if the user paginates. room, data.rooms[i].state, data.rooms[i].messages
// We must deep copy otherwise membership changes in old state
// will leak through to current state!
var oldStateEvents = utils.map(
utils.deepCopy(data.rooms[i].state), eventMapper
);
var stateEvents = utils.map(data.rooms[i].state, eventMapper);
room.oldState.setStateEvents(oldStateEvents);
room.currentState.setStateEvents(stateEvents);
// add events to the timeline *after* setting the state
// events so messages use the right display names. Initial sync
// returns messages in chronological order, so we need to reverse
// it to get most recent -> oldest. We need it in that order in
// order to diverge old/current state correctly.
room.addEventsToTimeline(
utils.map(
data.rooms[i].messages ? data.rooms[i].messages.chunk : [],
eventMapper
).reverse(), true
); );
// cache the name/summary/etc prior to storage since we don't // cache the name/summary/etc prior to storage since we don't
@ -1087,23 +1076,38 @@ function _pollForEvents(client) {
} }
// add events to room // add events to room
var roomIds = utils.keys(roomIdToEvents); var roomIds = utils.keys(roomIdToEvents);
for (i = 0; i < roomIds.length; i++) { utils.forEach(roomIds, function(roomId) {
var room = self.store.getRoom(roomIds[i]); var room = self.store.getRoom(roomId);
var shouldStoreRoom = false; var isBrandNewRoom = false;
if (!room) { if (!room) {
room = createNewRoom(self, roomIds[i]); room = createNewRoom(self, roomId);
shouldStoreRoom = true; isBrandNewRoom = true;
} }
room.addEvents(roomIdToEvents[roomIds[i]], "replace");
//var wasJoined = room.hasMembershipState(
// self.credentials.userId, "join"
//);
room.addEvents(roomIdToEvents[roomId], "replace");
room.recalculate(self.credentials.userId); room.recalculate(self.credentials.userId);
if (shouldStoreRoom) { // store the Room for things like invite events so developers
// can update the UI
if (isBrandNewRoom) {
self.store.storeRoom(room); self.store.storeRoom(room);
// TODO: Should be doing roomInitialSync here to pull in
// all state before emitting this(!)
self.emit("Room", room); self.emit("Room", room);
} }
} /* TODO invite->join trigger roominitialsync
var justJoined = room.hasMembershipState(
self.credentials.userId, "join"
);
if (!wasJoined && justJoined) {
// we've just transitioned into a join state for this room,
// so sync state.
_syncRoom(self, room);
} */
});
} }
if (data) { if (data) {
self.fromToken = data.end; self.fromToken = data.end;
@ -1122,6 +1126,45 @@ function _pollForEvents(client) {
}); });
} }
function _syncRoom(client, room) {
var defer = q.defer();
client.roomInitialSync(room.roomId, 8).done(function(res) {
_processRoomEvents(room, res.state, res.messages);
room.recalculate(client.credentials.userId);
client.store.storeRoom(room);
client.emit("Room", room);
defer.resolve(room);
}, function(err) {
defer.reject(err);
});
return defer.promise;
}
function _processRoomEvents(room, stateEventList, messageChunk) {
// "old" and "current" state are the same initially; they
// start diverging if the user paginates.
// We must deep copy otherwise membership changes in old state
// will leak through to current state!
var oldStateEvents = utils.map(
utils.deepCopy(stateEventList), _PojoToMatrixEventMapper
);
var stateEvents = utils.map(stateEventList, _PojoToMatrixEventMapper);
room.oldState.setStateEvents(oldStateEvents);
room.currentState.setStateEvents(stateEvents);
// add events to the timeline *after* setting the state
// events so messages use the right display names. Initial sync
// returns messages in chronological order, so we need to reverse
// it to get most recent -> oldest. We need it in that order in
// order to diverge old/current state correctly.
room.addEventsToTimeline(
utils.map(
messageChunk ? messageChunk.chunk : [],
_PojoToMatrixEventMapper
).reverse(), true
);
}
/** /**
* High level helper method to stop the client from polling and allow a * High level helper method to stop the client from polling and allow a
* clean shutdown. * clean shutdown.
@ -1178,6 +1221,24 @@ function createNewRoom(client, roomId) {
return room; return room;
} }
function _reject(callback, defer, err) {
if (callback) {
callback(err);
}
defer.reject(err);
}
function _resolve(callback, defer, res) {
if (callback) {
callback(null, res);
}
defer.resolve(res);
}
function _PojoToMatrixEventMapper(plainOldJsObject) {
return new MatrixEvent(plainOldJsObject);
}
/** */ /** */
module.exports.MatrixClient = MatrixClient; module.exports.MatrixClient = MatrixClient;
@ -1215,7 +1276,8 @@ module.exports.MatrixClient = MatrixClient;
*/ */
/** /**
* Fires whenever a new Room is added. <strong>This event is experimental and * Fires whenever a new Room is added. This will fire when you are invited to a
* room, as well as when you join a room. <strong>This event is experimental and
* may change.</strong> * may change.</strong>
* @event module:client~MatrixClient#"Room" * @event module:client~MatrixClient#"Room"
* @param {Room} room The newly created, fully populated room. * @param {Room} room The newly created, fully populated room.

View File

@ -55,6 +55,18 @@ utils.inherits(Room, EventEmitter);
}); });
}; };
/**
* Check if the given user_id has the given membership state.
* @param {string} userId The user ID to check.
* @param {string} membership The membership e.g. <code>'join'</code>
* @return {boolean} True if this user_id has the given membership state.
*/
Room.prototype.hasMembershipState = function(userId, membership) {
return utils.filter(this.currentState.getMembers(), function(m) {
return m.membership === membership && m.userId === userId;
}).length > 0;
};
/** /**
* Add some events to this room's timeline. Will fire "Room.timeline" for * Add some events to this room's timeline. Will fire "Room.timeline" for
* each event added. * each event added.

View File

@ -4,7 +4,6 @@
* of requests. * of requests.
* @module scheduler * @module scheduler
*/ */
var EventStatus = require("./models/event").EventStatus;
var utils = require("./utils"); var utils = require("./utils");
var q = require("q"); var q = require("q");