package grouptasks import ( "encoding/json" "fmt" "janex/admin-dashboard-backend/modules/cache" "janex/admin-dashboard-backend/modules/database" "janex/admin-dashboard-backend/modules/structs" "janex/admin-dashboard-backend/modules/utils" "janex/admin-dashboard-backend/socketclients" "os" "os/exec" "time" "github.com/google/uuid" "github.com/rs/zerolog/log" ) var root = "./groupTasks/groups/" func ReadGroups() { entries, err := os.ReadDir(root) if err != nil { log.Error().Msg("Failed to read groups directory, error: " + err.Error()) return } for _, entry := range entries { log.Info().Msgf("Entry: %s", entry.Name()) files, err := os.ReadDir(root + entry.Name()) if err != nil { log.Error().Msg("Failed to read groups directory files, error: " + err.Error()) return } for _, file := range files { log.Info().Msgf("File: %s", file.Name()) if file.Name() == "index.json" { content, err := os.ReadFile(root + entry.Name() + "/index.json") if err != nil { log.Error().Msg("Failed to read file content, error: " + err.Error()) return } var group structs.Group json.Unmarshal(content, &group) group.Id = entry.Name() log.Info().Msgf("Group: %s", group) cache.AddCategoryGroup(group) } } } } const ( RunGroupTaskStartTypeNormal = 0 RunGroupTaskStartTypeTryAgain = 1 ) type RunGroupTaskArgs struct { StartType uint8 GroupTaskId string Category string GroupId string Step uint8 TaskStepId string GlobalInputs string Parameters string } type GlobalInputParameters struct { ParameterName string `json:"parameterName"` Value string `json:"value"` } func RunGroupTask(args RunGroupTaskArgs) { log.Debug().Msgf("global input: %v", args.GlobalInputs) categoryGroup := GetCategoryGroupTaskByCategoryAndGroupId(args.Category, args.GroupId) log.Debug().Msgf("RunGroupTask %s", categoryGroup) log.Debug().Msgf("script path %s", root+categoryGroup.Id+"/"+categoryGroup.Tasks[args.Step-1].ScriptPath) groupTaskStep := structs.GroupTaskSteps{ GroupTasksId: args.GroupTaskId, Step: args.Step, Status: structs.GroupTasksStatusRunning, StartedAt: time.Now(), } if args.StartType == RunGroupTaskStartTypeNormal { groupTaskStep.Id = uuid.New().String() database.DB.Create(&groupTaskStep) socketclients.BroadcastMessage(structs.SendSocketMessage{ Cmd: utils.SentCmdNewGroupTaskStep, Body: groupTaskStep, }) } else if args.StartType == RunGroupTaskStartTypeTryAgain { groupTaskStep.Id = args.TaskStepId updateGroupTaskSteps(groupTaskStep) /* database.DB.Model(&structs.GroupTaskSteps{}).Where("id = ?", groupTaskStep.Id).Updates(groupTaskStep) socketclients.BroadcastMessage(structs.SendSocketMessage{ Cmd: utils.SentCmdUpdateGroupTaskStep, Body: groupTaskStep, }) */ } // set group task to running dbGroupTask := updateGroupTask(groupTaskStep.GroupTasksId, structs.GroupTasks{ Status: structs.GroupTasksStatusRunning, }) /* database.DB.Model(&structs.GroupTasks{}).Where("id = ?", groupTaskStep.GroupTasksId).Updates(structs.GroupTasks{ Status: structs.GroupTasksStatusRunning, }) var dbGroupTask structs.GroupTasks database.DB.First(&dbGroupTask, "id = ?", groupTaskStep.GroupTasksId) socketclients.BroadcastMessage(structs.SendSocketMessage{ Cmd: utils.SentCmdUpdateGroupTask, Body: dbGroupTask, })*/ // check task parameters var globalInputParameters []GlobalInputParameters if len(args.GlobalInputs) > 0 { // global inputs given in args because the group task was just created log.Info().Msgf("global inputs given %s", args.GlobalInputs) if err := json.Unmarshal([]byte(args.GlobalInputs), &globalInputParameters); err != nil { log.Error().Msgf("err unmarshalling global inputs %s", err.Error()) } } else { // global inputs not given in args - fetch it from the database log.Info().Msgf("global inputs not given in args %s", dbGroupTask.GlobalInputs) if err := json.Unmarshal([]byte(dbGroupTask.GlobalInputs), &globalInputParameters); err != nil { log.Error().Msgf("err unmarshalling global inputs %s", err.Error()) } } log.Info().Msgf("unmarshalled global inputs %s", globalInputParameters) log.Info().Msgf("task parameters %s", categoryGroup.Tasks[args.Step-1].Parameters) if len(categoryGroup.Tasks[args.Step-1].Parameters) != 0 && len(args.Parameters) == 0 { log.Error().Msg("task parameters not specified") updateGroupTask(groupTaskStep.GroupTasksId, structs.GroupTasks{ Status: structs.GroupTasksStatusInputRequired, }) groupTaskStep.Status = structs.GroupTasksStatusInputRequired updateGroupTaskSteps(groupTaskStep) return } // execute script cmd, err := exec.Command("python3", root+categoryGroup.Id+"/"+categoryGroup.Tasks[args.Step-1].ScriptPath).Output() cmdLog := string(cmd) if err != nil { if exitErr, ok := err.(*exec.ExitError); ok { exitCode := exitErr.ExitCode() log.Error().Msgf("exit code %d", exitCode) cmdLog += fmt.Sprintf("\nExit code: %v", exitCode) } log.Error().Msgf("error exec command %s", err.Error()) groupTaskStep.Status = structs.GroupTasksStatusFailed } else { groupTaskStep.Status = structs.GroupTasksStatusFinished } fmt.Println(cmdLog) groupTaskStep.Log = cmdLog groupTaskStep.EndedAt = time.Now() updateGroupTaskSteps(groupTaskStep) /* database.DB.Model(&structs.GroupTaskSteps{}).Where("id = ?", groupTaskStep.Id).Updates(groupTaskStep) socketclients.BroadcastMessage(structs.SendSocketMessage{ Cmd: utils.SentCmdUpdateGroupTaskStep, Body: groupTaskStep, }) */ log.Info().Msgf("run next task") if int(args.Step) < len(categoryGroup.Tasks) { if groupTaskStep.Status == structs.GroupTasksStatusFailed { // set group task to failed /*database.DB.Model(&structs.GroupTasks{}).Where("id = ?", groupTaskStep.GroupTasksId).Updates(structs.GroupTasks{ Status: structs.GroupTasksStatusFailed, }) var dbGroupTask structs.GroupTasks database.DB.First(&dbGroupTask, "id = ?", groupTaskStep.GroupTasksId) socketclients.BroadcastMessage(structs.SendSocketMessage{ Cmd: utils.SentCmdUpdateGroupTask, Body: dbGroupTask, }) */ updateGroupTask(groupTaskStep.GroupTasksId, structs.GroupTasks{ Status: structs.GroupTasksStatusFailed, }) } else { args.StartType = RunGroupTaskStartTypeNormal args.Step = args.Step + 1 updateGroupTask(groupTaskStep.GroupTasksId, structs.GroupTasks{ CurrentTasksStep: args.Step, }) /*database.DB.Model(&structs.GroupTasks{}).Where("id = ?", groupTaskStep.GroupTasksId).Updates(structs.GroupTasks{ CurrentTasksStep: args.Step, }) var dbGroupTask structs.GroupTasks database.DB.First(&dbGroupTask, "id = ?", groupTaskStep.GroupTasksId) socketclients.BroadcastMessage(structs.SendSocketMessage{ Cmd: utils.SentCmdUpdateGroupTask, Body: dbGroupTask, })*/ log.Debug().Msgf("RUN NEXT TASK %s", groupTaskStep) RunGroupTask(args) } } else { // set group task to finished updateGroupTask(groupTaskStep.GroupTasksId, structs.GroupTasks{ Status: structs.GroupTasksStatusFinished, EndedAt: time.Now(), }) /* database.DB.Model(&structs.GroupTasks{}).Where("id = ?", groupTaskStep.GroupTasksId).Updates(structs.GroupTasks{ Status: structs.GroupTasksStatusFinished, EndedAt: time.Now(), }) var dbGroupTask structs.GroupTasks database.DB.First(&dbGroupTask, "id = ?", groupTaskStep.GroupTasksId) socketclients.BroadcastMessage(structs.SendSocketMessage{ Cmd: utils.SentCmdUpdateGroupTask, Body: dbGroupTask, })*/ log.Info().Msg("SET TO FINISHED") } } // Updates group task and send it to websocket users func updateGroupTask(groupTasksId string, updates structs.GroupTasks) structs.GroupTasks { database.DB.Model(&structs.GroupTasks{}).Where("id = ?", groupTasksId).Updates(updates) var dbGroupTask structs.GroupTasks database.DB.First(&dbGroupTask, "id = ?", groupTasksId) socketclients.BroadcastMessage(structs.SendSocketMessage{ Cmd: utils.SentCmdUpdateGroupTask, Body: dbGroupTask, }) return dbGroupTask } // Updates group task steps and send it to websocket users func updateGroupTaskSteps(groupTaskStep structs.GroupTaskSteps) { database.DB.Model(&structs.GroupTaskSteps{}).Where("id = ?", groupTaskStep.Id).Updates(groupTaskStep) socketclients.BroadcastMessage(structs.SendSocketMessage{ Cmd: utils.SentCmdUpdateGroupTaskStep, Body: groupTaskStep, }) } func GetAllGroupTasks() []structs.GroupTasks { var groupTasks []structs.GroupTasks database.DB.Find(&groupTasks) return groupTasks } func GetAllGroupTasksSteps() []structs.GroupTaskSteps { var groupTaskStepsLogs []structs.GroupTaskSteps database.DB.Find(&groupTaskStepsLogs) return groupTaskStepsLogs } func GetCategoryGroupTaskByCategoryAndGroupId(category string, groupId string) structs.Group { for _, categoryGroup := range cache.GetCategoryGroups() { if categoryGroup.Category == category { for _, group := range categoryGroup.Groups { if group.Id == groupId { return group } } } } return structs.Group{} }