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) { broadcastMetadataForDoc(req, res, next) {
const { project_id } = req.params const { project_id } = req.params
const { doc_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( return MetaHandler.getMetaForDoc(project_id, doc_id, function(
err, err,
docMeta docMeta
@ -54,11 +55,16 @@ module.exports = MetaController = {
}) })
return next(err) return next(err)
} }
EditorRealTimeController.emitToRoom(project_id, 'broadcastDocMeta', { // default to broadcasting, unless explicitly disabled (for backwards compatibility)
docId: doc_id, if (broadcast !== false) {
meta: docMeta EditorRealTimeController.emitToRoom(project_id, 'broadcastDocMeta', {
}) docId: doc_id,
return res.sendStatus(200) 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 => metadata.loadDocMetaFromServer = docId =>
$http.post(`/project/${window.project_id}/doc/${docId}/metadata`, { $http
_csrf: window.csrfToken .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) { metadata.scheduleLoadDocMetaFromServer = function(docId) {
if (ide.$scope.permissionsLevel === 'readOnly') { 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. // The user will not be able to consume the meta data for edits anyways.
return return
} }
// De-bounce loading labels with a timeout // De-bounce loading labels with a timeout
const existingTimeout = debouncer[docId] const existingTimeout = debouncer[docId]

View file

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

View file

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