From c7952b32bca9e415e703022eee0aec2041c2783f Mon Sep 17 00:00:00 2001 From: anhefti Date: Wed, 7 Jul 2021 13:24:38 +0200 Subject: [PATCH] SEBSERV-182 --- .../content/MonitoringClientConnection.java | 6 +- .../gui/content/MonitoringRunningExam.java | 93 +++++++++++++------ .../gui/service/push/ServerPushContext.java | 8 +- .../session/ClientConnectionTable.java | 30 +++--- .../MonitoringProctoringService.java | 6 +- .../session/proctoring/zoomWindow.html | 3 - .../ZoomWindowScriptResolverTest.java | 5 +- 7 files changed, 101 insertions(+), 50 deletions(-) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringClientConnection.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringClientConnection.java index 0b909f0f..e71d9114 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringClientConnection.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringClientConnection.java @@ -36,6 +36,7 @@ import ch.ethz.seb.sebserver.gbl.model.session.ExtendedClientEvent; import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.util.Utils; +import ch.ethz.seb.sebserver.gui.content.MonitoringRunningExam.ProctoringUpdateErrorHandler; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.service.ResourceService; import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; @@ -269,11 +270,14 @@ public class MonitoringClientConnection implements TemplateComposer { final Supplier> notificationTableSupplier = _notificationTableSupplier; // server push update + final ProctoringUpdateErrorHandler proctoringUpdateErrorHandler = + new ProctoringUpdateErrorHandler(this.pageService, pageContext); + this.serverPushService.runServerPush( new ServerPushContext( content, Utils.truePredicate(), - MonitoringRunningExam.createServerPushUpdateErrorHandler(this.pageService, pageContext)), + proctoringUpdateErrorHandler), this.pollInterval, context -> clientConnectionDetails.updateData(), context -> clientConnectionDetails.updateGUI(notificationTableSupplier, pageContext)); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExam.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExam.java index 57d073b5..f2337e9a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExam.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExam.java @@ -149,13 +149,22 @@ public class MonitoringRunningExam implements TemplateComposer { restService.getBuilder(GetClientConnectionDataList.class) .withURIVariable(API.PARAM_PARENT_MODEL_ID, exam.getModelId()); + final ProctoringUpdateErrorHandler proctoringUpdateErrorHandler = + new ProctoringUpdateErrorHandler(this.pageService, pageContext); + + final ServerPushContext pushContext = new ServerPushContext( + content, + Utils.truePredicate(), + proctoringUpdateErrorHandler); + final ClientConnectionTable clientTable = new ClientConnectionTable( this.pageService, tablePane, this.asyncRunner, exam, indicators, - restCall); + restCall, + pushContext); clientTable .withDefaultAction( @@ -172,10 +181,7 @@ public class MonitoringRunningExam implements TemplateComposer { ActionDefinition.MONITOR_EXAM_NEW_PROCTOR_ROOM)); this.serverPushService.runServerPush( - new ServerPushContext( - content, - context -> clientTable.getUpdateErrors() < 5, - createServerPushUpdateErrorHandler(this.pageService, pageContext)), + pushContext, this.pollInterval, context -> clientTable.updateValues(), updateTableGUI(clientTable)); @@ -281,18 +287,26 @@ public class MonitoringRunningExam implements TemplateComposer { } } + final ProctoringUpdateErrorHandler proctoringUpdateErrorHandler = + new ProctoringUpdateErrorHandler(this.pageService, pageContext); + + final ServerPushContext pushContext = new ServerPushContext( + parent, + Utils.truePredicate(), + proctoringUpdateErrorHandler); + this.monitoringProctoringService.initCollectingRoomActions( + pushContext, pageContext, actionBuilder, proctoringSettings, proctoringGUIService); + this.serverPushService.runServerPush( - new ServerPushContext( - parent, - Utils.truePredicate(), - createServerPushUpdateErrorHandler(this.pageService, pageContext)), + pushContext, this.proctoringRoomUpdateInterval, context -> this.monitoringProctoringService.updateCollectingRoomActions( + context, pageContext, actionBuilder, proctoringSettings, @@ -480,30 +494,53 @@ public class MonitoringRunningExam implements TemplateComposer { }; } - static final Function createServerPushUpdateErrorHandler( - final PageService pageService, - final PageContext pageContext) { + static final class ProctoringUpdateErrorHandler implements Function { - return error -> { - log.error("Fialed to update server push: {}", error.getMessage()); + private final PageService pageService; + private final PageContext pageContext; + + private int errors = 0; + + public ProctoringUpdateErrorHandler( + final PageService pageService, + final PageContext pageContext) { + + this.pageService = pageService; + this.pageContext = pageContext; + } + + private boolean checkUserSession() { try { - pageService.getCurrentUser().get(); + this.pageService.getCurrentUser().get(); + return true; } catch (final Exception e) { - log.error("Failed to verify current user after server push error: {}", e.getMessage()); - log.info("Force logout and session cleanup..."); - pageContext.forwardToLoginPage(); - final MessageBox logoutSuccess = new Message( - pageContext.getShell(), - pageService.getI18nSupport().getText("sebserver.logout"), - Utils.formatLineBreaks( - pageService.getI18nSupport().getText("sebserver.logout.invalid-session.message")), - SWT.ICON_INFORMATION, - pageService.getI18nSupport()); - logoutSuccess.open(null); + try { + this.pageContext.forwardToLoginPage(); + final MessageBox logoutSuccess = new Message( + this.pageContext.getShell(), + this.pageService.getI18nSupport().getText("sebserver.logout"), + Utils.formatLineBreaks( + this.pageService.getI18nSupport() + .getText("sebserver.logout.invalid-session.message")), + SWT.ICON_INFORMATION, + this.pageService.getI18nSupport()); + logoutSuccess.open(null); + } catch (final Exception ee) { + log.warn("Unable to auto-logout: ", ee.getMessage()); + } return true; } - return false; - }; + } + + @Override + public Boolean apply(final Exception error) { + this.errors++; + log.error("Failed to update server push: {}", error.getMessage()); + if (this.errors > 5) { + checkUserSession(); + } + return this.errors > 5; + } } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/push/ServerPushContext.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/push/ServerPushContext.java index 63261278..f103e6c4 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/push/ServerPushContext.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/push/ServerPushContext.java @@ -21,7 +21,7 @@ public final class ServerPushContext { public final Composite anchor; public final Predicate runAgain; - public final Function errorHandler; + final Function errorHandler; boolean internalStop = false; public ServerPushContext( @@ -36,6 +36,12 @@ public final class ServerPushContext { this.runAgain = runAgain; } + public void reportError(final Exception error) { + if (this.errorHandler != null) { + this.internalStop = this.errorHandler.apply(error); + } + } + public boolean runAgain() { return !this.internalStop && this.runAgain.test(this); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java index 2a5cd7a1..1574e13d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java @@ -61,6 +61,7 @@ import ch.ethz.seb.sebserver.gui.service.ResourceService; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; +import ch.ethz.seb.sebserver.gui.service.push.ServerPushContext; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.DisposedOAuth2RestTemplateException; import ch.ethz.seb.sebserver.gui.service.session.IndicatorData.ThresholdColor; @@ -95,6 +96,8 @@ public final class ClientConnectionTable { private final AsyncRunner asyncRunner; private final Exam exam; private final RestCall>.RestCallBuilder restCallBuilder; + private final ServerPushContext pushConext; + private final Map indicatorMapping; private final Table table; private final ColorData colorData; @@ -116,7 +119,7 @@ public final class ClientConnectionTable { private boolean forceUpdateAll = false; private boolean updateInProgress = false; - private int updateErrors = 0; + //private int updateErrors = 0; public ClientConnectionTable( final PageService pageService, @@ -124,12 +127,14 @@ public final class ClientConnectionTable { final AsyncRunner asyncRunner, final Exam exam, final Collection indicators, - final RestCall>.RestCallBuilder restCallBuilder) { + final RestCall>.RestCallBuilder restCallBuilder, + final ServerPushContext pushConext) { this.pageService = pageService; this.asyncRunner = asyncRunner; this.exam = exam; this.restCallBuilder = restCallBuilder; + this.pushConext = pushConext; final WidgetFactory widgetFactory = pageService.getWidgetFactory(); final ResourceService resourceService = pageService.getResourceService(); @@ -190,9 +195,9 @@ public final class ClientConnectionTable { this.table.layout(); } - public int getUpdateErrors() { - return this.updateErrors; - } +// public int getUpdateErrors() { +// return this.updateErrors; +// } public WidgetFactory getWidgetFactory() { return this.pageService.getWidgetFactory(); @@ -322,14 +327,17 @@ public final class ClientConnectionTable { } this.updateInProgress = true; - this.asyncRunner.runAsync(this::updateValuesAsync); + final boolean needsSync = this.tableMapping != null && + this.table != null && + this.tableMapping.size() != this.table.getItemCount(); + this.asyncRunner.runAsync(() -> updateValuesAsync(needsSync)); } - private void updateValuesAsync() { + private void updateValuesAsync(final boolean needsSync) { try { - if (this.statusFilterChanged || this.forceUpdateAll) { + if (this.statusFilterChanged || this.forceUpdateAll || needsSync) { this.toDelete.clear(); this.toDelete.addAll(this.tableMapping.keySet()); } @@ -337,8 +345,8 @@ public final class ClientConnectionTable { .withHeader(API.EXAM_MONITORING_STATE_FILTER, this.statusFilterParam) .call() .get(error -> { - log.error("Unexpected error while trying to get client connection table data: ", error); recoverFromDisposedRestTemplate(error); + this.pushConext.reportError(error); return Collections.emptyList(); }) .forEach(data -> { @@ -367,11 +375,9 @@ public final class ClientConnectionTable { this.forceUpdateAll = false; this.updateInProgress = false; - this.updateErrors = 0; } catch (final Exception e) { - log.error("Unexpected error while updating client connection table: ", e); - this.updateErrors++; + this.pushConext.reportError(e); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/proctoring/MonitoringProctoringService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/proctoring/MonitoringProctoringService.java index 50ebe352..296bd102 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/proctoring/MonitoringProctoringService.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/proctoring/MonitoringProctoringService.java @@ -47,6 +47,7 @@ import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder; import ch.ethz.seb.sebserver.gui.service.page.event.ActionActivationEvent; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; +import ch.ethz.seb.sebserver.gui.service.push.ServerPushContext; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetProctoringSettings; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetCollectingRooms; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetProctorRoomConnection; @@ -152,6 +153,7 @@ public class MonitoringProctoringService { } public void initCollectingRoomActions( + final ServerPushContext pushContext, final PageContext pageContext, final PageActionBuilder actionBuilder, final ProctoringServiceSettings proctoringSettings, @@ -159,6 +161,7 @@ public class MonitoringProctoringService { proctoringGUIService.clearCollectingRoomActionState(); updateCollectingRoomActions( + pushContext, pageContext, actionBuilder, proctoringSettings, @@ -166,6 +169,7 @@ public class MonitoringProctoringService { } public void updateCollectingRoomActions( + final ServerPushContext pushContext, final PageContext pageContext, final PageActionBuilder actionBuilder, final ProctoringServiceSettings proctoringSettings, @@ -179,7 +183,7 @@ public class MonitoringProctoringService { .getBuilder(GetCollectingRooms.class) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .call() - .onError(error -> log.error("Failed to update proctoring rooms on GUI {}", error.getMessage())) + .onError(error -> pushContext.reportError(error)) .getOr(Collections.emptyList()) .stream() .forEach(room -> { diff --git a/src/main/resources/ch/ethz/seb/sebserver/gui/service/session/proctoring/zoomWindow.html b/src/main/resources/ch/ethz/seb/sebserver/gui/service/session/proctoring/zoomWindow.html index d6a9de3b..b0dd4266 100644 --- a/src/main/resources/ch/ethz/seb/sebserver/gui/service/session/proctoring/zoomWindow.html +++ b/src/main/resources/ch/ethz/seb/sebserver/gui/service/session/proctoring/zoomWindow.html @@ -99,9 +99,6 @@ }) window.addEventListener('unload', () => { - ZoomMtg.muteAll({ - muteAll: true - }); ZoomMtg.endMeeting({}); }); diff --git a/src/test/java/ch/ethz/seb/sebserver/gui/service/session/proctoring/ZoomWindowScriptResolverTest.java b/src/test/java/ch/ethz/seb/sebserver/gui/service/session/proctoring/ZoomWindowScriptResolverTest.java index aeb42f99..a2a20887 100644 --- a/src/test/java/ch/ethz/seb/sebserver/gui/service/session/proctoring/ZoomWindowScriptResolverTest.java +++ b/src/test/java/ch/ethz/seb/sebserver/gui/service/session/proctoring/ZoomWindowScriptResolverTest.java @@ -21,7 +21,7 @@ import ch.ethz.seb.sebserver.gui.service.session.proctoring.ProctoringGUIService public class ZoomWindowScriptResolverTest { @Test - public void testJitsiWindowScriptResolver() { + public void testZoomWindowScriptResolver() { final DefaultResourceLoader defaultResourceLoader = new DefaultResourceLoader(); final Resource resource = defaultResourceLoader.getResource(ZoomWindowScriptResolver.RES_PATH); final ZoomWindowScriptResolver zoomWindowScriptResolver = new ZoomWindowScriptResolver(resource); @@ -166,9 +166,6 @@ public class ZoomWindowScriptResolverTest { + " })\r\n" + " \r\n" + " window.addEventListener('unload', () => {\r\n" - + " ZoomMtg.muteAll({\r\n" - + " muteAll: true\r\n" - + " });\r\n" + " ZoomMtg.endMeeting({});\r\n" + " });\r\n" + " \r\n"