dynaclr
Version:
Dynamically compile and execute VB.NET and C#.NET code in-process in an entirely portable manner.
229 lines (203 loc) • 6.67 kB
JavaScript
var path = require('path')
exports.new = function(){
// **********************
// * START NODE WRAPPER *
// **********************
class Pointer {
constructor(){
this.value = undefined
//this.type = "ptr"
}
}
class CLR_Events extends Array {
constructor(CLR){
super()
this.CLR = CLR
this.isRunning = false
}
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){
//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.CLR.isReady){
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]()
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);
})
console.log(this.command + " " + this._getArgValues(this.args).join(" ") + "\n")
this.proc.stdin.write(this.command + " " + this._getArgValues(this.args).join(" ") + "\n");
}
_getArgValues(args){
var newArgs = []
this.args.forEach(
function(arg){
if(arg==undefined){
newArgs.push('')
} else {
if(arg.constructor.name=='Pointer'){
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.isReady = false
CLR.CLRProcess = require('child_process').spawn(require('path').resolve(__dirname,'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 {
//isReady determines the run state of new events.
CLR.isReady = true
//Call event.
CLR.onceReady()
//Process all currently setup data.
if(CLR.Events.length>0){
CLR.Events.runAll()
}
}
})
CLR.Events = new CLR_Events(CLR)
//UDFs
CLR.StringInject = function(str,CrLf="__CLR-CrLf__"){
var pRet = new Pointer
this.Events.new("StringInject",[CrLf,str.replace(/\n/g,CrLf)],pRet) //Note CLR.exe requires arguments to be the other way round -- easier command line passing
return pRet
}
CLR.StringReturn = function(ptr){
var pRet = new Pointer
this.Events.new("StringReturn",[ptr],pRet)
return pRet
}
CLR.StringGetPtr = function(v,argOptional,defaultValue){
//If v is a previously injected string pointer then return v
//If v is a string then return CLR.StringInject(v)
//If argument is optional return pointer with value = defaultValue (if available) else with value=0
//Else if argument is not optional (or if argOptional = undefined) throw error
//CASE: StringGetPtr(k=(new Pointer))
if (typeof v == 'object' && v.constructor.name == 'Pointer'){
return v
//CASE: StringGetPtr("my string")
} else if(v != undefined && v.constructor.name == "String") {
return this.StringInject(v)
//CASE: StringGetPtr()
} else if(!argOptional) {
throw Error("Invalid parameter input type.")
//CASE: StringGetPtr(,true) AND StringGetPtr(,true,"myDefaultValue")
} else {
vPtr = new Pointer
vPtr.value = defaultValue != undefined ? defaultValue : 0
}
}
CLR.LoadLibrary = function(AssemblyName, AppDomain){
var pRet = new Pointer
var AppDomainPtr = AppDomain ? AppDomain : 0
this.Events.new("CLR_LoadLibrary",[AssemblyName, AppDomainPtr],pRet)
return pRet
}
CLR.CreateObject = function(Assembly, TypeName, ArgsArr){
var pRet = new Pointer
ArgsArr = ArgsArr == undefined ? [] : ArgsArr
this.Events.new("CLR_CreateObject",[Assembly, TypeName,JSON.stringify(ArgsArr)],pRet)
return pRet
}
CLR.CompileAssembly = function(vCode, References, ProviderAssembly, ProviderType, AppDomain, vFileName, CompilerOptions){
var pRet = new Pointer
var CodePtr = this.StringGetPtr(vCode)
var AppDomainPtr = AppDomain ? AppDomain : 0
var FileNamePtr = this.StringGetPtr(vFileName, true)
CompilerOptions = CompilerOptions ? CompilerOptions : ""
this.Events.new("CLR_CompileAssembly",[CodePtr, typeof References == "object" ? References.join("|") : References, ProviderAssembly, ProviderType, AppDomainPtr, FileNamePtr, CompilerOptions],pRet)
return pRet
}
CLR.Execute = function( ObjPtr, FuncName, ArgsArr){
var pRet = new Pointer
ArgsArr = ArgsArr == undefined ? [] : ArgsArr
this.Events.new("CLR_Execute",[ObjPtr, FuncName, JSON.stringify(ArgsArr)],pRet)
return pRet
}
CLR.GetProperty = function( ObjPtr, Property){
var pRet = new Pointer
this.Events.new("CLR_GetProperty",[ObjPtr, Property],pRet)
return pRet
}
CLR.SetProperty = function( ObjPtr, Property, Value){
var pRet = new Pointer
this.Events.new("CLR_SetProperty",[ObjPtr,Property,JSON.stringify(Value)],pRet)
return pRet
}
CLR.AppDomain = {}
CLR.AppDomain.New = function(iAppDomain, BaseDir){
var pRet = new Pointer
var AppDomain = iAppDomain ? iAppDomain : 0
var BaseDirPtr = this.StringGetPtr(BaseDir)
this.Events.new("AppDomain_New",[AppDomain,BaseDirPtr],pRet)
return pRet
}
CLR.AppDomain.Drop = function(AppDomainPtr){
var pRet = new Pointer
if (AppDomainPtr.constructor.name == "Pointer"){
this.Events.new("AppDomain_Drop",[AppDomainPtr],pRet)
return pRet
} else {
throw new Error("AppDomain must be passed by reference to the Drop function.")
}
}
CLR.Finally = function(callback){
this.Events.new("Finally",[callback])
}
CLR.onceReady = function(){
console.log('CLR is ready for input...\n')
}
// ********************
// * END NODE WRAPPER *
// ********************
return CLR
}