You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-09 10:22:46 +03:00
Handle device change notifications from /sync
When we get a notification from /sync that a user has updated their device list, mark the list outdated, and then fire off a device query.
This commit is contained in:
@@ -1018,20 +1018,35 @@ MatrixBaseApis.prototype.uploadKeysRequest = function(content, opts, callback) {
|
||||
*
|
||||
* @param {string[]} userIds list of users to get keys for
|
||||
*
|
||||
* @param {module:client.callback=} callback
|
||||
* @param {Object=} opts
|
||||
*
|
||||
* @param {string=} opts.token sync token to pass in the query request, to help
|
||||
* the HS give the most recent results
|
||||
*
|
||||
* @return {module:client.Promise} Resolves: result object. Rejects: with
|
||||
* an error response ({@link module:http-api.MatrixError}).
|
||||
*/
|
||||
MatrixBaseApis.prototype.downloadKeysForUsers = function(userIds, callback) {
|
||||
const downloadQuery = {};
|
||||
|
||||
for (let i = 0; i < userIds.length; ++i) {
|
||||
downloadQuery[userIds[i]] = {};
|
||||
MatrixBaseApis.prototype.downloadKeysForUsers = function(userIds, opts) {
|
||||
if (utils.isFunction(opts)) {
|
||||
// opts used to be 'callback'.
|
||||
throw new Error(
|
||||
'downloadKeysForUsers no longer accepts a callback parameter',
|
||||
);
|
||||
}
|
||||
const content = {device_keys: downloadQuery};
|
||||
opts = opts || {};
|
||||
|
||||
const content = {
|
||||
device_keys: {},
|
||||
};
|
||||
if ('token' in opts) {
|
||||
content.token = opts.token;
|
||||
}
|
||||
userIds.forEach((u) => {
|
||||
content.device_keys[u] = {};
|
||||
});
|
||||
|
||||
return this._http.authedRequestWithPrefix(
|
||||
callback, "POST", "/keys/query", undefined, content,
|
||||
undefined, "POST", "/keys/query", undefined, content,
|
||||
httpApi.PREFIX_UNSTABLE,
|
||||
);
|
||||
};
|
||||
|
@@ -2638,8 +2638,6 @@ MatrixClient.prototype.startClient = function(opts) {
|
||||
};
|
||||
}
|
||||
|
||||
this._clientOpts = opts;
|
||||
|
||||
if (this._crypto) {
|
||||
this._crypto.uploadKeys(5).done();
|
||||
const tenMinutes = 1000 * 60 * 10;
|
||||
@@ -2657,6 +2655,13 @@ MatrixClient.prototype.startClient = function(opts) {
|
||||
console.error("Still have sync object whilst not running: stopping old one");
|
||||
this._syncApi.stop();
|
||||
}
|
||||
|
||||
// shallow-copy the opts dict before modifying and storing it
|
||||
opts = Object.assign({}, opts);
|
||||
|
||||
opts.crypto = this._crypto;
|
||||
this._clientOpts = opts;
|
||||
|
||||
this._syncApi = new SyncApi(this, opts);
|
||||
this._syncApi.sync();
|
||||
};
|
||||
@@ -3040,12 +3045,26 @@ module.exports.CRYPTO_ENABLED = CRYPTO_ENABLED;
|
||||
* </ul>
|
||||
*
|
||||
* @event module:client~MatrixClient#"sync"
|
||||
*
|
||||
* @param {string} state An enum representing the syncing state. One of "PREPARED",
|
||||
* "SYNCING", "ERROR", "STOPPED".
|
||||
*
|
||||
* @param {?string} prevState An enum representing the previous syncing state.
|
||||
* One of "PREPARED", "SYNCING", "ERROR", "STOPPED" <b>or null</b>.
|
||||
*
|
||||
* @param {?Object} data Data about this transition.
|
||||
*
|
||||
* @param {MatrixError} data.err The matrix error if <code>state=ERROR</code>.
|
||||
*
|
||||
* @param {String} data.oldSyncToken The 'since' token passed to /sync.
|
||||
* <code>null</code> for the first successful sync since this client was
|
||||
* started. Only present if <code>state=PREPARED</code> or
|
||||
* <code>state=SYNCING</code>.
|
||||
*
|
||||
* @param {String} data.nextSyncToken The 'next_batch' result from /sync, which
|
||||
* will become the 'since' token for the next call to /sync. Only present if
|
||||
* <code>state=PREPARED</code> or <code>state=SYNCING</code>.
|
||||
*
|
||||
* @example
|
||||
* matrixClient.on("sync", function(state, prevState, data) {
|
||||
* switch (state) {
|
||||
|
@@ -41,6 +41,8 @@ export default class DeviceList {
|
||||
|
||||
// userId -> promise
|
||||
this._keyDownloadsInProgressByUser = {};
|
||||
|
||||
this.lastKnownSyncToken = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,8 +290,13 @@ export default class DeviceList {
|
||||
_doKeyDownloadForUsers(downloadUsers) {
|
||||
console.log('Starting key download for ' + downloadUsers);
|
||||
|
||||
const token = this.lastKnownSyncToken;
|
||||
const opts = {};
|
||||
if (token) {
|
||||
opts.token = token;
|
||||
}
|
||||
return this._baseApis.downloadKeysForUsers(
|
||||
downloadUsers,
|
||||
downloadUsers, opts,
|
||||
).then((res) => {
|
||||
const dk = res.device_keys || {};
|
||||
|
||||
|
@@ -55,8 +55,6 @@ function Crypto(baseApis, eventEmitter, sessionStore, userId, deviceId) {
|
||||
this._userId = userId;
|
||||
this._deviceId = deviceId;
|
||||
|
||||
this._initialSyncCompleted = false;
|
||||
|
||||
this._olmDevice = new OlmDevice(sessionStore);
|
||||
this._deviceList = new DeviceList(baseApis, sessionStore, this._olmDevice);
|
||||
|
||||
@@ -115,6 +113,9 @@ function _registerEventHandlers(crypto, eventEmitter) {
|
||||
const rooms = eventEmitter.getRooms();
|
||||
crypto._onInitialSyncCompleted(rooms);
|
||||
}
|
||||
if (syncState === "SYNCING") {
|
||||
crypto._onSyncCompleted(data);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Error handling sync", e);
|
||||
}
|
||||
@@ -689,6 +690,18 @@ Crypto.prototype.decryptEvent = function(event) {
|
||||
alg.decryptEvent(event);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle the notification from /sync that a user has updated their device list.
|
||||
*
|
||||
* @param {String} userId
|
||||
*/
|
||||
Crypto.prototype.userDeviceListChanged = function(userId) {
|
||||
this._deviceList.invalidateUserDeviceList(userId);
|
||||
|
||||
// don't flush the outdated device list yet - we do it once we finish
|
||||
// processing the sync.
|
||||
};
|
||||
|
||||
/**
|
||||
* handle an m.room.encryption event
|
||||
*
|
||||
@@ -716,11 +729,6 @@ Crypto.prototype._onCryptoEvent = function(event) {
|
||||
* @param {module:models/room[]} rooms list of rooms the client knows about
|
||||
*/
|
||||
Crypto.prototype._onInitialSyncCompleted = function(rooms) {
|
||||
this._initialSyncCompleted = true;
|
||||
|
||||
// catch up on any m.new_device events which arrived during the initial sync.
|
||||
this._deviceList.refreshOutdatedDeviceLists().done();
|
||||
|
||||
if (this._sessionStore.getDeviceAnnounced()) {
|
||||
return;
|
||||
}
|
||||
@@ -779,6 +787,12 @@ Crypto.prototype._onInitialSyncCompleted = function(rooms) {
|
||||
});
|
||||
};
|
||||
|
||||
Crypto.prototype._onSyncCompleted = function(syncData) {
|
||||
// catch up on any new devices we got told about during the sync.
|
||||
this._deviceList.lastKnownSyncToken = syncData.nextSyncToken;
|
||||
this._deviceList.refreshOutdatedDeviceLists().done();
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle a key event
|
||||
*
|
||||
@@ -852,12 +866,6 @@ Crypto.prototype._onNewDeviceEvent = function(event) {
|
||||
}
|
||||
|
||||
this._deviceList.invalidateUserDeviceList(userId);
|
||||
|
||||
// we delay handling these until the intialsync has completed, so that we
|
||||
// can do all of them together.
|
||||
if (this._initialSyncCompleted) {
|
||||
this._deviceList.refreshOutdatedDeviceLists().done();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
18
src/sync.js
18
src/sync.js
@@ -58,6 +58,7 @@ function debuglog() {
|
||||
* @constructor
|
||||
* @param {MatrixClient} client The matrix client instance to use.
|
||||
* @param {Object} opts Config options
|
||||
* @param {module:crypto=} opts.crypto Crypto manager
|
||||
*/
|
||||
function SyncApi(client, opts) {
|
||||
this.client = client;
|
||||
@@ -529,13 +530,18 @@ SyncApi.prototype._sync = function(syncOptions) {
|
||||
}
|
||||
|
||||
// emit synced events
|
||||
const syncEventData = {
|
||||
oldSyncToken: syncToken,
|
||||
nextSyncToken: data.next_batch,
|
||||
};
|
||||
|
||||
if (!syncOptions.hasSyncedBefore) {
|
||||
self._updateSyncState("PREPARED");
|
||||
self._updateSyncState("PREPARED", syncEventData);
|
||||
syncOptions.hasSyncedBefore = true;
|
||||
}
|
||||
|
||||
// keep emitting SYNCING -> SYNCING for clients who want to do bulk updates
|
||||
self._updateSyncState("SYNCING");
|
||||
self._updateSyncState("SYNCING", syncEventData);
|
||||
|
||||
self._sync(syncOptions);
|
||||
}, function(err) {
|
||||
@@ -584,6 +590,7 @@ SyncApi.prototype._processSyncResponse = function(syncToken, data) {
|
||||
// next_batch: $token,
|
||||
// presence: { events: [] },
|
||||
// account_data: { events: [] },
|
||||
// device_lists: { changed: ["@user:server", ... ]},
|
||||
// to_device: { events: [] },
|
||||
// rooms: {
|
||||
// invite: {
|
||||
@@ -859,6 +866,13 @@ SyncApi.prototype._processSyncResponse = function(syncToken, data) {
|
||||
client.getNotifTimelineSet().addLiveEvent(event);
|
||||
});
|
||||
}
|
||||
|
||||
// Handle device list updates
|
||||
if (this.opts.crypto && data.device_lists && data.device_lists.changed) {
|
||||
data.device_lists.changed.forEach((u) => {
|
||||
this.opts.crypto.userDeviceListChanged(u);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user