From 021236b30ef7f3d2e190809782a304db068c6300 Mon Sep 17 00:00:00 2001 From: Joseph Scheuhammer Date: Fri, 5 Jun 2020 15:36:50 -0400 Subject: [PATCH 01/11] GPII-4218: Added inverse transformations for UIO+ Also tweaked the conole messagee for the PSP client and Browser client examples. --- .../browserChannelClient.js | 8 +- .../pspChannelClientApplyPrefs.js | 11 ++- .../pspChannelClientReadPrefs.js | 18 ++-- .../flowManager/src/BrowserChannel.js | 6 +- .../test/shared/BrowserChannelTestDefs.js | 2 +- .../src/WebSocketsSettingsHandler.js | 10 ++- testData/solutions/win32.json5 | 83 ++++++++++++++++++- 7 files changed, 116 insertions(+), 22 deletions(-) diff --git a/examples/browserChannelClient/browserChannelClient.js b/examples/browserChannelClient/browserChannelClient.js index 06e707769..d9fe25f78 100644 --- a/examples/browserChannelClient/browserChannelClient.js +++ b/examples/browserChannelClient/browserChannelClient.js @@ -24,7 +24,7 @@ var socket = new ws("ws://localhost:8081/browserChannel"); // eslint-disable-lin // 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"); socket.send(JSON.stringify({ type: "connect", payload: { @@ -34,16 +34,16 @@ 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"); + 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); } }); diff --git a/examples/pspChannelClient/pspChannelClientApplyPrefs.js b/examples/pspChannelClient/pspChannelClientApplyPrefs.js index bc8c3180a..246a2be09 100644 --- a/examples/pspChannelClient/pspChannelClientApplyPrefs.js +++ b/examples/pspChannelClient/pspChannelClientApplyPrefs.js @@ -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", diff --git a/examples/pspChannelClient/pspChannelClientReadPrefs.js b/examples/pspChannelClient/pspChannelClientReadPrefs.js index 4bc671a88..9031f7966 100644 --- a/examples/pspChannelClient/pspChannelClientReadPrefs.js +++ b/examples/pspChannelClient/pspChannelClientReadPrefs.js @@ -25,33 +25,35 @@ 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", value: { settingControls: { - "http://registry\\.gpii\\.net/common/magnification": { + "http://registry\\.gpii\\.net/common/DPIScale": { value: 1 } } diff --git a/gpii/node_modules/flowManager/src/BrowserChannel.js b/gpii/node_modules/flowManager/src/BrowserChannel.js index acc4f198e..91864f952 100644 --- a/gpii/node_modules/flowManager/src/BrowserChannel.js +++ b/gpii/node_modules/flowManager/src/BrowserChannel.js @@ -36,10 +36,14 @@ gpii.flowManager.browserChannel.sendError = function (request, message) { }; gpii.flowManager.browserChannel.receiveMessage = function (that, message, solutionsRegistryDataSource, platformReporter) { - var solutionId = message.payload.solutionId; + console.log("BC receiveMsg: " + JSON.stringify(message)); if (that.established) { gpii.flowManager.browserChannel.sendError(that, "Connection already established - cannot send a second connect message"); } + if (message.type !== "connect") { + gpii.flowManager.browserChannel.sendError(that, "Connection supports only '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 + diff --git a/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js b/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js index 6106d3469..5a2aebf07 100644 --- a/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js +++ b/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js @@ -252,7 +252,7 @@ gpii.tests.flowManager.browserChannel.testDefs = [{ sequence: [{ func: "gpii.tests.flowManager.browserChannel.checkClients" }, { - func: "{clientOne}.connect" + func: "{clientOne}.connect" // chromeClient (org.chrome.cloud4chrome) }, { event: "{clientOne}.events.onConnect", listener: "fluid.identity" diff --git a/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js b/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js index 9c52790c9..fe6c9c7d1 100644 --- a/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js +++ b/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js @@ -19,7 +19,7 @@ var fluid = require("infusion"), // For debugging -- see gpii.settingsHandlers.webSockets.settingsChanged() // below. -//var util = require("util"); +// var util = require("util"); fluid.defaults("gpii.settingsHandlers.webSockets.component", { gradeNames: ["fluid.modelComponent"], @@ -66,6 +66,12 @@ fluid.defaults("gpii.settingsHandlers.webSockets.component", { ///////////////// Clients ///////////////////// gpii.settingsHandlers.webSockets.addClient = function (that, solutionId, client) { + console.log("CLIENT: " + client.typeName); + client.events.onReceiveMessage.addListener(function (message) { + if (message.type === "onSettingsChanged") { + console.log("HANDLE SETTINGS CHANGED"); + } + }); var initialSettings = fluid.get(that.model.settings, [solutionId]); var currentValue = fluid.get(that.clients, [solutionId, client.id]); if (!currentValue) { @@ -75,7 +81,6 @@ gpii.settingsHandlers.webSockets.addClient = function (that, solutionId, client) that.removeClient(client); }); } - }; gpii.settingsHandlers.webSockets.removeClient = function (that, client) { @@ -106,7 +111,6 @@ gpii.settingsHandlers.webSockets.getImpl = function (payload, that) { var currentValue = fluid.get(that.model.settings, [path, key]); return currentValue; }); - return results; }; diff --git a/testData/solutions/win32.json5 b/testData/solutions/win32.json5 index 728c4177f..3813cdfd9 100644 --- a/testData/solutions/win32.json5 +++ b/testData/solutions/win32.json5 @@ -32569,7 +32569,88 @@ } } }, - "inverseCapabilitiesTransformations": {} + "inverseCapabilitiesTransformations": { + "http://registry\\.gpii\\.net/common/characterSpace": { + "transform": { + "type": "fluid.transforms.linearScale", + "inputPath": "characterSpace", + "offset": 1 + } + }, + "http://registry\\.gpii\\.net/common/highContrast/enabled": { + "transform": { + "type": "fluid.transforms.condition", + "condition": { + "transform": { + "type": "fluid.transforms.binaryOp", + "leftPath": "contrastTheme", + "operator": "!==", + "right": "default" + } + }, + "true": "true", + "false": "false" + } + }, + "http://registry\\.gpii\\.net/common/highContrastTheme": { + "transform": { + "type": "fluid.transforms.condition", + "condition": { + "transform": { + "type": "fluid.transforms.binaryOp", + "leftPath": "contrastTheme", + "operator": "!==", + "right": "default" + } + }, + "true": { + "transform": { + "type": "fluid.transforms.valueMapper", + "defaultInputPath": "contrastTheme", + "defaultOutputValue": "default", + "match": { + "bw": "black-white", + "wb": "white-black", + "by": "black-yellow", + "yb": "yellow-black", + "lgdg":"grey-black", + "gw": "grey-white", + "bbr": "black-brown" + } + } + }, + "false": "default" + } + }, + "http://registry\\.gpii\\.net/common/fontSize": { + "transform": { + "type": "fluid.transforms.round", + "scale": 2, + "input": { + "transform": { + "type": "fluid.transforms.binaryOp", + "leftPath": "fontSize", + "right": 12, + "operator": "*" + } + } + } + }, + "http://registry\\.gpii\\.net/common/inputsLarger/enabled": "inputsLargerEnabled", + "http://registry\\.gpii\\.net/common/lineSpace": "lineSpace", + "http://registry\\.gpii\\.net/common/highlightColor": "selectionTheme", + "http://registry\\.gpii\\.net/common/selfVoicing/enabled": "selfVoicingEnabled", + "http://registry\\.gpii\\.net/common/simplifiedUi/enabled": "simplifiedUiEnabled", + "http://registry\\.gpii\\.net/common/syllabification/enabled": "syllabificationEnabled", + "http://registry\\.gpii\\.net/common/tableOfContents": "tableOfContentsEnabled", + "http://registry\\.gpii\\.net/common/wordSpace": { + "transform": { + "type": "fluid.transforms.linearScale", + "offset": -1, + "inputPath": "wordSpace" + } + } + } } }, "isInstalled": [ From e277d5f2904f54ea8fd733a4e838ff769f6ef78d Mon Sep 17 00:00:00 2001 From: Joseph Scheuhammer Date: Fri, 5 Jun 2020 15:47:09 -0400 Subject: [PATCH 02/11] GPII-4218: Fixed lint errors --- testData/solutions/win32.json5 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/testData/solutions/win32.json5 b/testData/solutions/win32.json5 index 18c14069c..0688b9b25 100644 --- a/testData/solutions/win32.json5 +++ b/testData/solutions/win32.json5 @@ -32607,12 +32607,12 @@ "defaultInputPath": "contrastTheme", "defaultOutputValue": "default", "match": { - "bw": "black-white", - "wb": "white-black", - "by": "black-yellow", - "yb": "yellow-black", - "lgdg":"grey-black", - "gw": "grey-white", + "bw": "black-white", + "wb": "white-black", + "by": "black-yellow", + "yb": "yellow-black", + "lgdg":"grey-black", + "gw": "grey-white", "bbr": "black-brown" } } From 80bdcc80cd5d2db5552becd0de7310e6e7094565 Mon Sep 17 00:00:00 2001 From: Joseph Scheuhammer Date: Fri, 5 Jun 2020 16:25:02 -0400 Subject: [PATCH 03/11] GPII-4218: Removed UIO+ fabulous inverse transformation of 'contrastTheme' Removed because it does not validate: "ERROR: The capabilities transforms for win32.json5 -> net.gpii.uioPlus -> contrastTheme may result in data corruption." Also, it might actually be handled by another settings handler. --- testData/solutions/win32.json5 | 45 ---------------------------------- 1 file changed, 45 deletions(-) diff --git a/testData/solutions/win32.json5 b/testData/solutions/win32.json5 index 0688b9b25..07fb64f82 100644 --- a/testData/solutions/win32.json5 +++ b/testData/solutions/win32.json5 @@ -32575,51 +32575,6 @@ "offset": 1 } }, - "http://registry\\.gpii\\.net/common/highContrast/enabled": { - "transform": { - "type": "fluid.transforms.condition", - "condition": { - "transform": { - "type": "fluid.transforms.binaryOp", - "leftPath": "contrastTheme", - "operator": "!==", - "right": "default" - } - }, - "true": "true", - "false": "false" - } - }, - "http://registry\\.gpii\\.net/common/highContrastTheme": { - "transform": { - "type": "fluid.transforms.condition", - "condition": { - "transform": { - "type": "fluid.transforms.binaryOp", - "leftPath": "contrastTheme", - "operator": "!==", - "right": "default" - } - }, - "true": { - "transform": { - "type": "fluid.transforms.valueMapper", - "defaultInputPath": "contrastTheme", - "defaultOutputValue": "default", - "match": { - "bw": "black-white", - "wb": "white-black", - "by": "black-yellow", - "yb": "yellow-black", - "lgdg":"grey-black", - "gw": "grey-white", - "bbr": "black-brown" - } - } - }, - "false": "default" - } - }, "http://registry\\.gpii\\.net/common/fontSize": { "transform": { "type": "fluid.transforms.round", From d598a9f747d53cf5429e983a36dd081bba6a01d7 Mon Sep 17 00:00:00 2001 From: Joseph Scheuhammer Date: Mon, 15 Jun 2020 10:58:58 -0400 Subject: [PATCH 04/11] GPII-4218: Modified to support UIO+ "changeSettings" requests --- .../flowManager/src/BrowserChannel.js | 53 +++++++++++++++++-- .../test/shared/BrowserChannelTestDefs.js | 50 +++++++++++++++-- .../src/WebSocketsSettingsHandler.js | 18 ++++--- .../test/WebSocketsSettingsHandlerTests.js | 39 ++++++++++++++ 4 files changed, 146 insertions(+), 14 deletions(-) diff --git a/gpii/node_modules/flowManager/src/BrowserChannel.js b/gpii/node_modules/flowManager/src/BrowserChannel.js index 91864f952..e7d4adcad 100644 --- a/gpii/node_modules/flowManager/src/BrowserChannel.js +++ b/gpii/node_modules/flowManager/src/BrowserChannel.js @@ -24,6 +24,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 = { @@ -35,14 +40,32 @@ 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 the closing of 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) { console.log("BC receiveMsg: " + JSON.stringify(message)); + if (message.type !== "connect") { + return; + } if (that.established) { gpii.flowManager.browserChannel.sendError(that, "Connection already established - cannot send a second connect message"); } - if (message.type !== "connect") { - gpii.flowManager.browserChannel.sendError(that, "Connection supports only 'connect' message"); - } var solutionId = message.payload.solutionId; solutionsRegistryDataSource.get({os: platformReporter.reportPlatform().id}, function onSuccess(entries) { if (!(solutionId in entries)) { @@ -51,8 +74,32 @@ gpii.flowManager.browserChannel.receiveMessage = function (that, message, soluti } 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. If the message type is not + * "changeSettings", or if the socket connection has not been established, + * the message is ignored and this is a no-op. + * @param {Component} that - An instance of gpii.flowManager.browserChannel.handler. + * @param {Object} message - The "changeSettings" message and a payload of settings + * to modify. + */ +gpii.flowManager.browserChannel.receiveChangeSettingsMsg = function (that, message) { + console.log("BC receiveChangeSettingsMsg: " + JSON.stringify(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); + } +}; diff --git a/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js b/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js index 5a2aebf07..b50264b92 100644 --- a/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js +++ b/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js @@ -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", @@ -112,6 +123,13 @@ gpii.tests.flowManager.browserChannel.checkPersistentSettings = function (client expectedSettings, gpii.settingsHandlers.webSockets.instance.getSettingsForId(clientId)); }; +gpii.tests.flowManager.browserChannel.checkSettingsAfterSet = function (data, clientId, expectedSettings) { + jqUnit.assertDeepEq( + "The persistent settings for " + clientId + " are, after setting them,", + expectedSettings, data + ); +}; + gpii.tests.flowManager.browserChannel.loginAndSettingsChanged = function (multiArg, spec) { fluid.each(spec.clientIds, function (clientId) { var expectedSettings = gpii.tests.flowManager.browserChannel.payloads[clientId]; @@ -142,6 +160,7 @@ fluid.defaults("gpii.tests.flowManager.browserChannel.clientHolder", { path: "/browserChannel", port: "{configuration}.options.mainServerPort", solutionId: "", + settings: {}, events: { onSettingsChanged: null, connectionSucceeded: null @@ -161,13 +180,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", { @@ -294,7 +323,7 @@ gpii.tests.flowManager.browserChannel.testDefs = [{ }] }, { name: "Flow Manager BrowserChannel tests", - expect: 30, + expect: 31, config: { configName: "gpii.flowManager.tests.browserChannel.config", configPath: "%flowManager/test/configs" @@ -425,7 +454,22 @@ 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. As the source, it won't be notified of the change, but + // clientTwo, having the same ID, will. + { + func: "{clientOne}.sendChangeSettings" + }, + { + event: "{clientTwo}.events.onSettingsChanged", + listener: "gpii.tests.flowManager.browserChannel.checkSettingsAfterSet", + args: [ + "{arguments}.0", + "{clientTwo}.options.solutionId", + gpii.tests.flowManager.browserChannel.nvdaSetSettings + ] + }, + // Disconnect client 1 and try a spurious logout { func: "{clientOne}.disconnect" }, { diff --git a/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js b/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js index fe6c9c7d1..c5289be16 100644 --- a/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js +++ b/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js @@ -3,6 +3,7 @@ Copyright 2014, 2015 Emergya Copyright 2015 Raising the Floor - International + Copyright 2020 IDRC, OCAD University Licensed under the New BSD license. You may not use this file except in compliance with this License. @@ -67,11 +68,7 @@ fluid.defaults("gpii.settingsHandlers.webSockets.component", { gpii.settingsHandlers.webSockets.addClient = function (that, solutionId, client) { console.log("CLIENT: " + client.typeName); - client.events.onReceiveMessage.addListener(function (message) { - if (message.type === "onSettingsChanged") { - console.log("HANDLE SETTINGS CHANGED"); - } - }); + client.events.onReceiveMessage.addListener(gpii.flowManager.browserChannel.receiveChangeSettingsMsg); var initialSettings = fluid.get(that.model.settings, [solutionId]); var currentValue = fluid.get(that.clients, [solutionId, client.id]); if (!currentValue) { @@ -85,6 +82,7 @@ gpii.settingsHandlers.webSockets.addClient = function (that, solutionId, client) gpii.settingsHandlers.webSockets.removeClient = function (that, client) { for (var solutionId in that.clients) { + client.events.onReceiveMessage.removeListener(gpii.flowManager.browserChannel.receiveChangeSettingsMsg); delete that.clients[solutionId][client.id]; if ($.isEmptyObject(that.clients[solutionId])) { delete that.clients[solutionId]; @@ -141,16 +139,20 @@ gpii.settingsHandlers.webSockets.setImpl = function (payload, that) { if ($.isEmptyObject(that.model.settings[path])) { delete that.model.settings[path]; } - gpii.settingsHandlers.webSockets.notifySettings(path, that); + + gpii.settingsHandlers.webSockets.notifySettings(payload.options, that); return results; }; -gpii.settingsHandlers.webSockets.notifySettings = function (id, that) { +gpii.settingsHandlers.webSockets.notifySettings = function (clientOptions, that) { + var id = clientOptions.path; if (id in that.clients) { var newSettings = gpii.settingsHandlers.webSockets.getSettingsForId(that, id); for (var client in that.clients[id]) { - that.clients[id][client].sendTypedMessage("onSettingsChanged", newSettings); + if (client !== clientOptions.source) { + that.clients[id][client].sendTypedMessage("onSettingsChanged", newSettings); + } } } }; diff --git a/gpii/node_modules/settingsHandlers/test/WebSocketsSettingsHandlerTests.js b/gpii/node_modules/settingsHandlers/test/WebSocketsSettingsHandlerTests.js index 44a197ef8..6c84c45ee 100644 --- a/gpii/node_modules/settingsHandlers/test/WebSocketsSettingsHandlerTests.js +++ b/gpii/node_modules/settingsHandlers/test/WebSocketsSettingsHandlerTests.js @@ -92,6 +92,40 @@ webSocketsTests.payloads = { } ] }, + setPayloadNoNotify: { + "net.gpii.test": [ + { + settings: { + dog: "woof", + cat: "meow", + amount: 3, + cheese: ["gouda", "brugge"], + "beers.trappiste": "Chimay", + "beers.blanche": "Hoegaarden", + "beers.scotch": "Achouffe McChouffe" + }, + options: { + path: "net.gpii.test", + dontNotify: true + } + } + ] + }, + expectedSetReturnPayloadNoNotify: { + "net.gpii.test": [ + { + settings: { + dog: { oldValue: "woof", newValue: "woof" }, + cat: { oldValue: "meow" , newValue: "meow" }, + amount: { oldValue: 3, newValue: 3 }, + cheese: { oldValue: ["gouda", "brugge"], newValue: ["gouda", "brugge"] }, + "beers.trappiste": {oldValue: "Chimay", newValue: "Chimay" }, + "beers.blanche": {oldValue: "Hoegaarden", newValue: "Hoegaarden" }, + "beers.scotch": {oldValue: "Achouffe McChouffe", newValue: "Achouffe McChouffe" } + } + } + ] + }, restorePayload: { "net.gpii.test": [ { @@ -149,6 +183,11 @@ jqUnit.test("Checking wsSettingsHandler's get/set methods", function () { webSocketsTests.payloads.expectedSetReturnPayload, setReturnPayload); + var setReturnPayloadNoNotify = gpii.resolveSync(gpii.settingsHandlers.webSockets.set(webSocketsTests.payloads.setPayloadNoNotify)); + jqUnit.assertDeepEq("Set function returns the expected payload", + webSocketsTests.payloads.expectedSetReturnPayloadNoNotify, + setReturnPayloadNoNotify); + var restoreReturnPayload = gpii.resolveSync(gpii.settingsHandlers.webSockets.set(webSocketsTests.payloads.restorePayload)); jqUnit.assertDeepEq("Restore returns the expected payload", webSocketsTests.payloads.expectedRestoreReturnPayload, From 54a04cf4dcbe3d75aa6ab231d238a2f9d5a76057 Mon Sep 17 00:00:00 2001 From: Joseph Scheuhammer Date: Mon, 15 Jun 2020 17:40:20 -0400 Subject: [PATCH 05/11] GPII-4218: Modifed to send confirmation receipt to the source request When a browser channel client sends a request to change settings, instead of silence, they receive a "changeSettingsReceived" message type as a response. All other clients are sent the "onSettingsChanged" message type, as before. --- .../flowManager/src/BrowserChannel.js | 16 +-- .../test/shared/BrowserChannelTestDefs.js | 34 +++--- .../src/WebSocketsSettingsHandler.js | 104 ++++++++++++++++-- 3 files changed, 120 insertions(+), 34 deletions(-) diff --git a/gpii/node_modules/flowManager/src/BrowserChannel.js b/gpii/node_modules/flowManager/src/BrowserChannel.js index e7d4adcad..7a4917f57 100644 --- a/gpii/node_modules/flowManager/src/BrowserChannel.js +++ b/gpii/node_modules/flowManager/src/BrowserChannel.js @@ -48,9 +48,8 @@ gpii.flowManager.browserChannel.sendError = function (request, message) { * 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 the closing of the - * connection. The one exception is the "changeSettings" message type (see - * first point). + * - 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 @@ -59,7 +58,6 @@ gpii.flowManager.browserChannel.sendError = function (request, message) { * is running on. */ gpii.flowManager.browserChannel.receiveMessage = function (that, message, solutionsRegistryDataSource, platformReporter) { - console.log("BC receiveMsg: " + JSON.stringify(message)); if (message.type !== "connect") { return; } @@ -82,15 +80,13 @@ gpii.flowManager.browserChannel.receiveMessage = function (that, message, soluti }; /** - * Listener for the "changeSettings" message type. If the message type is not - * "changeSettings", or if the socket connection has not been established, - * the message is ignored and this is a no-op. + * 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 - The "changeSettings" message and a payload of settings - * to modify. + * @param {Object} message - Object containing the message type and its payload. */ gpii.flowManager.browserChannel.receiveChangeSettingsMsg = function (that, message) { - console.log("BC receiveChangeSettingsMsg: " + JSON.stringify(message)); if (message.type === "changeSettings" && that.established) { var wsPayload = {}; wsPayload[that.solutionId] = [{ diff --git a/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js b/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js index b50264b92..11cf7cad1 100644 --- a/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js +++ b/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js @@ -123,11 +123,13 @@ gpii.tests.flowManager.browserChannel.checkPersistentSettings = function (client expectedSettings, gpii.settingsHandlers.webSockets.instance.getSettingsForId(clientId)); }; -gpii.tests.flowManager.browserChannel.checkSettingsAfterSet = function (data, clientId, expectedSettings) { - jqUnit.assertDeepEq( - "The persistent settings for " + clientId + " are, after setting them,", - expectedSettings, data - ); +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) { @@ -163,6 +165,7 @@ fluid.defaults("gpii.tests.flowManager.browserChannel.clientHolder", { settings: {}, events: { onSettingsChanged: null, + changeSettingsReceived: null, connectionSucceeded: null }, listeners: { @@ -323,7 +326,7 @@ gpii.tests.flowManager.browserChannel.testDefs = [{ }] }, { name: "Flow Manager BrowserChannel tests", - expect: 31, + expect: 32, config: { configName: "gpii.flowManager.tests.browserChannel.config", configPath: "%flowManager/test/configs" @@ -339,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: { @@ -455,19 +465,13 @@ gpii.tests.flowManager.browserChannel.testDefs = [{ } }, // All three clients now connected - clientOne sends a "changeSettings" - // request. As the source, it won't be notified of the change, but - // clientTwo, having the same ID, will. + // request and gets back a receipt, whereas clientTwo receives the changes. { func: "{clientOne}.sendChangeSettings" }, { - event: "{clientTwo}.events.onSettingsChanged", - listener: "gpii.tests.flowManager.browserChannel.checkSettingsAfterSet", - args: [ - "{arguments}.0", - "{clientTwo}.options.solutionId", - gpii.tests.flowManager.browserChannel.nvdaSetSettings - ] + event: "{testCaseHolder}.events.clientOneChangeSettings", + listener: "gpii.tests.flowManager.browserChannel.checkSettingsAfterSet" }, // Disconnect client 1 and try a spurious logout { diff --git a/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js b/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js index c5289be16..526dd3128 100644 --- a/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js +++ b/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js @@ -66,8 +66,18 @@ fluid.defaults("gpii.settingsHandlers.webSockets.component", { ///////////////// Clients ///////////////////// +/** + * Add a client, a web sockets message handler, to the set of clients that this + * settings handler services. This also: + * - adds a listener to the client so thatit relays "changeSettings" message + * payloads to this settings handler. + * - sends a reply back to the client containing the current settings value for + * that client's solution. + * @param {Component} that - An instance of gpii.settingsHandlers.webSockets.component. + * @param {String} solutionId - The solution that the client handles. + * @param {Component} client - The client request handler to add. + */ gpii.settingsHandlers.webSockets.addClient = function (that, solutionId, client) { - console.log("CLIENT: " + client.typeName); client.events.onReceiveMessage.addListener(gpii.flowManager.browserChannel.receiveChangeSettingsMsg); var initialSettings = fluid.get(that.model.settings, [solutionId]); var currentValue = fluid.get(that.clients, [solutionId, client.id]); @@ -80,6 +90,12 @@ gpii.settingsHandlers.webSockets.addClient = function (that, solutionId, client) } }; +/** + * Remoove a client, a web sockets message handler, from the set of clients that + * this settings handler services. + * @param {Component} that - An instance of gpii.settingsHandlers.webSockets.component. + * @param {Component} client - The client request handler to remove. + */ gpii.settingsHandlers.webSockets.removeClient = function (that, client) { for (var solutionId in that.clients) { client.events.onReceiveMessage.removeListener(gpii.flowManager.browserChannel.receiveChangeSettingsMsg); @@ -92,6 +108,10 @@ gpii.settingsHandlers.webSockets.removeClient = function (that, client) { ///////////////// Settings ///////////////////// +/** + * For debugging: log changes to settings. + * @param {Object} change - The modified setting. + */ gpii.settingsHandlers.webSockets.settingsChanged = function (/*change*/) { // Function retained for debugging purposes // Warning: the 'change' argument can be a circular JSON structure; @@ -99,10 +119,28 @@ gpii.settingsHandlers.webSockets.settingsChanged = function (/*change*/) { // console.log("A change in settings has been registered: " + util.inspect(change)); }; +/** + * Get the current settings associated with the given solution persisted by this + * settings handler. + * @param {Component} that - An instance of gpii.settingsHandlers.webSockets.component. + * @param {String} solutionId - The solution whose setting are sought. + * @return {Object} - The current values of the settings for the solution. + */ gpii.settingsHandlers.webSockets.getSettingsForId = function (that, solutionId) { return fluid.get(that.model.settings, [solutionId]); }; +/** + * Get the current value of specified settings associated with the given + * solution. + * @param {Object} payload - The solution and its setting whose current values + * are to be retrieved. + * @param {String} payload.options.path - The relevant solution. + * @param {Object} payload.settings - The settings whose current values are + * sought. + * @param {Component} that - An instance of gpii.settingsHandlers.webSockets.component. + * @return {Object} - the current values of the settings passed in. + */ gpii.settingsHandlers.webSockets.getImpl = function (payload, that) { var path = payload.options.path; var results = fluid.transform(payload.settings, function (value, key) { @@ -112,6 +150,21 @@ gpii.settingsHandlers.webSockets.getImpl = function (payload, that) { return results; }; +/** + * Modify the persistent settings based on the values passed in, and notify + * relevant clients of the changes. + * @param {Object} payload - Information about which settings to modify. + * @param {Object} payload.settings - The new values of the settings. + * @param {String} payload.options.path - Solution id whose setting are to change. + * @param {String} payload.options.source - The client requesting the changes. + * This client will not be notified of + * any changes. Other clients, who + * support the same solution, will. + * @param {Component} that - An instance of gpii.settingsHandlers.webSockets.component. + * @param {String} solutionId - The solution whose setting are sought. + * @return {Object} - a set of old value, new value pairs showing the changes + * for each setting. + */ gpii.settingsHandlers.webSockets.setImpl = function (payload, that) { var path = payload.options.path; var results = fluid.transform(payload.settings, function (value, key) { @@ -141,29 +194,62 @@ gpii.settingsHandlers.webSockets.setImpl = function (payload, that) { } gpii.settingsHandlers.webSockets.notifySettings(payload.options, that); - return results; }; +/** + * Notify relevant clients about changes to their solution's settings with + * either a "onSettingsChanged" or "changeSettingsReceived" message type. The + * client that requested the changes is sent the "changeSettingsReceived" + * response. All others are notified of the changes ("onSettingsChanged"). + * @param {Object} clientOptions - Information about which solutions and clients + * to notify. + * @param {String} clientOptions.path - The relevant solution id. + * @param {Component} clientOptions.source - The client who requested the + * changes. + * @param {Component} that - An instance of gpii.settingsHandlers.webSockets.component. + * managing clients and their solution's settings. + */ gpii.settingsHandlers.webSockets.notifySettings = function (clientOptions, that) { - var id = clientOptions.path; - if (id in that.clients) { - var newSettings = gpii.settingsHandlers.webSockets.getSettingsForId(that, id); - for (var client in that.clients[id]) { - if (client !== clientOptions.source) { - that.clients[id][client].sendTypedMessage("onSettingsChanged", newSettings); + var solutionId = clientOptions.path; + if (solutionId in that.clients) { + var newSettings = gpii.settingsHandlers.webSockets.getSettingsForId(that, solutionId); + for (var clientId in that.clients[solutionId]) { + var client = that.clients[solutionId][clientId]; + if (client === clientOptions.source) { + client.sendTypedMessage("changeSettingsReceived", newSettings); + } else { + client.sendTypedMessage("onSettingsChanged", newSettings); } } } }; -// Top-level driver methods for SettingsHandler +/////////// Top-level driver methods for SettingsHandler /////////////// +/** + * Retrieve a solution's settings based on the given information. + * @param {Object} payload - The solution's settings to retreive. + * @param {String} payload.options.path - Solution identifier. + * @param {Object} payload.settings - The settings whose current values are + * sought. + * @return {Promise} - A promise whose value, when resolved, is the settings. + */ gpii.settingsHandlers.webSockets.get = function (payload) { var instance = gpii.settingsHandlers.webSockets.instance; // this is placed there by FlowManager's mountInstance return gpii.settingsHandlers.invokeSettingsHandler(instance.getImpl, payload); }; +/** + * Modify a solution's settings based on the given information. + * @param {Object} payload - Array of solutions, their clients and settings to + * modify. + * @param {Component} payload.solutionId[i] - The client requesting the change. + * @param {Object} payload.solutionId[i].settings - The new values for the settings. + * @param {String} payload.solutionId[i].options.path - Solution identifier. + * @param {Component} payload.solutionId[i].options.source - The client requesting the change. + * @return {Promise} - A promise whose value, when resolved, is the modified settings. + */ gpii.settingsHandlers.webSockets.set = function (payload) { var instance = gpii.settingsHandlers.webSockets.instance; // this is placed there by FlowManager's mountInstance return gpii.settingsHandlers.invokeSettingsHandler(instance.setImpl, payload); From d42c4594da18e29bfc4bcc991e61768d13ce283f Mon Sep 17 00:00:00 2001 From: Joseph Scheuhammer Date: Tue, 16 Jun 2020 15:14:01 -0400 Subject: [PATCH 06/11] GPII-4218: Fixed comments, tests, and examples. --- .../browserChannelClient.js | 22 +++++++++++ .../pspChannelClientReadPrefs.js | 2 +- .../flowManager/src/BrowserChannel.js | 14 +++++++ .../test/shared/BrowserChannelTestDefs.js | 2 +- .../src/WebSocketsSettingsHandler.js | 13 +++---- .../test/WebSocketsSettingsHandlerTests.js | 39 ------------------- 6 files changed, 44 insertions(+), 48 deletions(-) diff --git a/examples/browserChannelClient/browserChannelClient.js b/examples/browserChannelClient/browserChannelClient.js index d9fe25f78..097220269 100644 --- a/examples/browserChannelClient/browserChannelClient.js +++ b/examples/browserChannelClient/browserChannelClient.js @@ -21,6 +21,8 @@ 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 () { @@ -39,6 +41,7 @@ socket.on("message", function (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") { + 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 @@ -46,4 +49,23 @@ socket.on("message", function (data) { else if (message.type === "onSettingsChanged") { 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" + } + } + })); + } }); diff --git a/examples/pspChannelClient/pspChannelClientReadPrefs.js b/examples/pspChannelClient/pspChannelClientReadPrefs.js index 9031f7966..da7988d63 100644 --- a/examples/pspChannelClient/pspChannelClientReadPrefs.js +++ b/examples/pspChannelClient/pspChannelClientReadPrefs.js @@ -53,7 +53,7 @@ socket.on("message", function (data) { "type": "pullModel", value: { settingControls: { - "http://registry\\.gpii\\.net/common/DPIScale": { + "http://registry\\.gpii\\.net/common/magnification": { value: 1 } } diff --git a/gpii/node_modules/flowManager/src/BrowserChannel.js b/gpii/node_modules/flowManager/src/BrowserChannel.js index 7a4917f57..728739ed8 100644 --- a/gpii/node_modules/flowManager/src/BrowserChannel.js +++ b/gpii/node_modules/flowManager/src/BrowserChannel.js @@ -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"); diff --git a/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js b/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js index 11cf7cad1..9856241bd 100644 --- a/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js +++ b/gpii/node_modules/flowManager/test/shared/BrowserChannelTestDefs.js @@ -284,7 +284,7 @@ gpii.tests.flowManager.browserChannel.testDefs = [{ sequence: [{ func: "gpii.tests.flowManager.browserChannel.checkClients" }, { - func: "{clientOne}.connect" // chromeClient (org.chrome.cloud4chrome) + func: "{clientOne}.connect" // chromeClient (org.nvda-project) }, { event: "{clientOne}.events.onConnect", listener: "fluid.identity" diff --git a/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js b/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js index 526dd3128..1a256c68b 100644 --- a/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js +++ b/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js @@ -3,7 +3,7 @@ Copyright 2014, 2015 Emergya Copyright 2015 Raising the Floor - International - Copyright 2020 IDRC, OCAD University + Copyright 2020 OCAD University Licensed under the New BSD license. You may not use this file except in compliance with this License. @@ -91,7 +91,7 @@ gpii.settingsHandlers.webSockets.addClient = function (that, solutionId, client) }; /** - * Remoove a client, a web sockets message handler, from the set of clients that + * Remove a client, a web sockets message handler, from the set of clients that * this settings handler services. * @param {Component} that - An instance of gpii.settingsHandlers.webSockets.component. * @param {Component} client - The client request handler to remove. @@ -152,14 +152,13 @@ gpii.settingsHandlers.webSockets.getImpl = function (payload, that) { /** * Modify the persistent settings based on the values passed in, and notify - * relevant clients of the changes. + * relevant clients of the changes. In this regard, the client that requested + * the settings is sent an acknowledgement using a "changeSettingsReceived" + * message type. The other clients are sent a "onSettingsChanged" message. * @param {Object} payload - Information about which settings to modify. * @param {Object} payload.settings - The new values of the settings. - * @param {String} payload.options.path - Solution id whose setting are to change. + * @param {String} payload.options.path - Solution id whose settings are to change. * @param {String} payload.options.source - The client requesting the changes. - * This client will not be notified of - * any changes. Other clients, who - * support the same solution, will. * @param {Component} that - An instance of gpii.settingsHandlers.webSockets.component. * @param {String} solutionId - The solution whose setting are sought. * @return {Object} - a set of old value, new value pairs showing the changes diff --git a/gpii/node_modules/settingsHandlers/test/WebSocketsSettingsHandlerTests.js b/gpii/node_modules/settingsHandlers/test/WebSocketsSettingsHandlerTests.js index 6c84c45ee..44a197ef8 100644 --- a/gpii/node_modules/settingsHandlers/test/WebSocketsSettingsHandlerTests.js +++ b/gpii/node_modules/settingsHandlers/test/WebSocketsSettingsHandlerTests.js @@ -92,40 +92,6 @@ webSocketsTests.payloads = { } ] }, - setPayloadNoNotify: { - "net.gpii.test": [ - { - settings: { - dog: "woof", - cat: "meow", - amount: 3, - cheese: ["gouda", "brugge"], - "beers.trappiste": "Chimay", - "beers.blanche": "Hoegaarden", - "beers.scotch": "Achouffe McChouffe" - }, - options: { - path: "net.gpii.test", - dontNotify: true - } - } - ] - }, - expectedSetReturnPayloadNoNotify: { - "net.gpii.test": [ - { - settings: { - dog: { oldValue: "woof", newValue: "woof" }, - cat: { oldValue: "meow" , newValue: "meow" }, - amount: { oldValue: 3, newValue: 3 }, - cheese: { oldValue: ["gouda", "brugge"], newValue: ["gouda", "brugge"] }, - "beers.trappiste": {oldValue: "Chimay", newValue: "Chimay" }, - "beers.blanche": {oldValue: "Hoegaarden", newValue: "Hoegaarden" }, - "beers.scotch": {oldValue: "Achouffe McChouffe", newValue: "Achouffe McChouffe" } - } - } - ] - }, restorePayload: { "net.gpii.test": [ { @@ -183,11 +149,6 @@ jqUnit.test("Checking wsSettingsHandler's get/set methods", function () { webSocketsTests.payloads.expectedSetReturnPayload, setReturnPayload); - var setReturnPayloadNoNotify = gpii.resolveSync(gpii.settingsHandlers.webSockets.set(webSocketsTests.payloads.setPayloadNoNotify)); - jqUnit.assertDeepEq("Set function returns the expected payload", - webSocketsTests.payloads.expectedSetReturnPayloadNoNotify, - setReturnPayloadNoNotify); - var restoreReturnPayload = gpii.resolveSync(gpii.settingsHandlers.webSockets.set(webSocketsTests.payloads.restorePayload)); jqUnit.assertDeepEq("Restore returns the expected payload", webSocketsTests.payloads.expectedRestoreReturnPayload, From 64f18ade9e81a163efe97d978088ba5532e8e022 Mon Sep 17 00:00:00 2001 From: Joseph Scheuhammer Date: Tue, 16 Jun 2020 15:17:44 -0400 Subject: [PATCH 07/11] GPII-4218: Fixed one more comment --- .../settingsHandlers/src/WebSocketsSettingsHandler.js | 1 - 1 file changed, 1 deletion(-) diff --git a/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js b/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js index 1a256c68b..74442e456 100644 --- a/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js +++ b/gpii/node_modules/settingsHandlers/src/WebSocketsSettingsHandler.js @@ -160,7 +160,6 @@ gpii.settingsHandlers.webSockets.getImpl = function (payload, that) { * @param {String} payload.options.path - Solution id whose settings are to change. * @param {String} payload.options.source - The client requesting the changes. * @param {Component} that - An instance of gpii.settingsHandlers.webSockets.component. - * @param {String} solutionId - The solution whose setting are sought. * @return {Object} - a set of old value, new value pairs showing the changes * for each setting. */ From 4883decd56e5fd67f6718ef8efebf43fcdac7ce5 Mon Sep 17 00:00:00 2001 From: Joseph Scheuhammer Date: Wed, 17 Jun 2020 12:12:02 -0400 Subject: [PATCH 08/11] GPII-4218: Reinstated the UIO+ "fabulous" inverse transform of 'contrastTheme' Modified the inverse transformation so that it validates. --- testData/solutions/win32.json5 | 45 ++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/testData/solutions/win32.json5 b/testData/solutions/win32.json5 index bf744ea85..5ff2d6f70 100644 --- a/testData/solutions/win32.json5 +++ b/testData/solutions/win32.json5 @@ -32622,6 +32622,51 @@ "offset": 1 } }, + "http://registry\\.gpii\\.net/common/highContrast/enabled": { + "transform": { + "type": "fluid.transforms.condition", + "condition": { + "transform": { + "type": "fluid.transforms.binaryOp", + "leftPath": "contrastTheme", + "operator": "!==", + "right": "default" + } + }, + "true": "true", + "false": "false" + } + }, + "http://registry\\.gpii\\.net/common/highContrastTheme": { + "transform": { + "type": "fluid.transforms.condition", + "condition": { + "transform": { + "type": "fluid.transforms.binaryOp", + "leftPath": "contrastTheme", + "operator": "!==", + "right": "default" + } + }, + "true": { + "transform": { + "type": "fluid.transforms.valueMapper", + "defaultInputPath": "contrastTheme", + "defaultOutputValue": "default", + "match": { + "bw": "black-white", + "wb": "white-black", + "by": "black-yellow", + "yb": "yellow-black", + "lgdg":"grey-black", + "gw": "grey-white", + "bbr": "black-brown" + } + } + }, + "false": "regular-contrast" + } + }, "http://registry\\.gpii\\.net/common/fontSize": { "transform": { "type": "fluid.transforms.round", From a8f3d5504621fdfc948ea7b72ffd343ee32e1671 Mon Sep 17 00:00:00 2001 From: Joseph Scheuhammer Date: Fri, 19 Jun 2020 14:12:54 -0400 Subject: [PATCH 09/11] GPII-4218: Brought UIO+ high contrast transform into line with GPII-4492 --- testData/solutions/win32.json5 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/testData/solutions/win32.json5 b/testData/solutions/win32.json5 index 5ff2d6f70..038abacc9 100644 --- a/testData/solutions/win32.json5 +++ b/testData/solutions/win32.json5 @@ -32532,8 +32532,10 @@ }, "contrastTheme": { "transform": { - // Use the same condition for applying a high contrast theme to windows: - // (highContrast.enabled || highContrastTheme) && (highContrastTheme != "regular-contrast") + // Use the same conditions for applying a high + // contrast theme as specified for the + // "com.microsoft.windows.highContrast" solution: + // (highContrast.enabled !== false) && (highContrastTheme !== "regular-contrast") "type": "fluid.transforms.condition", "condition": { "transform": { @@ -32542,9 +32544,8 @@ "transform": { "type": "fluid.transforms.binaryOp", "leftPath": "http://registry\\.gpii\\.net/common/highContrast/enabled", - "left": false, - "operator": "||", - "rightPath": "http://registry\\.gpii\\.net/common/highContrastTheme", + "left": true, + "operator": "!==", "right": false } }, From d5c0caf9b756fe91f6afec6f54e5516573f2a8ce Mon Sep 17 00:00:00 2001 From: Joseph Scheuhammer Date: Fri, 19 Jun 2020 15:18:48 -0400 Subject: [PATCH 10/11] GPII-4218: Updated the BrowserChannel documentation --- documentation/BrowserChannel.md | 65 ++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/documentation/BrowserChannel.md b/documentation/BrowserChannel.md index 43739d51d..86e13fade 100644 --- a/documentation/BrowserChannel.md +++ b/documentation/BrowserChannel.md @@ -5,14 +5,34 @@ This document describes how the __Browser Channel__ and the __WebSockets__ setti This feature consists on: * A route in the Flow Manager that serves as the entry point for clients: `/browserChannel` -* The component behind this route is the _gpii.settingsHandlers.webSockets.component_ +* The components behind this route are the _gpii.flowManager.browserChannel.handler_ + and the _gpii.settingsHandlers.webSockets.component_ ## The browser channel -This handler processes every request to `http://localhost:8081/browserChannel` and is responsible for: +This handler processes every request to `ws://localhost:8081/browserChannel` and is responsible for: * Processing every request and determining whether a client is allowed or not to connect -* Registering and removing the clients as they are connecting or disconnecting +* Registering and removing the clients as they connect or disconnect. +* Processing modifications of settings that are caused by other aspects of the system, e.g. a new user logs in. + +The browser channel handler supports the following request messages and sends the +associated responses. When an error occurs, the handler sends an response and +closes the web sockets connection. + +* A client sends a connection request. In this example, the client is UIO+: + * request: `{type: "connect", solutionId: "net.gpii.uioPlus"}` + * response: `{type: "connectionSucceeded, "payload": {initial settings values for the solutionId}}` +* Client sends a request to change settings values: + * request: `{type: "changeSettings", "payload": {settings values to change}}` + * response: `{type: "changeSettingsReceived", "payload": {settings values after changing}}` +* Some other component of the system changes a setting relevant to connected clients: + * response: `{type: "onChangeSettings", "payload:" {settings values after changing}}` +* Error response when connecting with an unknown solution: + * response: `{isError: true, message: "Rejecting a connection request from _solutionId_. + The solution id was not found in the solutions registry"}` +* Error response when trying to connect more than once: + * response: `{isError: true, message: "Connection already established - cannot send a second connect message"}` ## The WebSockets settings handler @@ -21,8 +41,7 @@ of the system. The settings handler is an instance of `gpii.settingsHandler.web in _gpii/node_modules/settingsHandlers/src/WebSocketsComponent.js_. This component stores the information about clients and keeps a list of settings for every solution that makes use of -this settings handler. Also, this component create notifications for every connected client at any time when the -settings change. +this settings handler. Also, this component notifies connecteds client at any time when the settings change. ## Usage @@ -69,30 +88,34 @@ The workflow between the client and server can be summarised as follows: the *id* of the client, in this instance `net.gpii.uioPlus`. * The client will be registered if the solution's id can be found of the solutions registry, otherwise, the registration will be rejected and the system will emit en error, and the client will disconnect. -* When the flow manager emits either the _connectionSucceeded_ (after being registered) or the _onSettingsChanged_ - (after a user login/logout) signal to the client, it is delivering the current available settings for the client in - the following way: - +* The client can request changes to its settings by sending a _changeSettings_ message type. If successful, the client + is sent a _changeSettingsReceived_ message type. +* When a _connectionSucceeded_, _changeSettingsReceived_, or an _onSettingsChanged_ signal is sent to the client, the + current available settings for the client are sent as well, e.g.: ```json { - "screenReaderTTS/enabled":false, - "highContrast/enabled":true, - "invertColours":false, - "magnifierEnabled":true, - "magnification":2, - "fontSize":"medium", - "simplifier":false, - "highContrastTheme":"white-black" + "characterSpace":1, + "clickToSelectEnabled":false, + "contrastTheme":"wb", + "fontSize":1.1, + "inputsLargerEnabled":false, + "lineSpace":1, + "selectionTheme":"default", + "selfVoicingEnabled":false, + "simplifiedUiEnabled":false, + "syllabificationEnabled":false, + "tableOfContentsEnabled":false, + "wordSpace":1 } ``` -* When a client disconnects, it'll be removed from the list of registered clients +* When a client disconnects, it is removed from the list of registered clients ## Running the sample client -The client has been checked in to [../examples/browserChannelClient](../examples/browserChannelClient). To try it out, first -start the GPII in the CloudBased browserChannel test configuration from the root of universal with +An example client is avaiable at [../examples/browserChannelClient](../examples/browserChannelClient). To try it out, first +start the GPII test configuration from the root of universal with - node gpii.js gpii/configs gpii.config.cloudBased.production + npm start Then start the client from [../examples/browserChannelClient](../examples/browserChannelClient) with From f3fa4fa9940bb03bcbac42034ad7229776515aa3 Mon Sep 17 00:00:00 2001 From: Joseph Scheuhammer Date: Mon, 22 Jun 2020 10:00:07 -0400 Subject: [PATCH 11/11] GPII-4218: Fixed grammar --- documentation/BrowserChannel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/BrowserChannel.md b/documentation/BrowserChannel.md index 86e13fade..34a1f8588 100644 --- a/documentation/BrowserChannel.md +++ b/documentation/BrowserChannel.md @@ -41,7 +41,7 @@ of the system. The settings handler is an instance of `gpii.settingsHandler.web in _gpii/node_modules/settingsHandlers/src/WebSocketsComponent.js_. This component stores the information about clients and keeps a list of settings for every solution that makes use of -this settings handler. Also, this component notifies connecteds client at any time when the settings change. +this settings handler. Also, this component notifies connected clients whenever their settings change. ## Usage