Merge pull request #1709 from matrix-org/luke/fix-group-store-redundant-requests
Fix group store redundant requests
This commit is contained in:
commit
bd81ed6587
1 changed files with 85 additions and 69 deletions
|
@ -19,6 +19,14 @@ import { groupMemberFromApiObject, groupRoomFromApiObject } from '../groups';
|
||||||
import FlairStore from './FlairStore';
|
import FlairStore from './FlairStore';
|
||||||
import MatrixClientPeg from '../MatrixClientPeg';
|
import MatrixClientPeg from '../MatrixClientPeg';
|
||||||
|
|
||||||
|
function parseMembersResponse(response) {
|
||||||
|
return response.chunk.map((apiMember) => groupMemberFromApiObject(apiMember));
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseRoomsResponse(response) {
|
||||||
|
return response.chunk.map((apiRoom) => groupRoomFromApiObject(apiRoom));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the group summary for a room and provides an API to change it and
|
* Stores the group summary for a room and provides an API to change it and
|
||||||
* other useful group APIs that may have an effect on the group summary.
|
* other useful group APIs that may have an effect on the group summary.
|
||||||
|
@ -38,65 +46,68 @@ export default class GroupStore extends EventEmitter {
|
||||||
throw new Error('GroupStore needs a valid groupId to be created');
|
throw new Error('GroupStore needs a valid groupId to be created');
|
||||||
}
|
}
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
this._summary = {};
|
this._state = {};
|
||||||
this._rooms = [];
|
this._state[GroupStore.STATE_KEY.Summary] = {};
|
||||||
this._members = [];
|
this._state[GroupStore.STATE_KEY.GroupRooms] = [];
|
||||||
this._invitedMembers = [];
|
this._state[GroupStore.STATE_KEY.GroupMembers] = [];
|
||||||
|
this._state[GroupStore.STATE_KEY.GroupInvitedMembers] = [];
|
||||||
this._ready = {};
|
this._ready = {};
|
||||||
|
|
||||||
|
this._fetchResourcePromise = {};
|
||||||
|
this._resourceFetcher = {
|
||||||
|
[GroupStore.STATE_KEY.Summary]: () => {
|
||||||
|
return MatrixClientPeg.get()
|
||||||
|
.getGroupSummary(this.groupId);
|
||||||
|
},
|
||||||
|
[GroupStore.STATE_KEY.GroupRooms]: () => {
|
||||||
|
return MatrixClientPeg.get()
|
||||||
|
.getGroupRooms(this.groupId)
|
||||||
|
.then(parseRoomsResponse);
|
||||||
|
},
|
||||||
|
[GroupStore.STATE_KEY.GroupMembers]: () => {
|
||||||
|
return MatrixClientPeg.get()
|
||||||
|
.getGroupUsers(this.groupId)
|
||||||
|
.then(parseMembersResponse);
|
||||||
|
},
|
||||||
|
[GroupStore.STATE_KEY.GroupInvitedMembers]: () => {
|
||||||
|
return MatrixClientPeg.get()
|
||||||
|
.getGroupInvitedUsers(this.groupId)
|
||||||
|
.then(parseMembersResponse);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
this.on('error', (err) => {
|
this.on('error', (err) => {
|
||||||
console.error(`GroupStore for ${this.groupId} encountered error`, err);
|
console.error(`GroupStore for ${this.groupId} encountered error`, err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_fetchMembers() {
|
_fetchResource(stateKey) {
|
||||||
MatrixClientPeg.get().getGroupUsers(this.groupId).then((result) => {
|
// Ongoing request, ignore
|
||||||
this._members = result.chunk.map((apiMember) => {
|
if (this._fetchResourcePromise[stateKey]) return;
|
||||||
return groupMemberFromApiObject(apiMember);
|
|
||||||
});
|
|
||||||
this._ready[GroupStore.STATE_KEY.GroupMembers] = true;
|
|
||||||
this._notifyListeners();
|
|
||||||
}).catch((err) => {
|
|
||||||
console.error("Failed to get group member list: " + err);
|
|
||||||
this.emit('error', err);
|
|
||||||
});
|
|
||||||
|
|
||||||
MatrixClientPeg.get().getGroupInvitedUsers(this.groupId).then((result) => {
|
const clientPromise = this._resourceFetcher[stateKey]();
|
||||||
this._invitedMembers = result.chunk.map((apiMember) => {
|
|
||||||
return groupMemberFromApiObject(apiMember);
|
// Indicate ongoing request
|
||||||
});
|
this._fetchResourcePromise[stateKey] = clientPromise;
|
||||||
this._ready[GroupStore.STATE_KEY.GroupInvitedMembers] = true;
|
|
||||||
|
clientPromise.then((result) => {
|
||||||
|
this._state[stateKey] = result;
|
||||||
|
this._ready[stateKey] = true;
|
||||||
this._notifyListeners();
|
this._notifyListeners();
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
// Invited users not visible to non-members
|
// Invited users not visible to non-members
|
||||||
if (err.httpStatus === 403) {
|
if (stateKey === GroupStore.STATE_KEY.GroupInvitedMembers && err.httpStatus === 403) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.error("Failed to get group invited member list: " + err);
|
|
||||||
this.emit('error', err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_fetchSummary() {
|
console.error("Failed to get resource " + stateKey + ":" + err);
|
||||||
MatrixClientPeg.get().getGroupSummary(this.groupId).then((resp) => {
|
|
||||||
this._summary = resp;
|
|
||||||
this._ready[GroupStore.STATE_KEY.Summary] = true;
|
|
||||||
this._notifyListeners();
|
|
||||||
}).catch((err) => {
|
|
||||||
this.emit('error', err);
|
this.emit('error', err);
|
||||||
|
}).finally(() => {
|
||||||
|
// Indicate finished request, allow for future fetches
|
||||||
|
delete this._fetchResourcePromise[stateKey];
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
_fetchRooms() {
|
return clientPromise;
|
||||||
MatrixClientPeg.get().getGroupRooms(this.groupId).then((resp) => {
|
|
||||||
this._rooms = resp.chunk.map((apiRoom) => {
|
|
||||||
return groupRoomFromApiObject(apiRoom);
|
|
||||||
});
|
|
||||||
this._ready[GroupStore.STATE_KEY.GroupRooms] = true;
|
|
||||||
this._notifyListeners();
|
|
||||||
}).catch((err) => {
|
|
||||||
this.emit('error', err);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_notifyListeners() {
|
_notifyListeners() {
|
||||||
|
@ -108,10 +119,9 @@ export default class GroupStore extends EventEmitter {
|
||||||
* immediately triggers an update to send the current state of the
|
* immediately triggers an update to send the current state of the
|
||||||
* store (which could be the initial state).
|
* store (which could be the initial state).
|
||||||
*
|
*
|
||||||
* XXX: This also causes a fetch of all group data, which effectively
|
* This also causes a fetch of all group data, which might cause
|
||||||
* causes 4 separate HTTP requests. This is bad, we should at least
|
* 4 separate HTTP requests, but only said requests aren't already
|
||||||
* deduplicate these in order to fix:
|
* ongoing.
|
||||||
* https://github.com/vector-im/riot-web/issues/5901
|
|
||||||
*
|
*
|
||||||
* @param {function} fn the function to call when the store updates.
|
* @param {function} fn the function to call when the store updates.
|
||||||
* @return {Object} tok a registration "token" with a single
|
* @return {Object} tok a registration "token" with a single
|
||||||
|
@ -123,9 +133,11 @@ export default class GroupStore extends EventEmitter {
|
||||||
this.on('update', fn);
|
this.on('update', fn);
|
||||||
// Call to set initial state (before fetching starts)
|
// Call to set initial state (before fetching starts)
|
||||||
this.emit('update');
|
this.emit('update');
|
||||||
this._fetchSummary();
|
|
||||||
this._fetchRooms();
|
this._fetchResource(GroupStore.STATE_KEY.Summary);
|
||||||
this._fetchMembers();
|
this._fetchResource(GroupStore.STATE_KEY.GroupRooms);
|
||||||
|
this._fetchResource(GroupStore.STATE_KEY.GroupMembers);
|
||||||
|
this._fetchResource(GroupStore.STATE_KEY.GroupInvitedMembers);
|
||||||
|
|
||||||
// Similar to the Store of flux/utils, we return a "token" that
|
// Similar to the Store of flux/utils, we return a "token" that
|
||||||
// can be used to unregister the listener.
|
// can be used to unregister the listener.
|
||||||
|
@ -145,90 +157,94 @@ export default class GroupStore extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
getSummary() {
|
getSummary() {
|
||||||
return this._summary;
|
return this._state[GroupStore.STATE_KEY.Summary];
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupRooms() {
|
getGroupRooms() {
|
||||||
return this._rooms;
|
return this._state[GroupStore.STATE_KEY.GroupRooms];
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupMembers( ) {
|
getGroupMembers() {
|
||||||
return this._members;
|
return this._state[GroupStore.STATE_KEY.GroupMembers];
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupInvitedMembers( ) {
|
getGroupInvitedMembers() {
|
||||||
return this._invitedMembers;
|
return this._state[GroupStore.STATE_KEY.GroupInvitedMembers];
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupPublicity() {
|
getGroupPublicity() {
|
||||||
return this._summary.user ? this._summary.user.is_publicised : null;
|
return this._state[GroupStore.STATE_KEY.Summary].user ?
|
||||||
|
this._state[GroupStore.STATE_KEY.Summary].user.is_publicised : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
isUserPrivileged() {
|
isUserPrivileged() {
|
||||||
return this._summary.user ? this._summary.user.is_privileged : null;
|
return this._state[GroupStore.STATE_KEY.Summary].user ?
|
||||||
|
this._state[GroupStore.STATE_KEY.Summary].user.is_privileged : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
addRoomToGroup(roomId, isPublic) {
|
addRoomToGroup(roomId, isPublic) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.addRoomToGroup(this.groupId, roomId, isPublic)
|
.addRoomToGroup(this.groupId, roomId, isPublic)
|
||||||
.then(this._fetchRooms.bind(this));
|
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupRooms));
|
||||||
}
|
}
|
||||||
|
|
||||||
updateGroupRoomVisibility(roomId, isPublic) {
|
updateGroupRoomVisibility(roomId, isPublic) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.updateGroupRoomVisibility(this.groupId, roomId, isPublic)
|
.updateGroupRoomVisibility(this.groupId, roomId, isPublic)
|
||||||
.then(this._fetchRooms.bind(this));
|
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupRooms));
|
||||||
}
|
}
|
||||||
|
|
||||||
removeRoomFromGroup(roomId) {
|
removeRoomFromGroup(roomId) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.removeRoomFromGroup(this.groupId, roomId)
|
.removeRoomFromGroup(this.groupId, roomId)
|
||||||
// Room might be in the summary, refresh just in case
|
// Room might be in the summary, refresh just in case
|
||||||
.then(this._fetchSummary.bind(this))
|
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.Summary))
|
||||||
.then(this._fetchRooms.bind(this));
|
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupRooms));
|
||||||
}
|
}
|
||||||
|
|
||||||
inviteUserToGroup(userId) {
|
inviteUserToGroup(userId) {
|
||||||
return MatrixClientPeg.get().inviteUserToGroup(this.groupId, userId)
|
return MatrixClientPeg.get().inviteUserToGroup(this.groupId, userId)
|
||||||
.then(this._fetchMembers.bind(this));
|
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupInvitedMembers));
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptGroupInvite() {
|
acceptGroupInvite() {
|
||||||
return MatrixClientPeg.get().acceptGroupInvite(this.groupId)
|
return MatrixClientPeg.get().acceptGroupInvite(this.groupId)
|
||||||
// The user might be able to see more rooms now
|
// The user might be able to see more rooms now
|
||||||
.then(this._fetchRooms.bind(this))
|
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupRooms))
|
||||||
// The user should now appear as a member
|
// The user should now appear as a member
|
||||||
.then(this._fetchMembers.bind(this));
|
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupMembers))
|
||||||
|
// The user should now not appear as an invited member
|
||||||
|
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupInvitedMembers));
|
||||||
}
|
}
|
||||||
|
|
||||||
addRoomToGroupSummary(roomId, categoryId) {
|
addRoomToGroupSummary(roomId, categoryId) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.addRoomToGroupSummary(this.groupId, roomId, categoryId)
|
.addRoomToGroupSummary(this.groupId, roomId, categoryId)
|
||||||
.then(this._fetchSummary.bind(this));
|
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.Summary));
|
||||||
}
|
}
|
||||||
|
|
||||||
addUserToGroupSummary(userId, roleId) {
|
addUserToGroupSummary(userId, roleId) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.addUserToGroupSummary(this.groupId, userId, roleId)
|
.addUserToGroupSummary(this.groupId, userId, roleId)
|
||||||
.then(this._fetchSummary.bind(this));
|
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.Summary));
|
||||||
}
|
}
|
||||||
|
|
||||||
removeRoomFromGroupSummary(roomId) {
|
removeRoomFromGroupSummary(roomId) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.removeRoomFromGroupSummary(this.groupId, roomId)
|
.removeRoomFromGroupSummary(this.groupId, roomId)
|
||||||
.then(this._fetchSummary.bind(this));
|
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.Summary));
|
||||||
}
|
}
|
||||||
|
|
||||||
removeUserFromGroupSummary(userId) {
|
removeUserFromGroupSummary(userId) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.removeUserFromGroupSummary(this.groupId, userId)
|
.removeUserFromGroupSummary(this.groupId, userId)
|
||||||
.then(this._fetchSummary.bind(this));
|
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.Summary));
|
||||||
}
|
}
|
||||||
|
|
||||||
setGroupPublicity(isPublished) {
|
setGroupPublicity(isPublished) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.setGroupPublicity(this.groupId, isPublished)
|
.setGroupPublicity(this.groupId, isPublished)
|
||||||
.then(() => { FlairStore.invalidatePublicisedGroups(MatrixClientPeg.get().credentials.userId); })
|
.then(() => { FlairStore.invalidatePublicisedGroups(MatrixClientPeg.get().credentials.userId); })
|
||||||
.then(this._fetchSummary.bind(this));
|
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.Summary));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue