finished up to allow pings and instructions (quit) before connection
is fully established (also in requested status)
This commit is contained in:
parent
b61166674c
commit
8381b5d621
9 changed files with 51 additions and 33 deletions
|
@ -25,17 +25,21 @@ import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
|
||||||
public final class ClientConnection implements GrantEntity {
|
public final class ClientConnection implements GrantEntity {
|
||||||
|
|
||||||
public enum ConnectionStatus {
|
public enum ConnectionStatus {
|
||||||
UNDEFINED(false),
|
UNDEFINED(false, false),
|
||||||
CONNECTION_REQUESTED(false),
|
CONNECTION_REQUESTED(true, false),
|
||||||
AUTHENTICATED(true),
|
AUTHENTICATED(true, true),
|
||||||
ACTIVE(true),
|
ACTIVE(false, true),
|
||||||
CLOSED(false),
|
CLOSED(false, false),
|
||||||
DISABLED(false);
|
DISABLED(false, false);
|
||||||
|
|
||||||
|
public final boolean connectingStatus;
|
||||||
public final boolean establishedStatus;
|
public final boolean establishedStatus;
|
||||||
|
public final boolean indicatorActiveStatus;
|
||||||
|
|
||||||
ConnectionStatus(final boolean establishedStatus) {
|
ConnectionStatus(final boolean connectingStatus, final boolean establishedStatus) {
|
||||||
|
this.connectingStatus = connectingStatus;
|
||||||
this.establishedStatus = establishedStatus;
|
this.establishedStatus = establishedStatus;
|
||||||
|
this.indicatorActiveStatus = connectingStatus || establishedStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -364,7 +364,7 @@ public class MonitoringClientConnection implements TemplateComposer {
|
||||||
})
|
})
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER) &&
|
.publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER) &&
|
||||||
connectionData.clientConnection.status == ConnectionStatus.ACTIVE);
|
connectionData.clientConnection.status.indicatorActiveStatus);
|
||||||
|
|
||||||
if (connectionData.clientConnection.status == ConnectionStatus.ACTIVE) {
|
if (connectionData.clientConnection.status == ConnectionStatus.ACTIVE) {
|
||||||
final ProctoringServiceSettings procotringSettings = restService
|
final ProctoringServiceSettings procotringSettings = restService
|
||||||
|
|
|
@ -34,7 +34,6 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings;
|
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||||
|
@ -420,7 +419,7 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
|
|
||||||
private Set<EntityKey> selectionForQuitInstruction(final ClientConnectionTable clientTable) {
|
private Set<EntityKey> selectionForQuitInstruction(final ClientConnectionTable clientTable) {
|
||||||
final Set<String> connectionTokens = clientTable.getConnectionTokens(
|
final Set<String> connectionTokens = clientTable.getConnectionTokens(
|
||||||
ClientConnection.getStatusPredicate(ConnectionStatus.ACTIVE),
|
cc -> cc.status.indicatorActiveStatus,
|
||||||
true);
|
true);
|
||||||
if (connectionTokens == null || connectionTokens.isEmpty()) {
|
if (connectionTokens == null || connectionTokens.isEmpty()) {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
|
|
|
@ -189,7 +189,7 @@ public class ClientConnectionDetails {
|
||||||
final double value = indValue.getValue();
|
final double value = indValue.getValue();
|
||||||
final String displayValue = IndicatorValue.getDisplayValue(indValue);
|
final String displayValue = IndicatorValue.getDisplayValue(indValue);
|
||||||
|
|
||||||
if (!this.connectionData.clientConnection.status.establishedStatus) {
|
if (!this.connectionData.clientConnection.status.indicatorActiveStatus) {
|
||||||
|
|
||||||
form.setFieldValue(
|
form.setFieldValue(
|
||||||
indData.indicator.name,
|
indData.indicator.name,
|
||||||
|
|
|
@ -576,7 +576,7 @@ public final class ClientConnectionTable {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.connectionData.clientConnection.status.establishedStatus) {
|
if (!this.connectionData.clientConnection.status.indicatorActiveStatus) {
|
||||||
final String value = (indicatorData.indicator.type.showOnlyInActiveState)
|
final String value = (indicatorData.indicator.type.showOnlyInActiveState)
|
||||||
? Constants.EMPTY_NOTE
|
? Constants.EMPTY_NOTE
|
||||||
: IndicatorValue.getDisplayValue(indicatorValue);
|
: IndicatorValue.getDisplayValue(indicatorValue);
|
||||||
|
|
|
@ -72,7 +72,9 @@ public class InstructionProcessor {
|
||||||
final PageContext pageContext) {
|
final PageContext pageContext) {
|
||||||
|
|
||||||
final Set<String> connectionTokens = selectionFunction
|
final Set<String> connectionTokens = selectionFunction
|
||||||
.apply(ClientConnection.getStatusPredicate(ConnectionStatus.ACTIVE));
|
.apply(ClientConnection.getStatusPredicate(
|
||||||
|
ConnectionStatus.CONNECTION_REQUESTED,
|
||||||
|
ConnectionStatus.ACTIVE));
|
||||||
|
|
||||||
if (connectionTokens.isEmpty()) {
|
if (connectionTokens.isEmpty()) {
|
||||||
log.warn("Empty selection");
|
log.warn("Empty selection");
|
||||||
|
|
|
@ -145,28 +145,27 @@ public interface ClientConnectionDAO extends
|
||||||
* @return Result refer to the ClientConnection for the specified connection token or to an error if happened */
|
* @return Result refer to the ClientConnection for the specified connection token or to an error if happened */
|
||||||
Result<ClientConnection> byConnectionToken(String connectionToken);
|
Result<ClientConnection> byConnectionToken(String connectionToken);
|
||||||
|
|
||||||
/** Indicates if the client connection for exam and connection token is an active connection.
|
|
||||||
*
|
|
||||||
* @param examId the exam identifier
|
|
||||||
* @param connectionToken the connection token
|
|
||||||
* @return Result refer to the active connection flag or to an error when happened */
|
|
||||||
Result<Boolean> isActiveConnection(Long examId, String connectionToken);
|
|
||||||
|
|
||||||
/** Use this to check whether a single ClientConnection is up to date or needs a refresh.
|
/** Use this to check whether a single ClientConnection is up to date or needs a refresh.
|
||||||
*
|
*
|
||||||
* @param clientConnection the actual ClientConnection (from the internal cache)
|
* @param clientConnection the actual ClientConnection (from the internal cache)
|
||||||
* @return Result refer to true if the given ClientConnection is up to date */
|
* @return Result refer to true if the given ClientConnection is up to date */
|
||||||
Result<Boolean> isUpToDate(ClientConnection clientConnection);
|
Result<Boolean> isUpToDate(ClientConnection clientConnection);
|
||||||
|
|
||||||
|
/** Indicates if the client connection for given exam and connection token is
|
||||||
|
* in a ready state to send instructions.
|
||||||
|
*
|
||||||
|
* @param examId the exam identifier
|
||||||
|
* @param connectionToken the connection token
|
||||||
|
* @return Result refer to the active connection flag or to an error when happened */
|
||||||
|
Result<Boolean> isInInstructionStatus(Long examId, String connectionToken);
|
||||||
|
|
||||||
/** Filters a set of client connection tokens to a set containing only
|
/** Filters a set of client connection tokens to a set containing only
|
||||||
* connection tokens of active client connections.
|
* connection tokens of client connections that are in a ready state to send instructions.
|
||||||
*
|
*
|
||||||
* Use this if you have a bunch of client connections to filter only the active connections
|
* @param examId the exam identifier
|
||||||
*
|
* @param connectionToken a Set of connection tokens to filter
|
||||||
* @param examId
|
* @return Result refer to filtered Set of connection tokens or to an error when happened */
|
||||||
* @param connectionToken
|
Result<Set<String>> filterForInstructionStatus(Long examId, Set<String> connectionToken);
|
||||||
* @return */
|
|
||||||
Result<Set<String>> filterActive(Long examId, Set<String> connectionToken);
|
|
||||||
|
|
||||||
/** Used to get the VDI paired connection if it already exsits.
|
/** Used to get the VDI paired connection if it already exsits.
|
||||||
*
|
*
|
||||||
|
|
|
@ -530,8 +530,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
public Result<Boolean> isInInstructionStatus(final Long examId, final String connectionToken) {
|
||||||
public Result<Boolean> isActiveConnection(final Long examId, final String connectionToken) {
|
|
||||||
return Result.tryCatch(() -> this.clientConnectionRecordMapper
|
return Result.tryCatch(() -> this.clientConnectionRecordMapper
|
||||||
.selectByExample()
|
.selectByExample()
|
||||||
.where(
|
.where(
|
||||||
|
@ -540,6 +539,12 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
.and(
|
.and(
|
||||||
ClientConnectionRecordDynamicSqlSupport.examId,
|
ClientConnectionRecordDynamicSqlSupport.examId,
|
||||||
SqlBuilder.isEqualTo(examId))
|
SqlBuilder.isEqualTo(examId))
|
||||||
|
.and(
|
||||||
|
ClientConnectionRecordDynamicSqlSupport.status,
|
||||||
|
SqlBuilder.isEqualTo(ConnectionStatus.ACTIVE.name()))
|
||||||
|
.or(
|
||||||
|
ClientConnectionRecordDynamicSqlSupport.status,
|
||||||
|
SqlBuilder.isEqualTo(ConnectionStatus.CONNECTION_REQUESTED.name()))
|
||||||
.build()
|
.build()
|
||||||
.execute()
|
.execute()
|
||||||
.stream()
|
.stream()
|
||||||
|
@ -566,7 +571,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public Result<Set<String>> filterActive(final Long examId, final Set<String> connectionToken) {
|
public Result<Set<String>> filterForInstructionStatus(final Long examId, final Set<String> connectionToken) {
|
||||||
if (connectionToken == null || connectionToken.isEmpty()) {
|
if (connectionToken == null || connectionToken.isEmpty()) {
|
||||||
return Result.ofRuntimeError("Null or empty set reference");
|
return Result.ofRuntimeError("Null or empty set reference");
|
||||||
}
|
}
|
||||||
|
@ -578,10 +583,15 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
.and(
|
.and(
|
||||||
ClientConnectionRecordDynamicSqlSupport.examId,
|
ClientConnectionRecordDynamicSqlSupport.examId,
|
||||||
SqlBuilder.isEqualTo(examId))
|
SqlBuilder.isEqualTo(examId))
|
||||||
|
.and(
|
||||||
|
ClientConnectionRecordDynamicSqlSupport.status,
|
||||||
|
SqlBuilder.isEqualTo(ConnectionStatus.ACTIVE.name()))
|
||||||
|
.or(
|
||||||
|
ClientConnectionRecordDynamicSqlSupport.status,
|
||||||
|
SqlBuilder.isEqualTo(ConnectionStatus.CONNECTION_REQUESTED.name()))
|
||||||
.build()
|
.build()
|
||||||
.execute()
|
.execute()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(cc -> ConnectionStatus.ACTIVE.name().equals(cc.getStatus()))
|
|
||||||
.map(ClientConnectionRecord::getConnectionToken)
|
.map(ClientConnectionRecord::getConnectionToken)
|
||||||
.collect(Collectors.toSet()));
|
.collect(Collectors.toSet()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,7 @@ public class SEBClientInstructionServiceImpl implements SEBClientInstructionServ
|
||||||
return Result.tryCatch(() -> {
|
return Result.tryCatch(() -> {
|
||||||
|
|
||||||
final boolean isActive = this.clientConnectionDAO
|
final boolean isActive = this.clientConnectionDAO
|
||||||
.isActiveConnection(examId, connectionToken)
|
.isInInstructionStatus(examId, connectionToken)
|
||||||
.getOr(false);
|
.getOr(false);
|
||||||
|
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
|
@ -124,6 +124,10 @@ public class SEBClientInstructionServiceImpl implements SEBClientInstructionServ
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
throw new RuntimeException("Unexpected: ", e);
|
throw new RuntimeException("Unexpected: ", e);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.warn(
|
||||||
|
"The SEB client connection : {} is not in a ready state to process instructions. Instruction registration has been skipped",
|
||||||
|
connectionToken);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -140,7 +144,7 @@ public class SEBClientInstructionServiceImpl implements SEBClientInstructionServ
|
||||||
|
|
||||||
final String attributesString = Utils.toJsonObject(attributes);
|
final String attributesString = Utils.toJsonObject(attributes);
|
||||||
final Set<String> activeConnections = this.clientConnectionDAO
|
final Set<String> activeConnections = this.clientConnectionDAO
|
||||||
.filterActive(examId, connectionTokens)
|
.filterForInstructionStatus(examId, connectionTokens)
|
||||||
.getOrElse(Collections::emptySet);
|
.getOrElse(Collections::emptySet);
|
||||||
|
|
||||||
connectionTokens
|
connectionTokens
|
||||||
|
|
Loading…
Reference in a new issue