I'm currently wrapping an executable I've made with NodeJS. The executable can save strings for use in other processes within the executable. Each time the executable 'saves' a string it sends a pointer back to the server via stdout. The NodeJS server saves strings by sending them to stdin of the executable.
Originally I was writing code like this:
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.")
The above code injects a string
Mary had a
little lamb.
receives a pointer to the string, and then requests the string in the next step, by sending the pointer back to the host application.
To make coding algorithms easier I wanted a system like this:
strPtr = Exec("StringInject __CrLf__ Mary had a__CrLf__little lamb.")
str = Exec("StringReturn " + strPtr)
// do stuff with str
This is the code I made:
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])
}
I intended this to do the following:
- Functions StringInject,StringReturnandFinallycreate events and append them to theEventsarray.
- The runAll()function of theEventsobject, removes the first 'event' from its array and runs therun()function of the array, passing itself as a callback.
- The run functions writes to stdin of the executable, waits for a response in stdout, appends the data to the passed in pointer and then executes the runAll()function passed to it.
This is what I don't understand... When executing the multiple string injections:
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!",";")
I get the following data:
S_ptr_1 = {value:123,type:'ptr'}
S_ptr_2 = {value:123,type:'ptr'}
S_ptr_3 = {value:123,type:'ptr'}
Where as the data should be:
S_ptr_1 = {value:1,type:'ptr'}
S_ptr_2 = {value:2,type:'ptr'}
S_ptr_3 = {value:3,type:'ptr'}
The only scenario I can think this would happen is if, in pseudocode, the following happenned:
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
But why? Am I overlooking something or is there something fundamentally wrong with this algorithm?
via Sancarn
 
No comments:
Post a Comment