Merge pull request #3855 from overleaf/bg-skip-metadata-for-single-user

skip metadata broadcast for single user

GitOrigin-RevId: 4277870615aea1b07e1a8db6a26956be3661a443
This commit is contained in:
Brian Gough 2021-03-31 13:56:46 +01:00 committed by Copybot
parent 9ddaa8c9f6
commit 1d30feecaf
4 changed files with 132 additions and 51 deletions

View file

@ -42,7 +42,8 @@ module.exports = MetaController = {
broadcastMetadataForDoc(req, res, next) {
const { project_id } = req.params
const { doc_id } = req.params
logger.log({ project_id, doc_id }, 'getting labels for doc')
const { broadcast } = req.body
logger.log({ project_id, doc_id, broadcast }, 'getting labels for doc')
return MetaHandler.getMetaForDoc(project_id, doc_id, function(
err,
docMeta
@ -54,11 +55,16 @@ module.exports = MetaController = {
})
return next(err)
}
EditorRealTimeController.emitToRoom(project_id, 'broadcastDocMeta', {
docId: doc_id,
meta: docMeta
})
return res.sendStatus(200)
// default to broadcasting, unless explicitly disabled (for backwards compatibility)
if (broadcast !== false) {
EditorRealTimeController.emitToRoom(project_id, 'broadcastDocMeta', {
docId: doc_id,
meta: docMeta
})
return res.sendStatus(200)
} else {
return res.json({ docId: doc_id, meta: docMeta })
}
})
}
}

View file

