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

     1  package funcgroup
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"reflect"
     7  	"strings"
     8  	"time"
     9  
    10  	"database/sql"
    11  
    12  	"github.com/mdaxf/iac/documents"
    13  	tcom "github.com/mdaxf/iac/engine/com"
    14  	funcs "github.com/mdaxf/iac/engine/function"
    15  	"github.com/mdaxf/iac/engine/types"
    16  	"github.com/mdaxf/iac/logger"
    17  	"github.com/mdaxf/iac-signalr/signalr"
    18  )
    19  
    20  type FGroup struct {
    21  	FGobj               types.FuncGroup
    22  	DBTx                *sql.Tx
    23  	Ctx                 context.Context
    24  	CtxCancel           context.CancelFunc
    25  	Nextfuncgroup       string
    26  	SystemSession       map[string]interface{} // {sessionanme: value}
    27  	UserSession         map[string]interface{} // {sessionanme: value}
    28  	Externalinputs      map[string]interface{} // {sessionanme: value}
    29  	Externaloutputs     map[string]interface{} // {sessionanme: value}
    30  	funcCachedVariables map[string]interface{}
    31  	iLog                logger.Log
    32  	DocDBCon            *documents.DocDB
    33  	SignalRClient       signalr.Client
    34  	ErrorMessage        string
    35  	TestwithSc          bool
    36  	TestResults         map[string]interface{}
    37  }
    38  
    39  // NewFGroup creates a new instance of FGroup.
    40  // It takes various parameters including DocDBCon, SignalRClient, dbTx, fgobj, nextfuncgroup, systemSession, userSession, externalinputs, externaloutputs, ctx, and ctxcancel.
    41  // It initializes the FGroup struct with the provided values and returns a pointer to the newly created FGroup instance.
    42  
    43  func NewFGroup(DocDBCon *documents.DocDB, SignalRClient signalr.Client, dbTx *sql.Tx, fgobj types.FuncGroup, nextfuncgroup string, systemSession, userSession, externalinputs, externaloutputs map[string]interface{}, ctx context.Context, ctxcancel context.CancelFunc) *FGroup {
    44  	log := logger.Log{}
    45  	log.ModuleName = logger.TranCode
    46  	log.ControllerName = "Function Group"
    47  	if systemSession["UserNo"] != nil {
    48  		log.User = systemSession["UserNo"].(string)
    49  	} else {
    50  		log.User = "System"
    51  	}
    52  	startTime := time.Now()
    53  	defer func() {
    54  		elapsed := time.Since(startTime)
    55  		log.PerformanceWithDuration("engine.funcgroup.NewFGroup", elapsed)
    56  	}()
    57  	/*
    58  		defer func() {
    59  			if err := recover(); err != nil {
    60  				log.Error(fmt.Sprintf("There is error to engine.funcgroup.NewFGroup with error: %s", err))
    61  				return
    62  			}
    63  		}()
    64  	*/
    65  	return &FGroup{
    66  		FGobj:               fgobj,
    67  		DBTx:                dbTx,
    68  		Ctx:                 ctx,
    69  		CtxCancel:           ctxcancel,
    70  		Nextfuncgroup:       nextfuncgroup,
    71  		SystemSession:       systemSession,
    72  		UserSession:         userSession,
    73  		Externalinputs:      externalinputs,
    74  		Externaloutputs:     externaloutputs,
    75  		funcCachedVariables: map[string]interface{}{},
    76  		iLog:                log,
    77  		DocDBCon:            DocDBCon,
    78  		SignalRClient:       SignalRClient,
    79  		ErrorMessage:        "",
    80  		TestwithSc:          false,
    81  		TestResults:         map[string]interface{}{},
    82  	}
    83  
    84  }
    85  
    86  // Execute executes the function group by iterating over its functions and executing each one.
    87  // It also handles error recovery and logs performance metrics.
    88  // It takes no parameters and returns no values.
    89  func (c *FGroup) Execute() {
    90  	startTime := time.Now()
    91  	defer func() {
    92  		elapsed := time.Since(startTime)
    93  		c.iLog.PerformanceWithDuration("engine.funcgroup.Execute", elapsed)
    94  	}()
    95  
    96  	defer func() {
    97  		if r := recover(); r != nil {
    98  
    99  			c.iLog.Error(fmt.Sprintf("Panic: %s", r))
   100  			c.ErrorMessage = fmt.Sprintf("Panic: %s", r)
   101  			c.DBTx.Rollback()
   102  			c.CtxCancel()
   103  			if c.TestwithSc {
   104  				tcom.SendTestResultMessageBus("", c.FGobj.ID, "", "End", "",
   105  					c.Externalinputs, c.Externaloutputs, c.SystemSession, c.UserSession, fmt.Errorf(c.ErrorMessage), c.SystemSession["ClientID"].(string), c.SystemSession["UserNo"].(string))
   106  			}
   107  			return
   108  		}
   109  	}()
   110  
   111  	c.iLog.Info(fmt.Sprintf("Start process function group %s's %s ", c.FGobj.Name, reflect.ValueOf(c.Execute).Kind().String()))
   112  	c.iLog.Debug(fmt.Sprintf("systemSession: %s", logger.ConvertJson(c.SystemSession)))
   113  	c.iLog.Debug(fmt.Sprintf("userSession: %s", logger.ConvertJson(c.UserSession)))
   114  	c.iLog.Debug(fmt.Sprintf("externalinputs: %s", logger.ConvertJson(c.Externalinputs)))
   115  	c.iLog.Debug(fmt.Sprintf("externaloutputs: %s", logger.ConvertJson(c.Externaloutputs)))
   116  
   117  	systemSession := c.SystemSession
   118  	userSession := c.UserSession
   119  	funcCachedVariables := map[string]interface{}{}
   120  	externalinputs := c.Externalinputs
   121  	externaloutputs := c.Externaloutputs
   122  
   123  	if c.TestwithSc {
   124  
   125  		c.TestResults["Name"] = c.FGobj.Name
   126  		c.TestResults["Type"] = "FunctionGroup"
   127  		c.TestResults["Inputs"] = c.Externalinputs
   128  		c.TestResults["Outputs"] = c.Externaloutputs
   129  		c.TestResults["UserSession"] = c.UserSession
   130  		c.TestResults["SystemSession"] = systemSession
   131  		c.TestResults["StartTime"] = time.Now()
   132  		c.TestResults["Functions"] = []map[string]interface{}{}
   133  
   134  		tcom.SendTestResultMessageBus("", c.FGobj.ID, "", "Start", "",
   135  			externalinputs, externaloutputs, systemSession, userSession, nil, c.SystemSession["ClientID"].(string), c.SystemSession["UserNo"].(string))
   136  	}
   137  
   138  	for _, fobj := range c.FGobj.Functions {
   139  		//	f := *(funcs.NewFuncs(fobj, systemSession, userSession, externalinputs, externaloutputs, funcCachedVariables))
   140  		c.iLog.Info(fmt.Sprintf("Start process function %s", fobj.Name))
   141  		c.iLog.Debug(fmt.Sprintf("systemSession: %s", logger.ConvertJson(systemSession)))
   142  		c.iLog.Debug(fmt.Sprintf("funcCachedVariables: %s", logger.ConvertJson(c.funcCachedVariables)))
   143  		c.iLog.Debug(fmt.Sprintf("userSession: %s", logger.ConvertJson(userSession)))
   144  		c.iLog.Debug(fmt.Sprintf("externalinputs: %s", logger.ConvertJson(externalinputs)))
   145  		c.iLog.Debug(fmt.Sprintf("externaloutputs: %s", logger.ConvertJson(externaloutputs)))
   146  
   147  		f := &funcs.Funcs{
   148  			Fobj:                fobj,
   149  			Ctx:                 c.Ctx,
   150  			CtxCancel:           c.CtxCancel,
   151  			DBTx:                c.DBTx,
   152  			DocDBCon:            c.DocDBCon,
   153  			SignalRClient:       c.SignalRClient,
   154  			SystemSession:       systemSession,
   155  			UserSession:         userSession,
   156  			Externalinputs:      externalinputs,
   157  			Externaloutputs:     externaloutputs,
   158  			FuncCachedVariables: funcCachedVariables,
   159  			ErrorMessage:        "",
   160  			TestwithSc:          c.TestwithSc,
   161  			TestResults:         make([]map[string]interface{}, 0),
   162  		}
   163  
   164  		f.Execute()
   165  
   166  		if c.TestwithSc {
   167  			funcTestResults := c.TestResults["Functions"].([]map[string]interface{})
   168  
   169  			for _, ft := range f.TestResults {
   170  				funcTestResults = append(funcTestResults, ft)
   171  			}
   172  
   173  			c.TestResults["Functions"] = funcTestResults
   174  
   175  			tcom.SendTestResultMessageBus("", c.FGobj.ID, fobj.ID, "End", "",
   176  				f.Externalinputs, f.Externaloutputs, f.SystemSession, f.UserSession, fmt.Errorf(f.ErrorMessage), c.SystemSession["ClientID"].(string), c.SystemSession["UserNo"].(string))
   177  		}
   178  
   179  		if f.ErrorMessage != "" {
   180  			c.ErrorMessage = f.ErrorMessage
   181  			c.iLog.Error(fmt.Sprintf("Error: %s", c.ErrorMessage))
   182  			c.CtxCancel()
   183  			return
   184  		}
   185  
   186  		c.iLog.Info(fmt.Sprintf("End process function %s", fobj.Name))
   187  		//c.iLog.Debug(fmt.Sprintf("systemSession: %s", logger.ConvertJson(systemSession)))
   188  		c.iLog.Debug(fmt.Sprintf("funcCachedVariables: %s", logger.ConvertJson(funcCachedVariables)))
   189  		c.iLog.Debug(fmt.Sprintf("userSession: %s", logger.ConvertJson(userSession)))
   190  		c.iLog.Debug(fmt.Sprintf("externalinputs: %s", logger.ConvertJson(externalinputs)))
   191  		c.iLog.Debug(fmt.Sprintf("externaloutputs: %s", logger.ConvertJson(externaloutputs)))
   192  
   193  		userSession = f.UserSession
   194  		funcCachedVariables = f.FuncCachedVariables
   195  		externalinputs = f.Externalinputs
   196  		externaloutputs = f.Externaloutputs
   197  	}
   198  	c.UserSession = userSession
   199  	c.Externalinputs = externalinputs
   200  	c.Externaloutputs = externaloutputs
   201  	c.funcCachedVariables = funcCachedVariables
   202  	c.Nextfuncgroup = c.CheckRouter(c.FGobj.RouterDef)
   203  
   204  	if c.TestwithSc {
   205  		c.TestResults["EndTime"] = time.Now()
   206  		c.TestResults["Outputs"] = c.Externaloutputs
   207  		c.TestResults["Error"] = c.ErrorMessage
   208  		tcom.SendTestResultMessageBus("", c.FGobj.ID, "", "End", "",
   209  			externalinputs, externaloutputs, systemSession, userSession, nil, c.SystemSession["ClientID"].(string), c.SystemSession["UserNo"].(string))
   210  
   211  	}
   212  	c.iLog.Info(fmt.Sprintf("End process function group %s's %s ", c.FGobj.Name, reflect.ValueOf(c.Execute).Kind().String()))
   213  	c.iLog.Debug(fmt.Sprintf("systemSession: %s", logger.ConvertJson(c.SystemSession)))
   214  	c.iLog.Debug(fmt.Sprintf("funcCachedVariables: %s", logger.ConvertJson(c.funcCachedVariables)))
   215  	c.iLog.Debug(fmt.Sprintf("userSession: %s", logger.ConvertJson(c.UserSession)))
   216  	c.iLog.Debug(fmt.Sprintf("externalinputs: %s", logger.ConvertJson(c.Externalinputs)))
   217  	c.iLog.Debug(fmt.Sprintf("externaloutputs: %s", logger.ConvertJson(c.Externaloutputs)))
   218  	c.iLog.Debug(fmt.Sprintf("nextfuncgroup: %s", c.Nextfuncgroup))
   219  
   220  }
   221  
   222  // CheckRouter checks the router definition and determines the next function group to execute based on the provided RouterDef.
   223  // It returns the name of the next function group.
   224  func (c *FGroup) CheckRouter(RouterDef types.RouterDef) string {
   225  	startTime := time.Now()
   226  	defer func() {
   227  		elapsed := time.Since(startTime)
   228  		c.iLog.PerformanceWithDuration("engine.funcgroup.CheckRouter", elapsed)
   229  	}()
   230  
   231  	c.iLog.Info(fmt.Sprintf("Start process function group %s's %s ", c.FGobj.Name, reflect.ValueOf(c.CheckRouter).Kind().String()))
   232  	c.iLog.Debug(fmt.Sprintf("RouterDef: %s", logger.ConvertJson(RouterDef)))
   233  
   234  	variable := RouterDef.Variable
   235  	vartype := RouterDef.Vartype
   236  	values := RouterDef.Values
   237  	nextfuncgroups := RouterDef.Nextfuncgroups
   238  	defaultfuncgroup := RouterDef.Defaultfuncgroup
   239  
   240  	c.iLog.Debug(fmt.Sprintf("variable: %s, vartype: %s, values: %s, nextfg:%s, defaultfg:%s", variable, vartype, logger.ConvertJson(values), logger.ConvertJson(nextfuncgroups), defaultfuncgroup))
   241  	switch vartype {
   242  	case "systemSession":
   243  		c.iLog.Debug("start systemSession:")
   244  		if c.SystemSession[variable] != nil {
   245  			for i, value := range values {
   246  				if c.SystemSession[variable] == value {
   247  					c.iLog.Info(fmt.Sprintf("End process function group %s's %s 's Next func group: %s", c.FGobj.Name, reflect.ValueOf(c.CheckRouter).Kind().String(), nextfuncgroups[i]))
   248  					return nextfuncgroups[i]
   249  				}
   250  			}
   251  		}
   252  	case "userSession":
   253  		c.iLog.Debug("start userSession:")
   254  		if c.UserSession[variable] != nil {
   255  			for i, value := range values {
   256  				if c.UserSession[variable] == value {
   257  					c.iLog.Info(fmt.Sprintf("End process function group %s's %s 's Next func group: %s", c.FGobj.Name, reflect.ValueOf(c.CheckRouter).Kind().String(), nextfuncgroups[i]))
   258  					return nextfuncgroups[i]
   259  				}
   260  			}
   261  		}
   262  	/*case "":
   263  	case "funcCachedVariables": */
   264  	default:
   265  		c.iLog.Debug("start default:")
   266  		arr := strings.Split(variable, ".")
   267  		c.iLog.Debug(fmt.Sprintf("variable: %s arr: %s", variable, logger.ConvertJson(arr)))
   268  		if len(arr) == 2 {
   269  			c.iLog.Debug(fmt.Sprintf("function variables: %s", logger.ConvertJson(c.funcCachedVariables)))
   270  			if c.funcCachedVariables[arr[0]] != nil {
   271  				tempobj := c.funcCachedVariables[arr[0]].(map[string]interface{})
   272  				c.iLog.Debug(fmt.Sprintf("function variables: %s", logger.ConvertJson(tempobj)))
   273  				if tempobj[arr[1]] != nil {
   274  					c.iLog.Debug(fmt.Sprintf("function %s variable %s value: %s", arr[0], arr[1], logger.ConvertJson(tempobj[arr[1]])))
   275  					for i, value := range values {
   276  						if tempobj[arr[1]] == value {
   277  							c.iLog.Info(fmt.Sprintf("End process function group %s's %s 's Next func group: %s", c.FGobj.Name, reflect.ValueOf(c.CheckRouter).Kind().String(), nextfuncgroups[i]))
   278  							return nextfuncgroups[i]
   279  						}
   280  					}
   281  				}
   282  			}
   283  		}
   284  	}
   285  
   286  	c.iLog.Info(fmt.Sprintf("End process function group %s's %s 's Next func group: %s", c.FGobj.Name, reflect.ValueOf(c.CheckRouter).Kind().String(), defaultfuncgroup))
   287  
   288  	return defaultfuncgroup
   289  }