From e8bb0114f8a3e264864dbde997f2eebf81941c8b Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Wed, 16 Jun 2021 10:14:18 +0200 Subject: [PATCH] Merge pull request #4203 from overleaf/bg-admin-disable-service-worker disable service worker via admin page GitOrigin-RevId: 96ec9f07b32b831f5271827ab345ad831044f831 --- .../src/Features/ServerAdmin/AdminController.js | 6 ++++++ services/web/app/src/router.js | 5 +++++ services/web/app/views/admin/index.pug | 7 +++++++ .../js/ide/connection/ConnectionManager.js | 5 +++++ .../js/ide/pdf/controllers/PdfController.js | 15 +++++++++++---- .../ide/pdfng/directives/serviceWorkerManager.js | 15 +++++++++++++++ services/web/frontend/js/serviceWorker.js | 12 ++++++++++-- 7 files changed, 59 insertions(+), 6 deletions(-) diff --git a/services/web/app/src/Features/ServerAdmin/AdminController.js b/services/web/app/src/Features/ServerAdmin/AdminController.js index 7200154068..583c1e3e09 100644 --- a/services/web/app/src/Features/ServerAdmin/AdminController.js +++ b/services/web/app/src/Features/ServerAdmin/AdminController.js @@ -109,6 +109,12 @@ const AdminController = { return res.sendStatus(200) }, + unregisterServiceWorker: (req, res) => { + logger.warn('unregistering service worker for all users') + EditorRealTimeController.emitToAll('unregisterServiceWorker') + return res.sendStatus(200) + }, + openEditor(req, res) { logger.warn('opening editor') Settings.editorIsOpen = true diff --git a/services/web/app/src/router.js b/services/web/app/src/router.js index 6fffb6ecae..d8cbb30544 100644 --- a/services/web/app/src/router.js +++ b/services/web/app/src/router.js @@ -980,6 +980,11 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) { AuthorizationMiddleware.ensureUserIsSiteAdmin, AdminController.clearMessages ) + webRouter.post( + '/admin/unregisterServiceWorker', + AuthorizationMiddleware.ensureUserIsSiteAdmin, + AdminController.unregisterServiceWorker + ) privateApiRouter.post( '/disconnectAllUsers', diff --git a/services/web/app/views/admin/index.pug b/services/web/app/views/admin/index.pug index 51fbc00787..39ea393938 100644 --- a/services/web/app/views/admin/index.pug +++ b/services/web/app/views/admin/index.pug @@ -76,3 +76,10 @@ block content input.form-control(type='text', name='user_id', placeholder='user_id', required) .form-group button.btn-primary.btn(type='submit') Poll + + tab(heading="Advanced" bookmarkable-tab="advanced") + .row-spaced + form(method='post',action='/admin/unregisterServiceWorker') + input(name="_csrf", type="hidden", value=csrfToken) + button.btn.btn-danger(type="submit") Unregister service worker + p.small Will force service worker reload for all users with the editor open. diff --git a/services/web/frontend/js/ide/connection/ConnectionManager.js b/services/web/frontend/js/ide/connection/ConnectionManager.js index 577ac2c409..2ccfdb4dc5 100644 --- a/services/web/frontend/js/ide/connection/ConnectionManager.js +++ b/services/web/frontend/js/ide/connection/ConnectionManager.js @@ -274,6 +274,11 @@ The editor will refresh automatically in ${delay} seconds.\ sl_console.log('Reconnect gracefully') this.reconnectGracefully() }) + + this.ide.socket.on('unregisterServiceWorker', () => { + sl_console.log('Unregister service worker') + this.$scope.$broadcast('service-worker:unregister') + }) } updateConnectionManagerState(state) { diff --git a/services/web/frontend/js/ide/pdf/controllers/PdfController.js b/services/web/frontend/js/ide/pdf/controllers/PdfController.js index 3349f557c5..741517269d 100644 --- a/services/web/frontend/js/ide/pdf/controllers/PdfController.js +++ b/services/web/frontend/js/ide/pdf/controllers/PdfController.js @@ -6,7 +6,10 @@ import { react2angular } from 'react2angular' import { rootContext } from '../../../shared/context/root-context' import 'ace/ace' import getMeta from '../../../utils/meta' -import { waitForServiceWorker } from '../../pdfng/directives/serviceWorkerManager' +import { + waitForServiceWorker, + unregisterServiceWorker, +} from '../../pdfng/directives/serviceWorkerManager' import { trackPdfDownload } from './PdfJsMetrics' const AUTO_COMPILE_MAX_WAIT = 5000 @@ -272,18 +275,22 @@ App.controller( } }) + const serviceWorker = getMeta('ol-enablePdfCaching') + ? waitForServiceWorker() + : Promise.resolve() + + ide.$scope.$on('service-worker:unregister', unregisterServiceWorker) + function sendCompileRequest(options) { if (options == null) { options = {} } const url = `/project/${$scope.project_id}/compile` - let setup = Promise.resolve() const params = {} if (options.isAutoCompileOnLoad || options.isAutoCompileOnChange) { params.auto_compile = true } if (getMeta('ol-enablePdfCaching')) { - setup = waitForServiceWorker() params.enable_pdf_caching = true } // if the previous run was a check, clear the error logs @@ -314,7 +321,7 @@ App.controller( checkType = 'silent' } - return setup.then(() => + return serviceWorker.then(() => $http.post( url, { diff --git a/services/web/frontend/js/ide/pdfng/directives/serviceWorkerManager.js b/services/web/frontend/js/ide/pdfng/directives/serviceWorkerManager.js index 8ef34f2b2f..5ac9eaa65d 100644 --- a/services/web/frontend/js/ide/pdfng/directives/serviceWorkerManager.js +++ b/services/web/frontend/js/ide/pdfng/directives/serviceWorkerManager.js @@ -40,3 +40,18 @@ export function loadServiceWorker() { ) } } + +export function unregisterServiceWorker() { + if (supportsServiceWorker()) { + if (navigator.serviceWorker.controller) { + navigator.serviceWorker.controller.postMessage({ + type: 'disable', + }) + } + navigator.serviceWorker.getRegistrations().then(registrations => { + registrations.forEach(worker => { + worker.unregister() + }) + }) + } +} diff --git a/services/web/frontend/js/serviceWorker.js b/services/web/frontend/js/serviceWorker.js index 57fa7c88d0..3bb1afedba 100644 --- a/services/web/frontend/js/serviceWorker.js +++ b/services/web/frontend/js/serviceWorker.js @@ -721,9 +721,12 @@ function onFetchWithErrorHandling(event) { reportError(event, OError.tag(error, 'low level error in onFetch')) } } - +// allow fetch event listener to be removed if necessary +const controller = new AbortController() // listen to all network requests -self.addEventListener('fetch', onFetchWithErrorHandling) +self.addEventListener('fetch', onFetchWithErrorHandling, { + signal: controller.signal, +}) // complete setup ASAP self.addEventListener('install', event => { @@ -732,6 +735,11 @@ self.addEventListener('install', event => { self.addEventListener('activate', event => { event.waitUntil(self.clients.claim()) }) +self.addEventListener('message', event => { + if (event.data && event.data.type === 'disable') { + controller.abort() // removes the fetch event listener + } +}) /** *