Merge pull request #2713 from overleaf/jpa-custom-wsurl-for-beta-users

[misc] custom wsUrl for beta users

GitOrigin-RevId: e731ae7245e9c5586ae82cbc4c6716a74e56f2c9
This commit is contained in:
Jakob Ackermann 2020-04-02 12:01:41 +02:00 committed by Copybot
parent 50d715ea5d
commit 155b22caf9
9 changed files with 109 additions and 15 deletions

View file

@ -622,11 +622,6 @@ const ProjectController = {
const projectId = req.params.Project_id
// record failures to load the custom websocket
if ((req.query != null ? req.query.ws : undefined) === 'fallback') {
metrics.inc('load-editor-ws-fallback')
}
async.auto(
{
project(cb) {
@ -777,6 +772,23 @@ const ProjectController = {
allowedFreeTrial = !!subscription.freeTrial.allowed || true
}
let wsUrl = Settings.wsUrl
let metricName = 'load-editor-ws'
if (user.betaProgram && Settings.wsUrlBeta !== undefined) {
wsUrl = Settings.wsUrlBeta
metricName += '-beta'
}
if (req.query && req.query.ws === 'fallback') {
// `?ws=fallback` will connect to the bare origin, and ignore
// the custom wsUrl. Hence it must load the client side
// javascript from there too.
// Not resetting it here would possibly load a socket.io v2
// client and connect to a v0 endpoint.
wsUrl = undefined
metricName += '-fallback'
}
metrics.inc(metricName)
res.render('project/editor', {
title: project.name,
priority_title: true,
@ -831,6 +843,7 @@ const ProjectController = {
brandVariation,
allowedImageNames: Settings.allowedImageNames || [],
gitBridgePublicBaseUrl: Settings.gitBridgePublicBaseUrl,
wsUrl,
showSupport: Features.hasFeature('support')
})
timer.done()

View file

@ -66,7 +66,7 @@ html(
script.
window.sharelatex = {
siteUrl: '#{settings.siteUrl}',
wsUrl: '#{settings.wsUrl}',
wsUrl: '#{wsUrl}',
};
window.ab = {};
window.user_id = '#{getLoggedInUserId()}';

View file

@ -160,7 +160,7 @@ block content
window.overallThemes = JSON.parse('!{StringHelper.stringifyJsonForScript(overallThemes)}');
block foot-scripts
script(type="text/javascript" src='/socket.io/socket.io.js')
script(type="text/javascript" src=(wsUrl || '/socket.io') + '/socket.io.js')
script(src=mathJaxPath)
script(src=buildJsPath('libraries.js'))
script(src=buildJsPath('ide.js'))

View file

@ -196,6 +196,7 @@ module.exports = settings =
# Optional separate location for websocket connections, if unset defaults to siteUrl.
wsUrl: process.env['WEBSOCKET_URL']
wsUrlBeta: process.env['WEBSOCKET_URL_BETA']
# cookie domain
# use full domain for cookies to only be accessible from that domain,

View file

@ -101,9 +101,11 @@ define([], function() {
// initial connection attempt
this.updateConnectionManagerState('connecting')
const parsedURL = new URL(this.wsUrl || '/socket.io', window.location)
this.ide.socket = io.connect(
this.wsUrl,
parsedURL.origin,
{
resource: parsedURL.pathname,
reconnect: false,
'connect timeout': 30 * 1000,
'force new connection': true

View file

@ -66,6 +66,7 @@ module.exports = LaunchpadController = {
}
if (user && user.isAdmin) {
return res.render(Path.resolve(__dirname, '../views/launchpad'), {
wsUrl: Settings.wsUrl,
adminUserExists,
authMethod
})

View file

@ -9,7 +9,7 @@ block content
authMethod: "!{authMethod}"
}
script(type="text/javascript" src='/socket.io/socket.io.js')
script(type="text/javascript" src=(wsUrl || '/socket.io') + '/socket.io.js')
style.
hr { margin-bottom: 5px; }

View file

@ -171,6 +171,7 @@ describe('LaunchpadController', function() {
this.res.render.callCount.should.equal(1)
return this.res.render
.calledWith(viewPath, {
wsUrl: undefined,
adminUserExists: true,
authMethod: 'local'
})

View file

@ -129,6 +129,12 @@ describe('ProjectController', function() {
}
}
])
this.Metrics = {
Timer: class {
done() {}
},
inc: sinon.stub()
}
this.ProjectController = SandboxedModule.require(MODULE_PATH, {
globals: {
@ -140,12 +146,7 @@ describe('ProjectController', function() {
log() {},
err() {}
},
'metrics-sharelatex': {
Timer: class {
done() {}
},
inc() {}
},
'metrics-sharelatex': this.Metrics,
'@overleaf/o-error/http': HttpErrors,
'./ProjectDeleter': this.ProjectDeleter,
'./ProjectDuplicator': this.ProjectDuplicator,
@ -1145,6 +1146,81 @@ describe('ProjectController', function() {
}
this.ProjectController.loadEditor(this.req, this.res)
})
describe('wsUrl', function() {
function checkLoadEditorWsMetric(metric) {
it(`should inc metric ${metric}`, function(done) {
this.res.render = () => {
this.Metrics.inc.calledWith(metric).should.equal(true)
done()
}
this.ProjectController.loadEditor(this.req, this.res)
})
}
function checkWsFallback(isBeta) {
describe('with ws=fallback', function() {
beforeEach(function() {
this.req.query = {}
this.req.query.ws = 'fallback'
})
it('should unset the wsUrl', function(done) {
this.res.render = (pageName, opts) => {
;(opts.wsUrl || '/socket.io').should.equal('/socket.io')
done()
}
this.ProjectController.loadEditor(this.req, this.res)
})
checkLoadEditorWsMetric(
`load-editor-ws${isBeta ? '-beta' : ''}-fallback`
)
})
}
beforeEach(function() {
this.settings.wsUrl = '/other.socket.io'
})
it('should set the custom wsUrl', function(done) {
this.res.render = (pageName, opts) => {
opts.wsUrl.should.equal('/other.socket.io')
done()
}
this.ProjectController.loadEditor(this.req, this.res)
})
checkLoadEditorWsMetric('load-editor-ws')
checkWsFallback(false)
describe('beta program', function() {
beforeEach(function() {
this.settings.wsUrlBeta = '/beta.socket.io'
})
describe('for a normal user', function() {
it('should set the normal custom wsUrl', function(done) {
this.res.render = (pageName, opts) => {
opts.wsUrl.should.equal('/other.socket.io')
done()
}
this.ProjectController.loadEditor(this.req, this.res)
})
checkLoadEditorWsMetric('load-editor-ws')
checkWsFallback(false)
})
describe('for a beta user', function() {
beforeEach(function() {
this.user.betaProgram = true
})
it('should set the beta wsUrl', function(done) {
this.res.render = (pageName, opts) => {
opts.wsUrl.should.equal('/beta.socket.io')
done()
}
this.ProjectController.loadEditor(this.req, this.res)
})
checkLoadEditorWsMetric('load-editor-ws-beta')
checkWsFallback(true)
})
})
})
})
describe('userProjectsJson', function() {