SEBSERV-182

This commit is contained in:
anhefti 2021-07-07 13:24:38 +02:00
parent c217d4d854
commit c7952b32bc
7 changed files with 101 additions and 50 deletions

View file

@ -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<EntityTable<ClientNotification>> 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));

View file

@ -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<Exception, Boolean> createServerPushUpdateErrorHandler(
final PageService pageService,
final PageContext pageContext) {
static final class ProctoringUpdateErrorHandler implements Function<Exception, Boolean> {
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;
}
}
}

View file

@ -21,7 +21,7 @@ public final class ServerPushContext {
public final Composite anchor;
public final Predicate<ServerPushContext> runAgain;
public final Function<Exception, Boolean> errorHandler;
final Function<Exception, Boolean> 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);
}

View file

@ -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<Collection<ClientConnectionData>>.RestCallBuilder restCallBuilder;
private final ServerPushContext pushConext;
private final Map<Long, IndicatorData> 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<Indicator> indicators,
final RestCall<Collection<ClientConnectionData>>.RestCallBuilder restCallBuilder) {
final RestCall<Collection<ClientConnectionData>>.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);
}
}

View file

@ -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 -> {

View file

@ -99,9 +99,6 @@
})
window.addEventListener('unload', () => {
ZoomMtg.muteAll({
muteAll: true
});
ZoomMtg.endMeeting({});
});
</script>

View file

@ -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"
+ " </script>\r\n"