mirror of
https://github.com/flyandi/mazda-custom-application-sdk
synced 2024-12-23 03:35:29 -06:00
More CMU backend works
This commit is contained in:
parent
fb1eb10596
commit
846dd7ea78
11 changed files with 830 additions and 55 deletions
5
apps/app.helloworld/app.json
Normal file
5
apps/app.helloworld/app.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"id": "app.helloworld",
|
||||||
|
"name": "Hello World",
|
||||||
|
"enabled": true
|
||||||
|
}
|
1
apps/appdrive.json
Normal file
1
apps/appdrive.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"bla": "foo"}
|
93
gulpfile.js
93
gulpfile.js
|
@ -50,7 +50,9 @@ var
|
||||||
del = require('del'),
|
del = require('del'),
|
||||||
fs = require('fs'),
|
fs = require('fs'),
|
||||||
glob = require('glob'),
|
glob = require('glob'),
|
||||||
exec = require('child_process').exec;
|
exec = require('child_process').exec,
|
||||||
|
using = require('gulp-using'),
|
||||||
|
flatten = require('gulp-flatten');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package
|
* @package
|
||||||
|
@ -109,7 +111,7 @@ var buildJsonVersion = function(output, destination, name, attributes) {
|
||||||
/**
|
/**
|
||||||
* (build) local apps
|
* (build) local apps
|
||||||
*
|
*
|
||||||
* These tasks handle the copy and build of the local apps
|
* These tasks handles the example apps
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var appsPathInput = "./apps/",
|
var appsPathInput = "./apps/",
|
||||||
|
@ -149,59 +151,59 @@ gulp.task('build-apps', function(callback) {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tasks to build the runtime
|
* tasks to build the framework
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var systemPathOutput = output + "system/",
|
var systemPathOutput = output + "system/",
|
||||||
runtimePathInput = input + "runtime/",
|
frameworkPathInput = input + "framework/",
|
||||||
runtimePathOutput = systemPathOutput + "runtime/",
|
frameworkPathOutput = systemPathOutput + "framework/",
|
||||||
customPathInput = input + "custom/";
|
customPathInput = input + "custom/";
|
||||||
|
|
||||||
// (cleanup)
|
// (cleanup)
|
||||||
gulp.task('system-cleanup', function() {
|
gulp.task('framework-cleanup', function() {
|
||||||
return del(
|
return del(
|
||||||
[systemPathOutput + '**/*']
|
[systemPathOutput + '**/*']
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// (skeleton)
|
// (skeleton)
|
||||||
gulp.task('system-runtime-skeleton', function() {
|
gulp.task('framework-skeleton', function() {
|
||||||
|
|
||||||
return gulp.src(runtimePathInput + "skeleton/**/*", {
|
return gulp.src(frameworkPathInput + "skeleton/**/*", {
|
||||||
base: runtimePathInput + "skeleton"
|
base: frameworkPathInput + "skeleton"
|
||||||
})
|
})
|
||||||
.pipe(gulp.dest(runtimePathOutput));
|
.pipe(gulp.dest(frameworkPathOutput));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// (less)
|
// (less)
|
||||||
gulp.task('system-runtime-less', function() {
|
gulp.task('framework-less', function() {
|
||||||
|
|
||||||
return gulp.src(runtimePathInput + "less/*", {
|
return gulp.src(frameworkPathInput + "less/*", {
|
||||||
base: runtimePathInput + "less"
|
base: frameworkPathInput + "less"
|
||||||
})
|
})
|
||||||
.pipe(concat('runtime.css'))
|
.pipe(concat('framework.css'))
|
||||||
.pipe(less())
|
.pipe(less())
|
||||||
.pipe(gulp.dest(runtimePathOutput));
|
.pipe(gulp.dest(frameworkPathOutput));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// (Concatenate & Minify)
|
// (Concatenate & Minify)
|
||||||
gulp.task('system-runtime-js', function() {
|
gulp.task('framework-js', function() {
|
||||||
|
|
||||||
return gulp.src(runtimePathInput + "js/*", {
|
return gulp.src(frameworkPathInput + "js/*", {
|
||||||
base: runtimePathInput + "js"
|
base: frameworkPathInput + "js"
|
||||||
})
|
})
|
||||||
.pipe(concat('runtime.js'))
|
.pipe(concat('framework.js'))
|
||||||
.pipe(uglify())
|
.pipe(uglify())
|
||||||
.pipe(concatutil.header(fs.readFileSync(runtimePathInput + "resources/header.txt", "utf8"), {
|
.pipe(concatutil.header(fs.readFileSync(frameworkPathInput + "resources/header.txt", "utf8"), {
|
||||||
pkg: package
|
pkg: package
|
||||||
}))
|
}))
|
||||||
.pipe(gulp.dest(runtimePathOutput));
|
.pipe(gulp.dest(frameworkPathOutput));
|
||||||
});
|
});
|
||||||
|
|
||||||
// (copy custom app)
|
// (copy custom app)
|
||||||
gulp.task('system-custom', function() {
|
gulp.task('framework-custom', function() {
|
||||||
return gulp.src(customPathInput + "**/*", {
|
return gulp.src(customPathInput + "**/*", {
|
||||||
base: customPathInput
|
base: customPathInput
|
||||||
})
|
})
|
||||||
|
@ -209,25 +211,25 @@ gulp.task('system-custom', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
/** @job system-version */
|
/** @job system-version */
|
||||||
gulp.task('system-version', function() {
|
gulp.task('framework-version', function() {
|
||||||
|
|
||||||
buildJsonVersion("runtime.json", runtimePathOutput, "runtime-package", function(package) {
|
buildJsonVersion("framework.json", frameworkPathOutput, "framework-package", function(package) {
|
||||||
return {
|
return {
|
||||||
runtime: true,
|
framework: true,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// (build system)
|
// (build framework)
|
||||||
gulp.task('build-system', function(callback) {
|
gulp.task('build-framework', function(callback) {
|
||||||
runSequence(
|
runSequence(
|
||||||
'system-cleanup',
|
'framework-cleanup',
|
||||||
'system-runtime-skeleton',
|
'framework-skeleton',
|
||||||
'system-runtime-less',
|
'framework-less',
|
||||||
'system-runtime-js',
|
'framework-js',
|
||||||
'system-custom',
|
'framework-custom',
|
||||||
'system-version',
|
'framework-version',
|
||||||
callback
|
callback
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -380,6 +382,8 @@ gulp.task('build-sdcard', function(callback) {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build documentation
|
* Build documentation
|
||||||
*/
|
*/
|
||||||
|
@ -597,7 +601,7 @@ gulp.task('clean', function() {
|
||||||
gulp.task('default', function(callback) {
|
gulp.task('default', function(callback) {
|
||||||
runSequence(
|
runSequence(
|
||||||
'clean',
|
'clean',
|
||||||
'build-system',
|
'build-framework',
|
||||||
'build-install',
|
'build-install',
|
||||||
'build-uninstall',
|
'build-uninstall',
|
||||||
'build-sdcard',
|
'build-sdcard',
|
||||||
|
@ -605,3 +609,24 @@ gulp.task('default', function(callback) {
|
||||||
callback
|
callback
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node
|
||||||
|
*/
|
||||||
|
|
||||||
|
var nodePathInput = input + 'node-cmu/',
|
||||||
|
nodePathSource = input + 'node/latest/',
|
||||||
|
nodePathOutput = output + 'node/';
|
||||||
|
|
||||||
|
|
||||||
|
// (cleanup)
|
||||||
|
gulp.task('node', function() {
|
||||||
|
|
||||||
|
// copy embeeded files
|
||||||
|
gulp.src(nodePathInput + "**/*.js", {
|
||||||
|
base: nodePathInput
|
||||||
|
}).pipe(flatten()).pipe(gulp.dest(nodePathOutput + 'cmu'));
|
||||||
|
|
||||||
|
|
||||||
|
});
|
|
@ -15,6 +15,7 @@
|
||||||
"gulp-concat": "^2.6.0",
|
"gulp-concat": "^2.6.0",
|
||||||
"gulp-concat-util": "^0.5.5",
|
"gulp-concat-util": "^0.5.5",
|
||||||
"gulp-file": "^0.2.0",
|
"gulp-file": "^0.2.0",
|
||||||
|
"gulp-flatten": "^0.2.0",
|
||||||
"gulp-git": "^1.7.0",
|
"gulp-git": "^1.7.0",
|
||||||
"gulp-jsdoc": "^0.1.5",
|
"gulp-jsdoc": "^0.1.5",
|
||||||
"gulp-less": "^3.0.5",
|
"gulp-less": "^3.0.5",
|
||||||
|
@ -23,6 +24,7 @@
|
||||||
"gulp-replace": "^0.5.4",
|
"gulp-replace": "^0.5.4",
|
||||||
"gulp-tar": "^1.8.0",
|
"gulp-tar": "^1.8.0",
|
||||||
"gulp-uglify": "^1.5.2",
|
"gulp-uglify": "^1.5.2",
|
||||||
|
"gulp-using": "^0.1.0",
|
||||||
"gulp-webserver": "^0.9.1",
|
"gulp-webserver": "^0.9.1",
|
||||||
"run-sequence": "^1.1.5"
|
"run-sequence": "^1.1.5"
|
||||||
},
|
},
|
||||||
|
|
51
src/node-cmu/cmu-utils.js
Normal file
51
src/node-cmu/cmu-utils.js
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/**
|
||||||
|
* Custom Application SDK for Mazda Connect Infotainment System
|
||||||
|
*
|
||||||
|
* A micro framework that allows to write custom applications for the Mazda Connect Infotainment System
|
||||||
|
* that includes an easy to use abstraction layer to the JCI system.
|
||||||
|
*
|
||||||
|
* Written by Andreas Schwarz (http://github.com/flyandi/mazda-custom-applications-sdk)
|
||||||
|
* Copyright (c) 2016. All rights reserved.
|
||||||
|
*
|
||||||
|
* WARNING: The installation of this application requires modifications to your Mazda Connect system.
|
||||||
|
* If you don't feel comfortable performing these changes, please do not attempt to install this. You might
|
||||||
|
* be ending up with an unusuable system that requires reset by your Dealer. You were warned!
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program.
|
||||||
|
* If not, see http://www.gnu.org/licenses/
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A minimal implementation of the extend algorithm
|
||||||
|
* @param Any object
|
||||||
|
* @return object Returns an objec
|
||||||
|
*/
|
||||||
|
exports.extend = function(out) {
|
||||||
|
|
||||||
|
out = out || {};
|
||||||
|
|
||||||
|
for (var i = 1; i < arguments.length; i++) {
|
||||||
|
if (!arguments[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (var key in arguments[i]) {
|
||||||
|
if (arguments[i].hasOwnProperty(key))
|
||||||
|
out[key] = arguments[i][key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
};
|
356
src/node-cmu/cmu.js
Normal file
356
src/node-cmu/cmu.js
Normal file
|
@ -0,0 +1,356 @@
|
||||||
|
/**
|
||||||
|
* Custom Application SDK for Mazda Connect Infotainment System
|
||||||
|
*
|
||||||
|
* A micro framework that allows to write custom applications for the Mazda Connect Infotainment System
|
||||||
|
* that includes an easy to use abstraction layer to the JCI system.
|
||||||
|
*
|
||||||
|
* Written by Andreas Schwarz (http://github.com/flyandi/mazda-custom-applications-sdk)
|
||||||
|
* Copyright (c) 2016. All rights reserved.
|
||||||
|
*
|
||||||
|
* WARNING: The installation of this application requires modifications to your Mazda Connect system.
|
||||||
|
* If you don't feel comfortable performing these changes, please do not attempt to install this. You might
|
||||||
|
* be ending up with an unusuable system that requires reset by your Dealer. You were warned!
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program.
|
||||||
|
* If not, see http://www.gnu.org/licenses/
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const VERSION = "0.0.1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Definitions
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
|
||||||
|
const _webSocketServer = require("ws").Server;
|
||||||
|
const _extend = require("./cmu-utils").extend;
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimal Command
|
||||||
|
* @constants
|
||||||
|
*/
|
||||||
|
|
||||||
|
const REQUEST_VERSION = "version";
|
||||||
|
const REQUEST_PING = "ping";
|
||||||
|
const REQUEST_APPLICATIONS = "applications";
|
||||||
|
|
||||||
|
const RESULT_OK = 200;
|
||||||
|
const RESULT_PONG = 201;
|
||||||
|
const RESULT_NOTFOUND = 404;
|
||||||
|
const RESULT_ERROR = 500;
|
||||||
|
|
||||||
|
|
||||||
|
const MOUNTROOT_PATH = "/tmp/mnt/";
|
||||||
|
const APPLICATIONS_PATH = "/apps/";
|
||||||
|
|
||||||
|
const APPLICATION_JSON = "app.json";
|
||||||
|
const APPLICATION_CSS = "app.css";
|
||||||
|
const APPLICATION_JS = "app.js";
|
||||||
|
const APPLICATION_WORKER = "worker.js";
|
||||||
|
|
||||||
|
const APPDRIVE_JSON = "appdrive.json";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the CMU that is compiled into the node binary and runs the actual link between the
|
||||||
|
* custom applications and the CMU.
|
||||||
|
* @node-cmu
|
||||||
|
*/
|
||||||
|
|
||||||
|
function cmu() {
|
||||||
|
|
||||||
|
this.__construct();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prototypes
|
||||||
|
* @type The prototype object
|
||||||
|
*/
|
||||||
|
cmu.prototype = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The version number
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
version: VERSION,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The network object
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
network: {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The network port
|
||||||
|
*/
|
||||||
|
port: 9700,
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the CMU object
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
__construct: function()
|
||||||
|
{
|
||||||
|
this.applications = {};
|
||||||
|
|
||||||
|
this.__socket = new _webSocketServer({
|
||||||
|
port: this.network.port
|
||||||
|
});
|
||||||
|
|
||||||
|
this.__socket.on('connection', function(client) {
|
||||||
|
|
||||||
|
this.attachClient(client);
|
||||||
|
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preps a client
|
||||||
|
* @param object client The client instance
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
attachClient: function(client) {
|
||||||
|
|
||||||
|
client.on('message', function(message) {
|
||||||
|
|
||||||
|
this.handleClientData(client, message);
|
||||||
|
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
client.on('close', function() {
|
||||||
|
|
||||||
|
// do nothing
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on('error', function(e) {
|
||||||
|
|
||||||
|
// do nothing
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a client message
|
||||||
|
* @param object client The client instance
|
||||||
|
* @param string message The message payload
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
handleClientData: function(client, message, flags) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
var payload = JSON.parse(message);
|
||||||
|
|
||||||
|
// process minimal command interfae
|
||||||
|
if(payload.request) {
|
||||||
|
|
||||||
|
switch(payload.request) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current CMU backend version
|
||||||
|
* @type REQUEST_VERSION
|
||||||
|
*/
|
||||||
|
case REQUEST_VERSION:
|
||||||
|
|
||||||
|
return this.sendFromPayload(client, payload, {
|
||||||
|
version: this.getVersion()
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Heartbeat
|
||||||
|
* @type REQUEST_PING
|
||||||
|
*/
|
||||||
|
case REQUEST_PING:
|
||||||
|
|
||||||
|
return this.sendFromPayload(client, payload, {
|
||||||
|
outboundStamp: (new Date()).getTime()
|
||||||
|
}, RESULT_PONG);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current registered applications
|
||||||
|
* @type REQUEST_APPLICATIONS
|
||||||
|
*/
|
||||||
|
case REQUEST_APPLICATIONS:
|
||||||
|
|
||||||
|
// find applications
|
||||||
|
this.findApplications(function(applications, appdrive) {
|
||||||
|
|
||||||
|
this.sendFromPayload(client, payload, {
|
||||||
|
applications: applications,
|
||||||
|
appdrive: appdrive,
|
||||||
|
});
|
||||||
|
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default - Pass to application handler
|
||||||
|
* @type default
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch(e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a payload back to the client
|
||||||
|
* @param object client The client
|
||||||
|
* @param object payload The payload in object format
|
||||||
|
* @return boolean Returns the status of the operation
|
||||||
|
*/
|
||||||
|
sendFromPayload: function(client, payload, data, resultCode) {
|
||||||
|
|
||||||
|
var final = JSON.stringify(_extend({}, payload, data, {
|
||||||
|
result: resultCode || RESULT_OK
|
||||||
|
}));
|
||||||
|
|
||||||
|
client.send(final);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the version
|
||||||
|
* @getter
|
||||||
|
* @return string The version number
|
||||||
|
*/
|
||||||
|
getVersion: function() {
|
||||||
|
return this.version;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds all applications in known locations
|
||||||
|
* @return {[type]} [description]
|
||||||
|
*/
|
||||||
|
findApplications: function(callback) {
|
||||||
|
|
||||||
|
this.applications = {};
|
||||||
|
|
||||||
|
this.appdrive = false;
|
||||||
|
|
||||||
|
var result = [],
|
||||||
|
mountPoints = ['sd_nav', 'sda', 'sdb', 'sdc', 'sdd', 'sde'];
|
||||||
|
|
||||||
|
mountPoints.forEach(function(mountPoint) {
|
||||||
|
|
||||||
|
var path = [MOUNTROOT_PATH, mountPoint, APPLICATIONS_PATH].join(""),
|
||||||
|
|
||||||
|
appdriveFilename = [path, APPDRIVE_JSON].join("");
|
||||||
|
|
||||||
|
if(this._isFile(appdriveFilename)) {
|
||||||
|
|
||||||
|
this.appdrive = require(appdriveFilename);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this._isDir(path)) {
|
||||||
|
|
||||||
|
var files = fs.readdirSync(path);
|
||||||
|
|
||||||
|
if(files.length) files.forEach(function(appId) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* currently we only allow the first application to be registered
|
||||||
|
* otherwise you would need to restart the CMU
|
||||||
|
*/
|
||||||
|
|
||||||
|
if(!this.applications[appId]) {
|
||||||
|
|
||||||
|
var applicationPath = [path, appId, "/"].join("");
|
||||||
|
|
||||||
|
if(this._isDir(applicationPath)) {
|
||||||
|
|
||||||
|
var profile = {
|
||||||
|
appId: appId,
|
||||||
|
appPath: applicationPath,
|
||||||
|
files: {},
|
||||||
|
},
|
||||||
|
parts = [APPLICATION_JS, APPLICATION_JSON, APPLICATION_CSS, APPLICATION_WORKER],
|
||||||
|
found = 0;
|
||||||
|
|
||||||
|
parts.forEach(function(filename) {
|
||||||
|
|
||||||
|
var fullFilename = [applicationPath, filename].join("");
|
||||||
|
|
||||||
|
if(this._isFile(fullFilename)) {
|
||||||
|
|
||||||
|
profile.files[filename] = fullFilename;
|
||||||
|
found++;
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
|
||||||
|
if(found >= 1) {
|
||||||
|
this.applications[appId] = profile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
if(callback) callback(this.applications, this.appdrive);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __fileExists
|
||||||
|
*/
|
||||||
|
|
||||||
|
_isFile: function(path) {
|
||||||
|
try {
|
||||||
|
return fs.lstatSync(path).isFile();
|
||||||
|
} catch(e) {}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the directory exists
|
||||||
|
* @param {[type]} path [description]
|
||||||
|
* @return {Boolean} [description]
|
||||||
|
*/
|
||||||
|
_isDir: function(path) {
|
||||||
|
try {
|
||||||
|
return fs.lstatSync(path).isDirectory();
|
||||||
|
} catch(e) {}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = new cmu();
|
||||||
|
|
||||||
|
/**
|
||||||
|
/** eof */
|
25
src/node-cmu/test/index.html
Normal file
25
src/node-cmu/test/index.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="../../system/CustomApplications.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
CustomApplications.initialize();
|
||||||
|
|
||||||
|
|
||||||
|
Logger.subscribe(function(level, name, msg, color) {
|
||||||
|
console.log(
|
||||||
|
'%c[' + level + '] %c[' + name + '] ' + msg,
|
||||||
|
'color:' + color,
|
||||||
|
'color:black'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<strong>CMU Protocol Test</strong>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -67,6 +67,7 @@ RUN cd ${NODE_SOURCE_PACKAGE}
|
||||||
# Change work dir
|
# Change work dir
|
||||||
WORKDIR /armv7l/${NODE_SOURCE_PACKAGE}
|
WORKDIR /armv7l/${NODE_SOURCE_PACKAGE}
|
||||||
|
|
||||||
|
|
||||||
# Configure
|
# Configure
|
||||||
RUN ./configure --without-snapshot --dest-cpu=arm --dest-os=linux --fully-static --without-ssl --tag=CASDK-NODE
|
RUN ./configure --without-snapshot --dest-cpu=arm --dest-os=linux --fully-static --without-ssl --tag=CASDK-NODE
|
||||||
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
/* eslint-disable require-buffer */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
//const binding = process.binding('cmu');
|
|
||||||
const cmu = exports;
|
|
||||||
|
|
||||||
|
|
||||||
cmu.version = function() {
|
|
||||||
return "It a worked!";
|
|
||||||
}
|
|
|
@ -24,28 +24,127 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (GlobalError)
|
* This is the main system file that manages everything between the CMU backend server and the frontend.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
window.onerror = function() {
|
/**
|
||||||
console.error(arguments);
|
* (Logger)
|
||||||
}
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
window.Logger = {
|
||||||
|
|
||||||
|
levels: {
|
||||||
|
debug: 'DEBUG',
|
||||||
|
info: 'INFO',
|
||||||
|
error: 'ERROR',
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscriptions
|
||||||
|
* @array
|
||||||
|
*/
|
||||||
|
subscriptions: [],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (debug) debug message
|
||||||
|
*/
|
||||||
|
|
||||||
|
debug: function() {
|
||||||
|
this.__message(this.levels.debug, "#006600", Array.apply(null, arguments));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (error) error message
|
||||||
|
*/
|
||||||
|
|
||||||
|
error: function() {
|
||||||
|
this.__message(this.levels.error, "#FF0000", Array.apply(null, arguments));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (info) info message
|
||||||
|
*/
|
||||||
|
|
||||||
|
info: function() {
|
||||||
|
this.__message(this.levels.info, "#0000FF", Array.apply(null, arguments));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe
|
||||||
|
* @return {[type]} [description]
|
||||||
|
*/
|
||||||
|
subscribe: function(callback) {
|
||||||
|
|
||||||
|
if(typeof(callback) == "function") {
|
||||||
|
this.subscriptions.push(callback);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [__message description]
|
||||||
|
* @param {[type]} level [description]
|
||||||
|
* @param {[type]} color [description]
|
||||||
|
* @param {[type]} values [description]
|
||||||
|
* @return {[type]} [description]
|
||||||
|
*/
|
||||||
|
__message: function(level, color, values) {
|
||||||
|
|
||||||
|
var msg = [];
|
||||||
|
|
||||||
|
if(values.length > 1) {
|
||||||
|
values.forEach(function(value, index) {
|
||||||
|
|
||||||
|
if(index > 0) {
|
||||||
|
|
||||||
|
if(typeof(value) == "object") {
|
||||||
|
|
||||||
|
var keys = value, o = false;
|
||||||
|
|
||||||
|
if(Object.prototype.toString.call(value) == "[object Object]") {
|
||||||
|
var keys = Object.keys(value),
|
||||||
|
o = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
keys.forEach(function(v, index) {
|
||||||
|
msg.push(o ? '[' + v + '=' + value[v]+ ']' : '[' + v + ']');
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
msg.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = msg.join(" ");
|
||||||
|
|
||||||
|
this.subscriptions.forEach(function(subscription) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
subscription(level, values[0], msg, color);
|
||||||
|
} catch(e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (CustomApplicationsProxy)
|
* (CustomApplications)
|
||||||
*
|
*
|
||||||
* Registers itself between the JCI system and CustomApplication runtime.
|
* Registers itself between the JCI system and CustomApplication runtime.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
window.CustomApplicationsProxy = {
|
window.CustomApplications = {
|
||||||
|
|
||||||
|
ID: 'system',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (locals)
|
* (locals)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
debug: false,
|
debug: false,
|
||||||
bootstrapped: false,
|
bootstrapped: false,
|
||||||
|
|
||||||
|
@ -59,6 +158,226 @@ window.CustomApplicationsProxy = {
|
||||||
targetAppName: 'custom',
|
targetAppName: 'custom',
|
||||||
targetAppContext: 'Surface',
|
targetAppContext: 'Surface',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration
|
||||||
|
*/
|
||||||
|
configuration: {
|
||||||
|
|
||||||
|
networkHost: '127.0.0.1',
|
||||||
|
networkPort: 9700,
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commands
|
||||||
|
*/
|
||||||
|
commands: {
|
||||||
|
|
||||||
|
REQUEST_PING: 'ping',
|
||||||
|
REQUEST_APPLICATIONS: 'applications',
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Results
|
||||||
|
*/
|
||||||
|
results: {
|
||||||
|
|
||||||
|
RESULT_OK: 200,
|
||||||
|
RESULT_PONG: 201,
|
||||||
|
RESULT_NOTFOUND: 404,
|
||||||
|
RESULT_ERROR: 500,
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the proxy
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
initialize: function() {
|
||||||
|
|
||||||
|
this.requests = {};
|
||||||
|
|
||||||
|
this.obtainConnection();
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Establishes a connection between the front and backend
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
obtainConnection: function() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
this.client = new WebSocket('ws://' + this.configuration.networkHost + ':' + this.configuration.networkPort);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ping
|
||||||
|
*/
|
||||||
|
this.client.ping = function() {
|
||||||
|
|
||||||
|
this.request(this.commands.REQUEST_PING, {
|
||||||
|
inboundStamp: (new Date()).getTime()
|
||||||
|
}, function(error, result) {
|
||||||
|
|
||||||
|
Logger.info(this.ID, "ping", {
|
||||||
|
lost: error,
|
||||||
|
time: !error ? result.outboundStamp - result.inboundStamp : 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
}.bind(this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* onOpen
|
||||||
|
* @event
|
||||||
|
*/
|
||||||
|
this.client.onopen = function() {
|
||||||
|
|
||||||
|
Logger.info(this.ID, "connection open");
|
||||||
|
|
||||||
|
this.client.ping();
|
||||||
|
|
||||||
|
this.requestApplications();
|
||||||
|
|
||||||
|
}.bind(this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* onMessage
|
||||||
|
* @event
|
||||||
|
*/
|
||||||
|
this.client.onmessage = function(message) {
|
||||||
|
|
||||||
|
this.handleReturnRequest(message);
|
||||||
|
|
||||||
|
}.bind(this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* onError
|
||||||
|
* @event
|
||||||
|
*/
|
||||||
|
this.client.onerror = function(error) {
|
||||||
|
|
||||||
|
Logger.error(CustomApplications.ID, 'ClientError', error);
|
||||||
|
|
||||||
|
}.bind(this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* onClose
|
||||||
|
* @event
|
||||||
|
*/
|
||||||
|
this.client.onclose = function(event) {
|
||||||
|
|
||||||
|
this.client = null;
|
||||||
|
|
||||||
|
if(event.code == 3110) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
|
||||||
|
CustomApplications.obtainConnection();
|
||||||
|
|
||||||
|
}, 5000); // retry later
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}.bind(this);
|
||||||
|
|
||||||
|
} catch(e) {
|
||||||
|
|
||||||
|
this.client = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [request description]
|
||||||
|
* @return {[type]} [description]
|
||||||
|
*/
|
||||||
|
request: function(request, payload, callback) {
|
||||||
|
|
||||||
|
// check connection state
|
||||||
|
if(!this.client || this.client.readyState != 1) return callback(true, {});
|
||||||
|
|
||||||
|
// prepare id
|
||||||
|
var id = false;
|
||||||
|
while(!id || this.requests[id]) {
|
||||||
|
id = (new Date()).getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
// register request
|
||||||
|
this.requests[id] = callback;
|
||||||
|
|
||||||
|
// sanity check
|
||||||
|
payload = payload || {};
|
||||||
|
|
||||||
|
// add request id
|
||||||
|
payload.requestId = id;
|
||||||
|
|
||||||
|
payload.request = request;
|
||||||
|
|
||||||
|
// execute
|
||||||
|
return this.client.send(JSON.stringify(payload));
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes a request
|
||||||
|
* @param {[type]} data [description]
|
||||||
|
* @return {[type]} [description]
|
||||||
|
*/
|
||||||
|
handleReturnRequest: function(message) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
// parse message
|
||||||
|
var payload = JSON.parse(message.data);
|
||||||
|
|
||||||
|
// check against active requests
|
||||||
|
if(payload.requestId && this.requests[payload.requestId]) {
|
||||||
|
|
||||||
|
var callback = this.requests[payload.requestId];
|
||||||
|
|
||||||
|
if(typeof(callback) == "function") {
|
||||||
|
|
||||||
|
callback(payload.result == this.results.RESULT_ERROR, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete this.requests[payload.requestId];
|
||||||
|
|
||||||
|
return; // all done
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch(e) {
|
||||||
|
|
||||||
|
Logger.error(CustomApplications.ID, 'handleReturnRequest', e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trys to load the Custom Applications
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
requestApplications: function() {
|
||||||
|
|
||||||
|
if(typeof(CustomApplicationsHandler) != "undefined") return false;
|
||||||
|
|
||||||
|
if(!this.request(this.commands.REQUEST_APPLICATIONS, false, function(error, result) {
|
||||||
|
|
||||||
|
if(error) {
|
||||||
|
|
||||||
|
return setTimeout(function() {
|
||||||
|
|
||||||
|
this.requestApplications();
|
||||||
|
|
||||||
|
}.bind(this), 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(result);
|
||||||
|
|
||||||
|
}.bind(this)));
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (bootstrap)
|
* (bootstrap)
|
||||||
|
@ -349,7 +668,7 @@ window.CustomApplicationsProxy = {
|
||||||
|
|
||||||
if(window.opera) {
|
if(window.opera) {
|
||||||
window.opera.addEventListener('AfterEvent.load', function (e) {
|
window.opera.addEventListener('AfterEvent.load', function (e) {
|
||||||
CustomApplicationsProxy.bootstrap();
|
CustomApplications.initialize();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue