finished up to allow pings and instructions (quit) before connection

is fully established (also in requested status)
This commit is contained in:
anhefti 2021-06-21 17:30:10 +02:00
parent b61166674c
commit 8381b5d621
9 changed files with 51 additions and 33 deletions

View file

@ -25,17 +25,21 @@ import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
public final class ClientConnection implements GrantEntity {
public enum ConnectionStatus {
UNDEFINED(false),
CONNECTION_REQUESTED(false),
AUTHENTICATED(true),
ACTIVE(true),
CLOSED(false),
DISABLED(false);
UNDEFINED(false, false),
CONNECTION_REQUESTED(true, false),
AUTHENTICATED(true, true),
ACTIVE(false, true),
CLOSED(false, false),
DISABLED(false, false);
public final boolean connectingStatus;
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.indicatorActiveStatus = connectingStatus || establishedStatus;
}
}

View file

@ -364,7 +364,7 @@ public class MonitoringClientConnection implements TemplateComposer {
})
.noEventPropagation()
.publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER) &&
connectionData.clientConnection.status == ConnectionStatus.ACTIVE);
connectionData.clientConnection.status.indicatorActiveStatus);
if (connectionData.clientConnection.status == ConnectionStatus.ACTIVE) {
final ProctoringServiceSettings procotringSettings = restService

View file

@ -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.Indicator;
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.ClientConnectionData;
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) {
final Set<String> connectionTokens = clientTable.getConnectionTokens(
ClientConnection.getStatusPredicate(ConnectionStatus.ACTIVE),
cc -> cc.status.indicatorActiveStatus,
true);
if (connectionTokens == null || connectionTokens.isEmpty()) {
return Collections.emptySet();

View file

@ -189,7 +189,7 @@ public class ClientConnectionDetails {
final double value = indValue.getValue();
final String displayValue = IndicatorValue.getDisplayValue(indValue);
if (!this.connectionData.clientConnection.status.establishedStatus) {
if (!this.connectionData.clientConnection.status.indicatorActiveStatus) {
form.setFieldValue(
indData.indicator.name,

View file

@ -576,7 +576,7 @@ public final class ClientConnectionTable {
continue;
}
if (!this.connectionData.clientConnection.status.establishedStatus) {
if (!this.connectionData.clientConnection.status.indicatorActiveStatus) {
final String value = (indicatorData.indicator.type.showOnlyInActiveState)
? Constants.EMPTY_NOTE
: IndicatorValue.getDisplayValue(indicatorValue);

View file

@ -72,7 +72,9 @@ public class InstructionProcessor {
final PageContext pageContext) {
final Set<String> connectionTokens = selectionFunction
.apply(ClientConnection.getStatusPredicate(ConnectionStatus.ACTIVE));
.apply(ClientConnection.getStatusPredicate(
ConnectionStatus.CONNECTION_REQUESTED,
ConnectionStatus.ACTIVE));
if (connectionTokens.isEmpty()) {
log.warn("Empty selection");

View file

@ -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 */
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.
*
* @param clientConnection the actual ClientConnection (from the internal cache)
* @return Result refer to true if the given ClientConnection is up to date */
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
* 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
* @param connectionToken
* @return */
Result<Set<String>> filterActive(Long examId, Set<String> connectionToken);
* @param examId the exam identifier
* @param connectionToken a Set of connection tokens to filter
* @return Result refer to filtered Set of connection tokens or to an error when happened */
Result<Set<String>> filterForInstructionStatus(Long examId, Set<String> connectionToken);
/** Used to get the VDI paired connection if it already exsits.
*

View file

@ -530,8 +530,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
}
@Override
@Transactional(readOnly = true)
public Result<Boolean> isActiveConnection(final Long examId, final String connectionToken) {
public Result<Boolean> isInInstructionStatus(final Long examId, final String connectionToken) {
return Result.tryCatch(() -> this.clientConnectionRecordMapper
.selectByExample()
.where(
@ -540,6 +539,12 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
.and(
ClientConnectionRecordDynamicSqlSupport.examId,
SqlBuilder.isEqualTo(examId))
.and(
ClientConnectionRecordDynamicSqlSupport.status,
SqlBuilder.isEqualTo(ConnectionStatus.ACTIVE.name()))
.or(
ClientConnectionRecordDynamicSqlSupport.status,
SqlBuilder.isEqualTo(ConnectionStatus.CONNECTION_REQUESTED.name()))
.build()
.execute()
.stream()
@ -566,7 +571,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
@Override
@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()) {
return Result.ofRuntimeError("Null or empty set reference");
}
@ -578,10 +583,15 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
.and(
ClientConnectionRecordDynamicSqlSupport.examId,
SqlBuilder.isEqualTo(examId))
.and(
ClientConnectionRecordDynamicSqlSupport.status,
SqlBuilder.isEqualTo(ConnectionStatus.ACTIVE.name()))
.or(
ClientConnectionRecordDynamicSqlSupport.status,
SqlBuilder.isEqualTo(ConnectionStatus.CONNECTION_REQUESTED.name()))
.build()
.execute()
.stream()
.filter(cc -> ConnectionStatus.ACTIVE.name().equals(cc.getStatus()))
.map(ClientConnectionRecord::getConnectionToken)
.collect(Collectors.toSet()));
}

View file

@ -110,7 +110,7 @@ public class SEBClientInstructionServiceImpl implements SEBClientInstructionServ
return Result.tryCatch(() -> {
final boolean isActive = this.clientConnectionDAO
.isActiveConnection(examId, connectionToken)
.isInInstructionStatus(examId, connectionToken)
.getOr(false);
if (isActive) {
@ -124,6 +124,10 @@ public class SEBClientInstructionServiceImpl implements SEBClientInstructionServ
} catch (final Exception 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 Set<String> activeConnections = this.clientConnectionDAO
.filterActive(examId, connectionTokens)
.filterForInstructionStatus(examId, connectionTokens)
.getOrElse(Collections::emptySet);
connectionTokens