diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f16b237f..0109bee4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,35 @@ +Changes in [0.7.12](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.7.12) (2017-06-19) +================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.7.12-rc.1...v0.7.12) + + * No changes + + +Changes in [0.7.12-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.7.12-rc.1) (2017-06-15) +============================================================================================================ +[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.7.11...v0.7.12-rc.1) + + * allow setting iceTransportPolicy to relay through forceTURN option + [\#462](https://github.com/matrix-org/matrix-js-sdk/pull/462) + +Changes in [0.7.11](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.7.11) (2017-06-12) +================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.7.11-rc.1...v0.7.11) + + * Add a bunch of logging around sending messages + [\#460](https://github.com/matrix-org/matrix-js-sdk/pull/460) + +Changes in [0.7.11-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.7.11-rc.1) (2017-06-09) +============================================================================================================ +[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.7.10...v0.7.11-rc.1) + + * Make TimelineWindow.load resolve quicker if we have the events + [\#458](https://github.com/matrix-org/matrix-js-sdk/pull/458) + * Stop peeking when a matrix client is stopped + [\#451](https://github.com/matrix-org/matrix-js-sdk/pull/451) + * Update README: Clarify how to install libolm + [\#450](https://github.com/matrix-org/matrix-js-sdk/pull/450) + Changes in [0.7.10](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.7.10) (2017-06-02) ================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.7.9...v0.7.10) diff --git a/package.json b/package.json index da27fa5a5..5e004136c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-js-sdk", - "version": "0.7.10", + "version": "0.7.12", "description": "Matrix Client-Server SDK for Javascript", "main": "index.js", "scripts": { diff --git a/src/base-apis.js b/src/base-apis.js index 671ddcb01..35ef0938c 100644 --- a/src/base-apis.js +++ b/src/base-apis.js @@ -678,6 +678,31 @@ MatrixBaseApis.prototype.setRoomDirectoryVisibilityAppService = ); }; +// User Directory Operations +// ========================= + +/** + * Query the user directory with a term matching user IDs, display names and domains. + * @param {object} opts options + * @param {string} opts.term the term with which to search. + * @param {number} opts.limit the maximum number of results to return. The server will + * apply a limit if unspecified. + * @return {module:client.Promise} Resolves: an array of results. + */ +MatrixBaseApis.prototype.searchUserDirectory = function(opts) { + const body = { + search_term: opts.term, + }; + + if (opts.limit !== undefined) { + body.limit = opts.limit; + } + + return this._http.authedRequest( + undefined, "POST", "/user_directory/search", undefined, body, + ); +}; + // Media operations // ================ diff --git a/src/client.js b/src/client.js index cb3b16951..b3f7f2b9d 100644 --- a/src/client.js +++ b/src/client.js @@ -947,6 +947,8 @@ MatrixClient.prototype.sendEvent = function(roomId, eventType, content, txnId, txnId = this.makeTxnId(); } + console.log(`sendEvent of type ${eventType} in ${roomId} with txnId ${txnId}`); + // we always construct a MatrixEvent when sending because the store and // scheduler use them. We'll extract the params back out if it turns out // the client has no scheduler or store. @@ -1071,7 +1073,12 @@ function _sendEventHttpRequest(client, event) { return client._http.authedRequest( undefined, "PUT", path, undefined, event.getWireContent(), - ); + ).then((res) => { + console.log( + `Event sent to ${event.getRoomId()} with event id ${res.event_id}`, + ); + return res; + }); } /** diff --git a/src/crypto/DeviceList.js b/src/crypto/DeviceList.js index e3d55e318..2b608475b 100644 --- a/src/crypto/DeviceList.js +++ b/src/crypto/DeviceList.js @@ -76,6 +76,10 @@ export default class DeviceList { if (this._keyDownloadsInProgressByUser[u]) { // already a key download in progress/queued for this user; its results // will be good enough for us. + console.log( + `downloadKeys: already have a download in progress for ` + + `${u}: awaiting its result`, + ); promises.push(this._keyDownloadsInProgressByUser[u]); } else if (forceDownload || trackingStatus != TRACKING_STATUS_UP_TO_DATE) { usersToDownload.push(u); @@ -88,6 +92,10 @@ export default class DeviceList { promises.push(downloadPromise); } + if (promises.length === 0) { + console.log("downloadKeys: already have all necessary keys"); + } + return q.all(promises).then(() => { return this._getDevicesFromStore(userIds); }); diff --git a/src/crypto/algorithms/megolm.js b/src/crypto/algorithms/megolm.js index c6add41f2..697ffded8 100644 --- a/src/crypto/algorithms/megolm.js +++ b/src/crypto/algorithms/megolm.js @@ -183,6 +183,7 @@ MegolmEncryption.prototype._ensureOutboundSession = function(devicesInRoom) { } if (!session) { + console.log(`Starting new megolm session for room ${self._roomId}`); session = self._prepareNewSession(); } @@ -353,6 +354,8 @@ MegolmEncryption.prototype._shareKeyWithDevices = function(session, devicesByUse // TODO: retries return self._baseApis.sendToDevice("m.room.encrypted", contentMap); }).then(function() { + console.log(`Completed megolm keyshare in ${self._roomId}`); + // Add the devices we have shared with to session.sharedWithDevices. // // we deliberately iterate over devicesByUser (ie, the devices we @@ -387,6 +390,8 @@ MegolmEncryption.prototype._shareKeyWithDevices = function(session, devicesByUse */ MegolmEncryption.prototype.encryptMessage = function(room, eventType, content) { const self = this; + console.log(`Starting to encrypt event for ${this._roomId}`); + return this._getDevicesInRoom(room).then(function(devicesInRoom) { // check if any of these devices are not yet known to the user. // if so, warn the user so they can verify or ignore. diff --git a/src/models/room.js b/src/models/room.js index 1d0d7d97f..a1f88cd7c 100644 --- a/src/models/room.js +++ b/src/models/room.js @@ -752,6 +752,8 @@ ALLOWED_TRANSITIONS[EventStatus.CANCELLED] = * @fires module:client~MatrixClient#event:"Room.localEchoUpdated" */ Room.prototype.updatePendingEvent = function(event, newStatus, newEventId) { + console.log(`setting pendingEvent status to ${newStatus} in ${event.getRoomId()}`); + // if the message was sent, we expect an event id if (newStatus == EventStatus.SENT && !newEventId) { throw new Error("updatePendingEvent called with status=SENT, " + diff --git a/src/store/indexeddb-local-backend.js b/src/store/indexeddb-local-backend.js index 7f87c5739..ccf330d96 100644 --- a/src/store/indexeddb-local-backend.js +++ b/src/store/indexeddb-local-backend.js @@ -163,8 +163,27 @@ LocalIndexedDBStoreBackend.prototype = { * @return {Promise} Resolved when the database is cleared. */ clearDatabase: function() { - console.log("Removing indexeddb instance: ", this._dbName); - return promiseifyRequest(this.indexedDB.deleteDatabase(this._dbName)); + return new q.Promise((resolve, reject) => { + console.log(`Removing indexeddb instance: ${this._dbName}`); + const req = this.indexedDB.deleteDatabase(this._dbName); + + req.onblocked = () => { + reject(new Error( + "unable to delete indexeddb because it is open elsewhere", + )); + }; + + req.onerror = (ev) => { + reject(new Error( + "unable to delete indexeddb: " + ev.target.error, + )); + }; + + req.onsuccess = () => { + console.log(`Removed indexeddb instance: ${this._dbName}`); + resolve(); + }; + }); }, /** diff --git a/src/store/indexeddb.js b/src/store/indexeddb.js index e2172dcb7..d1387eb50 100644 --- a/src/store/indexeddb.js +++ b/src/store/indexeddb.js @@ -150,7 +150,7 @@ IndexedDBStore.prototype.deleteAllData = function() { return this.backend.clearDatabase().then(() => { console.log("Deleted indexeddb data."); }, (err) => { - console.error("Failed to delete indexeddb data: ", err); + console.error(`Failed to delete indexeddb data: ${err}`); throw err; }); }; diff --git a/src/timeline-window.js b/src/timeline-window.js index 523f8fcda..b68190cea 100644 --- a/src/timeline-window.js +++ b/src/timeline-window.js @@ -95,10 +95,30 @@ TimelineWindow.prototype.load = function(initialEventId, initialWindowSize) { const self = this; initialWindowSize = initialWindowSize || 20; - // given an EventTimeline, and an event index within it, initialise our + // given an EventTimeline, find the event we were looking for, and initialise our // fields so that the event in question is in the middle of the window. - const initFields = function(timeline, eventIndex) { - const endIndex = Math.min(timeline.getEvents().length, + const initFields = function(timeline) { + let eventIndex; + + const events = timeline.getEvents(); + + if (!initialEventId) { + // we were looking for the live timeline: initialise to the end + eventIndex = events.length; + } else { + for (let i = 0; i < events.length; i++) { + if (events[i].getId() == initialEventId) { + eventIndex = i; + break; + } + } + + if (eventIndex === undefined) { + throw new Error("getEventTimeline result didn't include requested event"); + } + } + + const endIndex = Math.min(events.length, eventIndex + Math.ceil(initialWindowSize / 2)); const startIndex = Math.max(0, endIndex - initialWindowSize); self._start = new TimelineIndex(timeline, startIndex - timeline.getBaseIndex()); @@ -110,24 +130,19 @@ TimelineWindow.prototype.load = function(initialEventId, initialWindowSize) { // we already have the data we need, which is important to keep room-switching // feeling snappy. // - // TODO: ideally we'd spot getEventTimeline returning a resolved promise and - // skip straight to the find-event loop. if (initialEventId) { - return this._client.getEventTimeline(this._timelineSet, initialEventId) - .then(function(tl) { - // make sure that our window includes the event - for (let i = 0; i < tl.getEvents().length; i++) { - if (tl.getEvents()[i].getId() == initialEventId) { - initFields(tl, i); - return; - } - } - throw new Error("getEventTimeline result didn't include requested event"); - }); + const prom = this._client.getEventTimeline(this._timelineSet, initialEventId); + + const promState = prom.inspect(); + if (promState.state == 'fulfilled') { + initFields(promState.value); + return q(); + } else { + return prom.then(initFields); + } } else { - // start with the most recent events const tl = this._timelineSet.getLiveTimeline(); - initFields(tl, tl.getEvents().length); + initFields(tl); return q(); } }; diff --git a/src/webrtc/call.js b/src/webrtc/call.js index 6ae945e5f..a44e18ad6 100644 --- a/src/webrtc/call.js +++ b/src/webrtc/call.js @@ -71,6 +71,7 @@ const DEBUG = true; // set true to enable console logging. * @param {Object} opts Config options. * @param {string} opts.roomId The room ID for this call. * @param {Object} opts.webRtc The WebRTC globals from the browser. + * @param {boolean} opts.forceTURN whether relay through TURN should be forced. * @param {Object} opts.URL The URL global. * @param {Array} opts.turnServers Optional. A list of TURN servers. * @param {MatrixClient} opts.client The Matrix Client instance to send events to. @@ -79,6 +80,7 @@ function MatrixCall(opts) { this.roomId = opts.roomId; this.client = opts.client; this.webRtc = opts.webRtc; + this.forceTURN = opts.forceTURN; this.URL = opts.URL; // Array of Objects with urls, username, credential keys this.turnServers = opts.turnServers || []; @@ -1184,6 +1186,7 @@ const _createPeerConnection = function(self) { } const pc = new self.webRtc.RtcPeerConnection({ + iceTransportPolicy: self.forceTURN ? 'relay' : undefined, iceServers: servers, }); pc.oniceconnectionstatechange = hookCallback(self, self._onIceConnectionStateChanged); @@ -1293,9 +1296,11 @@ module.exports.setVideoInput = function(deviceId) { videoInput = deviceId; }; * Create a new Matrix call for the browser. * @param {MatrixClient} client The client instance to use. * @param {string} roomId The room the call is in. + * @param {Object?} options optional options map. + * @param {boolean} options.forceTURN whether relay through TURN should be forced. * @return {MatrixCall} the call or null if the browser doesn't support calling. */ -module.exports.createNewMatrixCall = function(client, roomId) { +module.exports.createNewMatrixCall = function(client, roomId, options) { const w = global.window; const doc = global.document; if (!w || !doc) { @@ -1351,6 +1356,8 @@ module.exports.createNewMatrixCall = function(client, roomId) { URL: w.URL, roomId: roomId, turnServers: client.getTurnServers(), + // call level options + forceTURN: options ? options.forceTURN : false, }; return new MatrixCall(opts); };