You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-26 17:03:12 +03:00
Do all prep for /sync calls
This includes managing filters in localStorage. The /sync response is not yet parsed.
This commit is contained in:
@@ -31,9 +31,6 @@ try {
|
|||||||
// Olm not installed.
|
// Olm not installed.
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// Internal: rate limiting
|
|
||||||
|
|
||||||
var OLM_ALGORITHM = "m.olm.v1.curve25519-aes-sha2";
|
var OLM_ALGORITHM = "m.olm.v1.curve25519-aes-sha2";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -147,7 +144,6 @@ function MatrixClient(opts) {
|
|||||||
this.callList = {
|
this.callList = {
|
||||||
// callId: MatrixCall
|
// callId: MatrixCall
|
||||||
};
|
};
|
||||||
this._config = {}; // see startClient()
|
|
||||||
|
|
||||||
// try constructing a MatrixCall to see if we are running in an environment
|
// try constructing a MatrixCall to see if we are running in an environment
|
||||||
// which has WebRTC. If we are, listen for and handle m.call.* events.
|
// which has WebRTC. If we are, listen for and handle m.call.* events.
|
||||||
@@ -2197,6 +2193,7 @@ MatrixClient.prototype.startClient = function(opts) {
|
|||||||
// client is already running.
|
// client is already running.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.clientRunning = true;
|
||||||
// backwards compat for when 'opts' was 'historyLen'.
|
// backwards compat for when 'opts' was 'historyLen'.
|
||||||
if (typeof opts === "number") {
|
if (typeof opts === "number") {
|
||||||
opts = {
|
opts = {
|
||||||
@@ -2204,14 +2201,6 @@ MatrixClient.prototype.startClient = function(opts) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
opts = opts || {};
|
|
||||||
opts.initialSyncLimit = opts.initialSyncLimit || 8;
|
|
||||||
opts.includeArchivedRooms = opts.includeArchivedRooms || false;
|
|
||||||
opts.resolveInvitesToProfiles = opts.resolveInvitesToProfiles || false;
|
|
||||||
opts.pollTimeout = opts.pollTimeout || (30 * 1000);
|
|
||||||
opts.pendingEventOrdering = opts.pendingEventOrdering || "chronological";
|
|
||||||
this._config = opts;
|
|
||||||
|
|
||||||
if (CRYPTO_ENABLED && this.sessionStore !== null) {
|
if (CRYPTO_ENABLED && this.sessionStore !== null) {
|
||||||
this.uploadKeys(5);
|
this.uploadKeys(5);
|
||||||
}
|
}
|
||||||
@@ -2219,11 +2208,8 @@ MatrixClient.prototype.startClient = function(opts) {
|
|||||||
// periodically poll for turn servers if we support voip
|
// periodically poll for turn servers if we support voip
|
||||||
checkTurnServers(this);
|
checkTurnServers(this);
|
||||||
|
|
||||||
var syncApi = new SyncApi(this);
|
var syncApi = new SyncApi(this, opts);
|
||||||
syncApi.sync({
|
syncApi.sync();
|
||||||
historyLen: this._config.initialSyncLimit,
|
|
||||||
includeArchived: this._config.includeArchivedRooms
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2233,6 +2219,7 @@ MatrixClient.prototype.startClient = function(opts) {
|
|||||||
MatrixClient.prototype.stopClient = function() {
|
MatrixClient.prototype.stopClient = function() {
|
||||||
this.clientRunning = false;
|
this.clientRunning = false;
|
||||||
// TODO: f.e. Room => self.store.storeRoom(room) ?
|
// TODO: f.e. Room => self.store.storeRoom(room) ?
|
||||||
|
// TODO: Actually stop the SyncApi
|
||||||
};
|
};
|
||||||
|
|
||||||
function setupCallEventHandler(client) {
|
function setupCallEventHandler(client) {
|
||||||
|
|||||||
@@ -81,7 +81,9 @@ module.exports.createClient = function(opts) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
opts.request = opts.request || request;
|
opts.request = opts.request || request;
|
||||||
opts.store = opts.store || new module.exports.MatrixInMemoryStore();
|
opts.store = opts.store || new module.exports.MatrixInMemoryStore({
|
||||||
|
localStorage: global.localStorage
|
||||||
|
});
|
||||||
opts.scheduler = opts.scheduler || new module.exports.MatrixScheduler();
|
opts.scheduler = opts.scheduler || new module.exports.MatrixScheduler();
|
||||||
return new module.exports.MatrixClient(opts);
|
return new module.exports.MatrixClient(opts);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,8 +8,13 @@
|
|||||||
/**
|
/**
|
||||||
* Construct a new in-memory data store for the Matrix Client.
|
* Construct a new in-memory data store for the Matrix Client.
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @param {Object=} opts Config options
|
||||||
|
* @param {LocalStorage} opts.localStorage The local storage instance to persist some forms
|
||||||
|
* of data such as tokens. Rooms will NOT be stored. See {@link WebStorageStore} to
|
||||||
|
* persist rooms.
|
||||||
*/
|
*/
|
||||||
module.exports.MatrixInMemoryStore = function MatrixInMemoryStore() {
|
module.exports.MatrixInMemoryStore = function MatrixInMemoryStore(opts) {
|
||||||
|
opts = opts || {};
|
||||||
this.rooms = {
|
this.rooms = {
|
||||||
// roomId: Room
|
// roomId: Room
|
||||||
};
|
};
|
||||||
@@ -22,6 +27,7 @@ module.exports.MatrixInMemoryStore = function MatrixInMemoryStore() {
|
|||||||
// filterId: Filter
|
// filterId: Filter
|
||||||
// }
|
// }
|
||||||
};
|
};
|
||||||
|
this.localStorage = opts.localStorage;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.MatrixInMemoryStore.prototype = {
|
module.exports.MatrixInMemoryStore.prototype = {
|
||||||
@@ -139,6 +145,37 @@ module.exports.MatrixInMemoryStore.prototype = {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return this.filters[userId][filterId];
|
return this.filters[userId][filterId];
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a filter ID with the given name.
|
||||||
|
* @param {string} filterName The filter name.
|
||||||
|
* @return {?string} The filter ID or null.
|
||||||
|
*/
|
||||||
|
getFilterIdByName: function(filterName) {
|
||||||
|
if (!this.localStorage) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return this.localStorage.getItem("mxjssdk_memory_filter_" + filterName);
|
||||||
|
}
|
||||||
|
catch(e) {}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a filter name to ID mapping.
|
||||||
|
* @param {string} filterName
|
||||||
|
* @param {string} filterId
|
||||||
|
*/
|
||||||
|
setFilterIdByName: function(filterName, filterId) {
|
||||||
|
if (!this.localStorage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
this.localStorage.setItem("mxjssdk_memory_filter_" + filterName, filterId);
|
||||||
|
}
|
||||||
|
catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|||||||
@@ -113,6 +113,15 @@ StubStore.prototype = {
|
|||||||
*/
|
*/
|
||||||
getFilter: function(userId, filterId) {
|
getFilter: function(userId, filterId) {
|
||||||
return null;
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a filter ID with the given name.
|
||||||
|
* @param {string} filterName The filter name.
|
||||||
|
* @return {?string} The filter ID or null.
|
||||||
|
*/
|
||||||
|
getFilterIdByName: function(filterName) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|||||||
174
lib/sync.js
174
lib/sync.js
@@ -14,6 +14,10 @@ var User = require("./models/user");
|
|||||||
var Room = require("./models/room");
|
var Room = require("./models/room");
|
||||||
var utils = require("./utils");
|
var utils = require("./utils");
|
||||||
var MatrixEvent = require("./models/event").MatrixEvent;
|
var MatrixEvent = require("./models/event").MatrixEvent;
|
||||||
|
var httpApi = require("./http-api");
|
||||||
|
var Filter = require("./filter");
|
||||||
|
|
||||||
|
var FILTER_SYNC = "FILTER_SYNC";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>Internal class - unstable.</b>
|
* <b>Internal class - unstable.</b>
|
||||||
@@ -21,9 +25,15 @@ var MatrixEvent = require("./models/event").MatrixEvent;
|
|||||||
* @constructor
|
* @constructor
|
||||||
* @param {MatrixClient} client The matrix client instance to use.
|
* @param {MatrixClient} client The matrix client instance to use.
|
||||||
*/
|
*/
|
||||||
function SyncApi(client) {
|
function SyncApi(client, opts) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.opts = {};
|
opts = opts || {};
|
||||||
|
opts.initialSyncLimit = opts.initialSyncLimit || 8;
|
||||||
|
opts.includeArchivedRooms = opts.includeArchivedRooms || false;
|
||||||
|
opts.resolveInvitesToProfiles = opts.resolveInvitesToProfiles || false;
|
||||||
|
opts.pollTimeout = opts.pollTimeout || (30 * 1000);
|
||||||
|
opts.pendingEventOrdering = opts.pendingEventOrdering || "chronological";
|
||||||
|
this.opts = opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,65 +54,128 @@ SyncApi.prototype.syncRoom = function(room) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Main entry point
|
* Main entry point
|
||||||
* @param {Object} opts
|
|
||||||
* @param {Number} opts.historyLen
|
|
||||||
* @param {Boolean} opts.includeArchived
|
|
||||||
*/
|
*/
|
||||||
SyncApi.prototype.sync = function(opts) {
|
SyncApi.prototype.sync = function() {
|
||||||
console.log("SyncApi.sync");
|
console.log("SyncApi.sync");
|
||||||
this.opts = opts || {};
|
|
||||||
this._prepareForSync();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Number=} attempt
|
|
||||||
*/
|
|
||||||
SyncApi.prototype._prepareForSync = function(attempt) {
|
|
||||||
var client = this.client;
|
var client = this.client;
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
// We need to do one-off checks before we can begin the /sync loop.
|
||||||
|
// These are:
|
||||||
|
// 1) We need to get push rules so we can check if events should bing as we get
|
||||||
|
// them from /sync.
|
||||||
|
// 2) We need to get/create a filter which we can use for /sync.
|
||||||
|
|
||||||
|
function getPushRules(attempt) {
|
||||||
|
attempt = attempt || 0;
|
||||||
|
attempt += 1;
|
||||||
|
|
||||||
|
client.pushRules().done(function(result) {
|
||||||
|
console.log("Got push rules");
|
||||||
|
client.pushRules = result;
|
||||||
|
getFilter(); // Now get the filter
|
||||||
|
}, retryHandler(attempt, getPushRules));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFilter(attempt) {
|
||||||
|
attempt = attempt || 0;
|
||||||
|
attempt += 1;
|
||||||
|
|
||||||
|
|
||||||
|
// Get or create filter
|
||||||
|
var filterId = client.store.getFilterIdByName(FILTER_SYNC);
|
||||||
|
if (filterId) {
|
||||||
|
// super, just use that.
|
||||||
|
console.log("Using existing filter ID %s", filterId);
|
||||||
|
self._sync({ filterId: filterId });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a filter
|
||||||
|
var filter = new Filter(client.credentials.userId);
|
||||||
|
filter.setTimelineLimit(self.opts.initialSyncLimit);
|
||||||
|
client.createFilter(filter.getDefinition()).done(function(filter) {
|
||||||
|
client.store.setFilterIdByName(FILTER_SYNC, filter.filterId);
|
||||||
|
console.log("Created filter ", filter.filterId);
|
||||||
|
self._sync({ filterId: filter.filterId }); // Now start the /sync loop
|
||||||
|
}, retryHandler(attempt, getFilter));
|
||||||
|
}
|
||||||
|
|
||||||
|
// sets the sync state to error and waits a bit before re-invoking the function.
|
||||||
|
function retryHandler(attempt, fnToRun) {
|
||||||
|
return function(err) {
|
||||||
|
startSyncingRetryTimer(client, attempt, function() {
|
||||||
|
fnToRun(attempt);
|
||||||
|
});
|
||||||
|
updateSyncState(client, "ERROR", { error: err });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (client.isGuest()) {
|
if (client.isGuest()) {
|
||||||
// no push rules for guests
|
// no push rules for guests
|
||||||
this._sync();
|
getFilter();
|
||||||
return;
|
}
|
||||||
|
else {
|
||||||
|
getPushRules();
|
||||||
}
|
}
|
||||||
|
|
||||||
attempt = attempt || 1;
|
|
||||||
// we do push rules before syncing so when we gets events down we know immediately
|
|
||||||
// whether they are bing-worthy.
|
|
||||||
client.pushRules().done(function(result) {
|
|
||||||
client.pushRules = result;
|
|
||||||
self._sync();
|
|
||||||
}, function(err) {
|
|
||||||
attempt += 1;
|
|
||||||
startSyncingRetryTimer(client, attempt, function() {
|
|
||||||
self._prepareForSync(attempt);
|
|
||||||
});
|
|
||||||
updateSyncState(client, "ERROR", { error: err });
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Invoke me to do /sync calls
|
||||||
|
* @param {Object} syncOptions
|
||||||
|
* @param {string} syncOptions.filterId
|
||||||
|
* @param {boolean} syncOptions.hasSyncedBefore
|
||||||
* @param {Number=} attempt
|
* @param {Number=} attempt
|
||||||
*/
|
*/
|
||||||
SyncApi.prototype._sync = function(attempt) {
|
SyncApi.prototype._sync = function(syncOptions, attempt) {
|
||||||
var opts = this.opts;
|
|
||||||
var client = this.client;
|
var client = this.client;
|
||||||
var self = this;
|
var self = this;
|
||||||
var historyLen = opts.historyLen;
|
|
||||||
var includeArchived = opts.includeArchived;
|
|
||||||
attempt = attempt || 1;
|
attempt = attempt || 1;
|
||||||
|
|
||||||
var qps = { limit: historyLen };
|
// TODO include archived rooms flag.
|
||||||
if (includeArchived) {
|
|
||||||
qps.archived = true;
|
var qps = {
|
||||||
}
|
filter: syncOptions.filterId,
|
||||||
|
timeout: this.opts.pollTimeout,
|
||||||
|
since: client.store.getSyncToken() || undefined // do not send 'null'
|
||||||
|
};
|
||||||
|
|
||||||
if (client._guestRooms && client._isGuest) {
|
if (client._guestRooms && client._isGuest) {
|
||||||
qps.room_id = JSON.stringify(client._guestRooms);
|
qps.room_id = JSON.stringify(client._guestRooms);
|
||||||
}
|
}
|
||||||
client._http.authedRequest(
|
|
||||||
undefined, "GET", "/initialSync", qps
|
client._http.authedRequestWithPrefix(
|
||||||
|
undefined, "GET", "/sync", qps, undefined, httpApi.PREFIX_V2_ALPHA
|
||||||
).done(function(data) {
|
).done(function(data) {
|
||||||
|
// data looks like:
|
||||||
|
// {
|
||||||
|
// next_batch: $token,
|
||||||
|
// presence: [PresencEvents],
|
||||||
|
// rooms: {
|
||||||
|
// invite: {
|
||||||
|
// $roomid: {
|
||||||
|
// invite_state: { events: [] }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// join: {
|
||||||
|
// $roomid: {
|
||||||
|
// state: { events: [] },
|
||||||
|
// timeline: { events: [], prev_batch: $token, limited: true },
|
||||||
|
// ephemeral: { events: [] },
|
||||||
|
// account_data: { events: [] }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// leave: {
|
||||||
|
// $roomid: {
|
||||||
|
// state: { events: [] },
|
||||||
|
// timeline: { events: [], prev_batch: $token }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
console.log("Got data %s", data);
|
||||||
|
|
||||||
|
/*
|
||||||
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 (!(client.store instanceof StubStore)) {
|
if (!(client.store instanceof StubStore)) {
|
||||||
@@ -180,7 +253,6 @@ SyncApi.prototype._sync = function(attempt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
client.store.setSyncToken(data.end);
|
|
||||||
var events = [];
|
var events = [];
|
||||||
for (i = 0; i < data.presence.length; i++) {
|
for (i = 0; i < data.presence.length; i++) {
|
||||||
events.push(new MatrixEvent(data.presence[i]));
|
events.push(new MatrixEvent(data.presence[i]));
|
||||||
@@ -204,16 +276,22 @@ SyncApi.prototype._sync = function(attempt) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
client.clientRunning = true;
|
|
||||||
updateSyncState(client, "PREPARED");
|
// assume success until we fail which may be 30+ secs */
|
||||||
// assume success until we fail which may be 30+ secs
|
|
||||||
|
client.store.setSyncToken(data.next_batch);
|
||||||
|
|
||||||
|
if (!syncOptions.hasSyncedBefore) {
|
||||||
|
updateSyncState(client, "PREPARED");
|
||||||
|
syncOptions.hasSyncedBefore = true;
|
||||||
|
}
|
||||||
updateSyncState(client, "SYNCING");
|
updateSyncState(client, "SYNCING");
|
||||||
self._pollForEvents();
|
self._sync(syncOptions);
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
console.error("/initialSync error (%s attempts): %s", attempt, err);
|
console.error("/sync error (%s attempts): %s", attempt, err);
|
||||||
attempt += 1;
|
attempt += 1;
|
||||||
startSyncingRetryTimer(client, attempt, function() {
|
startSyncingRetryTimer(client, attempt, function() {
|
||||||
self._sync(attempt);
|
self._sync(syncOptions, attempt);
|
||||||
});
|
});
|
||||||
updateSyncState(client, "ERROR", { error: err });
|
updateSyncState(client, "ERROR", { error: err });
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user