SEBSERV-182
This commit is contained in:
parent
c217d4d854
commit
c7952b32bc
7 changed files with 101 additions and 50 deletions
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 -> {
|
||||
|
|
|
@ -99,9 +99,6 @@
|
|||
})
|
||||
|
||||
window.addEventListener('unload', () => {
|
||||
ZoomMtg.muteAll({
|
||||
muteAll: true
|
||||
});
|
||||
ZoomMtg.endMeeting({});
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue