github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/engine/function/funcs.go (about) 1 package funcs 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "reflect" 8 "strconv" 9 "strings" 10 "time" 11 12 "database/sql" 13 14 "github.com/mdaxf/iac/documents" 15 "github.com/mdaxf/iac/engine/types" 16 "github.com/mdaxf/iac/logger" 17 "github.com/mdaxf/iac-signalr/signalr" 18 ) 19 20 type Funcs struct { 21 Fobj types.Function 22 DBTx *sql.Tx 23 Ctx context.Context 24 CtxCancel context.CancelFunc 25 SystemSession map[string]interface{} // {sessionanme: value} 26 UserSession map[string]interface{} // {sessionanme: value} 27 Externalinputs map[string]interface{} // {sessionanme: value} 28 Externaloutputs map[string]interface{} // {sessionanme: value} 29 FuncCachedVariables map[string]interface{} 30 iLog logger.Log 31 FunctionInputs []map[string]interface{} 32 FunctionOutputs []map[string]interface{} 33 ExecutionNumber int 34 ExecutionCount int 35 FunctionMappedInputs map[string]interface{} 36 DocDBCon *documents.DocDB 37 SignalRClient signalr.Client 38 ErrorMessage string 39 TestwithSc bool 40 TestResults []map[string]interface{} 41 } 42 43 // NewFuncs creates a new instance of the Funcs struct. 44 // It initializes the Funcs struct with the provided parameters and returns a pointer to the created instance. 45 // The Funcs struct represents a collection of functions and their associated data for execution. 46 // Parameters: 47 // - DocDBCon: A pointer to the DocDB connection object. 48 // - SignalRClient: The SignalR client object. 49 // - dbTx: A pointer to the SQL transaction object. 50 // - fobj: The function object. 51 // - systemSession: A map containing system session data. 52 // - userSession: A map containing user session data. 53 // - externalinputs: A map containing external input data. 54 // - externaloutputs: A map containing external output data. 55 // - funcCachedVariables: A map containing cached variables for the function. 56 // - ctx: The context object. 57 // - ctxcancel: The cancel function for the context. 58 // Returns: 59 // - A pointer to the created Funcs instance. 60 61 func NewFuncs(DocDBCon *documents.DocDB, SignalRClient signalr.Client, dbTx *sql.Tx, fobj types.Function, systemSession, userSession, externalinputs, externaloutputs, funcCachedVariables map[string]interface{}, ctx context.Context, ctxcancel context.CancelFunc) *Funcs { 62 log := logger.Log{} 63 log.ModuleName = logger.TranCode 64 log.ControllerName = "Function" 65 if systemSession["User"] != nil { 66 log.User = systemSession["User"].(string) 67 } else { 68 log.User = "System" 69 } 70 startTime := time.Now() 71 defer func() { 72 elapsed := time.Since(startTime) 73 log.PerformanceWithDuration("engine.funcs.NewFuncs", elapsed) 74 }() 75 76 var newdata []map[string]interface{} 77 78 systemSession["UTCTime"] = time.Now().UTC() 79 systemSession["LocalTime"] = time.Now() 80 if systemSession["UserNo"] == nil { 81 systemSession["UserNo"] = "System" 82 } 83 if systemSession["UserID"] == nil { 84 systemSession["UserID"] = 0 85 } 86 87 if systemSession["WorkSpace"] == nil { 88 systemSession["WorkSpace"] = "" 89 } 90 91 return &Funcs{ 92 Fobj: fobj, 93 DBTx: dbTx, 94 Ctx: ctx, 95 CtxCancel: ctxcancel, 96 SystemSession: systemSession, 97 UserSession: userSession, 98 Externalinputs: externalinputs, 99 Externaloutputs: externaloutputs, 100 FuncCachedVariables: funcCachedVariables, 101 iLog: log, 102 FunctionInputs: newdata, 103 FunctionOutputs: newdata, 104 ExecutionNumber: 1, 105 ExecutionCount: 0, 106 DocDBCon: DocDBCon, 107 SignalRClient: SignalRClient, 108 ErrorMessage: "", 109 TestwithSc: false, 110 TestResults: newdata, 111 } 112 } 113 114 // HandleInputs handles the inputs for the Funcs struct. 115 // It retrieves the inputs from various sources such as system session, user session, pre-function, and external inputs. 116 // The retrieved inputs are then converted to the appropriate data types and stored in the newinputs map. 117 // Finally, it returns the list of input names, input values, and the newinputs map. 118 // Returns: 119 // - A list of input names. 120 // - A list of input values. 121 // - A map containing the new inputs. 122 // - An error if there was an error in the process. 123 124 func (f *Funcs) HandleInputs() ([]string, []string, map[string]interface{}, error) { 125 /* startTime := time.Now() 126 defer func() { 127 elapsed := time.Since(startTime) 128 f.iLog.PerformanceWithDuration("engine.funcs.HandleInputs", elapsed) 129 }() 130 */defer func() { 131 if err := recover(); err != nil { 132 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.HandleInputs with error: %s", err)) 133 f.CancelExecution(fmt.Sprintf("There is error to engine.funcs.HandleInputs with error: %s", err)) 134 return 135 } 136 }() 137 138 f.iLog.Debug(fmt.Sprintf("Start process %s", reflect.ValueOf(f.HandleInputs).Kind().String())) 139 140 f.iLog.Debug(fmt.Sprintf("function inputs: %s", logger.ConvertJson(f.Fobj.Inputs))) 141 142 newinputs := make(map[string]interface{}) 143 namelist := make([]string, len(f.Fobj.Inputs)) 144 valuelist := make([]string, len(f.Fobj.Inputs)) 145 146 inputs := f.Fobj.Inputs 147 // newinputs = f.FunctionMappedInputs 148 149 for i, _ := range inputs { 150 // f.iLog.Debug(fmt.Sprintf("function input: %s, Source: %s", logger.ConvertJson(inputs[i]), inputs[i].Source)) 151 switch inputs[i].Source { 152 case types.Fromsyssession: 153 154 if f.SystemSession[inputs[i].Aliasname] != nil { 155 inputs[i].Value = f.SystemSession[inputs[i].Aliasname].(string) 156 } else { 157 158 f.iLog.Error(fmt.Sprintf("Error in SetInputs: %s SystemSession[%s]", "System Session not found", inputs[i].Aliasname)) 159 // f.DBTx.Rollback() 160 } 161 case types.Fromusersession: 162 if f.UserSession[inputs[i].Aliasname] != nil { 163 inputs[i].Value = f.UserSession[inputs[i].Aliasname].(string) 164 } else { 165 f.iLog.Error(fmt.Sprintf("Error in SetInputs: %s UserSession[%s]", "User Session not found", inputs[i].Aliasname)) 166 // f.DBTx.Rollback() 167 } 168 case types.Prefunction: 169 arr := strings.Split(inputs[i].Aliasname, ".") 170 f.iLog.Debug(fmt.Sprintf("Prefunction: %s", logger.ConvertJson(arr))) 171 if len(arr) == 2 { 172 f.iLog.Debug(fmt.Sprintf("Prefunction variables: %s", logger.ConvertJson(f.FuncCachedVariables))) 173 if f.FuncCachedVariables[arr[0]] != nil { 174 value, _ := f.checkinputvalue(arr[1], f.FuncCachedVariables[arr[0]].(map[string]interface{})) 175 inputs[i].Value = value 176 } else { 177 f.iLog.Error(fmt.Sprintf("Error in SetInputs: %s Prefunction[%s]", "Prefunction not found", inputs[i].Aliasname)) 178 // f.DBTx.Rollback() 179 if inputs[i].Datatype == types.DateTime { 180 if inputs[i].Defaultvalue == "" { 181 inputs[i].Value = time.Now().Format(types.DateTimeFormat) 182 } else { 183 inputs[i].Value = inputs[i].Defaultvalue 184 } 185 186 } else if inputs[i].Datatype == types.Integer { 187 if inputs[i].Defaultvalue == "" { 188 inputs[i].Value = "0" 189 } else { 190 inputs[i].Value = inputs[i].Defaultvalue 191 } 192 } else if inputs[i].Datatype == types.Float { 193 if inputs[i].Defaultvalue == "" { 194 inputs[i].Value = "0.0" 195 } else { 196 inputs[i].Value = inputs[i].Defaultvalue 197 } 198 199 } else if inputs[i].Datatype == types.Bool { 200 if inputs[i].Defaultvalue == "" { 201 inputs[i].Value = "false" 202 } else { 203 inputs[i].Value = inputs[i].Defaultvalue 204 } 205 206 } else { 207 208 inputs[i].Value = inputs[i].Defaultvalue 209 } 210 } 211 } else { 212 f.iLog.Error(fmt.Sprintf("Error in SetInputs: %s Prefunction[%s]", "Prefunction not found", inputs[i].Aliasname)) 213 // f.DBTx.Rollback() 214 if inputs[i].Datatype == types.DateTime { 215 if inputs[i].Defaultvalue == "" { 216 inputs[i].Value = time.Now().Format(types.DateTimeFormat) 217 } else { 218 inputs[i].Value = inputs[i].Defaultvalue 219 } 220 221 } else if inputs[i].Datatype == types.Integer { 222 if inputs[i].Defaultvalue == "" { 223 inputs[i].Value = "0" 224 } else { 225 inputs[i].Value = inputs[i].Defaultvalue 226 } 227 } else if inputs[i].Datatype == types.Float { 228 if inputs[i].Defaultvalue == "" { 229 inputs[i].Value = "0.0" 230 } else { 231 inputs[i].Value = inputs[i].Defaultvalue 232 } 233 234 } else if inputs[i].Datatype == types.Bool { 235 if inputs[i].Defaultvalue == "" { 236 inputs[i].Value = "false" 237 } else { 238 inputs[i].Value = inputs[i].Defaultvalue 239 } 240 241 } else { 242 243 inputs[i].Value = inputs[i].Defaultvalue 244 } 245 } 246 247 case types.Fromexternal: 248 f.iLog.Debug(fmt.Sprintf("Externalinputs: %s", logger.ConvertJson(f.Externalinputs))) 249 value, _ := f.checkinputvalue(inputs[i].Aliasname, f.Externalinputs) 250 inputs[i].Value = value 251 252 } 253 254 f.iLog.Debug(fmt.Sprintf("function input: %s, Source: %v, value: %s type: %d", logger.ConvertJson(inputs[i]), inputs[i].Source, inputs[i].Value, inputs[i].Datatype)) 255 switch inputs[i].Datatype { 256 257 case types.Integer: 258 259 if inputs[i].List == false { 260 261 temp := f.ConverttoInt(inputs[i].Value) 262 newinputs[inputs[i].Name] = temp 263 264 } 265 if inputs[i].List == true { 266 267 f.iLog.Debug(fmt.Sprintf("check value %s if it isArray: %s", inputs[i].Value, reflect.ValueOf(inputs[i].Value).Kind().String())) 268 269 var tempstr []string 270 err := json.Unmarshal([]byte(inputs[i].Value), &tempstr) 271 f.iLog.Debug(fmt.Sprintf("Unmarshal %s result: %s length:%d", inputs[i].Value, logger.ConvertJson(tempstr), len(tempstr))) 272 273 if err != nil { 274 //f.iLog.Error(fmt.Sprintf("Unmarshal %s error: %s", inputs[i].Value, err.Error())) 275 276 var tempint []int 277 err := json.Unmarshal([]byte(inputs[i].Value), &tempint) 278 if err != nil { 279 //f.iLog.Error(fmt.Sprintf("Unmarshal %s error: %s", inputs[i].Value, err.Error())) 280 281 var tempfloat []float64 282 err := json.Unmarshal([]byte(inputs[i].Value), &tempfloat) 283 if err != nil { 284 //f.iLog.Error(fmt.Sprintf("Unmarshal %s error: %s", inputs[i].Value, err.Error())) 285 // f.DBTx.Rollback() 286 287 str := inputs[i].Value 288 str = strings.TrimPrefix(str, "[") 289 str = strings.TrimSuffix(str, "]") 290 strList := strings.Split(str, ",") 291 292 intList := make([]int, len(strList)) 293 for index, str := range strList { 294 intList[index] = f.ConverttoInt(str) 295 } 296 newinputs[inputs[i].Name] = intList 297 298 } else { 299 temp := make([]int, 0) 300 for _, str := range tempfloat { 301 temp = append(temp, int(str)) 302 } 303 newinputs[inputs[i].Name] = temp 304 } 305 306 } else { 307 newinputs[inputs[i].Name] = tempint 308 } 309 } else { 310 temp := make([]int, 0) 311 for _, str := range tempstr { 312 temp = append(temp, f.ConverttoInt(str)) 313 } 314 newinputs[inputs[i].Name] = temp 315 316 } 317 /* 318 if isArray(inputs[i].Value) { 319 320 321 322 } else { 323 temp := make([]int, 0) 324 temp = append(temp, f.ConverttoInt(inputs[i].Value)) 325 newinputs[inputs[i].Name] = temp 326 } */ 327 328 } 329 case types.Float: 330 if inputs[i].List == false { 331 332 temp := f.ConverttoFloat(inputs[i].Value) 333 newinputs[inputs[i].Name] = temp 334 335 } 336 if inputs[i].List == true { 337 338 var temp []float64 339 err := json.Unmarshal([]byte(inputs[i].Value), &temp) 340 if err != nil { 341 f.iLog.Error(fmt.Sprintf("Unmarshal %s error: %s", inputs[i].Value, err.Error())) 342 // f.DBTx.Rollback() 343 } 344 newinputs[inputs[i].Name] = temp 345 346 } 347 case types.Bool: 348 if inputs[i].List == false { 349 temp := f.ConverttoBool(inputs[i].Value) 350 newinputs[inputs[i].Name] = temp 351 } 352 if inputs[i].List == true { 353 354 var temp []bool 355 err := json.Unmarshal([]byte(inputs[i].Value), &temp) 356 if err != nil { 357 f.iLog.Error(fmt.Sprintf("Unmarshal %s error: %s", inputs[i].Value, err.Error())) 358 // f.DBTx.Rollback() 359 } 360 newinputs[inputs[i].Name] = temp 361 362 } 363 case types.DateTime: 364 if inputs[i].List == false { 365 366 temp := f.ConverttoDateTime(inputs[i].Value) 367 newinputs[inputs[i].Name] = temp 368 369 } 370 if inputs[i].List == true { 371 372 var temp []time.Time 373 var datetimeStrings []string 374 err := json.Unmarshal([]byte(inputs[i].Value), &datetimeStrings) 375 if err != nil { 376 f.iLog.Error(fmt.Sprintf("Unmarshal %s error: %s", inputs[i].Value, err.Error())) 377 // f.DBTx.Rollback() 378 } 379 for _, dtStr := range datetimeStrings { 380 dt, err := time.Parse("2006-01-02 15:04:05", dtStr) 381 if err != nil { 382 f.iLog.Error(fmt.Sprintf("Parse %s error: %s", dtStr, err.Error())) 383 // f.DBTx.Rollback() 384 } 385 temp = append(temp, dt) 386 } 387 388 newinputs[inputs[i].Name] = temp 389 390 } 391 default: 392 if inputs[i].List == false { 393 newinputs[inputs[i].Name] = inputs[i].Value 394 395 } 396 if inputs[i].List == true { 397 398 var temp []string 399 err := json.Unmarshal([]byte(inputs[i].Value), &temp) 400 if err != nil { 401 f.iLog.Error(fmt.Sprintf("Unmarshal %s error: %s", inputs[i].Value, err.Error())) 402 // f.DBTx.Rollback() 403 } 404 405 newinputs[inputs[i].Name] = temp 406 407 } 408 } 409 namelist[i] = inputs[i].Name 410 valuelist[i] = inputs[i].Value 411 } 412 413 f.FunctionMappedInputs = newinputs 414 415 return namelist, valuelist, newinputs, nil 416 } 417 418 // SetInputs sets the inputs for the Funcs object. 419 // It handles the mapping of inputs and prepares them for execution. 420 // It returns the list of input names, the list of input values, and a map of new inputs. 421 422 func (f *Funcs) SetInputs() ([]string, []string, map[string]interface{}) { 423 /* startTime := time.Now() 424 defer func() { 425 elapsed := time.Since(startTime) 426 f.iLog.PerformanceWithDuration("engine.funcs.SetInputs", elapsed) 427 }() 428 */defer func() { 429 if err := recover(); err != nil { 430 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.SetInputs with error: %s", err)) 431 f.CancelExecution(fmt.Sprintf("There is error to engine.funcs.HandleInputs with error: %s", err)) 432 return 433 } 434 }() 435 436 f.iLog.Debug(fmt.Sprintf("Start process %s", reflect.ValueOf(f.SetInputs).Kind().String())) 437 438 namelist, valuelist, newinputs, err := f.HandleInputs() 439 440 if err != nil { 441 f.iLog.Error(fmt.Sprintf("Error in SetInputs: %s", err.Error())) 442 } 443 inputs := f.Fobj.Inputs 444 445 if f.ExecutionNumber > 1 { 446 f.iLog.Debug(fmt.Sprintf("function inputs: %s execution count: %d/%d", logger.ConvertJson(inputs), f.ExecutionCount, f.ExecutionNumber)) 447 448 f.iLog.Debug(fmt.Sprintf("function mapped inputs: %s", logger.ConvertJson(f.FunctionMappedInputs))) 449 for i := 0; i < len(inputs); i++ { 450 451 // newinputs[inputs[i].Name] = inputs[i].Value 452 namelist[i] = inputs[i].Name 453 f.iLog.Debug(fmt.Sprintf("function input: %s, Source: %d", logger.ConvertJson(inputs[i]), inputs[i].Source)) 454 if f.ExecutionNumber > 1 && inputs[i].Repeat && inputs[i].List { 455 456 //valuelist[i] = (f.FunctionMappedInputs[inputs[i].Name]).([]interface{})[f.ExecutionCount].(string) 457 if inputs[i].Datatype == types.DateTime { 458 temp := (f.FunctionMappedInputs[inputs[i].Name]).([]time.Time)[f.ExecutionCount] 459 newinputs[inputs[i].Name] = temp.Format("2006-01-02 15:04:05") 460 valuelist[i] = temp.Format("2006-01-02 15:04:05") 461 } else if inputs[i].Datatype == types.Integer { 462 temp := (f.FunctionMappedInputs[inputs[i].Name]).([]int)[f.ExecutionCount] 463 newinputs[inputs[i].Name] = strconv.Itoa(temp) 464 valuelist[i] = strconv.Itoa(temp) 465 } else if inputs[i].Datatype == types.Float { 466 temp := (f.FunctionMappedInputs[inputs[i].Name]).([]float64)[f.ExecutionCount] 467 newinputs[inputs[i].Name] = strconv.FormatFloat(temp, 'f', -1, 64) 468 valuelist[i] = strconv.FormatFloat(temp, 'f', -1, 64) 469 } else if inputs[i].Datatype == types.Bool { 470 temp := (f.FunctionMappedInputs[inputs[i].Name]).([]bool)[f.ExecutionCount] 471 newinputs[inputs[i].Name] = strconv.FormatBool(temp) 472 valuelist[i] = strconv.FormatBool(temp) 473 } else { 474 valuelist[i] = (f.FunctionMappedInputs[inputs[i].Name]).([]string)[f.ExecutionCount] 475 newinputs[inputs[i].Name] = (f.FunctionMappedInputs[inputs[i].Name]).([]string)[f.ExecutionCount] 476 } 477 478 } else { 479 newinputs[inputs[i].Name] = f.FunctionMappedInputs[inputs[i].Name] 480 valuelist[i] = inputs[i].Value 481 } 482 483 //inputs[i].Value 484 } 485 486 f.iLog.Debug(fmt.Sprintf("function mapped inputs: %s for execution: %d/%d", logger.ConvertJson(newinputs), f.ExecutionCount, f.ExecutionNumber)) 487 } 488 //f.Fobj.Inputs = inputs 489 490 return namelist, valuelist, newinputs 491 } 492 493 // isArray checks if the given value is an array or a slice. 494 // It uses reflection to determine the kind of the value. 495 // Returns true if the value is an array or a slice, false otherwise. 496 func isArray(value interface{}) bool { 497 // Use reflection to check if the value's kind is an array 498 499 val := reflect.ValueOf(value) 500 return val.Kind() == reflect.Array || val.Kind() == reflect.Slice 501 } 502 503 // checkifRepeatExecution checks if the function should be repeated execution based on the inputs. 504 // It returns the count of repetitions and an error if any. 505 // Returns: 506 // - The count of repetitions. 507 // - An error if there was an error in the process. 508 509 func (f *Funcs) checkifRepeatExecution() (int, error) { 510 /* startTime := time.Now() 511 defer func() { 512 elapsed := time.Since(startTime) 513 f.iLog.PerformanceWithDuration("engine.funcs.checkifRepeatExecution", elapsed) 514 }() 515 defer func() { 516 if err := recover(); err != nil { 517 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.checkifRepeatExecution with error: %s", err)) 518 return 519 } 520 }() 521 */ 522 inputs := f.Fobj.Inputs 523 lastcount := -2 524 525 _, _, newinputs, err := f.HandleInputs() 526 527 if err != nil { 528 f.iLog.Error(fmt.Sprintf("Error in SetInputs: %s", err.Error())) 529 } 530 531 f.Fobj.Inputs = inputs 532 f.iLog.Debug(fmt.Sprintf("parse inputs result: %s", logger.ConvertJson(newinputs))) 533 for _, input := range inputs { 534 535 f.iLog.Debug(fmt.Sprintf("checkifRepeatExecution input: %s", logger.ConvertJson(input))) 536 537 count := -1 538 if input.Repeat && input.List { 539 inputvalue := newinputs[input.Name] 540 if isArray(inputvalue) { 541 if input.Datatype == types.DateTime { 542 count = len(inputvalue.([]time.Time)) 543 } else if input.Datatype == types.Integer { 544 count = len(inputvalue.([]int)) 545 } else if input.Datatype == types.Float { 546 count = len(inputvalue.([]float64)) 547 } else if input.Datatype == types.Bool { 548 count = len(inputvalue.([]bool)) 549 } else { 550 count = len(inputvalue.([]string)) 551 } 552 553 } else { 554 count = 1 555 } 556 f.iLog.Debug(fmt.Sprintf("checkifRepeatExecution input.Value: %s, count: %d, lastcount %d", input.Value, count, lastcount)) 557 if lastcount == -2 { 558 lastcount = count 559 } else if lastcount != count { 560 return -1, nil 561 } 562 563 } 564 } 565 566 if lastcount > 0 { 567 return lastcount, nil 568 } else { 569 return 1, nil 570 } 571 } 572 573 // checkinputvalue is a function that checks the input value for a given alias name and variables. 574 // It returns the result as a string and an error if any. 575 // Parameters: 576 // - Aliasname: The alias name of the input. 577 // - variables: A map containing the variables. 578 // Returns: 579 // - The result as a string. 580 // - An error if there was an error in the process. 581 func (f *Funcs) checkinputvalue(Aliasname string, variables map[string]interface{}) (string, error) { 582 /* startTime := time.Now() 583 defer func() { 584 elapsed := time.Since(startTime) 585 f.iLog.PerformanceWithDuration("engine.funcs.checkinputvalue", elapsed) 586 }() 587 defer func() { 588 if err := recover(); err != nil { 589 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.checkinputvalue with error: %s", err)) 590 return 591 } 592 }() */ 593 594 var err error 595 err = nil 596 var Result string 597 if variables[Aliasname] != nil { 598 if resultMap, ok := variables[Aliasname].([]interface{}); ok { 599 Result = "[" 600 for index, value := range resultMap { 601 _value, err := json.Marshal(value) 602 if err != nil { 603 f.iLog.Error(fmt.Sprintf("Marshal %s error: %s", Aliasname, err.Error())) 604 // f.DBTx.Rollback() 605 } 606 607 if index == 0 { 608 Result += string(_value) 609 } else { 610 Result = Result + "," + string(_value) 611 } 612 } 613 Result += "]" 614 } else if resultMap, ok := variables[Aliasname].(map[string]interface{}); ok { 615 value, err := json.Marshal(resultMap) 616 if err != nil { 617 f.iLog.Error(fmt.Sprintf("Marshal %s error: %s", Aliasname, err.Error())) 618 // f.DBTx.Rollback() 619 } else { 620 Result = string(value) 621 } 622 623 Result = string(value) 624 } else if resultMap, ok := variables[Aliasname].([]string); ok { 625 Result = "" 626 for index, value := range resultMap { 627 if index == 0 { 628 Result = value 629 } else { 630 Result = Result + "," + value 631 } 632 } 633 } else { 634 635 /*temp, err := json.Marshal(variables[Aliasname]) 636 if err != nil { 637 f.iLog.Error(fmt.Sprintf("Marshal %s error: %s", Aliasname, err.Error())) 638 } 639 f.iLog.Debug(fmt.Sprintf("checkinputvalue %s temp: %s", variables[Aliasname], temp)) */ 640 switch variables[Aliasname].(type) { 641 case int: 642 if variables[Aliasname] == "" { 643 Result = strconv.Itoa(0) 644 } else { 645 Result = strconv.Itoa(variables[Aliasname].(int)) 646 } 647 case int64: 648 if variables[Aliasname] == "" { 649 Result = strconv.Itoa(0) 650 } else { 651 value := int(variables[Aliasname].(int64)) 652 Result = strconv.Itoa(value) 653 } 654 case float64: 655 if variables[Aliasname] == "" { 656 Result = strconv.FormatFloat(0.0, 'f', -1, 64) 657 } else { 658 Result = strconv.FormatFloat(variables[Aliasname].(float64), 'f', -1, 64) 659 } 660 case bool: 661 if variables[Aliasname] == "" { 662 Result = strconv.FormatBool(false) 663 } else { 664 Result = strconv.FormatBool(variables[Aliasname].(bool)) 665 } 666 case string: 667 Result = variables[Aliasname].(string) 668 case time.Time: 669 Result = variables[Aliasname].(time.Time).Format(types.DateTimeFormat) 670 case nil: 671 Result = "" 672 default: 673 Result = fmt.Sprint(variables[Aliasname]) 674 675 } 676 Result = string(Result) 677 } 678 } else { 679 f.iLog.Error(fmt.Sprintf("Error in SetInputs: %s Externalinputs[%s]", "Externalinputs not found", Aliasname)) 680 // f.DBTx.Rollback() 681 682 } 683 684 f.iLog.Debug(fmt.Sprintf("checkinputvalue %s result: %s", variables[Aliasname], Result)) 685 return Result, err 686 } 687 688 // customMarshal is a function that takes an interface{} as input and returns a string representation of the input object in JSON format. 689 // The function uses reflection to iterate over the fields of the input object and constructs a JSON string by concatenating the field names and values. 690 // The field names are obtained from the "json" tag of the struct fields. 691 // If the input object is not a struct, the function returns an empty string. 692 // Parameters: 693 // - v: The input object. 694 // Returns: 695 // - A string representation of the input object in JSON format. 696 697 func customMarshal(v interface{}) string { 698 699 var jsonStr string 700 switch reflect.TypeOf(v).Kind() { 701 case reflect.Struct: 702 t := reflect.TypeOf(v) 703 v := reflect.ValueOf(v) 704 jsonStr += "{" 705 for i := 0; i < t.NumField(); i++ { 706 fieldName := t.Field(i).Tag.Get("json") 707 fieldValue := fmt.Sprintf("%v", v.Field(i)) 708 jsonStr += fmt.Sprintf(`%s:%s,`, fieldName, fieldValue) 709 } 710 jsonStr = jsonStr[:len(jsonStr)-1] // Remove trailing comma 711 jsonStr += "}" 712 } 713 return jsonStr 714 } 715 716 // ConverttoInt converts a string to an integer. 717 // It measures the performance of the conversion and logs any errors that occur. 718 // If an error occurs during the conversion, it returns 0. 719 // Parameters: 720 // - str: The string to be converted. 721 // Returns: 722 // - The converted integer value. 723 724 func (f *Funcs) ConverttoInt(str string) int { 725 /* startTime := time.Now() 726 defer func() { 727 elapsed := time.Since(startTime) 728 f.iLog.PerformanceWithDuration("engine.funcs.ConverttoInt", elapsed) 729 }() 730 defer func() { 731 if err := recover(); err != nil { 732 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.ConverttoInt with error: %s", err)) 733 return 734 } 735 }() 736 */ 737 temp, err := strconv.Atoi(str) 738 if err != nil { 739 f.iLog.Error(fmt.Sprintf("Convert %s to int error: %s", str, err.Error())) 740 } 741 742 return temp 743 } 744 745 // ConverttoFloat converts a string to a float64 value. 746 // It uses the strconv.ParseFloat function to perform the conversion. 747 // If the conversion fails, an error is logged and the function returns 0. 748 // The performance of this function is logged using the provided iLog instance. 749 // Parameters: 750 // - str: The string to be converted. 751 // Returns: 752 // - The converted float64 value. 753 754 func (f *Funcs) ConverttoFloat(str string) float64 { 755 /* startTime := time.Now() 756 defer func() { 757 elapsed := time.Since(startTime) 758 f.iLog.PerformanceWithDuration("engine.funcs.ConverttoFloat", elapsed) 759 }() 760 defer func() { 761 if err := recover(); err != nil { 762 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.ConverttoFloat with error: %s", err)) 763 return 764 } 765 }() 766 */ 767 temp, err := strconv.ParseFloat(str, 64) 768 if err != nil { 769 f.iLog.Error(fmt.Sprintf("Convert %s to float error: %s", str, err.Error())) 770 } 771 772 return temp 773 } 774 775 // ConverttoBool converts a string to a boolean value. 776 // It uses the strconv.ParseBool function to parse the string. 777 // If the string cannot be parsed, an error is logged and false is returned. 778 // The performance of this function is logged using the iLog.PerformanceWithDuration method. 779 // If a panic occurs during the execution of this function, the panic is recovered and logged as an error. 780 // Parameters: 781 // - str: The string to be converted to a boolean value. 782 // Returns: 783 // - bool: The boolean value parsed from the string. 784 785 func (f *Funcs) ConverttoBool(str string) bool { 786 /* startTime := time.Now() 787 defer func() { 788 elapsed := time.Since(startTime) 789 f.iLog.PerformanceWithDuration("engine.funcs.ConverttoBool", elapsed) 790 }() 791 defer func() { 792 if err := recover(); err != nil { 793 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.ConverttoBool with error: %s", err)) 794 return 795 } 796 }() 797 */ 798 temp, err := strconv.ParseBool(str) 799 if err != nil { 800 f.iLog.Error(fmt.Sprintf("Convert %s to bool error: %s", str, err.Error())) 801 } 802 803 return temp 804 } 805 806 // ConverttoDateTime converts a string to a time.Time value. 807 // It uses the specified DateTimeFormat to parse the string. 808 // If the string cannot be parsed, an error is logged and the zero time value is returned. 809 // The function also logs the performance duration of the conversion. 810 // If a panic occurs during the execution of this function, the panic is recovered and logged as an error. 811 // Parameters: 812 // - str: The string to be converted to a time.Time value. 813 // Returns: 814 // - time.Time: The time.Time value parsed from the string. 815 816 func (f *Funcs) ConverttoDateTime(str string) time.Time { 817 /* startTime := time.Now() 818 defer func() { 819 elapsed := time.Since(startTime) 820 f.iLog.PerformanceWithDuration("engine.funcs.ConverttoDatTime", elapsed) 821 }() 822 defer func() { 823 if err := recover(); err != nil { 824 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.ConverttoDateTime with error: %s", err)) 825 return 826 } 827 }() 828 */ 829 temp, err := time.Parse(types.DateTimeFormat, str) 830 if err != nil { 831 f.iLog.Error(fmt.Sprintf("Convert %s to time error: %s", str, err.Error())) 832 } 833 834 return temp 835 } 836 837 // SetOutputs sets the outputs of the function. 838 // It takes a map of string keys and interface{} values representing the outputs. 839 // The function logs the performance duration and any errors that occur during execution. 840 // It also appends the outputs to the FunctionOutputs slice. 841 // Parameters: 842 // - outputs: A map of string keys and interface{} values representing the outputs. 843 844 func (f *Funcs) SetOutputs(outputs map[string]interface{}) { 845 /* startTime := time.Now() 846 defer func() { 847 elapsed := time.Since(startTime) 848 f.iLog.PerformanceWithDuration("engine.funcs.SetOutputs", elapsed) 849 }() 850 defer func() { 851 if err := recover(); err != nil { 852 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.SetOutputs with error: %s", err)) 853 return 854 } 855 }() 856 */ 857 f.iLog.Debug(fmt.Sprintf("function's ouputs: %s", logger.ConvertJson(outputs))) 858 859 f.FunctionOutputs = append(f.FunctionOutputs, outputs) 860 861 } 862 863 // SetfuncOutputs sets the function outputs for the Funcs struct. 864 // It combines the outputs from multiple function executions into a single output map. 865 // If the execution number is greater than 1, it iterates over the function outputs and combines them. 866 // Otherwise, it sets the single function output. 867 // The function also measures the performance duration and logs any errors that occur during execution. 868 // If a panic occurs during the execution of this function, the panic is recovered and logged as an error. 869 // Parameters: 870 // - outputs: A map of string keys and interface{} values representing the outputs. 871 872 func (f *Funcs) SetfuncOutputs() { 873 /* startTime := time.Now() 874 defer func() { 875 elapsed := time.Since(startTime) 876 f.iLog.PerformanceWithDuration("engine.funcs.SetfuncOutputs", elapsed) 877 }() 878 defer func() { 879 if err := recover(); err != nil { 880 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.SetfuncOutputs with error: %s", err)) 881 return 882 } 883 }() 884 */ 885 newoutputs := make(map[string]interface{}) 886 if f.ExecutionNumber > 1 { 887 for index, outputs := range f.FunctionOutputs { 888 for key, value := range outputs { 889 if newoutputs[key] == nil { 890 newoutputs[key] = make([]interface{}, f.ExecutionNumber) 891 } 892 newoutputs[key].([]interface{})[index] = value 893 } 894 } 895 896 f.SetfuncSingleOutputs(newoutputs) 897 } else { 898 f.SetfuncSingleOutputs(f.FunctionOutputs[0]) 899 } 900 901 } 902 903 // SetfuncSingleOutputs sets the single outputs of the Funcs object based on the provided map of outputs. 904 // It iterates through the outputs of the Funcs object and assigns the corresponding values from the map to the appropriate destinations. 905 // The UserSession, Externaloutputs, and FuncCachedVariables are updated accordingly. 906 // If an error occurs during the process, it is recovered and logged. 907 // The performance duration of the function is also logged. 908 // Parameters: 909 // - outputs: A map of string keys and interface{} values representing the outputs. 910 // Returns: 911 // - An error if there was an error in the process. 912 func (f *Funcs) SetfuncSingleOutputs(outputs map[string]interface{}) { 913 /* startTime := time.Now() 914 defer func() { 915 elapsed := time.Since(startTime) 916 f.iLog.PerformanceWithDuration("engine.funcs.SetfuncSingleOutputs", elapsed) 917 }() 918 defer func() { 919 if err := recover(); err != nil { 920 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.SetfuncSingleOutputs with error: %s", err)) 921 return 922 } 923 }() 924 */ 925 for i := 0; i < len(f.Fobj.Outputs); i++ { 926 if outputs[f.Fobj.Outputs[i].Name] == nil { 927 continue 928 } 929 930 for j := 0; j < len(f.Fobj.Outputs[i].Outputdest); j++ { 931 932 switch f.Fobj.Outputs[i].Outputdest[j] { 933 case types.Tosession: 934 f.UserSession[f.Fobj.Outputs[i].Aliasname[j]] = outputs[f.Fobj.Outputs[i].Name] 935 936 case types.Toexternal: 937 f.Externaloutputs[f.Fobj.Outputs[i].Aliasname[j]] = outputs[f.Fobj.Outputs[i].Name] 938 939 } 940 } 941 942 f.FuncCachedVariables[f.Fobj.Name] = outputs 943 } 944 f.iLog.Debug(fmt.Sprintf("UserSession after function: %s", logger.ConvertJson(f.UserSession))) 945 f.iLog.Debug(fmt.Sprintf("Externaloutputs after function: %s", logger.ConvertJson(f.Externaloutputs))) 946 f.iLog.Debug(fmt.Sprintf("FuncCachedVariables after function: %s", logger.ConvertJson(f.FuncCachedVariables[f.Fobj.Name]))) 947 948 } 949 950 // ConvertfromBytes converts a byte buffer into a map[string]interface{}. 951 // It takes a byte buffer as input and returns a map containing the converted data. 952 // The function also logs the performance duration and handles any panics that occur during execution. 953 // If there is an error during the JSON unmarshaling process, it is logged as well. 954 955 func (f *Funcs) ConvertfromBytes(bytesbuffer []byte) map[string]interface{} { 956 /* startTime := time.Now() 957 defer func() { 958 elapsed := time.Since(startTime) 959 f.iLog.PerformanceWithDuration("engine.funcs.ConvertfromBytes", elapsed) 960 }() 961 defer func() { 962 if err := recover(); err != nil { 963 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.ConvertfromBytes with error: %s", err)) 964 return 965 } 966 }() 967 */ 968 f.iLog.Debug(fmt.Sprintf("Start process %s", reflect.ValueOf(f.ConvertfromBytes).Kind().String())) 969 970 temobj := make(map[string]interface{}) 971 for i := 0; i < len(f.Fobj.Outputs); i++ { 972 temobj[f.Fobj.Outputs[i].Name] = f.Fobj.Outputs[i].Defaultvalue 973 } 974 975 err := json.Unmarshal(bytesbuffer, &temobj) 976 if err != nil { 977 f.iLog.Error(fmt.Sprintf("error: %v", err.Error())) 978 } 979 return temobj 980 } 981 982 // Execute executes the function. 983 // It measures the execution time, handles panics, and executes the appropriate function based on the function type. 984 // It also sets the function outputs and updates the execution count. 985 func (f *Funcs) Execute() { 986 startTime := time.Now() 987 defer func() { 988 elapsed := time.Since(startTime) 989 f.iLog.PerformanceWithDuration("engine.funcs.Execute", elapsed) 990 }() 991 992 defer func() { 993 if r := recover(); r != nil { 994 f.iLog.Error(fmt.Sprintf("Panic in Execute: %s", r)) 995 f.CancelExecution(fmt.Sprintf("Panic in Execute: %s", r)) 996 f.ErrorMessage = fmt.Sprintf("Panic in Execute: %s", r) 997 return 998 } 999 }() 1000 1001 f.iLog.Debug(fmt.Sprintf("Execute function: %s", f.Fobj.Name)) 1002 //f.iLog.Debug(fmt.Sprintf("Start process %s", reflect.ValueOf(f.Execute).Kind().String())) 1003 number, err := f.checkifRepeatExecution() 1004 1005 if err != nil { 1006 f.iLog.Error(fmt.Sprintf("Error in Execute: %s", err.Error())) 1007 } 1008 if number < 1 { 1009 f.iLog.Debug(fmt.Sprintf("No repeat execution")) 1010 outputs := make(map[string]interface{}) 1011 f.SetOutputs(outputs) 1012 return 1013 } 1014 f.iLog.Debug(fmt.Sprintf("Execute the function: %s, inputs: %s mapped inputs: %s", f.Fobj.Name, logger.ConvertJson(f.Fobj.Inputs), logger.ConvertJson(f.FunctionMappedInputs))) 1015 f.iLog.Debug(fmt.Sprintf("Repeat execution: %d", number)) 1016 1017 f.ExecutionNumber = number 1018 f.ExecutionCount = 0 1019 1020 for i := 0; i < f.ExecutionNumber; i++ { 1021 f.ErrorMessage = "" 1022 f.iLog.Debug(fmt.Sprintf("Execute the function: %s, execution count: %d / %d", f.Fobj.Name, i+1, f.ExecutionNumber)) 1023 switch f.Fobj.Functype { 1024 case types.InputMap: 1025 inputmapfuncs := InputMapFuncs{} 1026 inputmapfuncs.Execute(f) 1027 1028 case types.GoExpr: 1029 goexprfuncs := GoExprFuncs{} 1030 goexprfuncs.Execute(f) 1031 case types.Javascript: 1032 jsfuncs := JSFuncs{} 1033 jsfuncs.Execute(f) 1034 1035 case types.Query: 1036 qfuncs := QueryFuncs{} 1037 qfuncs.Execute(f) 1038 1039 case types.SubTranCode: 1040 stcfuncs := SubTranCodeFuncs{} 1041 //stcfuncs := NewSubTran() 1042 stcfuncs.Execute(f) 1043 1044 case types.StoreProcedure: 1045 spfuncs := StoreProcFuncs{} 1046 spfuncs.Execute(f) 1047 1048 case types.TableInsert: 1049 ti := TableInsertFuncs{} 1050 ti.Execute(f) 1051 1052 case types.TableUpdate: 1053 tu := TableUpdateFuncs{} 1054 tu.Execute(f) 1055 1056 case types.TableDelete: 1057 td := TableDeleteFuncs{} 1058 td.Execute(f) 1059 1060 case types.CollectionInsert: 1061 ci := CollectionInsertFuncs{} 1062 ci.Execute(f) 1063 1064 case types.CollectionUpdate: 1065 cu := CollectionUpdateFuncs{} 1066 cu.Execute(f) 1067 1068 case types.CollectionDelete: 1069 cd := CollectionDeleteFuncs{} 1070 cd.Execute(f) 1071 1072 case types.ThrowError: 1073 te := ThrowErrorFuncs{} 1074 te.Execute(f) 1075 1076 case types.SendMessage: 1077 sm := SendMessageFuncs{} 1078 sm.Execute(f) 1079 1080 case types.SendEmail: 1081 se := EmailFuncs{} 1082 se.Execute(f) 1083 1084 case types.ExplodeWorkFlow: 1085 wf := WorkFlowFunc{} 1086 wf.Execute_Explode(f) 1087 1088 case types.StartWorkFlowTask: 1089 wf := WorkFlowFunc{} 1090 wf.Execute_StartTask(f) 1091 1092 case types.CompleteWorkFlowTask: 1093 wf := WorkFlowFunc{} 1094 wf.Execute_CompleteTask(f) 1095 1096 case types.SendMessagebyKafka: 1097 sm := SendMessagebyKafka{} 1098 sm.Execute(f) 1099 1100 case types.WebServiceCall: 1101 ws := WebServiceCallFunc{} 1102 ws.Execute(f) 1103 } 1104 1105 f.iLog.Debug(fmt.Sprintf("executed function %s with outputs: %s", f.Fobj.Name, logger.ConvertJson(f.FunctionOutputs))) 1106 1107 f.ExecutionCount = i + 1 1108 1109 if f.TestwithSc == true { 1110 functioninputs := map[string]interface{}{} 1111 1112 for _, input := range f.Fobj.Inputs { 1113 functioninputs[input.Name] = input.Value 1114 } 1115 1116 TestResult := make(map[string]interface{}) 1117 TestResult["Name"] = f.Fobj.Name 1118 TestResult["Type"] = "Function" 1119 TestResult["FunctionType"] = f.Fobj.Functype 1120 TestResult["Inputs"] = functioninputs 1121 TestResult["Outputs"] = f.FunctionOutputs 1122 TestResult["UserSession"] = f.UserSession 1123 TestResult["SystemSession"] = f.SystemSession 1124 TestResult["ExecutionCount"] = f.ExecutionCount 1125 TestResult["ExecutionNumber"] = f.ExecutionNumber 1126 TestResult["ExecutionTime"] = time.Since(startTime) 1127 TestResult["Error"] = f.ErrorMessage 1128 f.TestResults = append(f.TestResults, TestResult) 1129 } 1130 1131 } 1132 f.SetfuncOutputs() 1133 } 1134 1135 func (f *Funcs) Validate() (bool, error) { 1136 startTime := time.Now() 1137 defer func() { 1138 elapsed := time.Since(startTime) 1139 f.iLog.PerformanceWithDuration("engine.funcs.Validate", elapsed) 1140 }() 1141 /* defer func() { 1142 if err := recover(); err != nil { 1143 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.Validate with error: %s", err)) 1144 return 1145 } 1146 }() 1147 */ 1148 return true, nil 1149 } 1150 1151 // CancelExecution cancels the execution of the function and rolls back any database transaction. 1152 // It takes an error message as input and logs the error message along with the function name. 1153 // It also cancels the context and returns. 1154 func (f *Funcs) CancelExecution(errormessage string) { 1155 startTime := time.Now() 1156 defer func() { 1157 elapsed := time.Since(startTime) 1158 f.iLog.PerformanceWithDuration("engine.funcs.CancelExecution", elapsed) 1159 }() 1160 /* defer func() { 1161 if err := recover(); err != nil { 1162 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.CancelExecution with error: %s", err)) 1163 return 1164 } 1165 }() 1166 */ 1167 f.iLog.Error(fmt.Sprintf("There is error during functoin %s execution: %s", f.Fobj.Name, errormessage)) 1168 f.DBTx.Rollback() 1169 f.CtxCancel() 1170 f.Ctx.Done() 1171 return 1172 } 1173 1174 // convertMap converts a map[string][]interface{} to a map[string]interface{}. 1175 // It iterates over the input map and assigns the first value of each key's slice 1176 // to the corresponding key in the output map. If a key's slice has more than one 1177 // value, the entire slice is assigned to the key in the output map. 1178 // The function also logs the performance duration and debug information. 1179 // It returns the converted map[string]interface{}. 1180 1181 func (f *Funcs) convertMap(m map[string][]interface{}) map[string]interface{} { 1182 /* startTime := time.Now() 1183 defer func() { 1184 elapsed := time.Since(startTime) 1185 f.iLog.PerformanceWithDuration("engine.funcs.convertMap", elapsed) 1186 }() 1187 defer func() { 1188 if err := recover(); err != nil { 1189 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.convertMap with error: %s", err)) 1190 return 1191 } 1192 }() 1193 */ 1194 f.iLog.Debug(fmt.Sprintf("Convert Map to Json Objects: %s", m)) 1195 1196 result := make(map[string]interface{}) 1197 for key, value := range m { 1198 var interfaceValue interface{} 1199 if len(value) == 1 { 1200 interfaceValue = value[0] 1201 } else { 1202 interfaceValue = value 1203 } 1204 result[key] = interfaceValue 1205 } 1206 1207 f.iLog.Debug(fmt.Sprintf("Convert Map to Json Objects result: %s", result)) 1208 return result 1209 } 1210 1211 // revertMap reverts a map[string]interface{} to a map[string][]interface{}. 1212 // It converts each value in the input map to an array, preserving the original key-value pairs. 1213 // If the value is already an array, it is preserved as is. Otherwise, it is converted to a single-element array. 1214 // The reverted map is returned as the result. 1215 func (f *Funcs) revertMap(m map[string]interface{}) map[string][]interface{} { 1216 /* startTime := time.Now() 1217 defer func() { 1218 elapsed := time.Since(startTime) 1219 f.iLog.PerformanceWithDuration("engine.funcs.revertMap", elapsed) 1220 }() 1221 defer func() { 1222 if err := recover(); err != nil { 1223 f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.revertMap with error: %s", err)) 1224 return 1225 } 1226 }() 1227 */ 1228 f.iLog.Debug(fmt.Sprintf("Revert Json Objects to array: %s", m)) 1229 reverted := make(map[string][]interface{}) 1230 1231 for k, v := range m { 1232 switch t := v.(type) { 1233 case []interface{}: 1234 reverted[k] = t 1235 default: 1236 reverted[k] = []interface{}{v} 1237 } 1238 } 1239 f.iLog.Debug(fmt.Sprintf("Revert Json Objects to array result: %s", reverted)) 1240 1241 return reverted 1242 }