Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New: network connection test #270

Merged
merged 8 commits into from
Apr 24, 2023
Merged
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