Skip to content

Commit

Permalink
New: network connection test (#270)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielghost authored Apr 24, 2023
1 parent dde37cf commit ec5ef8a
Show file tree
Hide file tree
Showing 8 changed files with 279 additions and 73 deletions.
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This extension provides course tracking functionality (hence the name [spoor](ht
**Spoor** makes use of the excellent [pipwerks SCORM API Wrapper](https://github.com/pipwerks/scorm-api-wrapper/).

[Visit the **Spoor** wiki](https://github.com/adaptlearning/adapt-contrib-spoor/wiki) for more information about its functionality and for explanations of key properties.

## Installation

As one of Adapt's *[core extensions](https://github.com/adaptlearning/adapt_framework/wiki/Core-Plug-ins-in-the-Adapt-Learning-Framework#extensions),* **Spoor** is included with the [installation of the Adapt framework](https://github.com/adaptlearning/adapt_framework/wiki/Manual-installation-of-the-Adapt-framework#installation) and the [installation of the Adapt authoring tool](https://github.com/adaptlearning/adapt_authoring/wiki/Installing-Adapt-Origin).
Expand Down Expand Up @@ -131,6 +131,17 @@ Determines the 'exit state' (`cmi.core.exit` in SCORM 1.2, `cmi.exit` in SCORM 2
##### \_setCompletedWhenFailed (boolean):
Determines whether the `cmi.completion_status` is set to "completed" if the assessment is "failed". Only valid for SCORM 2004, where the logic for completion and success is separate. The default is `true`.

##### \_connectionTest (object):
The settings used to configure the connection test when committing data to the LMS. The LMS API usually returns true for each data transmission regardless of the ability to persist the data. Contains the following attributes:

* **\_isEnabled** (boolean): Determines whether the connection should be tested. The default is `true`.

* **\_testOnSetValue** (boolean): Determines whether the connection should be tested for each call to set data on the LMS. The default is `true`.

* **_silentRetryLimit** (number): The limit for silent retry attempts to establish a connection before raising an error. The default is `2`.

* **_silentRetryDelay** (number): The interval in milliseconds between silent connection retries. The default is `1000`.

#### \_showCookieLmsResetButton (boolean):
Determines whether a reset button will be available to relaunch the course and optionally clear tracking data (scorm_test_harness.html only). The default is `false`.

Expand Down
8 changes: 7 additions & 1 deletion example.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@
"_commitOnVisibilityChangeHidden": true,
"_exitStateIfIncomplete": "auto",
"_exitStateIfComplete": "auto",
"_setCompletedWhenFailed": true
"_setCompletedWhenFailed": true,
"_connectionTest": {
"_isEnabled": true,
"_testOnSetValue": true,
"_silentRetryLimit": 0,
"_silentRetryDelay": 2000
}
},
"_showCookieLmsResetButton": false,
"_shouldPersistCookieLMSData": true
Expand Down
33 changes: 1 addition & 32 deletions js/adapt-stateful-session.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,38 +51,7 @@ export default class StatefulSession extends Backbone.Controller {
this.scorm.initialize();
return;
}
if (settings._showDebugWindow) {
this.scorm.showDebugWindow();
}
this.scorm.setVersion(settings._scormVersion || '1.2');
if (_.isBoolean(settings._suppressErrors)) {
this.scorm.suppressErrors = settings._suppressErrors;
}
if (_.isBoolean(settings._commitOnStatusChange)) {
this.scorm.commitOnStatusChange = settings._commitOnStatusChange;
}
if (_.isBoolean(settings._commitOnAnyChange)) {
this.scorm.commitOnAnyChange = settings._commitOnAnyChange;
}
if (_.isFinite(settings._timedCommitFrequency)) {
this.scorm.timedCommitFrequency = settings._timedCommitFrequency;
}
if (_.isFinite(settings._maxCommitRetries)) {
this.scorm.maxCommitRetries = settings._maxCommitRetries;
}
if (_.isFinite(settings._commitRetryDelay)) {
this.scorm.commitRetryDelay = settings._commitRetryDelay;
}
if ('_exitStateIfIncomplete' in settings) {
this.scorm.exitStateIfIncomplete = settings._exitStateIfIncomplete;
}
if ('_exitStateIfComplete' in settings) {
this.scorm.exitStateIfComplete = settings._exitStateIfComplete;
}
if (_.isBoolean(settings._setCompletedWhenFailed)) {
this.scorm.setCompletedWhenFailed = settings._setCompletedWhenFailed;
}
this.scorm.initialize();
this.scorm.initialize(settings);
}

restoreSession() {
Expand Down
79 changes: 79 additions & 0 deletions js/scorm/Connection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import Adapt from 'core/js/adapt';

export default class Connection {

constructor({
_isEnabled = true,
_silentRetryLimit = 2,
_silentRetryDelay = 1000,
_testOnSetValue = true
} = {}, ScormWrapper) {
this.test = this.test.bind(this);
this._isEnabled = _isEnabled;
this._isInProgress = false;
this._isSilentDisconnection = false;
this._isDisconnected = false;
this._silentRetryLimit = _silentRetryLimit;
this._silentRetryDelay = _silentRetryDelay;
this._silentRetryTimeout = null;
this._silentRetryCount = 0;
this._testOnSetValue = _testOnSetValue;
this._scorm = ScormWrapper;
}

async test() {
if (!this._isEnabled || this._isInProgress) return;
this._isInProgress = true;
try {
const response = await fetch(`connection.txt?nocache=${Date.now()}`);
if (response?.ok) return this.onConnectionSuccess();
} catch (err) {}
this.onConnectionError();
}

async testOnSetValue() {
if (!this._isEnabled || !this._testOnSetValue) return;
return this.test();
}

reset() {
this._silentRetryCount = 0;
this._isSilentDisconnection = false;
if (this._silentRetryTimeout === null) return;
window.clearTimeout(this._silentRetryTimeout);
this._silentRetryTimeout = null;
}

stop() {
this.reset();
this._isEnabled = false;
}

/**
* @todo Remove need for commit?
*/
onConnectionSuccess() {
if (this._isDisconnected) {
this._scorm.commit();
if (!this._isSilentDisconnection) Adapt.trigger('tracking:connectionSuccess');
}
this._isInProgress = false;
this._isDisconnected = false;
this.reset();
}

onConnectionError() {
if (!this._isEnabled) return;
this._isInProgress = false;
this._isDisconnected = true;
if (this._silentRetryCount < this._silentRetryLimit) {
this._isSilentDisconnection = true;
this._silentRetryCount++;
this._silentRetryTimeout = window.setTimeout(this.test, this._silentRetryDelay);
return;
}
this.reset();
this._scorm.handleConnectionError(this.test);
}

}
Loading

0 comments on commit ec5ef8a

Please sign in to comment.