Explorar o código

Merge pull request #4203 from overleaf/bg-admin-disable-service-worker

disable service worker via admin page

GitOrigin-RevId: 96ec9f07b32b831f5271827ab345ad831044f831
Jakob Ackermann %!s(int64=5) %!d(string=hai) anos
pai
achega
e8bb0114f8

+ 6 - 0
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

+ 5 - 0
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',

+ 7 - 0
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.

+ 5 - 0
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) {

+ 11 - 4
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,
           {

+ 15 - 0
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()
+      })
+    })
+  }
+}

+ 10 - 2
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
+  }
+})
 
 /**
  *