github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/engine/function/jsfuncs.go (about)

     1  package funcs
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/dop251/goja"
     8  	"github.com/mdaxf/iac/logger"
     9  	"github.com/robertkrimen/otto"
    10  )
    11  
    12  type JSFuncs struct {
    13  }
    14  
    15  // Execute executes the JavaScript function defined in the Funcs object.
    16  // It sets the inputs, runs the JavaScript code, and sets the outputs.
    17  // If there is an error during execution, it logs the error and returns.
    18  // The execution time is also logged.
    19  func (cf *JSFuncs) Execute(f *Funcs) {
    20  	startTime := time.Now()
    21  	defer func() {
    22  		elapsed := time.Since(startTime)
    23  		f.iLog.PerformanceWithDuration("engine.funcs.JSFuncs.Execute", elapsed)
    24  	}()
    25  	defer func() {
    26  		if err := recover(); err != nil {
    27  			errmsg := fmt.Sprintf("There is error to engine.funcs.JSFuncs.Execute with error: %s", err)
    28  			f.iLog.Error(errmsg)
    29  			f.CancelExecution(errmsg)
    30  			f.ErrorMessage = errmsg
    31  			return
    32  		}
    33  	}()
    34  	f.iLog.Debug(fmt.Sprintf("Start process %s : %s", "JSFuncs.Execute", f.Fobj.Name))
    35  
    36  	namelist, _, inputs := f.SetInputs()
    37  
    38  	vm := goja.New()
    39  
    40  	for i := 0; i < len(namelist); i++ {
    41  		vm.Set(namelist[i], inputs[namelist[i]])
    42  	}
    43  	f.iLog.Debug(fmt.Sprintf("Fucntion %s script: %s", f.Fobj.Name, f.Fobj.Content))
    44  
    45  	value, err := vm.RunString(f.Fobj.Content)
    46  	if err != nil {
    47  		f.iLog.Error(fmt.Sprintf("Error in JSFuncs.Execute: %s", err.Error()))
    48  		return
    49  	}
    50  
    51  	result := value.Export()
    52  	f.iLog.Debug(fmt.Sprintf("Fucntion %s result: %s", f.Fobj.Name, result))
    53  
    54  	outputs := make(map[string]interface{})
    55  
    56  	for i := 0; i < len(f.Fobj.Outputs); i++ {
    57  		value := vm.Get(f.Fobj.Outputs[i].Name)
    58  		outputs[f.Fobj.Outputs[i].Name] = value.String()
    59  	}
    60  	f.iLog.Debug(fmt.Sprintf("Fucntion %s outputs: %s", f.Fobj.Name, outputs))
    61  	f.SetOutputs(outputs)
    62  }
    63  
    64  // Validate validates the given Funcs object using JavaScript functions.
    65  // It executes the JavaScript code stored in the Content field of the Funcs object using the goja VM.
    66  // If the JavaScript code throws an error, it returns false and the error.
    67  // Otherwise, it returns true and nil.
    68  
    69  func (cf *JSFuncs) Validate(f *Funcs) (bool, error) {
    70  	startTime := time.Now()
    71  	defer func() {
    72  		elapsed := time.Since(startTime)
    73  		f.iLog.PerformanceWithDuration("engine.funcs.JSFuncs.Validate", elapsed)
    74  	}()
    75  	/*	defer func() {
    76  			if err := recover(); err != nil {
    77  				f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.JSFuncs.Validate with error: %s", err))
    78  				f.ErrorMessage = fmt.Sprintf("There is error to engine.funcs.JSFuncs.Validate with error: %s", err)
    79  				return
    80  			}
    81  		}()
    82  	*/
    83  	vm := goja.New()
    84  	_, err := vm.RunString(f.Fobj.Content)
    85  	if err != nil {
    86  		return false, err
    87  	}
    88  
    89  	return true, nil
    90  }
    91  
    92  // Testfunction is a function that executes JavaScript code using the goja VM.
    93  // It takes a content string, inputs interface{}, and outputs []string as parameters.
    94  // The function returns a map[string]interface{} containing the values of the specified outputs,
    95  // and an error if there was an error during execution.
    96  // The execution time is also logged.
    97  func (cf *JSFuncs) Testfunction(content string, inputs interface{}, outputs []string) (map[string]interface{}, error) {
    98  	iLog := logger.Log{ModuleName: logger.TranCode, User: "System", ControllerName: "JSFuncs"}
    99  	startTime := time.Now()
   100  	defer func() {
   101  		elapsed := time.Since(startTime)
   102  		iLog.PerformanceWithDuration("engine.funcs.JSFuncs.Execute", elapsed)
   103  	}()
   104  	defer func() {
   105  		if err := recover(); err != nil {
   106  			iLog.Error(fmt.Sprintf("There is error to engine.funcs.JSFuncs.Execute with error: %s", err))
   107  			//ErrorMessage = fmt.Sprintf("There is error to engine.funcs.JSFuncs.Execute with error: %s", err)
   108  			return
   109  		}
   110  	}()
   111  
   112  	namelist := make([]string, 0)
   113  	valuelist := make([]interface{}, 0)
   114  
   115  	for key, value := range inputs.(map[string]interface{}) {
   116  		namelist = append(namelist, key)
   117  		valuelist = append(valuelist, value)
   118  	}
   119  
   120  	vm := goja.New()
   121  
   122  	for i := 0; i < len(namelist); i++ {
   123  		vm.Set(namelist[i], valuelist[i])
   124  	}
   125  
   126  	value, err := vm.RunString(content)
   127  
   128  	if err != nil {
   129  		println(err.Error())
   130  		return nil, err
   131  	}
   132  
   133  	result := value.Export()
   134  	functionoutputs := make(map[string]interface{})
   135  
   136  	println(result)
   137  
   138  	for i := 0; i < len(outputs); i++ {
   139  		value := vm.Get(outputs[i])
   140  		functionoutputs[outputs[i]] = value
   141  	}
   142  
   143  	return functionoutputs, nil
   144  }
   145  
   146  func (cf *JSFuncs) Execute_otto(f *Funcs) {
   147  	startTime := time.Now()
   148  	defer func() {
   149  		elapsed := time.Since(startTime)
   150  		f.iLog.PerformanceWithDuration("engine.funcs.JSFuncs.Execute", elapsed)
   151  	}()
   152  	defer func() {
   153  		if err := recover(); err != nil {
   154  			f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.JSFuncs.Execute with error: %s", err))
   155  			f.ErrorMessage = fmt.Sprintf("There is error to engine.funcs.JSFuncs.Execute with error: %s", err)
   156  			return
   157  		}
   158  	}()
   159  	f.iLog.Debug(fmt.Sprintf("Start process %s : %s", "JSFuncs.Execute", f.Fobj.Name))
   160  
   161  	namelist, _, inputs := f.SetInputs()
   162  
   163  	vm := otto.New()
   164  	for i := 0; i < len(namelist); i++ {
   165  		vm.Set(namelist[i], inputs[namelist[i]])
   166  	}
   167  	f.iLog.Debug(fmt.Sprintf("Fucntion %s script: %s", f.Fobj.Name, f.Fobj.Content))
   168  
   169  	vm.Run(f.Fobj.Content)
   170  
   171  	outputs := make(map[string]interface{})
   172  
   173  	for i := 0; i < len(f.Fobj.Outputs); i++ {
   174  		if value, err := vm.Get(f.Fobj.Outputs[i].Name); err == nil {
   175  			outputs[f.Fobj.Outputs[i].Name] = value.String()
   176  		} else {
   177  			f.iLog.Error(fmt.Sprintf("Error in JSFuncs.Execute: %s", err.Error()))
   178  			return
   179  		}
   180  	}
   181  
   182  	f.SetOutputs(outputs)
   183  }
   184  
   185  func (cf *JSFuncs) Validate_otto(f *Funcs) (bool, error) {
   186  	vm := otto.New()
   187  	_, err := vm.Compile("", f.Fobj.Content)
   188  	if err != nil {
   189  		return false, err
   190  	}
   191  
   192  	return true, nil
   193  }
   194  
   195  func (cf *JSFuncs) Testfunction_otto(content string, inputs interface{}, outputs []string) (map[string]interface{}, error) {
   196  
   197  	/* pass, err := cf.Validate(f)
   198  
   199  	if !pass {
   200  		return nil, err
   201  	}
   202  	*/
   203  	namelist := make([]string, 0)
   204  	valuelist := make([]interface{}, 0)
   205  
   206  	for key, value := range inputs.(map[string]interface{}) {
   207  		namelist = append(namelist, key)
   208  		valuelist = append(valuelist, value)
   209  	}
   210  
   211  	vm := otto.New()
   212  	for i := 0; i < len(namelist); i++ {
   213  		vm.Set(namelist[i], valuelist[i])
   214  	}
   215  
   216  	vm.Run(content)
   217  
   218  	functionoutputs := make(map[string]interface{})
   219  
   220  	for i := 0; i < len(outputs); i++ {
   221  		if value, err := vm.Get(outputs[i]); err == nil {
   222  			functionoutputs[outputs[i]] = value
   223  		} else {
   224  			fmt.Println(err)
   225  		}
   226  	}
   227  	return functionoutputs, nil
   228  }