ugh. poll integration pipe on Firefox 3.6.
This commit is contained in:
parent
f12e5e6a74
commit
390bcc37fb
|
@ -36,13 +36,12 @@ const INTEGRATION_MIN_VERSION = "3.1a0";
|
||||||
Zotero.Integration = new function() {
|
Zotero.Integration = new function() {
|
||||||
var _fifoFile = null;
|
var _fifoFile = null;
|
||||||
var _tmpFile = null;
|
var _tmpFile = null;
|
||||||
var _shCmd = null;
|
|
||||||
var _shProc = null;
|
|
||||||
var _osascriptFile;
|
var _osascriptFile;
|
||||||
var _inProgress = false;
|
var _inProgress = false;
|
||||||
var _integrationVersionsOK = null;
|
var _integrationVersionsOK = null;
|
||||||
var _pipeMode = false;
|
var _pipeMode = false;
|
||||||
var _winUser32;
|
var _winUser32;
|
||||||
|
var _timer;
|
||||||
|
|
||||||
this.sessions = {};
|
this.sessions = {};
|
||||||
|
|
||||||
|
@ -233,22 +232,21 @@ Zotero.Integration = new function() {
|
||||||
}};
|
}};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads from the temp file set up to handle integration pipe and executes the appropriate
|
* Polling mechanism for file
|
||||||
* integration command
|
|
||||||
*
|
|
||||||
* Used to read from the integration pipe on Fx 3.6
|
|
||||||
*/
|
*/
|
||||||
var _integrationPipeObserverFx36 = {"observe":function(subject) {
|
var _integrationPipeObserverFx36 = {"notify":function() {
|
||||||
// if we had an error reading from the pipe, return immediately, because trying to read
|
if(_fifoFile.fileSize === 0) return;
|
||||||
// again will probably just cause us to loop
|
|
||||||
if(subject.exitValue !== 0) {
|
|
||||||
Components.utils.reportError("Zotero: An error occurred reading from integration pipe");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read from pipe
|
// read from pipe (file, actually)
|
||||||
var string = Zotero.File.getContents(_tmpFile);
|
var string = Zotero.File.getContents(_fifoFile);
|
||||||
|
|
||||||
|
// clear file
|
||||||
|
var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
|
||||||
|
createInstance(Components.interfaces.nsIFileOutputStream);
|
||||||
|
foStream.init(_fifoFile, 0x02 | 0x08 | 0x20, 0666, 0);
|
||||||
|
foStream.close();
|
||||||
|
|
||||||
|
// run command
|
||||||
_parseIntegrationPipeCommand(string);
|
_parseIntegrationPipeCommand(string);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
@ -256,22 +254,17 @@ Zotero.Integration = new function() {
|
||||||
* Initializes the nsIInputStream and nsIInputStreamPump to read from _fifoFile
|
* Initializes the nsIInputStream and nsIInputStreamPump to read from _fifoFile
|
||||||
*/
|
*/
|
||||||
function _initializePipeStreamPump() {
|
function _initializePipeStreamPump() {
|
||||||
if(_pipeMode === "deferredOpen") {
|
// Fx >4 supports deferred open; no need to use sh
|
||||||
// Fx >4 supports deferred open; no need to use sh
|
var fifoStream = Components.classes["@mozilla.org/network/file-input-stream;1"].
|
||||||
var fifoStream = Components.classes["@mozilla.org/network/file-input-stream;1"].
|
createInstance(Components.interfaces.nsIFileInputStream);
|
||||||
createInstance(Components.interfaces.nsIFileInputStream);
|
fifoStream.QueryInterface(Components.interfaces.nsIFileInputStream);
|
||||||
fifoStream.QueryInterface(Components.interfaces.nsIFileInputStream);
|
// 16 = open as deferred so that we don't block on open
|
||||||
// 16 = open as deferred so that we don't block on open
|
fifoStream.init(_fifoFile, -1, 0, 16);
|
||||||
fifoStream.init(_fifoFile, -1, 0, 16);
|
|
||||||
|
var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"].
|
||||||
var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"].
|
createInstance(Components.interfaces.nsIInputStreamPump);
|
||||||
createInstance(Components.interfaces.nsIInputStreamPump);
|
pump.init(fifoStream, -1, -1, 4096, 1, true);
|
||||||
pump.init(fifoStream, -1, -1, 4096, 1, true);
|
pump.asyncRead(_integrationPipeListenerFx42, null);
|
||||||
pump.asyncRead(_integrationPipeListenerFx42, null);
|
|
||||||
} else {
|
|
||||||
// Fx 3.6 doesn't support deferred open
|
|
||||||
_shProc.runAsync(_shCmd, _shCmd.length, _integrationPipeObserverFx36);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -294,7 +287,7 @@ Zotero.Integration = new function() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(Zotero.isMac) {
|
if(Zotero.isMac) {
|
||||||
_pipeMode = "subprocess";
|
_pipeMode = "poll";
|
||||||
} else {
|
} else {
|
||||||
_pipeMode = "fx36thread";
|
_pipeMode = "fx36thread";
|
||||||
}
|
}
|
||||||
|
@ -302,151 +295,141 @@ Zotero.Integration = new function() {
|
||||||
|
|
||||||
Zotero.debug("Using integration pipe mode "+_pipeMode);
|
Zotero.debug("Using integration pipe mode "+_pipeMode);
|
||||||
|
|
||||||
// make a new pipe
|
if(_pipeMode === "poll") {
|
||||||
var mkfifo = Components.classes["@mozilla.org/file/local;1"].
|
// create empty file
|
||||||
createInstance(Components.interfaces.nsILocalFile);
|
var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
|
||||||
mkfifo.initWithPath("/usr/bin/mkfifo");
|
createInstance(Components.interfaces.nsIFileOutputStream);
|
||||||
if(!mkfifo.exists()) mkfifo.initWithPath("/bin/mkfifo");
|
foStream.init(_fifoFile, 0x02 | 0x08 | 0x20, 0666, 0);
|
||||||
if(!mkfifo.exists()) mkfifo.initWithPath("/usr/local/bin/mkfifo");
|
foStream.close();
|
||||||
|
|
||||||
// get sh
|
|
||||||
var sh = Components.classes["@mozilla.org/file/local;1"].
|
|
||||||
createInstance(Components.interfaces.nsILocalFile);
|
|
||||||
sh.initWithPath("/bin/sh");
|
|
||||||
|
|
||||||
if(mkfifo.exists() && sh.exists()) {
|
|
||||||
// create named pipe
|
|
||||||
var proc = Components.classes["@mozilla.org/process/util;1"].
|
|
||||||
createInstance(Components.interfaces.nsIProcess);
|
|
||||||
proc.init(mkfifo);
|
|
||||||
proc.run(true, [_fifoFile.path], 1);
|
|
||||||
|
|
||||||
if(_fifoFile.exists()) {
|
// no deferred open capability, so we need to poll
|
||||||
if(_pipeMode === "subprocess") {
|
// has to be global so that we don't get garbage collected
|
||||||
// no deferred open capability, so we need to use the sh/tmpfile hack
|
_timer = Components.classes["@mozilla.org/timer;1"].
|
||||||
|
createInstance(Components.interfaces.nsITimer);
|
||||||
// make a tmp file
|
_timer.initWithCallback(_integrationPipeObserverFx36, 1000,
|
||||||
_tmpFile = Components.classes["@mozilla.org/file/directory_service;1"].
|
Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
|
||||||
getService(Components.interfaces.nsIProperties).
|
|
||||||
get("TmpD", Components.interfaces.nsIFile);
|
|
||||||
_tmpFile.append("zoteroIntegrationTmp");
|
|
||||||
_tmpFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666);
|
|
||||||
|
|
||||||
// begin reading from named pipe
|
|
||||||
_shCmd = ["-c", "cat '"+_fifoFile.path.replace("'", "'\\''")+"' > '"+
|
|
||||||
_tmpFile.path.replace("'", "'\\''")+"'"];
|
|
||||||
Zotero.debug("Calling sh "+_shCmd.join(" "));
|
|
||||||
|
|
||||||
_shProc = Components.classes["@mozilla.org/process/util;1"].
|
|
||||||
createInstance(Components.interfaces.nsIProcess);
|
|
||||||
_shProc.init(sh);
|
|
||||||
|
|
||||||
_initializePipeStreamPump();
|
|
||||||
} else if(_pipeMode === "deferredOpen") {
|
|
||||||
_initializePipeStreamPump();
|
|
||||||
} else if(_pipeMode === "fx36thread") {
|
|
||||||
var main = Components.classes["@mozilla.org/thread-manager;1"].getService().mainThread;
|
|
||||||
var background = Components.classes["@mozilla.org/thread-manager;1"].getService().newThread(0);
|
|
||||||
|
|
||||||
function mainThread(agent, cmd, doc) {
|
|
||||||
this.agent = agent;
|
|
||||||
this.cmd = cmd;
|
|
||||||
this.document = doc;
|
|
||||||
}
|
|
||||||
mainThread.prototype.run = function() {
|
|
||||||
Zotero.Integration.execCommand(this.agent, this.cmd, this.document);
|
|
||||||
}
|
|
||||||
|
|
||||||
function fifoThread() {}
|
|
||||||
fifoThread.prototype.run = function() {
|
|
||||||
var fifoStream = Components.classes["@mozilla.org/network/file-input-stream;1"].
|
|
||||||
createInstance(Components.interfaces.nsIFileInputStream);
|
|
||||||
var line = {};
|
|
||||||
while(true) {
|
|
||||||
fifoStream.QueryInterface(Components.interfaces.nsIFileInputStream);
|
|
||||||
fifoStream.init(_fifoFile, -1, 0, 0);
|
|
||||||
fifoStream.QueryInterface(Components.interfaces.nsILineInputStream);
|
|
||||||
fifoStream.readLine(line);
|
|
||||||
fifoStream.close();
|
|
||||||
|
|
||||||
var parts = line.value.split(" ");
|
|
||||||
var agent = parts[0];
|
|
||||||
var cmd = parts[1];
|
|
||||||
var document = parts.length >= 3 ? line.value.substr(agent.length+cmd.length+2) : null;
|
|
||||||
if(agent == "Zotero" && cmd == "shutdown") return;
|
|
||||||
main.dispatch(new mainThread(agent, cmd, document), background.DISPATCH_NORMAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fifoThread.prototype.QueryInterface = mainThread.prototype.QueryInterface = function(iid) {
|
|
||||||
if (iid.equals(Components.interfaces.nsIRunnable) ||
|
|
||||||
iid.equals(Components.interfaces.nsISupports)) return this;
|
|
||||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
background.dispatch(new fifoThread(), background.DISPATCH_NORMAL);
|
|
||||||
} else if(_pipeMode === "fx4thread") {
|
|
||||||
Components.utils.import("resource://gre/modules/ctypes.jsm");
|
|
||||||
|
|
||||||
// get possible names for libc
|
|
||||||
if(Zotero.isMac) {
|
|
||||||
var possibleLibcs = ["/usr/lib/libc.dylib"];
|
|
||||||
} else {
|
|
||||||
var possibleLibcs = [
|
|
||||||
"libc.so.6",
|
|
||||||
"libc.so.6.1",
|
|
||||||
"libc.so"
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// try all possibilities
|
|
||||||
while(possibleLibcs.length) {
|
|
||||||
var libc = possibleLibcs.shift();
|
|
||||||
try {
|
|
||||||
var lib = ctypes.open(libc);
|
|
||||||
break;
|
|
||||||
} catch(e) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// throw appropriate error on failure
|
|
||||||
if(!lib) {
|
|
||||||
throw "libc could not be loaded. Please post on the Zotero Forums so we can add "+
|
|
||||||
"support for your operating system.";
|
|
||||||
}
|
|
||||||
|
|
||||||
// int mkfifo(const char *path, mode_t mode);
|
|
||||||
var mkfifo = lib.declare("mkfifo", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.unsigned_int);
|
|
||||||
|
|
||||||
// make pipe
|
|
||||||
var ret = mkfifo(_fifoFile.path, 0600);
|
|
||||||
if(!_fifoFile.exists()) return false;
|
|
||||||
lib.close();
|
|
||||||
|
|
||||||
// set up worker
|
|
||||||
var worker = Components.classes["@mozilla.org/threads/workerfactory;1"]
|
|
||||||
.createInstance(Components.interfaces.nsIWorkerFactory)
|
|
||||||
.newChromeWorker("chrome://zotero/content/xpcom/integration_worker.js");
|
|
||||||
worker.onmessage = function(event) {
|
|
||||||
if(event.data[0] == "Exception") {
|
|
||||||
throw event.data[1];
|
|
||||||
} else if(event.data[0] == "Debug") {
|
|
||||||
Zotero.debug(event.data[1]);
|
|
||||||
} else {
|
|
||||||
Zotero.Integration.execCommand(event.data[0], event.data[1], event.data[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
worker.postMessage({"path":_fifoFile.path, "libc":libc});
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Components.utils.reportError("Zotero: mkfifo failed -- not initializing integration pipe");
|
|
||||||
return false;
|
|
||||||
} else {
|
} else {
|
||||||
Components.utils.reportError("Zotero: mkfifo or sh not found -- not initializing integration pipe");
|
// make a new pipe
|
||||||
return false;
|
var mkfifo = Components.classes["@mozilla.org/file/local;1"].
|
||||||
|
createInstance(Components.interfaces.nsILocalFile);
|
||||||
|
mkfifo.initWithPath("/usr/bin/mkfifo");
|
||||||
|
if(!mkfifo.exists()) mkfifo.initWithPath("/bin/mkfifo");
|
||||||
|
if(!mkfifo.exists()) mkfifo.initWithPath("/usr/local/bin/mkfifo");
|
||||||
|
|
||||||
|
if(mkfifo.exists()) {
|
||||||
|
// create named pipe
|
||||||
|
var proc = Components.classes["@mozilla.org/process/util;1"].
|
||||||
|
createInstance(Components.interfaces.nsIProcess);
|
||||||
|
proc.init(mkfifo);
|
||||||
|
proc.run(true, [_fifoFile.path], 1);
|
||||||
|
|
||||||
|
if(_fifoFile.exists()) {
|
||||||
|
if(_pipeMode === "deferredOpen") {
|
||||||
|
_initializePipeStreamPump();
|
||||||
|
} else if(_pipeMode === "fx36thread") {
|
||||||
|
var main = Components.classes["@mozilla.org/thread-manager;1"].getService().mainThread;
|
||||||
|
var background = Components.classes["@mozilla.org/thread-manager;1"].getService().newThread(0);
|
||||||
|
|
||||||
|
function mainThread(agent, cmd, doc) {
|
||||||
|
this.agent = agent;
|
||||||
|
this.cmd = cmd;
|
||||||
|
this.document = doc;
|
||||||
|
}
|
||||||
|
mainThread.prototype.run = function() {
|
||||||
|
Zotero.Integration.execCommand(this.agent, this.cmd, this.document);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fifoThread() {}
|
||||||
|
fifoThread.prototype.run = function() {
|
||||||
|
var fifoStream = Components.classes["@mozilla.org/network/file-input-stream;1"].
|
||||||
|
createInstance(Components.interfaces.nsIFileInputStream);
|
||||||
|
var line = {};
|
||||||
|
while(true) {
|
||||||
|
fifoStream.QueryInterface(Components.interfaces.nsIFileInputStream);
|
||||||
|
fifoStream.init(_fifoFile, -1, 0, 0);
|
||||||
|
fifoStream.QueryInterface(Components.interfaces.nsILineInputStream);
|
||||||
|
fifoStream.readLine(line);
|
||||||
|
fifoStream.close();
|
||||||
|
|
||||||
|
var parts = line.value.split(" ");
|
||||||
|
var agent = parts[0];
|
||||||
|
var cmd = parts[1];
|
||||||
|
var document = parts.length >= 3 ? line.value.substr(agent.length+cmd.length+2) : null;
|
||||||
|
if(agent == "Zotero" && cmd == "shutdown") return;
|
||||||
|
main.dispatch(new mainThread(agent, cmd, document), background.DISPATCH_NORMAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fifoThread.prototype.QueryInterface = mainThread.prototype.QueryInterface = function(iid) {
|
||||||
|
if (iid.equals(Components.interfaces.nsIRunnable) ||
|
||||||
|
iid.equals(Components.interfaces.nsISupports)) return this;
|
||||||
|
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
background.dispatch(new fifoThread(), background.DISPATCH_NORMAL);
|
||||||
|
} else if(_pipeMode === "fx4thread") {
|
||||||
|
Components.utils.import("resource://gre/modules/ctypes.jsm");
|
||||||
|
|
||||||
|
// get possible names for libc
|
||||||
|
if(Zotero.isMac) {
|
||||||
|
var possibleLibcs = ["/usr/lib/libc.dylib"];
|
||||||
|
} else {
|
||||||
|
var possibleLibcs = [
|
||||||
|
"libc.so.6",
|
||||||
|
"libc.so.6.1",
|
||||||
|
"libc.so"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// try all possibilities
|
||||||
|
while(possibleLibcs.length) {
|
||||||
|
var libc = possibleLibcs.shift();
|
||||||
|
try {
|
||||||
|
var lib = ctypes.open(libc);
|
||||||
|
break;
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// throw appropriate error on failure
|
||||||
|
if(!lib) {
|
||||||
|
throw "libc could not be loaded. Please post on the Zotero Forums so we can add "+
|
||||||
|
"support for your operating system.";
|
||||||
|
}
|
||||||
|
|
||||||
|
// int mkfifo(const char *path, mode_t mode);
|
||||||
|
var mkfifo = lib.declare("mkfifo", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.unsigned_int);
|
||||||
|
|
||||||
|
// make pipe
|
||||||
|
var ret = mkfifo(_fifoFile.path, 0600);
|
||||||
|
if(!_fifoFile.exists()) return false;
|
||||||
|
lib.close();
|
||||||
|
|
||||||
|
// set up worker
|
||||||
|
var worker = Components.classes["@mozilla.org/threads/workerfactory;1"]
|
||||||
|
.createInstance(Components.interfaces.nsIWorkerFactory)
|
||||||
|
.newChromeWorker("chrome://zotero/content/xpcom/integration_worker.js");
|
||||||
|
worker.onmessage = function(event) {
|
||||||
|
if(event.data[0] == "Exception") {
|
||||||
|
throw event.data[1];
|
||||||
|
} else if(event.data[0] == "Debug") {
|
||||||
|
Zotero.debug(event.data[1]);
|
||||||
|
} else {
|
||||||
|
Zotero.Integration.execCommand(event.data[0], event.data[1], event.data[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
worker.postMessage({"path":_fifoFile.path, "libc":libc});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Components.utils.reportError("Zotero: mkfifo failed -- not initializing integration pipe");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Components.utils.reportError("Zotero: mkfifo or sh not found -- not initializing integration pipe");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -549,15 +532,16 @@ Zotero.Integration = new function() {
|
||||||
* Destroys the integration pipe.
|
* Destroys the integration pipe.
|
||||||
*/
|
*/
|
||||||
this.destroy = function() {
|
this.destroy = function() {
|
||||||
// send shutdown message to fifo thread
|
if(_pipeMode !== "poll") {
|
||||||
var oStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
|
// send shutdown message to fifo thread
|
||||||
getService(Components.interfaces.nsIFileOutputStream);
|
var oStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
|
||||||
oStream.init(_fifoFile, 0x02 | 0x10, 0, 0);
|
getService(Components.interfaces.nsIFileOutputStream);
|
||||||
var cmd = "Zotero shutdown\n";
|
oStream.init(_fifoFile, 0x02 | 0x10, 0, 0);
|
||||||
oStream.write(cmd, cmd.length);
|
var cmd = "Zotero shutdown\n";
|
||||||
oStream.close();
|
oStream.write(cmd, cmd.length);
|
||||||
|
oStream.close();
|
||||||
|
}
|
||||||
_fifoFile.remove(false);
|
_fifoFile.remove(false);
|
||||||
if(_pipeMode === "subprocess") _tmpFile.remove(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue
Block a user