@ -80,9 +80,19 @@ export default App.factory('metadata', function($http, ide) {
})
metadata.loadDocMetaFromServer = docId =>
$http.post(`/project/${window.project_id}/doc/${docId}/metadata`, {
_csrf: window.csrfToken
})
$http
.post(`/project/${window.project_id}/doc/${docId}/metadata`, {
// Don't broadcast metadata when there are no other users in the
// project.
broadcast: ide.$scope.onlineUsersCount > 0,
_csrf: window.csrfToken
})
.then(function(response) {
const { data } = response
// handle the POST response like a broadcast event when there are no
// other users in the project.
metadata.onBroadcastDocMeta(data)
})
metadata.scheduleLoadDocMetaFromServer = function(docId) {
if (ide.$scope.permissionsLevel === 'readOnly') {
@ -90,7 +100,6 @@ export default App.factory('metadata', function($http, ide) {
// The user will not be able to consume the meta data for edits anyways.
return
}
// De-bounce loading labels with a timeout
const existingTimeout = debouncer[docId]

View file

@ -32,6 +32,7 @@ export default OnlineUsersManager = (function() {
this.$scope.onlineUsers = {}
this.$scope.onlineUserCursorHighlights = {}
this.$scope.onlineUsersArray = []
this.$scope.onlineUsersCount = 0
this.$scope.$on('cursor:editor:update', (event, position) => {
return this.sendCursorPositionUpdate(position)
@ -115,6 +116,9 @@ export default OnlineUsersManager = (function() {
this.$scope.onlineUsersArray.push(user)
}
// keep a count of the other online users
this.$scope.onlineUsersCount = this.$scope.onlineUsersArray.length
this.$scope.onlineUserCursorHighlights = {}
for (client_id in this.$scope.onlineUsers) {
const client = this.$scope.onlineUsers[client_id]

View file

@ -103,53 +103,114 @@ describe('MetaController', function() {
.callsArgWith(2, null, this.fakeLabels)
this.EditorRealTimeController.emitToRoom = sinon.stub()
this.docId = 'somedoc'
this.req = { params: { project_id: this.projectId, doc_id: this.docId } }
this.res = { sendStatus: sinon.stub() }
this.res = { sendStatus: sinon.stub(), json: sinon.stub() }
return (this.next = sinon.stub())
})
it('should call MetaHandler.getMetaForDoc', function() {
this.MetadataController.broadcastMetadataForDoc(
this.req,
this.res,
this.next
)
this.MetaHandler.getMetaForDoc.callCount.should.equal(1)
return this.MetaHandler.getMetaForDoc
.calledWith(this.projectId)
.should.equal(true)
describe('with broadcast:true', function() {
beforeEach(function() {
this.req = {
params: { project_id: this.projectId, doc_id: this.docId },
body: { broadcast: true }
}
})
it('should call MetaHandler.getMetaForDoc', function() {
this.MetadataController.broadcastMetadataForDoc(
this.req,
this.res,
this.next
)
this.MetaHandler.getMetaForDoc.callCount.should.equal(1)
return this.MetaHandler.getMetaForDoc
.calledWith(this.projectId)
.should.equal(true)
})
it('should call not call next with an error', function() {
this.MetadataController.broadcastMetadataForDoc(
this.req,
this.res,
this.next
)
return this.next.callCount.should.equal(0)
})
it('should send a success response', function() {
this.MetadataController.broadcastMetadataForDoc(
this.req,
this.res,
this.next
)
this.res.sendStatus.callCount.should.equal(1)
return this.res.sendStatus.calledWith(200).should.equal(true)
})
it('should emit a message to room', function() {
this.MetadataController.broadcastMetadataForDoc(
this.req,
this.res,
this.next
)
this.EditorRealTimeController.emitToRoom.callCount.should.equal(1)
const { lastCall } = this.EditorRealTimeController.emitToRoom
expect(lastCall.args[0]).to.equal(this.projectId)
expect(lastCall.args[1]).to.equal('broadcastDocMeta')
return expect(lastCall.args[2]).to.have.all.keys(['docId', 'meta'])
})
})
it('should call not call next with an error', function() {
this.MetadataController.broadcastMetadataForDoc(
this.req,
this.res,
this.next
)
return this.next.callCount.should.equal(0)
})
describe('with broadcast:false', function() {
beforeEach(function() {
this.req = {
params: { project_id: this.projectId, doc_id: this.docId },
body: { broadcast: false }
}
})
it('should send a success response', function() {
this.MetadataController.broadcastMetadataForDoc(
this.req,
this.res,
this.next
)
this.res.sendStatus.callCount.should.equal(1)
return this.res.sendStatus.calledWith(200).should.equal(true)
})
it('should call MetaHandler.getMetaForDoc', function() {
this.MetadataController.broadcastMetadataForDoc(
this.req,
this.res,
this.next
)
this.MetaHandler.getMetaForDoc.callCount.should.equal(1)
return this.MetaHandler.getMetaForDoc
.calledWith(this.projectId)
.should.equal(true)
})
it('should emit a message to room', function() {
this.MetadataController.broadcastMetadataForDoc(
this.req,
this.res,
this.next
)
this.EditorRealTimeController.emitToRoom.callCount.should.equal(1)
const { lastCall } = this.EditorRealTimeController.emitToRoom
expect(lastCall.args[0]).to.equal(this.projectId)
expect(lastCall.args[1]).to.equal('broadcastDocMeta')
return expect(lastCall.args[2]).to.have.all.keys(['docId', 'meta'])
it('should call not call next with an error', function() {
this.MetadataController.broadcastMetadataForDoc(
this.req,
this.res,
this.next
)
return this.next.callCount.should.equal(0)
})
it('should send the metadata in the response', function() {
this.MetadataController.broadcastMetadataForDoc(
this.req,
this.res,
this.next
)
this.res.json.callCount.should.equal(1)
return this.res.json
.calledWith({ docId: this.docId, meta: this.fakeLabels })
.should.equal(true)
})
it('should not emit a message to room', function() {
this.MetadataController.broadcastMetadataForDoc(
this.req,
this.res,
this.next
)
return this.EditorRealTimeController.emitToRoom.callCount.should.equal(
0
)
})
})
describe('when MetaHandler.getMetaForDoc produces an error', function() {
@ -160,7 +221,8 @@ describe('MetaController', function() {
this.EditorRealTimeController.emitToRoom = sinon.stub()
this.docId = 'somedoc'
this.req = {
params: { project_id: this.projectId, doc_id: this.docId }
params: { project_id: this.projectId, doc_id: this.docId },
body: { broadcast: true }
}
this.res = { json: sinon.stub() }
return (this.next = sinon.stub())