Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions examples/browserChannelClient/browserChannelClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ var ws = require("ws");

var socket = new ws("ws://localhost:8081/browserChannel"); // eslint-disable-line new-cap

var changeSetting = false;

// When the connection is done, the client tells to the flow manager its id

socket.on("open", function () {
console.log("## Socket connected");
console.log("## browserChannelClient: Socket connected");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it common for GPII to use console.log instead of fluid.log?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:-) GPII, in general, uses fluid.log(). But, some examples and other demo code do not. This particular example doesn't require infusion, or kettle for that matter, and only needs the ws WebSocket package.

I'm inclined to re-write it as an infusion component and possibly use kettle for the requests. That way, it would resemble how UIO+ or Morphic clients access the /browserchannel endpoint. But, I'm not sure that's a high priority.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@klown, yes I'm not sure either. I'll defer to @amb26 for that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving this with console.log is fine

socket.send(JSON.stringify({
type: "connect",
payload: {
Expand All @@ -34,16 +36,36 @@ socket.on("open", function () {
});

socket.on("message", function (data) {
console.log("## Received the following message: " + data);
console.log("## browserChannelClient: Received the following message: " + data);
var message = JSON.parse(data);
// Right after sending the id to the flow manager, the server will return back
// the current settings in the system (if any)
if (message.type === "connectionSucceeded") {
console.log("## Got initial settings ", message.payload, " on connection");
changeSetting = true;
console.log("## browserChannelClient: Got initial settings ", message.payload, " on connection");
}
// By listening to this message type, the client will be notified when the system has
// new settings to be applied on the client side
else if (message.type === "onSettingsChanged") {
console.log("## Got changed settings ", message.payload);
console.log("## browserChannelClient: Got changed settings ", message.payload);
}
// Log acknowledgement that the "changeSettings" message was sent
else if (message.type === "changeSettingsReceived") {
console.log("## browserChannelClient: ChangeSettings was successfully sent ", message.payload);
}

// Change two settings, and be done.
if (changeSetting) {
changeSetting = false;
socket.send(JSON.stringify({
type: "changeSettings",
payload: {
settings: {
characterSpace: 1,
clickToSelectEnabled: false,
contrastTheme: "default"
}
}
}));
}
});
11 changes: 7 additions & 4 deletions examples/pspChannelClient/pspChannelClientApplyPrefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,22 @@ var socket = new ws("ws://localhost:8081/pspChannel"); // eslint-disable-line ne

// When the connection is done, the server will send the initial data of the current session if any
socket.on("open", function () {
console.log("## Socket connected");
console.log("## pspChannelClientApplyPrefs: Socket connected");
});

socket.on("message", function (data) {
var message = JSON.parse(data);
console.log("## Received the following message: " + JSON.stringify(message, null, 4));
console.log("## pspChannelClientApplyPrefs: Received the following message: " + JSON.stringify(message, null, 4));

if (message.type === "preferencesApplied") {
console.log("Preferences have been applied");
console.log("## pspChannelClientApplyPrefs: Preferences have been applied");
socket.close();
return;
};
} else {
console.log("## pspChannelClientApplyPrefs: Message type '" + message.type + "' not 'preferencesApplied'");
}

console.log("## pspChannelClientApplyPrefs: Sending 'modelChanged' request");
socket.send(JSON.stringify(
{
"type": "modelChanged",
Expand Down
16 changes: 9 additions & 7 deletions examples/pspChannelClient/pspChannelClientReadPrefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,29 @@ var readRequestCount = 0;

// When the connection is done, the server will send the initial data of the current session if any
socket.on("open", function () {
console.log("## Socket connected");
console.log("## pspChannelClientReadPrefs: Socket connected");
});

socket.on("message", function (data) {
var message = JSON.parse(data);
console.log("## Received the following message: " + JSON.stringify(message, null, 4));
console.log("## pspChannelClientReadPrefs: Received the following message: " + JSON.stringify(message, null, 4));

if (message.type === "preferenceReadSuccess") {
console.log("Preference has been read");
console.log("## pspChannelClientReadPrefs: Preference has been read");
socket.close();
return;
};
if (message.type === "preferenceReadFail") {
console.log("Preference cannot be read");
} else if (message.type === "preferenceReadFail") {
console.log("## pspChannelClientReadPrefs: Preference cannot be read");
socket.close();
return;
};
} else {
console.log("## pspChannelClientReadPrefs: Message type '" + message.type + "' not reading success/failure");
}

if (readRequestCount === 0) {
readRequestCount++;
// Only send the read request once
console.log("## pspChannelClientReadPrefs: Sending 'pullModel' request");
socket.send(JSON.stringify(
{
"type": "pullModel",
Expand Down
63 changes: 62 additions & 1 deletion gpii/node_modules/flowManager/src/BrowserChannel.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
/*!
GPII BrowserChannel Handler

Copyright 2014, 2015 Emergya
Copyright 2015-2018 Raising the Floor - International
Copyright 2020 OCAD University

Licensed under the New BSD license. You may not use this file except in
compliance with this License.

You may obtain a copy of the License at
https://github.com/gpii/universal/LICENSE.txt
*/

"use strict";

var fluid = require("infusion");
Expand All @@ -24,6 +38,11 @@ fluid.defaults("gpii.flowManager.browserChannel.handler", {
}
});

/**
* Send an error response for the request.
* @param {Component} request - An instance of gpii.flowManager.browserChannel.handler.
* @param {String} message - Error message text to include in the response.
*/
gpii.flowManager.browserChannel.sendError = function (request, message) {
fluid.log("Sending browserChannel error ", message);
var error = {
Expand All @@ -35,20 +54,62 @@ gpii.flowManager.browserChannel.sendError = function (request, message) {
request.ws.close(1008, "Solution id not authorized");
};

/**
* Handler for all message types:
* - an initial "connect" message type establishes the connection and
* initializes the channel and its relationship with the WebSockets settings
* handler. This includes dynamically attaching the
* gpii.flowManager.browserChannel.receiveChangeSettingsMsg() listener to
* handle "changeSettings" message types after the connection is established.
* - any subsequent "connect" message types are silently ignored,
* - all other message types cause an error response and close the connection
* The one exception is the "changeSettings" message type (see first point).
* @param {Component} that - An instance of gpii.flowManager.browserChannel.handler.
* @param {Object} message - Object containing the message type and its payload.
* @param {Component} solutionsRegistryDataSource - Used to match the solution
* given in the payload.
* @param {Component} platformReporter - Used to determine the platform this
* is running on.
*/
gpii.flowManager.browserChannel.receiveMessage = function (that, message, solutionsRegistryDataSource, platformReporter) {
var solutionId = message.payload.solutionId;
if (message.type !== "connect") {
return;
}
if (that.established) {
gpii.flowManager.browserChannel.sendError(that, "Connection already established - cannot send a second connect message");
}
var solutionId = message.payload.solutionId;
solutionsRegistryDataSource.get({os: platformReporter.reportPlatform().id}, function onSuccess(entries) {
if (!(solutionId in entries)) {
gpii.flowManager.browserChannel.sendError(that, "Rejecting a connection request from '" + solutionId +
"'. The solution id was not found in the solutions registry");
} else {
gpii.settingsHandlers.webSockets.instance.addClient(solutionId, that);
that.established = true;
that.solutionId = solutionId;
}
}, function (error) {
gpii.flowManager.browserChannel.sendError(that, error.message);
});
};

/**
* Listener for the "changeSettings" message type. This is added as a listener
* after the connection has been established. That is, this will not function
* without a previous "connect" message type.
* @param {Component} that - An instance of gpii.flowManager.browserChannel.handler.
* @param {Object} message - Object containing the message type and its payload.
*/
gpii.flowManager.browserChannel.receiveChangeSettingsMsg = function (that, message) {
if (message.type === "changeSettings" && that.established) {
var wsPayload = {};
wsPayload[that.solutionId] = [{
options: {
path: that.solutionId,
source: that
},
settings: message.payload.settings
}];
gpii.settingsHandlers.webSockets.set(wsPayload);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ gpii.tests.flowManager.browserChannel.payloads = {
}
};

// Modify two of the settings for 'org.nvda-project' to test set function via
// BrowserChannel.
gpii.tests.flowManager.browserChannel.nvdaSetSettings = fluid.extend(
true, {},
gpii.tests.flowManager.browserChannel.payloads["org.nvda-project"],
{
"speech.espeak.rate": 50,
"keyboard.speakTypedCharacters": "False"
}
);

gpii.tests.flowManager.browserChannel.reportPlatform = function () {
return {
id: "win32",
Expand Down Expand Up @@ -112,6 +123,15 @@ gpii.tests.flowManager.browserChannel.checkPersistentSettings = function (client
expectedSettings, gpii.settingsHandlers.webSockets.instance.getSettingsForId(clientId));
};

gpii.tests.flowManager.browserChannel.checkSettingsAfterSet = function (responses, expectedSettings) {
fluid.each(responses, function (settingsArray, response) {
jqUnit.assertDeepEq(
"The persistent settings for " + response + " are, after setting them,",
expectedSettings, settingsArray[0]
);
});
};

gpii.tests.flowManager.browserChannel.loginAndSettingsChanged = function (multiArg, spec) {
fluid.each(spec.clientIds, function (clientId) {
var expectedSettings = gpii.tests.flowManager.browserChannel.payloads[clientId];
Expand Down Expand Up @@ -142,8 +162,10 @@ fluid.defaults("gpii.tests.flowManager.browserChannel.clientHolder", {
path: "/browserChannel",
port: "{configuration}.options.mainServerPort",
solutionId: "",
settings: {},
events: {
onSettingsChanged: null,
changeSettingsReceived: null,
connectionSucceeded: null
},
listeners: {
Expand All @@ -161,13 +183,23 @@ fluid.defaults("gpii.tests.flowManager.browserChannel.clientHolder", {
solutionId: "{that}.options.solutionId"
}
}
},
sendChangeSettings: {
func: "{that}.send",
args: {
type: "changeSettings",
payload: {
settings: "{that}.options.settings"
}
}
}
}
});

fluid.defaults("gpii.tests.flowManager.browserChannel.chromeClient", {
gradeNames: "gpii.tests.flowManager.browserChannel.clientHolder",
solutionId: "org.nvda-project"
solutionId: "org.nvda-project",
settings: gpii.tests.flowManager.browserChannel.nvdaSetSettings
});

fluid.defaults("gpii.tests.flowManager.browserChannel.firefoxClient", {
Expand Down Expand Up @@ -252,7 +284,7 @@ gpii.tests.flowManager.browserChannel.testDefs = [{
sequence: [{
func: "gpii.tests.flowManager.browserChannel.checkClients"
}, {
func: "{clientOne}.connect"
func: "{clientOne}.connect" // chromeClient (org.nvda-project)
}, {
event: "{clientOne}.events.onConnect",
listener: "fluid.identity"
Expand Down Expand Up @@ -294,7 +326,7 @@ gpii.tests.flowManager.browserChannel.testDefs = [{
}]
}, {
name: "Flow Manager BrowserChannel tests",
expect: 30,
expect: 32,
config: {
configName: "gpii.flowManager.tests.browserChannel.config",
configPath: "%flowManager/test/configs"
Expand All @@ -310,6 +342,13 @@ gpii.tests.flowManager.browserChannel.testDefs = [{
gpiiKey: "{loginChromeAndFirefox}.options.gpiiKey",
clientIds: ["org.nvda-project", "org.gnome.orca"]
}]
},
clientOneChangeSettings: {
events: {
"clientOneChangeReceipt": "{clientOne}.events.changeSettingsReceived",
"clientTwoSettingsChanged": "{clientTwo}.events.onSettingsChanged"
},
args: ["{arguments}", "{clientOne}.options.settings"]
}
},
components: {
Expand Down Expand Up @@ -425,7 +464,16 @@ gpii.tests.flowManager.browserChannel.testDefs = [{
"org.gnome.orca": 1
}
},
// All three clients now logged in - disconnect client 1 and try a spurious logout
// All three clients now connected - clientOne sends a "changeSettings"
// request and gets back a receipt, whereas clientTwo receives the changes.
{
func: "{clientOne}.sendChangeSettings"
},
{
event: "{testCaseHolder}.events.clientOneChangeSettings",
listener: "gpii.tests.flowManager.browserChannel.checkSettingsAfterSet"
},
// Disconnect client 1 and try a spurious logout
{
func: "{clientOne}.disconnect"
}, {
Expand Down
Loading