*/
angular.module('egCoreMod')
+.constant("HATCH_CONFIG", {
+ /* TODO: Extension name will change once the extension is
+ * registered and will presumably be different per browser.
+ * Current extension name is borrowed from:
+ * https://chromium.googlesource.com/chromium/src/+/master/chrome/common/extensions/docs/examples/api/nativeMessaging
+ */
+ EXT_NAME_CHROME : "knldjmfmopnpolahpmmgbagdohdnhkik"
+})
+
.factory('egHatch',
- ['$q','$window','$timeout','$interpolate','$http','$cookies',
- function($q , $window , $timeout , $interpolate , $http , $cookies) {
+ ['$q','$window','$timeout','$interpolate','$http','$cookies','HATCH_CONFIG',
+ function($q , $window , $timeout , $interpolate , $http , $cookies , HATCH_CONFIG) {
var service = {};
- service.msgId = 0;
+ service.port = null; // Hatch extension connection
+ service.msgId = 1;
service.messages = {};
service.pending = [];
- service.socket = null;
service.hatchAvailable = null;
- service.defaultHatchURL = 'wss://localhost:8443/hatch';
- // write a message to the Hatch websocket
+ // write a message to the Hatch port
service.sendToHatch = function(msg) {
var msg2 = {};
});
console.debug("sending to Hatch: " + JSON.stringify(msg2,null,2));
- service.socket.send(JSON.stringify(msg2));
+ service.port.postMessage(msg2);
}
// Send the request to Hatch if it's available.
msg.deferred = service.messages[msg.msgid].deferred;
delete service.messages[msg.msgid]; // un-cache
- // resolve / reject
- if (msg.error) {
- throw new Error(
- "egHatch command failed : "
- + JSON.stringify(msg.error, null, 2));
+ if (msg.status != 200) {
+ msg.deferred.reject();
+ throw new Error("Hatch command failed with status="
+ + msg.status + " and message=" + msg.message);
+
} else {
msg.deferred.resolve(msg.content);
}
}
service.hatchClosed = function() {
- service.socket = null;
+ service.port = null;
service.printers = [];
service.printConfig = {};
while ( (msg = service.pending.shift()) ) {
service.onHatchClose();
}
- service.hatchURL = function() {
- return service.getLocalItem('eg.hatch.url')
- || service.defaultHatchURL;
- }
-
// Returns true if Hatch is required or if we are currently
// communicating with the Hatch service.
service.usingHatch = function() {
service.hatchConnect = function() {
- if (service.socket &&
- service.socket.readyState == service.socket.CONNECTING) {
- // connection in progress. Nothing to do. Our queued
- // message will be delivered when onopen() fires
- return;
- }
+ if (service.port) return;
+
+ service.initting = true;
try {
- service.socket = new WebSocket(service.hatchURL());
+ service.port =
+ chrome.runtime.connect(HATCH_CONFIG.EXT_NAME_CHROME);
} catch(e) {
service.hatchAvailable = false;
service.hatchClosed();
+ console.debug("Hatch connection failed: " + e);
return;
}
- service.socket.onopen = function() {
- console.debug('connected to Hatch');
- service.hatchAvailable = true;
- if (service.onHatchOpen)
- service.onHatchOpen();
- while ( (msg = service.pending.shift()) ) {
- service.sendToHatch(msg);
- };
- }
+ service.port.onDisconnect.addListener(function() {
+ if (service.hatchAvailable === false) return; // already noted
+ service.hatchAvailable = null; // reset
+ service.hatchClosed();
+ });
- service.socket.onclose = function() {
- if (service.hatchAvailable === false) return; // already registered
+ service.port.onMessage.addListener(function(msg) {
+ console.debug('Hatch says: ' + JSON.stringify(msg, null, 2));
- // onclose() will be called regularly as we disconnect from
- // Hatch via timeouts. Return hatchAvailable to its unknow state
- service.hatchAvailable = null;
- service.hatchClosed();
- }
+ if (service.initting) {
+ service.initting = false;
+ console.debug("Hatch init completed with " + msg.message);
- service.socket.onerror = function() {
- if (service.hatchAvailable === false) return; // already registered
- service.hatchAvailable = false;
- console.debug(
- "unable to connect to Hatch server at " + service.hatchURL());
- service.hatchClosed();
- }
+ if (msg.status == 200) {
+ service.hatchOpened();
+ } else {
+ console.warn("Hatch init failed");
+ }
- service.socket.onmessage = function(evt) {
- var msgStr = evt.data;
- if (!msgStr) throw new Error("Hatch returned empty message");
+ } else {
+ service.resolveRequest(msg);
+ }
+ });
- var msgObj = JSON.parse(msgStr);
- console.debug('Hatch says ' + JSON.stringify(msgObj, null, 2));
- service.resolveRequest(msgObj);
- }
+ console.debug('Connected to Hatch');
+ service.hatchAvailable = true;
+
+ // The first message to Hatch must be "init"
+ service.attemptHatchDelivery({action : 'init'});
+ }
+
+ service.hatchOpened = function() {
+ // let others know we're connected
+ if (service.onHatchOpen) service.onHatchOpen();
+
+ // Deliver any previously queued requests
+ while ( (msg = service.pending.shift()) ) {
+ service.sendToHatch(msg);
+ };
}
service.getPrintConfig = function() {
service.getRemoteItem = function(key) {
return service.attemptHatchDelivery({
key : key,
- action : 'get',
- });
+ action : 'get'
+ })
}
service.getLocalItem = function(key) {
* tmp values are removed during logout or browser close.
*/
service.setItem = function(key, value) {
- var str = JSON.stringify(value);
-
- return service.setRemoteItem(key, str)['catch'](
+ return service.setRemoteItem(key, value)['catch'](
function(msg) {
if (service.hatchRequired()) {
console.error("Unable to setItem: " + key
+ "; hatchRequired=true, but hatch is not connected");
return null;
}
- return service.setLocalItem(msg.key, null, str);
+ return service.setLocalItem(msg.key, value);
}
);
}
service.setRemoteItem = function(key, value) {
return service.attemptHatchDelivery({
key : key,
- value : value,
+ content : value,
action : 'set',
});
}
$window.sessionStorage.setItem(key, jsonified);
}
- // appends the value to the existing item stored at key.
- // If not item is found at key, this behaves just like setItem()
- service.appendItem = function(key, value) {
- return service.appendRemoteItem(key, value)['catch'](
- function(msg) {
- if (service.hatchRequired()) {
- console.error("Unable to appendItem: " + key
- + "; hatchRequired=true, but hatch is not connected");
- return null;
- }
- service.appendLocalItem(msg.key, msg.value);
- }
- );
- }
-
- service.appendRemoteItem = function(key, value) {
- return service.attemptHatchDelivery({
- key : key,
- value : value,
- action : 'append',
- });
- }
-
// assumes the appender and appendee are both strings
// TODO: support arrays as well
service.appendLocalItem = function(key, value) {