diff --git a/gpii.js b/gpii.js index 4280439..306770f 100644 --- a/gpii.js +++ b/gpii.js @@ -14,8 +14,9 @@ var fluid = require("universal"), gpii = fluid.registerNamespace("gpii"); fluid.require("gsettingsBridge", require); +fluid.require("orca", require); gpii.config.makeConfigLoader({ nodeEnv: gpii.config.getNodeEnv("fm.ps.sr.dr.mm.os.development"), configPath: gpii.config.getConfigPath() || "../node_modules/universal/gpii/configs" -}); \ No newline at end of file +}); diff --git a/node_modules/orca/index.js b/node_modules/orca/index.js new file mode 100644 index 0000000..d2dfff4 --- /dev/null +++ b/node_modules/orca/index.js @@ -0,0 +1,18 @@ +/*! + * GPII Orca Settings Handler + * + * Copyright 2013 Emergya + * Author Javier Hernández + * + * 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 + * */ + +var fluid = require("universal"); + +var loader = fluid.getLoader(__dirname); + +loader.require("./orcaSettingsHandler.js"); diff --git a/node_modules/orca/orcaSettingsHandler.js b/node_modules/orca/orcaSettingsHandler.js new file mode 100644 index 0000000..ab563c2 --- /dev/null +++ b/node_modules/orca/orcaSettingsHandler.js @@ -0,0 +1,147 @@ +/*! + * GPII Orca Settings Handler + * + * Copyright 2013 Emergya + * Author Javier Hernández + * + * 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 + * */ + +(function () { + "use strict"; + + var fluid = require("universal"); + var gpii = fluid.registerNamespace("gpii"); + var fs = require("fs"); + var spawn = require("child_process").spawn; + var path = require("path"); + + // Workaround to load orca's user-settings.conf file according to + // comments on https://github.com/joyent/node/issues/6073 + // + require.extensions['.conf'] = require.extensions['.json']; + + var ORCA_ARGS = ["--disable", "speech", + "--disable", "braille", + "--disable", "braille-monitor", + "--disable", "main-window", + "--disable", "splash-window"]; + + var HOME = process.env.HOME; + var XDG_DATA_HOME = process.env.XDG_DATA_HOME || path.resolve(HOME, ".local/share"); + var orcaSettingsFile = path.resolve(XDG_DATA_HOME, "orca/user-settings.conf"); + + fluid.registerNamespace("gpii.launch"); + fluid.registerNamespace("gpii.orca"); + + // TODO: Remove this method and all the blocking stuff. + // (see https://github.com/GPII/linux/pull/16) + // + // This setting handler has to be converted to an asynchronous as soon as + // the lifecycle manager can handle asynchronous actions. + // + // The reason for this blocking code is because we need a mechanism to know + // when the Orca's settings file has been created. + // + // The blocking "while loop" is where this method is used and is a big + // stability risk to the system, since it blocks the node event loop + // possibly indefinitely. + // + // Once we can make this setting handler to be asynchronous, we can use + // fs.watch or any other similar asynchronous approaches to know + // when the orca settings file is being created. + // + function wait(millis) { + var date = new Date(); + var curDate; + + do { curDate = new Date(); } + while(curDate-date < millis); + } + + function applySettings(app) { + var settings = app["org.gnome.orca"][0].settings; + var options = app["org.gnome.orca"][0].options; + var user = options.user; + + var userSettings = require(orcaSettingsFile); + var defaultProfiles = fluid.copy(userSettings.profiles); + var defaultStartingProfile = fluid.copy(userSettings.general.startingProfile); + var customizedProfile = fluid.copy(userSettings.general); + + if ("profiles" in settings) { + userSettings.profiles = settings.profiles; + userSettings.general.startingProfile = settings["general.startingProfile"]; + } else { + fluid.log("orcaSettingsHandler: User ", user, + " has requested these following settings: ", settings); + + for (var k in settings) { + fluid.set(customizedProfile, k, settings[k], fluid.model.escapedSetConfig); + } + + customizedProfile.profile = customizedProfile.activeProfile = + customizedProfile.startingProfile = + [user, user]; + + userSettings.profiles[user] = customizedProfile; + userSettings.general.startingProfile = [user, user]; + } + + fs.writeFileSync(orcaSettingsFile, + JSON.stringify(userSettings, null, 4)); + + var newSettingsResponse = { + "profiles": { + "oldValue": defaultProfiles, + "newValue": userSettings.profiles + }, + "general.startingProfile": { + "oldValue": defaultStartingProfile, + "newValue": [user, user] + } + }; + + return { "options": options, "settings": newSettingsResponse}; + } + + gpii.orca.set = function (profile) { + var returnObj = fluid.copy(profile); + + var exists = fs.existsSync(orcaSettingsFile); + if (!exists) { + var orcaSpawn = spawn("orca", ORCA_ARGS); + var pass = 0; + var maxPass = 10; + var err; + + while(!fs.existsSync(orcaSettingsFile)) { + if (pass == maxPass) { + err = "Time limit exceeded [" + maxPass*500 + + "ms] for creating Orca's configuration file"; + break; + } + wait(500); + pass++; + } + + orcaSpawn.kill("SIGKILL"); + if (err) { + fluid.fail(err); + fluid.log(err); + return; + } + } + + var returnValue = applySettings(profile); + returnObj['org.gnome.orca'][0].options = returnValue.options; + returnObj['org.gnome.orca'][0].settings = returnValue.settings; + + return returnObj; + }; + +})(); diff --git a/node_modules/orca/package.json b/node_modules/orca/package.json new file mode 100644 index 0000000..872bcc1 --- /dev/null +++ b/node_modules/orca/package.json @@ -0,0 +1,19 @@ +{ + "name": "orca", + "description": "GPII Orca Settings Handler", + "version": "0.1", + "author": "Javier Hernández", + "bugs": "http://wiki.gpii.net/index.php/Main_Page", + "homepage": "http://gpii.net/", + "dependencies": {}, + "licenses": [ + { + "type": "BSD-3-Clause", + "url": "http://www.opensource.org/licenses/BSD-3-Clause" + } + ], + "keywords": ["gpii", "accessibility", "settings", "fluid"], + "repository": "git://github.com:GPII/linux.git", + "main": "./index.js", + "engines": { "node" : ">=0.1.9" } +} diff --git a/node_modules/orca/test/orcaSettingsHandlerTests.js b/node_modules/orca/test/orcaSettingsHandlerTests.js new file mode 100644 index 0000000..288851b --- /dev/null +++ b/node_modules/orca/test/orcaSettingsHandlerTests.js @@ -0,0 +1,82 @@ +/*! +Orca Settings Handler Tests + +Copyright 2013 Emergya + +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 +*/ + +var fluid = require("universal"), + gpii = fluid.registerNamespace("gpii"), + jqUnit = fluid.require("jqUnit"), + fs = require("fs"); + var orcaSettingsHandler = require("../orcaSettingsHandler"); + var orca = fluid.registerNamespace("gpii.orca"); + +jqUnit.module("OrcaSettingsHandler Module"); + +jqUnit.test("Running tests for Orca Settings Handler", function () { + jqUnit.expect(10); + + var payload = { + "org.gnome.orca": [{ + options: { + "user": "test1" + }, + settings: { + "enableBraille": true, + "enableEchoByWord": true, + "enableEchoByCharacter": false, + "voices.default.rate": 100, + "enableTutorialMessages": false, + "voices.default.family": { "locale": "es", "name": "spanish-latin-american" }, + "verbalizePunctuationStyle": 0 + } + }] + }; + + var returnPayload = orca.set(payload); + + // Check if profile exists + // + jqUnit.assertTrue("Profile 'test1' exists", returnPayload["org.gnome.orca"][0].settings.profiles.newValue.test1); + + // Check if 'test1' is the default starting profile + // + actual = returnPayload["org.gnome.orca"][0].settings["general.startingProfile"].newValue; + jqUnit.assertDeepEq("'test1' is the new starting profile", ['test1', 'test1'], actual); + + // Check for specific one-to-one settings from the payload + // + for (var setting in ["enableBraille", "enableEchoByWord", "enableEchoByCharacter", "enableTutorialMessages", "verbalizePunctuationStyle"]) { + jqUnit.assertDeepEq("Checking " + setting + " setting", + payload["org.gnome.orca"][0].settings[setting], + returnPayload["org.gnome.orca"][0].settings.profiles.newValue.test1[setting]); + } + + // Check for voices' stuff + // + jqUnit.assertDeepEq("Checking for voices.default.rate setting", + payload["org.gnome.orca"][0].settings["voices.default.rate"], + returnPayload["org.gnome.orca"][0].settings.profiles.newValue.test1.voices.default.rate); + + jqUnit.assertDeepEq("Checking for voices.default.family setting", + payload["org.gnome.orca"][0].settings["voices.default.family"], + returnPayload["org.gnome.orca"][0].settings.profiles.newValue.test1.voices.default.family); + + // Let's simulate a logout and restore the settings file into its initial state + // + var newPayload = fluid.copy(payload); + newPayload['org.gnome.orca'][0].settings.profiles = returnPayload["org.gnome.orca"][0].settings.profiles.oldValue; + newPayload['org.gnome.orca'][0].settings['general.startingProfile'] = returnPayload["org.gnome.orca"][0].settings["general.startingProfile"].oldValue; + var newReturnPayload = orca.set(newPayload); + + // Check if 'test1' profile has been removed successfully + // + jqUnit.assertFalse("Profile 'test1' does not exists", newReturnPayload["org.gnome.orca"][0].settings.profiles.newValue.test1); + +});