From 58a68106bc769502e21d27d43100ed6bd660d314 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 18 Jul 2016 01:40:05 +0100 Subject: [PATCH 1/4] generic account data support --- lib/client.js | 61 ++++++++++++++++++++++++++++++++------------- lib/store/memory.js | 24 +++++++++++++++++- lib/store/stub.js | 18 ++++++++++++- lib/sync.js | 14 ++++++++++- 4 files changed, 96 insertions(+), 21 deletions(-) diff --git a/lib/client.js b/lib/client.js index ea0a67720..36a23e63c 100644 --- a/lib/client.js +++ b/lib/client.js @@ -903,6 +903,37 @@ MatrixClient.prototype.getUsers = function() { return this.store.getUsers(); }; +// User Account Data operations +// ============================ + +/** + * Set account data event for the current user. + * @param {string} eventType The event type + * @param {Object} the contents object for the event + * @param {module:client.callback} callback Optional. + * @return {module:client.Promise} Resolves: TODO + * @return {module:http-api.MatrixError} Rejects: with an error response. + */ +MatrixClient.prototype.setAccountData = function(eventType, contents, callback) { + var path = utils.encodeUri("/user/$userId/account_data/$type", { + $userId: this.credentials.userId, + $type: eventType, + }); + return this._http.authedRequest( + callback, "PUT", path, undefined, contents + ); +}; + +/** + * Get account data event of given type for the current user. + * @param {string} eventType The event type + * @param {module:client.callback} callback Optional. + * @return {?object} The contents of the given account data event + */ +MatrixClient.prototype.getAccountData = function(eventType) { + return this.store.getAccountData(eventType); +}; + // Room operations // =============== @@ -1086,23 +1117,6 @@ MatrixClient.prototype.deleteRoomTag = function(roomId, tagName, callback) { ); }; -/** - * @param {string} eventType event type to be set - * @param {object} content event content - * @param {module:client.callback} callback Optional. - * @return {module:client.Promise} Resolves: TODO - * @return {module:http-api.MatrixError} Rejects: with an error response. - */ -MatrixClient.prototype.setAccountData = function(eventType, content, callback) { - var path = utils.encodeUri("/user/$userId/account_data/$type", { - $userId: this.credentials.userId, - $type: eventType, - }); - return this._http.authedRequest( - callback, "PUT", path, undefined, content - ); -}; - /** * @param {string} roomId * @param {string} eventType event type to be set @@ -3991,7 +4005,7 @@ module.exports.CRYPTO_ENABLED = CRYPTO_ENABLED; * }); */ - /** +/** * Fires when a device is marked as verified/unverified/blocked/unblocked by * {@link module:client~MatrixClient#setDeviceVerified|MatrixClient.setDeviceVerified} or * {@link module:client~MatrixClient#setDeviceBlocked|MatrixClient.setDeviceBlocked}. @@ -4001,6 +4015,17 @@ module.exports.CRYPTO_ENABLED = CRYPTO_ENABLED; * @param {module:client~DeviceInfo} device information about the verified device */ +/** + * Fires whenever new user-scoped account_data is added. + * @event module:client~MatrixClient#"Room" + * @param {MatrixEvent} event The event describing the account_data just added + * @example + * matrixClient.on("accountData", function(event){ + * myAccountData[event.type] = event.content; + * }); + */ + + // EventEmitter JSDocs /** diff --git a/lib/store/memory.js b/lib/store/memory.js index af8e5392c..9db001fe7 100644 --- a/lib/store/memory.js +++ b/lib/store/memory.js @@ -43,6 +43,9 @@ module.exports.MatrixInMemoryStore = function MatrixInMemoryStore(opts) { // filterId: Filter // } }; + this.accountData = { + // type : content + }; this.localStorage = opts.localStorage; }; @@ -244,7 +247,26 @@ module.exports.MatrixInMemoryStore.prototype = { this.localStorage.setItem("mxjssdk_memory_filter_" + filterName, filterId); } catch (e) {} - } + }, + + /** + * Store user-scoped account data events + * @param {Array} events The events to store. + */ + storeAccountDataEvents: function(events) { + var self = this; + events.forEach(function(event) { + self.accountData[event.type] = event.content; + }); + }, + + /** + * Get account data event by event type + * @param {string} eventType The event type being queried + */ + getAccountData: function(eventType) { + return this.accountData[eventType]; + }, // TODO //setMaxHistoryPerRoom: function(maxHistory) {}, diff --git a/lib/store/stub.js b/lib/store/stub.js index 41fa7a25f..c635c93f6 100644 --- a/lib/store/stub.js +++ b/lib/store/stub.js @@ -162,7 +162,23 @@ StubStore.prototype = { */ setFilterIdByName: function(filterName, filterId) { - } + }, + + /** + * Store user-scoped account data events + * @param {Array} events The events to store. + */ + storeAccountDataEvents: function(events) { + + }, + + /** + * Get account data event by event type + * @param {string} eventType The event type being queried + */ + getAccountData: function(eventType) { + + }, // TODO //setMaxHistoryPerRoom: function(maxHistory) {}, diff --git a/lib/sync.js b/lib/sync.js index 0d34f3fa8..76741eeed 100644 --- a/lib/sync.js +++ b/lib/sync.js @@ -605,7 +605,19 @@ SyncApi.prototype._processSyncResponse = function(syncToken, data) { }); } - // the returned json structure is abit crap, so make it into a + // handle non-room account_data + if (data.account_data && utils.isArray(data.account_data.events)) { + client.store.storeAccountDataEvents( + data.account_data.events.map(client.getEventMapper()).map( + function(accountDataEvent) { + client.emit("accountData", accountDataEvent); + return accountDataEvent; + } + ) + ); + } + + // the returned json structure is a bit crap, so make it into a // nicer form (array) after applying sanity to make sure we don't fail // on missing keys (on the off chance) var inviteRooms = []; From fa28297add5c2c8cc86fcfd059e3e26090ea5907 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 20 Jul 2016 10:17:54 +0100 Subject: [PATCH 2/4] thinkos --- lib/store/memory.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/store/memory.js b/lib/store/memory.js index 9db001fe7..311478d74 100644 --- a/lib/store/memory.js +++ b/lib/store/memory.js @@ -256,13 +256,14 @@ module.exports.MatrixInMemoryStore.prototype = { storeAccountDataEvents: function(events) { var self = this; events.forEach(function(event) { - self.accountData[event.type] = event.content; + self.accountData[event.getType()] = event; }); }, /** * Get account data event by event type * @param {string} eventType The event type being queried + * @return {MatrixEvent} the user account_data event of given type */ getAccountData: function(eventType) { return this.accountData[eventType]; From c00a830cbb528fbef7e36013d43292663515c4bc Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 20 Jul 2016 11:59:38 +0100 Subject: [PATCH 3/4] fix nightmare bug where Room.accountData wasn't being emitted by Room objects --- lib/sync.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/sync.js b/lib/sync.js index 76741eeed..f7c6e98ea 100644 --- a/lib/sync.js +++ b/lib/sync.js @@ -88,6 +88,7 @@ SyncApi.prototype.createRoom = function(roomId) { "Room.receipt", "Room.tags", "Room.timelineReset", "Room.localEchoUpdated", + "Room.accountData", ]); this._registerStateListeners(room); return room; From 1412646a55a1828dd436e3795f5238894b8fa82c Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 20 Jul 2016 15:40:58 +0100 Subject: [PATCH 4/4] fix review feedback --- lib/client.js | 2 +- lib/store/memory.js | 6 ++++-- lib/sync.js | 14 +++++++------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/client.js b/lib/client.js index 36a23e63c..c257edffb 100644 --- a/lib/client.js +++ b/lib/client.js @@ -909,7 +909,7 @@ MatrixClient.prototype.getUsers = function() { /** * Set account data event for the current user. * @param {string} eventType The event type - * @param {Object} the contents object for the event + * @param {Object} content the contents object for the event * @param {module:client.callback} callback Optional. * @return {module:client.Promise} Resolves: TODO * @return {module:http-api.MatrixError} Rejects: with an error response. diff --git a/lib/store/memory.js b/lib/store/memory.js index 311478d74..26a397817 100644 --- a/lib/store/memory.js +++ b/lib/store/memory.js @@ -250,7 +250,9 @@ module.exports.MatrixInMemoryStore.prototype = { }, /** - * Store user-scoped account data events + * Store user-scoped account data events. + * N.B. that account data only allows a single event per type, so multiple + * events with the same type will replace each other. * @param {Array} events The events to store. */ storeAccountDataEvents: function(events) { @@ -263,7 +265,7 @@ module.exports.MatrixInMemoryStore.prototype = { /** * Get account data event by event type * @param {string} eventType The event type being queried - * @return {MatrixEvent} the user account_data event of given type + * @return {?MatrixEvent} the user account_data event of given type, if any */ getAccountData: function(eventType) { return this.accountData[eventType]; diff --git a/lib/sync.js b/lib/sync.js index f7c6e98ea..24c77a2ca 100644 --- a/lib/sync.js +++ b/lib/sync.js @@ -608,13 +608,13 @@ SyncApi.prototype._processSyncResponse = function(syncToken, data) { // handle non-room account_data if (data.account_data && utils.isArray(data.account_data.events)) { - client.store.storeAccountDataEvents( - data.account_data.events.map(client.getEventMapper()).map( - function(accountDataEvent) { - client.emit("accountData", accountDataEvent); - return accountDataEvent; - } - ) + var events = data.account_data.events.map(client.getEventMapper()); + client.store.storeAccountDataEvents(events); + events.forEach( + function(accountDataEvent) { + client.emit("accountData", accountDataEvent); + return accountDataEvent; + } ); }