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
Merge remote-tracking branch 'origin/develop' into dbkr/wasm
This commit is contained in:
44
CHANGELOG.md
44
CHANGELOG.md
@@ -1,3 +1,47 @@
|
||||
Changes in [0.12.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.12.0) (2018-10-16)
|
||||
==================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.12.0-rc.1...v0.12.0)
|
||||
|
||||
* No changes since rc.1
|
||||
|
||||
Changes in [0.12.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.12.0-rc.1) (2018-10-11)
|
||||
============================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.11.1...v0.12.0-rc.1)
|
||||
|
||||
BREAKING CHANGES
|
||||
----------------
|
||||
* If js-sdk finds data in the store that is incompatible with the options currently being used,
|
||||
it will emit sync state ERROR with an error of type InvalidStoreError. It will also stop trying
|
||||
to sync in this situation: the app must stop the client and then either clear the store or
|
||||
change the options (in this case, enable or disable lazy loading of members) and then start
|
||||
the client again.
|
||||
|
||||
All Changes
|
||||
-----------
|
||||
|
||||
* never replace /sync'ed memberships with OOB ones
|
||||
[\#760](https://github.com/matrix-org/matrix-js-sdk/pull/760)
|
||||
* Don't fail to start up if lazy load check fails
|
||||
[\#759](https://github.com/matrix-org/matrix-js-sdk/pull/759)
|
||||
* Make e2e work on Edge
|
||||
[\#754](https://github.com/matrix-org/matrix-js-sdk/pull/754)
|
||||
* throw error with same name and message over idb worker boundary
|
||||
[\#758](https://github.com/matrix-org/matrix-js-sdk/pull/758)
|
||||
* Default to a room version of 1 when there is no room create event
|
||||
[\#755](https://github.com/matrix-org/matrix-js-sdk/pull/755)
|
||||
* Silence bluebird warnings
|
||||
[\#757](https://github.com/matrix-org/matrix-js-sdk/pull/757)
|
||||
* allow non-ff merge from release branch into master
|
||||
[\#750](https://github.com/matrix-org/matrix-js-sdk/pull/750)
|
||||
* Reject with the actual error on indexeddb error
|
||||
[\#751](https://github.com/matrix-org/matrix-js-sdk/pull/751)
|
||||
* Update mocha to v5
|
||||
[\#744](https://github.com/matrix-org/matrix-js-sdk/pull/744)
|
||||
* disable lazy loading for guests as they cant create filters
|
||||
[\#748](https://github.com/matrix-org/matrix-js-sdk/pull/748)
|
||||
* Revert "Add getMediaLimits to client"
|
||||
[\#745](https://github.com/matrix-org/matrix-js-sdk/pull/745)
|
||||
|
||||
Changes in [0.11.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.11.1) (2018-10-01)
|
||||
==================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.11.1-rc.1...v0.11.1)
|
||||
|
52
README.md
52
README.md
@@ -30,9 +30,61 @@ In Node.js
|
||||
console.log("Public Rooms: %s", JSON.stringify(data));
|
||||
});
|
||||
```
|
||||
|
||||
See below for how to include libolm to enable end-to-end-encryption. Please check
|
||||
[the Node.js terminal app](examples/node) for a more complex example.
|
||||
|
||||
To start the client:
|
||||
|
||||
```javascript
|
||||
await client.startClient({initialSyncLimit: 10});
|
||||
```
|
||||
|
||||
You can perform a call to `/sync` to get the current state of the client:
|
||||
|
||||
```javascript
|
||||
client.once('sync', function(state, prevState, res) {
|
||||
if(state === 'PREPARED') {
|
||||
console.log("prepared");
|
||||
} else {
|
||||
console.log(state);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
To send a message:
|
||||
|
||||
```javascript
|
||||
var content = {
|
||||
"body": "message text",
|
||||
"msgtype": "m.text"
|
||||
};
|
||||
client.sendEvent("roomId", "m.room.message", content, "", (err, res) => {
|
||||
console.log(err);
|
||||
});
|
||||
```
|
||||
|
||||
To listen for message events:
|
||||
|
||||
```javascript
|
||||
client.on("Room.timeline", function(event, room, toStartOfTimeline) {
|
||||
if (event.getType() !== "m.room.message") {
|
||||
return; // only use messages
|
||||
}
|
||||
console.log(event.event.content.body);
|
||||
});
|
||||
```
|
||||
|
||||
By default, the `matrix-js-sdk` client uses the `MatrixInMemoryStore` to store events as they are received. For example to iterate through the currently stored timeline for a room:
|
||||
|
||||
```javascript
|
||||
Object.keys(client.store.rooms).forEach((roomId) => {
|
||||
client.getRoom(roomId).timeline.forEach(t => {
|
||||
console.log(t.event);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
What does this SDK do?
|
||||
----------------------
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "matrix-js-sdk",
|
||||
"version": "0.11.1",
|
||||
"version": "0.12.0",
|
||||
"description": "Matrix Client-Server SDK for Javascript",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@@ -21,6 +21,7 @@
|
||||
"prepublish": "npm run clean && npm run build && git rev-parse HEAD > git-revision.txt"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/matrix-org/matrix-js-sdk"
|
||||
},
|
||||
"keywords": [
|
||||
|
@@ -201,22 +201,6 @@ describe("RoomMember", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("supersedesOutOfBand", function() {
|
||||
it("should be set by markSupersedesOutOfBand", function() {
|
||||
const member = new RoomMember();
|
||||
expect(member.supersedesOutOfBand()).toEqual(false);
|
||||
member.markSupersedesOutOfBand();
|
||||
expect(member.supersedesOutOfBand()).toEqual(true);
|
||||
});
|
||||
it("should be cleared by clearSupersedesOutOfBand", function() {
|
||||
const member = new RoomMember();
|
||||
member.markSupersedesOutOfBand();
|
||||
expect(member.supersedesOutOfBand()).toEqual(true);
|
||||
member.clearSupersedesOutOfBand();
|
||||
expect(member.supersedesOutOfBand()).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("setMembershipEvent", function() {
|
||||
const joinEvent = utils.mkMembership({
|
||||
event: true,
|
||||
|
@@ -299,41 +299,25 @@ describe("RoomState", function() {
|
||||
expect(eventReceived).toEqual(true);
|
||||
});
|
||||
|
||||
it("should overwrite existing members", function() {
|
||||
it("should never overwrite existing members", function() {
|
||||
const oobMemberEvent = utils.mkMembership({
|
||||
user: userA, mship: "join", room: roomId, event: true,
|
||||
});
|
||||
state.markOutOfBandMembersStarted();
|
||||
state.setOutOfBandMembers([oobMemberEvent]);
|
||||
const memberA = state.getMember(userA);
|
||||
expect(memberA.events.member.getId()).toEqual(oobMemberEvent.getId());
|
||||
expect(memberA.isOutOfBand()).toEqual(true);
|
||||
});
|
||||
|
||||
it("should allow later state events to overwrite", function() {
|
||||
const oobMemberEvent = utils.mkMembership({
|
||||
user: userA, mship: "join", room: roomId, event: true,
|
||||
});
|
||||
const memberEvent = utils.mkMembership({
|
||||
user: userA, mship: "join", room: roomId, event: true,
|
||||
});
|
||||
|
||||
state.markOutOfBandMembersStarted();
|
||||
state.setOutOfBandMembers([oobMemberEvent]);
|
||||
state.setStateEvents([memberEvent]);
|
||||
|
||||
const memberA = state.getMember(userA);
|
||||
expect(memberA.events.member.getId()).toEqual(memberEvent.getId());
|
||||
expect(memberA.events.member.getId()).toNotEqual(oobMemberEvent.getId());
|
||||
expect(memberA.isOutOfBand()).toEqual(false);
|
||||
});
|
||||
|
||||
it("should emit members when updating a member", function() {
|
||||
const doesntExistYetUserId = "@doesntexistyet:hs";
|
||||
const oobMemberEvent = utils.mkMembership({
|
||||
user: userA, mship: "join", room: roomId, event: true,
|
||||
user: doesntExistYetUserId, mship: "join", room: roomId, event: true,
|
||||
});
|
||||
let eventReceived = false;
|
||||
state.once('RoomState.members', (_, __, member) => {
|
||||
expect(member.userId).toEqual(userA);
|
||||
expect(member.userId).toEqual(doesntExistYetUserId);
|
||||
eventReceived = true;
|
||||
});
|
||||
|
||||
@@ -341,28 +325,6 @@ describe("RoomState", function() {
|
||||
state.setOutOfBandMembers([oobMemberEvent]);
|
||||
expect(eventReceived).toEqual(true);
|
||||
});
|
||||
|
||||
|
||||
it("should not overwrite members updated since starting loading oob",
|
||||
function() {
|
||||
const oobMemberEvent = utils.mkMembership({
|
||||
user: userA, mship: "join", room: roomId, event: true,
|
||||
});
|
||||
|
||||
const existingMemberEvent = utils.mkMembership({
|
||||
user: userA, mship: "join", room: roomId, event: true,
|
||||
});
|
||||
|
||||
state.markOutOfBandMembersStarted();
|
||||
state.setStateEvents([existingMemberEvent]);
|
||||
expect(state.getMember(userA).supersedesOutOfBand()).toEqual(true);
|
||||
state.setOutOfBandMembers([oobMemberEvent]);
|
||||
|
||||
const memberA = state.getMember(userA);
|
||||
expect(memberA.events.member.getId()).toEqual(existingMemberEvent.getId());
|
||||
expect(memberA.isOutOfBand()).toEqual(false);
|
||||
expect(memberA.supersedesOutOfBand()).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("clone", function() {
|
||||
@@ -386,20 +348,6 @@ describe("RoomState", function() {
|
||||
expect(state.getJoinedMemberCount()).toEqual(copy.getJoinedMemberCount());
|
||||
});
|
||||
|
||||
it("should copy supersedes flag when OOB loading is progress",
|
||||
function() {
|
||||
// include OOB members in copy
|
||||
state.markOutOfBandMembersStarted();
|
||||
state.setStateEvents([utils.mkMembership({
|
||||
user: userA, mship: "join", room: roomId, event: true,
|
||||
})]);
|
||||
const copy = state.clone();
|
||||
const memberA = state.getMember(userA);
|
||||
const memberACopy = copy.getMember(userA);
|
||||
expect(memberA.supersedesOutOfBand()).toEqual(true);
|
||||
expect(memberACopy.supersedesOutOfBand()).toEqual(true);
|
||||
});
|
||||
|
||||
it("should mark old copy as not waiting for out of band anymore", function() {
|
||||
state.markOutOfBandMembersStarted();
|
||||
const copy = state.clone();
|
||||
|
@@ -44,7 +44,6 @@ const ContentHelpers = require("./content-helpers");
|
||||
|
||||
import ReEmitter from './ReEmitter';
|
||||
import RoomList from './crypto/RoomList';
|
||||
import {InvalidStoreError} from './errors';
|
||||
|
||||
import Crypto from './crypto';
|
||||
import { isCryptoAvailable } from './crypto';
|
||||
@@ -53,16 +52,6 @@ import { isCryptoAvailable } from './crypto';
|
||||
// and need to migrate, but they spam the console with warnings.
|
||||
Promise.config({warnings: false});
|
||||
|
||||
const LAZY_LOADING_MESSAGES_FILTER = {
|
||||
lazy_load_members: true,
|
||||
};
|
||||
|
||||
const LAZY_LOADING_SYNC_FILTER = {
|
||||
room: {
|
||||
state: LAZY_LOADING_MESSAGES_FILTER,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
const SCROLLBACK_DELAY_MS = 3000;
|
||||
const CRYPTO_ENABLED = isCryptoAvailable();
|
||||
@@ -772,6 +761,17 @@ MatrixClient.prototype.getGroups = function() {
|
||||
return this.store.getGroups();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the config for the media repository.
|
||||
* @param {module:client.callback} callback Optional.
|
||||
* @return {module:client.Promise} Resolves with an object containing the config.
|
||||
*/
|
||||
MatrixClient.prototype.getMediaConfig = function(callback) {
|
||||
return this._http.requestWithPrefix(
|
||||
callback, "GET", "/config", undefined, undefined, httpApi.PREFIX_MEDIA_R0,
|
||||
);
|
||||
};
|
||||
|
||||
// Room ops
|
||||
// ========
|
||||
|
||||
@@ -2068,7 +2068,7 @@ MatrixClient.prototype.getEventTimeline = function(timelineSet, eventId) {
|
||||
|
||||
let params = undefined;
|
||||
if (this._clientOpts.lazyLoadMembers) {
|
||||
params = {filter: JSON.stringify(LAZY_LOADING_MESSAGES_FILTER)};
|
||||
params = {filter: JSON.stringify(Filter.LAZY_LOADING_MESSAGES_FILTER)};
|
||||
}
|
||||
|
||||
// TODO: we should implement a backoff (as per scrollback()) to deal more
|
||||
@@ -2149,7 +2149,7 @@ function(roomId, fromToken, limit, dir, timelineFilter = undefined) {
|
||||
if (this._clientOpts.lazyLoadMembers) {
|
||||
// create a shallow copy of LAZY_LOADING_MESSAGES_FILTER,
|
||||
// so the timelineFilter doesn't get written into it below
|
||||
filter = Object.assign({}, LAZY_LOADING_MESSAGES_FILTER);
|
||||
filter = Object.assign({}, Filter.LAZY_LOADING_MESSAGES_FILTER);
|
||||
}
|
||||
if (timelineFilter) {
|
||||
// XXX: it's horrific that /messages' filter parameter doesn't match
|
||||
@@ -3106,29 +3106,6 @@ MatrixClient.prototype.startClient = async function(opts) {
|
||||
// shallow-copy the opts dict before modifying and storing it
|
||||
opts = Object.assign({}, opts);
|
||||
|
||||
if (opts.lazyLoadMembers && this.isGuest()) {
|
||||
opts.lazyLoadMembers = false;
|
||||
}
|
||||
if (opts.lazyLoadMembers) {
|
||||
const supported = await this.doesServerSupportLazyLoading();
|
||||
if (supported) {
|
||||
opts.filter = await this.createFilter(LAZY_LOADING_SYNC_FILTER);
|
||||
} else {
|
||||
console.log("LL: lazy loading requested but not supported " +
|
||||
"by server, so disabling");
|
||||
opts.lazyLoadMembers = false;
|
||||
}
|
||||
}
|
||||
// need to vape the store when enabling LL and wasn't enabled before
|
||||
const shouldClear = await this._wasLazyLoadingToggled(opts.lazyLoadMembers);
|
||||
if (shouldClear) {
|
||||
const reason = InvalidStoreError.TOGGLED_LAZY_LOADING;
|
||||
throw new InvalidStoreError(reason, !!opts.lazyLoadMembers);
|
||||
}
|
||||
if (opts.lazyLoadMembers && this._crypto) {
|
||||
this._crypto.enableLazyLoading();
|
||||
}
|
||||
|
||||
opts.crypto = this._crypto;
|
||||
opts.canResetEntireTimeline = (roomId) => {
|
||||
if (!this._canResetTimelineCallback) {
|
||||
@@ -3137,40 +3114,19 @@ MatrixClient.prototype.startClient = async function(opts) {
|
||||
return this._canResetTimelineCallback(roomId);
|
||||
};
|
||||
this._clientOpts = opts;
|
||||
await this._storeClientOptions(this._clientOpts);
|
||||
this._syncApi = new SyncApi(this, opts);
|
||||
this._syncApi.sync();
|
||||
};
|
||||
|
||||
/**
|
||||
* Is the lazy loading option different than in previous session?
|
||||
* @param {bool} lazyLoadMembers current options for lazy loading
|
||||
* @return {bool} whether or not the option has changed compared to the previous session */
|
||||
MatrixClient.prototype._wasLazyLoadingToggled = async function(lazyLoadMembers) {
|
||||
lazyLoadMembers = !!lazyLoadMembers;
|
||||
// assume it was turned off before
|
||||
// if we don't know any better
|
||||
let lazyLoadMembersBefore = false;
|
||||
const isStoreNewlyCreated = await this.store.isNewlyCreated();
|
||||
if (!isStoreNewlyCreated) {
|
||||
const prevClientOptions = await this.store.getClientOptions();
|
||||
if (prevClientOptions) {
|
||||
lazyLoadMembersBefore = !!prevClientOptions.lazyLoadMembers;
|
||||
}
|
||||
return lazyLoadMembersBefore !== lazyLoadMembers;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* store client options with boolean/string/numeric values
|
||||
* to know in the next session what flags the sync data was
|
||||
* created with (e.g. lazy loading)
|
||||
* @param {object} opts the complete set of client options
|
||||
* @return {Promise} for store operation */
|
||||
MatrixClient.prototype._storeClientOptions = function(opts) {
|
||||
MatrixClient.prototype._storeClientOptions = function() {
|
||||
const primTypes = ["boolean", "string", "number"];
|
||||
const serializableOpts = Object.entries(opts)
|
||||
const serializableOpts = Object.entries(this._clientOpts)
|
||||
.filter(([key, value]) => {
|
||||
return primTypes.includes(typeof value);
|
||||
})
|
||||
|
@@ -92,6 +92,19 @@ export default class IndexedDBCryptoStore {
|
||||
console.log(`connected to indexeddb ${this._dbName}`);
|
||||
resolve(new IndexedDBCryptoStoreBackend.Backend(db));
|
||||
};
|
||||
}).then((backend) => {
|
||||
// Edge has IndexedDB but doesn't support compund keys which we use fairly extensively.
|
||||
// Try a dummy query which will fail if the browser doesn't support compund keys, so
|
||||
// we can fall back to a different backend.
|
||||
return backend.doTxn(
|
||||
'readonly',
|
||||
[IndexedDBCryptoStore.STORE_INBOUND_GROUP_SESSIONS],
|
||||
(txn) => {
|
||||
backend.getEndToEndInboundGroupSession('', '', txn, () => {});
|
||||
}).then(() => {
|
||||
return backend;
|
||||
},
|
||||
);
|
||||
}).catch((e) => {
|
||||
console.warn(
|
||||
`unable to connect to indexeddb ${this._dbName}` +
|
||||
|
@@ -2,7 +2,7 @@
|
||||
// because of http://babeljs.io/docs/usage/caveats/#classes
|
||||
function InvalidStoreError(reason, value) {
|
||||
const message = `Store is invalid because ${reason}, ` +
|
||||
`please delete all data and retry`;
|
||||
`please stop the client, delete all data and start the client again`;
|
||||
const instance = Reflect.construct(Error, [message]);
|
||||
Reflect.setPrototypeOf(instance, Reflect.getPrototypeOf(this));
|
||||
instance.reason = reason;
|
||||
|
@@ -51,6 +51,17 @@ function Filter(userId, filterId) {
|
||||
this.definition = {};
|
||||
}
|
||||
|
||||
Filter.LAZY_LOADING_MESSAGES_FILTER = {
|
||||
lazy_load_members: true,
|
||||
};
|
||||
|
||||
Filter.LAZY_LOADING_SYNC_FILTER = {
|
||||
room: {
|
||||
state: Filter.LAZY_LOADING_MESSAGES_FILTER,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the ID of this filter on your homeserver (if known)
|
||||
* @return {?Number} The filter ID
|
||||
|
@@ -59,7 +59,6 @@ function RoomMember(roomId, userId) {
|
||||
member: null,
|
||||
};
|
||||
this._isOutOfBand = false;
|
||||
this._supersedesOutOfBand = false;
|
||||
this._updateModifiedTime();
|
||||
}
|
||||
utils.inherits(RoomMember, EventEmitter);
|
||||
@@ -80,31 +79,6 @@ RoomMember.prototype.isOutOfBand = function() {
|
||||
return this._isOutOfBand;
|
||||
};
|
||||
|
||||
/**
|
||||
* Does the member supersede an incoming out-of-band
|
||||
* member? If so the out-of-band member should be ignored.
|
||||
* @return {bool}
|
||||
*/
|
||||
RoomMember.prototype.supersedesOutOfBand = function() {
|
||||
return this._supersedesOutOfBand;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mark the member as superseding the future incoming
|
||||
* out-of-band members.
|
||||
*/
|
||||
RoomMember.prototype.markSupersedesOutOfBand = function() {
|
||||
this._supersedesOutOfBand = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear the member superseding the future incoming
|
||||
* out-of-band members, as loading finished or failed.
|
||||
*/
|
||||
RoomMember.prototype.clearSupersedesOutOfBand = function() {
|
||||
this._supersedesOutOfBand = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update this room member's membership event. May fire "RoomMember.name" if
|
||||
* this event updates this member's name.
|
||||
|
@@ -220,8 +220,7 @@ RoomState.prototype.clone = function() {
|
||||
// if loading is in progress (through _oobMemberFlags)
|
||||
// since these are not new members, we're merely copying them
|
||||
// set the status to not started
|
||||
// after copying, we set back the status and
|
||||
// copy the superseding flag from the current state
|
||||
// after copying, we set back the status
|
||||
const status = this._oobMemberFlags.status;
|
||||
this._oobMemberFlags.status = OOB_STATUS_NOTSTARTED;
|
||||
|
||||
@@ -249,14 +248,6 @@ RoomState.prototype.clone = function() {
|
||||
copyMember.markOutOfBand();
|
||||
}
|
||||
});
|
||||
} else if (this._oobMemberFlags.status == OOB_STATUS_INPROGRESS) {
|
||||
// copy markSupersedesOutOfBand flags
|
||||
this.getMembers().forEach((member) => {
|
||||
if (member.supersedesOutOfBand()) {
|
||||
const copyMember = copy.getMember(member.userId);
|
||||
copyMember.markSupersedesOutOfBand();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return copy;
|
||||
@@ -341,11 +332,6 @@ RoomState.prototype.setStateEvents = function(stateEvents) {
|
||||
|
||||
const member = self._getOrCreateMember(userId, event);
|
||||
member.setMembershipEvent(event, self);
|
||||
// if out of band members are loading,
|
||||
// mark the member as more recent
|
||||
if (self._oobMemberFlags.status == OOB_STATUS_INPROGRESS) {
|
||||
member.markSupersedesOutOfBand();
|
||||
}
|
||||
|
||||
self._updateMember(member);
|
||||
self.emit("RoomState.members", event, self, member);
|
||||
@@ -434,12 +420,6 @@ RoomState.prototype.markOutOfBandMembersFailed = function() {
|
||||
if (this._oobMemberFlags.status !== OOB_STATUS_INPROGRESS) {
|
||||
return;
|
||||
}
|
||||
// the request failed, there is nothing to supersede
|
||||
// in case of a retry, these event would not supersede the
|
||||
// retry anymore.
|
||||
this.getMembers().forEach((m) => {
|
||||
m.clearSupersedesOutOfBand();
|
||||
});
|
||||
this._oobMemberFlags.status = OOB_STATUS_NOTSTARTED;
|
||||
};
|
||||
|
||||
@@ -483,27 +463,15 @@ RoomState.prototype._setOutOfBandMember = function(stateEvent) {
|
||||
}
|
||||
const userId = stateEvent.getStateKey();
|
||||
const existingMember = this.getMember(userId);
|
||||
if (existingMember) {
|
||||
const existingMemberEvent = existingMember.events.member;
|
||||
// ignore out of band members with events we are
|
||||
// already aware of.
|
||||
if (existingMemberEvent.getId() === stateEvent.getId()) {
|
||||
return;
|
||||
}
|
||||
// this member was updated since we started
|
||||
// loading the out of band members.
|
||||
// Ignore the out of band member and clear
|
||||
// the "supersedes" flag as the out of members are now loaded
|
||||
if (existingMember.supersedesOutOfBand()) {
|
||||
existingMember.clearSupersedesOutOfBand();
|
||||
return;
|
||||
}
|
||||
// never replace members received as part of the sync
|
||||
if (existingMember && !existingMember.isOutOfBand()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const member = this._getOrCreateMember(userId, stateEvent);
|
||||
member.setMembershipEvent(stateEvent, this);
|
||||
// needed to know which members need to be stored seperately
|
||||
// as the are not part of the sync accumulator
|
||||
// as they are not part of the sync accumulator
|
||||
// this is cleared by setMembershipEvent so when it's updated through /sync
|
||||
member.markOutOfBand();
|
||||
|
||||
|
72
src/sync.js
72
src/sync.js
@@ -33,6 +33,8 @@ const utils = require("./utils");
|
||||
const Filter = require("./filter");
|
||||
const EventTimeline = require("./models/event-timeline");
|
||||
|
||||
import {InvalidStoreError} from './errors';
|
||||
|
||||
const DEBUG = true;
|
||||
|
||||
// /sync requests allow you to set a timeout= but the request may continue
|
||||
@@ -100,6 +102,7 @@ function SyncApi(client, opts) {
|
||||
this._connectionReturnedDefer = null;
|
||||
this._notifEvents = []; // accumulator of sync events in the current sync response
|
||||
this._failedSyncCount = 0; // Number of consecutive failed /sync requests
|
||||
this._storeIsInvalid = false; // flag set if the store needs to be cleared before we can start
|
||||
|
||||
if (client.getNotifTimelineSet()) {
|
||||
client.reEmitter.reEmit(client.getNotifTimelineSet(),
|
||||
@@ -422,6 +425,26 @@ SyncApi.prototype.recoverFromSyncStartupError = async function(savedSyncPromise,
|
||||
await keepaliveProm;
|
||||
};
|
||||
|
||||
/**
|
||||
* Is the lazy loading option different than in previous session?
|
||||
* @param {bool} lazyLoadMembers current options for lazy loading
|
||||
* @return {bool} whether or not the option has changed compared to the previous session */
|
||||
SyncApi.prototype._wasLazyLoadingToggled = async function(lazyLoadMembers) {
|
||||
lazyLoadMembers = !!lazyLoadMembers;
|
||||
// assume it was turned off before
|
||||
// if we don't know any better
|
||||
let lazyLoadMembersBefore = false;
|
||||
const isStoreNewlyCreated = await this.client.store.isNewlyCreated();
|
||||
if (!isStoreNewlyCreated) {
|
||||
const prevClientOptions = await this.client.store.getClientOptions();
|
||||
if (prevClientOptions) {
|
||||
lazyLoadMembersBefore = !!prevClientOptions.lazyLoadMembers;
|
||||
}
|
||||
return lazyLoadMembersBefore !== lazyLoadMembers;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Main entry point
|
||||
*/
|
||||
@@ -444,6 +467,8 @@ SyncApi.prototype.sync = function() {
|
||||
// 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.
|
||||
// 3) We need to check the lazy loading option matches what was used in the
|
||||
// stored sync. If it doesn't, we can't use the stored sync.
|
||||
|
||||
async function getPushRules() {
|
||||
try {
|
||||
@@ -458,9 +483,47 @@ SyncApi.prototype.sync = function() {
|
||||
getPushRules();
|
||||
return;
|
||||
}
|
||||
getFilter(); // Now get the filter and start syncing
|
||||
checkLazyLoadStatus(); // advance to the next stage
|
||||
}
|
||||
|
||||
const checkLazyLoadStatus = async () => {
|
||||
if (this.opts.lazyLoadMembers && client.isGuest()) {
|
||||
this.opts.lazyLoadMembers = false;
|
||||
}
|
||||
if (this.opts.lazyLoadMembers) {
|
||||
const supported = await client.doesServerSupportLazyLoading();
|
||||
if (supported) {
|
||||
this.opts.filter = await client.createFilter(
|
||||
Filter.LAZY_LOADING_SYNC_FILTER,
|
||||
);
|
||||
} else {
|
||||
console.log("LL: lazy loading requested but not supported " +
|
||||
"by server, so disabling");
|
||||
this.opts.lazyLoadMembers = false;
|
||||
}
|
||||
}
|
||||
// need to vape the store when enabling LL and wasn't enabled before
|
||||
const shouldClear = await this._wasLazyLoadingToggled(this.opts.lazyLoadMembers);
|
||||
if (shouldClear) {
|
||||
this._storeIsInvalid = true;
|
||||
const reason = InvalidStoreError.TOGGLED_LAZY_LOADING;
|
||||
const error = new InvalidStoreError(reason, !!this.opts.lazyLoadMembers);
|
||||
this._updateSyncState("ERROR", { error });
|
||||
// bail out of the sync loop now: the app needs to respond to this error.
|
||||
// we leave the state as 'ERROR' which isn't great since this normally means
|
||||
// we're retrying. The client must be stopped before clearing the stores anyway
|
||||
// so the app should stop the client, clear the store and start it again.
|
||||
console.warn("InvalidStoreError: store is not usable: stopping sync.");
|
||||
return;
|
||||
}
|
||||
if (this.opts.lazyLoadMembers && this._crypto) {
|
||||
this.opts.crypto.enableLazyLoading();
|
||||
}
|
||||
await this.client._storeClientOptions();
|
||||
|
||||
getFilter(); // Now get the filter and start syncing
|
||||
};
|
||||
|
||||
async function getFilter() {
|
||||
let filter;
|
||||
if (self.opts.filter) {
|
||||
@@ -588,7 +651,12 @@ SyncApi.prototype._syncFromCache = async function(savedSync) {
|
||||
console.error("Error processing cached sync", e.stack || e);
|
||||
}
|
||||
|
||||
this._updateSyncState("PREPARED", syncEventData);
|
||||
// Don't emit a prepared if we've bailed because the store is invalid:
|
||||
// in this case the client will not be usable until stopped & restarted
|
||||
// so this would be useless and misleading.
|
||||
if (!this._storeIsInvalid) {
|
||||
this._updateSyncState("PREPARED", syncEventData);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user