185 lines
3.8 KiB
JavaScript
185 lines
3.8 KiB
JavaScript
|
|
import { PythonShell } from "python-shell";
|
||
|
|
|
||
|
|
export default class Bindings {
|
||
|
|
constructor(initialProps) {
|
||
|
|
|
||
|
|
this.pythonShell = new PythonShell("./python/index.py", { mode: "text" });
|
||
|
|
this.responseQueue = new Array();
|
||
|
|
this.sendQueue = new Array();
|
||
|
|
this.isSending = false;
|
||
|
|
this.streamCallback = null;
|
||
|
|
|
||
|
|
this.pythonShell.on("message", function(message) {
|
||
|
|
if (typeof message === "string" && message.startsWith("__STREAM__")) {
|
||
|
|
var dataStr = message.substring(10);
|
||
|
|
var data = null;
|
||
|
|
|
||
|
|
try {
|
||
|
|
data = JSON.parse(dataStr);
|
||
|
|
} catch (err) {
|
||
|
|
console.error("Invalid streamed JSON:", dataStr);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (this.streamCallback) {
|
||
|
|
this.streamCallback(data);
|
||
|
|
}
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var response = null;
|
||
|
|
|
||
|
|
try {
|
||
|
|
response = JSON.parse(message);
|
||
|
|
} catch (err) {
|
||
|
|
console.error("Invalid JSON response:", message);
|
||
|
|
var resolve = this.responseQueue.shift();
|
||
|
|
|
||
|
|
if (resolve) {
|
||
|
|
resolve({ error: "Invalid JSON from Python" });
|
||
|
|
}
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var resolve = this.responseQueue.shift();
|
||
|
|
|
||
|
|
if (resolve) {
|
||
|
|
resolve(response);
|
||
|
|
}
|
||
|
|
|
||
|
|
this.processSendQueue();
|
||
|
|
|
||
|
|
}.bind(this));
|
||
|
|
|
||
|
|
this.pythonShell.on("error", function(err) {
|
||
|
|
console.error("PythonShell error:", err);
|
||
|
|
});
|
||
|
|
|
||
|
|
this.pythonShell.on("stderr", function(stderr) {
|
||
|
|
console.error("PythonShell stderr:", stderr);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Set initial properties if any
|
||
|
|
if (initialProps && typeof initialProps === "object") {
|
||
|
|
var keys = Object.keys(initialProps);
|
||
|
|
|
||
|
|
for (var i = 0; i < keys.length; i++) {
|
||
|
|
var key = keys[i];
|
||
|
|
var value = initialProps[key];
|
||
|
|
|
||
|
|
this.callMethod("setProperty", key, value);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return new Proxy(this, {
|
||
|
|
get: function(target, prop) {
|
||
|
|
if (typeof prop === "string") {
|
||
|
|
if (prop === "end") {
|
||
|
|
return target.end.bind(target);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (prop === "onMessage") {
|
||
|
|
return target.onMessage.bind(target);
|
||
|
|
}
|
||
|
|
|
||
|
|
return function() {
|
||
|
|
var args = new Array(arguments.length);
|
||
|
|
|
||
|
|
for (var i = 0; i < arguments.length; i++) {
|
||
|
|
args[i] = arguments[i];
|
||
|
|
}
|
||
|
|
|
||
|
|
return target.callMethod(prop, ...args);
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
return undefined;
|
||
|
|
},
|
||
|
|
|
||
|
|
set: function(target, prop, value) {
|
||
|
|
return target.callMethod("setProperty", prop, value)
|
||
|
|
.then(function() {
|
||
|
|
return true;
|
||
|
|
})
|
||
|
|
.catch(function(err) {
|
||
|
|
console.error(err);
|
||
|
|
return false;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
onMessage(callback) {
|
||
|
|
this.streamCallback = callback;
|
||
|
|
}
|
||
|
|
|
||
|
|
callMethod(method) {
|
||
|
|
var args = new Array(arguments.length - 1);
|
||
|
|
|
||
|
|
for (var i = 1; i < arguments.length; i++) {
|
||
|
|
args[i - 1] = arguments[i];
|
||
|
|
}
|
||
|
|
|
||
|
|
return new Promise(function(resolve, reject) {
|
||
|
|
this.responseQueue.push(function(response) {
|
||
|
|
if (response.error) {
|
||
|
|
reject(new Error(response.error));
|
||
|
|
} else {
|
||
|
|
resolve(response.result !== undefined ? response.result : response);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
var params = {};
|
||
|
|
|
||
|
|
if (method === "setProperty" && args.length === 2) {
|
||
|
|
params = { name: args[0], value: args[1] };
|
||
|
|
} else if (args.length === 1 && typeof args[0] === "object") {
|
||
|
|
params = args[0];
|
||
|
|
} else if (args.length > 0) {
|
||
|
|
params = { args: args };
|
||
|
|
}
|
||
|
|
|
||
|
|
this.sendQueue.push({ method: method, params: params });
|
||
|
|
|
||
|
|
this.processSendQueue();
|
||
|
|
|
||
|
|
}.bind(this));
|
||
|
|
}
|
||
|
|
|
||
|
|
processSendQueue() {
|
||
|
|
if (this.isSending === true) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (this.sendQueue.length === 0) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var message = this.sendQueue.shift();
|
||
|
|
|
||
|
|
this.isSending = true;
|
||
|
|
|
||
|
|
try {
|
||
|
|
this.pythonShell.send(JSON.stringify(message));
|
||
|
|
} catch (err) {
|
||
|
|
var resolve = this.responseQueue.shift();
|
||
|
|
|
||
|
|
if (resolve) {
|
||
|
|
resolve({ error: err.message });
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
this.isSending = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
end() {
|
||
|
|
this.pythonShell.end(function(err) {
|
||
|
|
if (err !== undefined && err !== null) {
|
||
|
|
console.error("Error ending PythonShell:", err);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|