我目前正在包装我用NodeJS制作的可执行文件。可执行文件可以保存字符串以用于可执行文件中的其他进程。每次可执行文件“保存”字符串时,它都会通过stdout将指针发送回服务器。 NodeJS服务器通过将字符串发送到可执行文件的stdin来保存字符串。
最初我写的是这样的代码:
CLRProcess.stdout.once('data',function(strptr){
CLRProcess.stdout.once('data', function(str){
console.log(str.toString())
})
CLRProcess.stdin.write("StringReturn " + strptr.toString())
})
CLRProcess.stdin.write("StringInject __CrLf__ Mary had a__CrLf__little lamb.")
上面的代码注入一个字符串
Mary had a
little lamb.
接收指向该字符串的指针,然后通过将指针发送回主机应用程序来请求下一步中的字符串。
为了使编码算法更容易,我想要一个这样的系统:
strPtr = Exec("StringInject __CrLf__ Mary had a__CrLf__little lamb.")
str = Exec("StringReturn " + strPtr)
// do stuff with str
这是我制作的代码:
class Pointer {
constructor(){
this.value = undefined
this.type = "ptr"
}
}
class CLR_Events extends Array {
constructor(CLR){
super()
this.CLR = CLR
}
runAll(){
if(this.length>0){
//Contribution by le_m: https://stackoverflow.com/a/44447739/6302131. See Contrib#1
this.shift().run(this.runAll.bind(this))
}
}
new(cmd,args,ret){
var requireRun = !(this.length>0) //If events array is initially empty, a run is required
var e = new CLR_Event(cmd,args,ret,this.CLR)
this.push(e)
if(requireRun){
this.runAll()
}
}
}
class CLR_Event {
constructor(cmd,args,ret,CLR){
this.command = cmd;
this.args = args
this.CLR = CLR
this.proc = CLR.CLRProcess;
this.ptr = ret
}
run(callback){
//Implementing event to execute callback after some other events have been created.
if(this.command == "Finally"){
this.args[0]()
console.log("Running Finally")
return callback(null)
}
//Implementation for all CLR events.
var thisEvent = this
this.proc.stdout.once('data',function(data){
this.read()
data = JSON.parse(data.toString())
thisEvent.ptr.value = data
callback(data);
})
this.proc.stdin.write(this.command + " " + this._getArgValues(this.args).join(" ") + "\n");
}
_getArgValues(args){
var newArgs = []
this.args.forEach(
function(arg){
if(arg.type=='ptr'){
if(typeof arg.value == "object"){
newArgs.push(JSON.stringify(arg.value))
} else {
newArgs.push(arg.value)
}
} else if(typeof arg == "object"){
newArgs.push(JSON.stringify(arg))
} else {
newArgs.push(arg)
}
}
)
return newArgs
}
}
var CLR = {}
CLR.CLRProcess = require('child_process').spawn('DynaCLR.exe')
CLR.CLRProcess.stdout.once('data',function(data){
if(data!="Ready for input."){
CLR.CLRProcess.kill()
CLR = undefined
throw new Error("Cannot create CLR process")
} else {
console.log('CLR is ready for input...')
}
})
CLR.Events = new CLR_Events(CLR)
//UDFs
CLR.StringInject = function(str,CrLf="__CLR-CrLf__"){
var ptr = new Pointer
this.Events.new("StringInject",[CrLf,str.replace(/\n/g,CrLf)],ptr) //Note CLR.exe requires arguments to be the other way round -- easier command line passing
return ptr
}
CLR.StringReturn = function(ptr){
var sRet = new Pointer
this.Events.new("StringReturn",[ptr],sRet)
return sRet
}
CLR.Finally = function(callback){
this.Events.new("Finally",[callback])
}
我打算这样做:
StringInject
,StringReturn
和Finally
创建事件并将其附加到Events
数组。runAll()
对象的Events
函数,从其数组中删除第一个'event'并运行数组的run()
函数,将其自身作为回调传递。runAll()
函数。这是我不明白的......当执行多个字符串注入时:
S_ptr_1 = CLR.StringInject("Hello world!")
S_ptr_2 = CLR.StringInject("Hello world!__CLR-CrLf__My name is Sancarn!")
S_ptr_3 = CLR.StringInject("Mary had a little lamb;And it's name was Doug!",";")
我得到以下数据:
S_ptr_1 = {value:123,type:'ptr'}
S_ptr_2 = {value:123,type:'ptr'}
S_ptr_3 = {value:123,type:'ptr'}
数据应该在哪里:
S_ptr_1 = {value:1,type:'ptr'}
S_ptr_2 = {value:2,type:'ptr'}
S_ptr_3 = {value:3,type:'ptr'}
我能想到这种情况的唯一情况是,如果在伪代码中,会发生以下情况:
CLRProcess.stdin.write("StringInject Val1")
CLRProcess.stdin.write("StringInject Val2")
CLRProcess.stdin.write("StringInject Val3")
CLRProcess.stdout.once('data') ==> S_ptr_1
CLRProcess.stdout.once('data') ==> S_ptr_2
CLRProcess.stdout.once('data') ==> S_ptr_3
但为什么呢?我是否忽略了某些东西,或者这个算法是否存在根本错误?
答案 0 :(得分:1)
我发现了问题,我设法创建了一个解决方案。
CLR.StringInject
调用CLR_Events.new()
CLR_Events.new()
,首先检查数组是否为空或是否有事件,创建新事件并将事件推送到events数组。如果数组最初为空,则调用CLR_Events.runAll()
。
CLR_Events.runAll()
然后删除CLR_Events.runAll()数组的第一个元素并执行它在STDOUT上设置监听器并将数据写入STDIN。
然后下一行代码运行:
调用 CLR.StringInject
调用CLR_Events.new()
CLR_Events.new()
,首先检查数组是否为空或是否有事件,它看到数组为空,因此调用runAll()
这就是问题。
runAll()
将调用自身来调用events数组中的下一个事件。但是Events
数组始终为空,因为CLR_Events.new()
不知道如何检查当前是否正在执行某个事件。它只检查数组中是否有事件。所以现在我们已经写了两次STDIN并在STDOUT上设置了2个监听器。这链接到第三个命令,最终意味着所有返回的对象包含相同的数据。
要解决这个问题,我必须创建一个this.isRunning
变量。
RunAll()
If isRunning == false
isRunning
才应为false:
即。在回调后,isRunning
应设置为false。
这可确保所有事件在同一回调循环中触发。
然后我的回调出现了一些其他问题,因为this
在undefined
中是:{/ p>
function(){
this.runAll.bind(this)()
if (!(this.length>0)) this.isRunning = false
}
要解决此问题,我必须在回调定义之前添加CLREvents
变量来存储this
,并在回调中将this
替换为CLREvents
。现在它终于按预期工作了。
完整的工作代码:
class Pointer {
constructor(){
this.value = undefined
this.type = "ptr"
}
}
class CLR_Events extends Array {
constructor(CLR){
super()
this.CLR = CLR
this.isRunning = false
}
runAll(){
console.log('RunAll')
this.isRunning = true
if(this.length>0){
//Contribution by le_m: https://stackoverflow.com/a/44447739/6302131. See Contrib#1
var CLREvents = this
this.shift().run(function(){
CLREvents.runAll.bind(CLREvents)()
if (!(CLREvents.length>0)) CLREvents.isRunning = false
})
}
}
new(cmd,args,ret){
console.log("New Event: " + JSON.stringify([cmd,args,ret]) + " - requireRun:" + (!(this.length>0)).toString())
//If events array is initially empty, a run is required
var requireRun = !(this.length>0)
var e = new CLR_Event(cmd,args,ret,this.CLR)
this.push(e)
if(!this.isRunning){
this.runAll()
}
}
}
class CLR_Event {
constructor(cmd,args,ret,CLR){
this.command = cmd;
this.args = args
this.CLR = CLR
this.proc = CLR.CLRProcess;
this.ptr = ret
}
run(callback){
console.log("RunOne")
//Implementing event to execute callback after some other events have been created.
if(this.command == "Finally"){
this.args[0]()
console.log("Running Finally")
return callback(null)
}
//Implementation for all CLR events.
var thisEvent = this
this.proc.stdout.once('data',function(data){
console.log('Callback')
this.read()
data = JSON.parse(data.toString())
thisEvent.ptr.value = data
callback(data);
})
this.proc.stdin.write(this.command + " " + this._getArgValues(this.args).join(" ") + "\n");
}
_getArgValues(args){
var newArgs = []
this.args.forEach(
function(arg){
if(arg.type=='ptr'){
if(typeof arg.value == "object"){
newArgs.push(JSON.stringify(arg.value))
} else {
newArgs.push(arg.value)
}
} else if(typeof arg == "object"){
newArgs.push(JSON.stringify(arg))
} else {
newArgs.push(arg)
}
}
)
return newArgs
}
}
var CLR = {}
CLR.CLRProcess = require('child_process').spawn('DynaCLR.exe')
CLR.CLRProcess.stdout.once('data',function(data){
if(data!="Ready for input."){
CLR.CLRProcess.kill()
CLR = undefined
throw new Error("Cannot create CLR process")
} else {
console.log('CLR is ready for input...\n')
/* Example 1 - Using String Inject */
S_ptr_1 = CLR.StringInject("Hello world!")
S_ptr_2 = CLR.StringInject("Hello world!__CLR-CrLf__My name is Sancarn!")
S_ptr_3 = CLR.StringInject("Mary had a little lamb;And it's name was Doug!",";")
console.log(S_ptr_1)
console.log(S_ptr_2)
console.log(S_ptr_3)
}
})
CLR.Events = new CLR_Events(CLR)
//UDFs
CLR.StringInject = function(str,CrLf="__CLR-CrLf__"){
var ptr = new Pointer
this.Events.new("StringInject",[CrLf,str.replace(/\n/g,CrLf)],ptr) //Note CLR.exe requires arguments to be the other way round -- easier command line passing
return ptr
}
CLR.StringReturn = function(ptr){
var sRet = new Pointer
this.Events.new("StringReturn",[ptr],sRet)
return sRet
}
CLR.Finally = function(callback){
this.Events.new("Finally",[callback])
}