service.hatchAvailable = null;
service.hatchURL = 'wss://localhost:8443/hatch';
- service.hatchSend = function(msg) {
+ // write a message to the Hatch websocket
+ service.sendToHatch = function(msg) {
+ var msg2 = {};
+ // shallow copy and scrub msg before sending
+ angular.forEach(msg, function(val, key) {
+ if (key == 'deferred') return;
+ msg2[key] = val;
+ });
+ service.socket.send(JSON.stringify(msg2));
+ }
+
+ // Send the request to Hatch if it's available.
+ // Otherwise handle the request locally.
+ service.dispatchRequest = function(msg) {
msg.msgid = '' + (service.msgId++);
msg.deferred = $q.defer();
-
service.messages[msg.msgid] = msg;
- if (service.hatchAvailable === true) {
- service.socket.send(JSON.stringify(msg));
+ if (service.hatchAvailable === false) {
+ // Hatch is known to be closed
+ service.pending.push(msg);
+ service.handleRequestsLocally();
+
+ } else if (service.hatchAvailable === true) {
+ // Hatch is known to be open
+ service.sendToHatch(msg);
+
} else {
+ // Hatch status unknown; attempt to connect
service.pending.push(msg);
service.hatchConnect();
}
return msg.deferred.promise;
}
- // if we are unable to connect to Hatch, handle messages locally
- service.redirectPendingMessages = function() {
+ // resolve the promise on the given request and remove
+ // it from our tracked requests.
+ service.resolveRequest = function(msg) {
+
+ var srcMsg = service.messages[msg.msgid];
+ if (!srcMsg) {
+ console.log(
+ "egPrintStore found no source message for response " +
+ msg.msgid
+ );
+ return;
+ }
+
+ // remove the source message
+ delete service.messages[msg.msgid];
+
+ // resolve / reject
+ if (msg.success) {
+ console.debug("command succeeded : " + msg.success);
+ srcMsg.deferred.resolve(msg.success);
+ } else {
+ console.error("command failed : " + msg.error);
+ srcMsg.deferred.reject(msg.error);
+ }
+ }
+
+ // pass each request off to its local handler function
+ service.handleRequestsLocally = function() {
service.socket = null;
service.hatchAvailable = false;
angular.forEach(service.pending, function(msg) {
- delete service.pending[msg.msgid];
switch(msg.action) {
case 'print':
- return service.browserPrint(msg.mime, msg.value);
+ return service.browserPrint(msg);
+ case 'keys':
+ case 'get':
+ case 'set':
+ case 'append':
+ case 'remove':
+ return service.handleLocalStorageRequest(msg);
}
+ service.resolveRequest(msg);
});
}
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;
+ }
+
try {
service.socket = new WebSocket(service.hatchURL);
} catch(e) {
- service.redirectPendingMessages();
+ service.handleRequestsLocally();
return;
}
if (service.onHatchOpen)
service.onHatchOpen();
angular.forEach(service.pending, function(msg) {
- service.socket.send(JSON.stringify(msg));
+ service.sendToHatch(msg);
});
}
service.socket.onerror = function() {
console.debug(
"unable to connect to Hatch server at " + service.hatchURL);
- service.redirectPendingMessages();
+ service.handleRequestsLocally();
if (service.onHatchClose)
service.onHatchClose();
}
console.debug('Hatch says ' + msgStr);
var msgObj = JSON.parse(msgStr);
-
- if (msgObj.success) {
- console.debug("hatch command succeeded : " + msgObj.success);
- } else {
- console.error("hatch command failed : " + msgObj.error);
- }
-
- var srcMsg = service.messages[msgObj.msgid];
- if (srcMsg) {
- delete service.messages[msgObj.msgid];
- srcMsg.deferred.resolve(msgObj);
- }
+ service.resolveRequest(msgObj);
}
}
- service.browserPrint = function(contentType, content) {
+ service.browserPrint = function(msg) {
// let our local print container handle printing
- service.onBrowserPrint(contentType, content);
+ service.onBrowserPrint(msg.contentType, msg.content);
+ msg.success = true; // assume browser print succeeded
}
service.print = function(contentType, content) {
return $q.when();
}
- return service.hatchSend({
+ return service.dispatchRequest({
key : 'no-op',
action : 'print',
content : content,
});
}
+ service.getItem = function(key) {
+ }
+
+ service.setItem = function(key, value) {
+ if (key === null || value === null) {
+ logger.warn("invalid key or value in egPrintStore.setItem()");
+ return $q.reject();
+ }
+ return service.dispatchRequest({
+ key : key,
+ value : value,
+ action : 'set',
+ });
+ }
+
+ service.removeItem = function() {
+ }
+
+ // if set, prefix limits the return set to keys starting with 'prefix'
+ service.getKeys = function(prefix) {
+ return service.dispatchRequest({
+ key : prefix,
+ action : 'keys',
+ });
+ }
+
+ // get, set, remove, append, keys : via $window.localStorage
+ service.handleLocalStorageRequest = function(msg) {
+ switch(msg.action) {
+ case 'keys':
+ var keys = [];
+ var idx = 0;
+ while (true) {
+ var key = $window.localStorage.keys(idx);
+ if (key === null) break;
+ keys.push(key);
+ }
+ msg.success = keys;
+ break;
+
+ case 'set':
+ $window.localStorage.setItem(msg.key, msg.value);
+ msg.success = true;
+ break;
+
+ // ...
+ }
+ }
+
return service;
}])
template : '<div>{{printContent}}</div>',
controller : ['$scope','$window','$timeout','egPrintStore',
function($scope, $window, $timeout, egPrintStore) {
- egPrintStore.onBrowserPrint = function(mime, data) {
- console.log('printing ' + data.length + ' chars of ' + mime);
- switch(mime) {
+ egPrintStore.onBrowserPrint = function(contentType, content) {
+ console.log('printing ' + content.length + ' chars of ' + contentType);
+ switch(contentType) {
case 'text/csv':
case 'text/plain':
- $scope.printContent = data;
+ $scope.printContent = content;
break;
case 'text/html':
console.error('print text/html not yet supported');