/* |-------------------------------------------------------------------------- | Manifest |-------------------------------------------------------------------------- | | Name: | - Progress | | Purpose: | - Manage, monitor, and report task progress through standardized | lifecycle-aware progress tracking. | | Guideline: | - Use countable progress when current and target values are available. | - Use uncountable progress when only activity status is available. | - Always provide a valid lifecycle state. | - Use standardized response structures for all executions. | | Example: | - ObrimProgress("countable", map[string]any{ | "state":"running", | "current":25, | "target":100, | }) | | - ObrimProgress("uncountable", map[string]any{ | "state":"running", | "placeholder":"Synchronizing resources", | }) | |-------------------------------------------------------------------------- */ /* |-------------------------------------------------------------------------- | Credit |-------------------------------------------------------------------------- | | Contributor: | - Rajon Ahmed | - Scionite | |-------------------------------------------------------------------------- */ package progress import ( "fmt" "math" "strings" "sync" "go/module/essential/visible/service/helper/log" "go/module/essential/visible/service/helper/status" ) const ( obrimProgressTypeCountable = "countable" obrimProgressTypeUncountable = "uncountable" obrimProgressStateStarted = "started" obrimProgressStateRunning = "running" obrimProgressStateCompleted = "completed" obrimProgressStateCanceled = "canceled" obrimProgressVisualWidth = 20 ) var ( // obrimProgressStateMutex protects lifecycle transitions. obrimProgressStateMutex sync.Mutex ) // ObrimProgress manages lifecycle-aware countable and uncountable progress tracking operations. func ObrimProgress(progressType string, config map[string]any) map[string]any { obrimProgressStateMutex.Lock() defer obrimProgressStateMutex.Unlock() if !obrimProgressValidate(progressType, config) { return obrimProgressBuildResponse( false, "FAILED_PROGRESS_MISCONFIGURED", nil, ) } // lifecycleState stores validated lifecycle state. lifecycleState := strings.ToLower(fmt.Sprintf("%v", config["state"])) if !obrimProgressHandleState(lifecycleState) { return obrimProgressBuildResponse( false, "FAILED_PROGRESS_MISCONFIGURED", nil, ) } switch progressType { case obrimProgressTypeCountable: return obrimProgressCountable(config) case obrimProgressTypeUncountable: return obrimProgressUncountable(config) default: return obrimProgressBuildResponse( false, "FAILED_PROGRESS_MISCONFIGURED", nil, ) } } // obrimProgressValidate validates input parameters and configuration consistency. func obrimProgressValidate(progressType string, config map[string]any) bool { if strings.TrimSpace(progressType) == "" { log.ObrimLog("ERROR", "Progress type is missing.") status.ObrimStatus("ERROR", "Progress type is required.") return false } if config == nil { log.ObrimLog("ERROR", "Progress configuration is missing.") status.ObrimStatus("ERROR", "Progress configuration is required.") return false } // lifecycleState stores lifecycle state. lifecycleState := strings.ToLower(fmt.Sprintf("%v", config["state"])) switch lifecycleState { case obrimProgressStateStarted, obrimProgressStateRunning, obrimProgressStateCompleted, obrimProgressStateCanceled: default: log.ObrimLog("ERROR", "Invalid progress lifecycle state.") status.ObrimStatus("ERROR", "Invalid progress lifecycle state.") return false } switch progressType { case obrimProgressTypeCountable: _, currentExists := config["current"] _, targetExists := config["target"] if !currentExists || !targetExists { return false } // targetValue stores target progress value. targetValue, ok := obrimProgressConvertToInt(config["target"]) if !ok || targetValue <= 0 { return false } case obrimProgressTypeUncountable: placeholder, ok := config["placeholder"].(string) if !ok || strings.TrimSpace(placeholder) == "" { return false } default: return false } return true } // obrimProgressHandleState processes lifecycle state transitions. func obrimProgressHandleState(state string) bool { switch state { case obrimProgressStateStarted: log.ObrimLog("INIT", "Progress tracking started.") status.ObrimStatus("INFO", "Progress started.") return true case obrimProgressStateRunning: log.ObrimLog("PROGRESS", "Progress tracking updated.") status.ObrimStatus("INFO", "Progress running.") return true case obrimProgressStateCompleted: log.ObrimLog("SUCCESS", "Progress tracking completed.") status.ObrimStatus("SUCCESS", "Progress completed.") return true case obrimProgressStateCanceled: log.ObrimLog("WARNING", "Progress tracking canceled.") status.ObrimStatus("WARNING", "Progress canceled.") return true } return false } // obrimProgressCountable processes countable progress tracking workflows. func obrimProgressCountable(config map[string]any) map[string]any { // lifecycleState stores lifecycle state. lifecycleState := strings.ToLower(fmt.Sprintf("%v", config["state"])) // currentValue stores current progress value. currentValue, _ := obrimProgressConvertToInt(config["current"]) // targetValue stores target progress value. targetValue, _ := obrimProgressConvertToInt(config["target"]) // percentage stores normalized completion percentage. percentage := obrimProgressCalculatePercentage( currentValue, targetValue, ) // progressMessage stores human readable progress message. progressMessage := obrimProgressGenerateMessage( obrimProgressTypeCountable, lifecycleState, percentage, "", ) // progressVisual stores visual progress representation. progressVisual := obrimProgressGenerateVisual( obrimProgressTypeCountable, percentage, "", ) payload := map[string]any{ "state": lifecycleState, "current": currentValue, "target": targetValue, "percentage": percentage, "message": progressMessage, "visual": progressVisual, } return obrimProgressBuildResponse( true, "SUCCESS_PROGRESS_TRACKED", payload, ) } // obrimProgressCalculatePercentage calculates and normalizes completion percentages. func obrimProgressCalculatePercentage(current int, target int) int { if target <= 0 { return 0 } if current < 0 { return 0 } percentage := int( math.Round( (float64(current) / float64(target)) * 100, ), ) if percentage > 100 { return 100 } if percentage < 0 { return 0 } return percentage } // obrimProgressUncountable processes uncountable progress tracking workflows. func obrimProgressUncountable(config map[string]any) map[string]any { // lifecycleState stores lifecycle state. lifecycleState := strings.ToLower(fmt.Sprintf("%v", config["state"])) // placeholder stores resolved placeholder text. placeholder := obrimProgressResolvePlaceholder(config) // progressMessage stores human readable progress message. progressMessage := obrimProgressGenerateMessage( obrimProgressTypeUncountable, lifecycleState, 0, placeholder, ) // progressVisual stores visual progress representation. progressVisual := obrimProgressGenerateVisual( obrimProgressTypeUncountable, 0, placeholder, ) payload := map[string]any{ "state": lifecycleState, "placeholder": placeholder, "message": progressMessage, "visual": progressVisual, } return obrimProgressBuildResponse( true, "SUCCESS_PROGRESS_TRACKED", payload, ) } // obrimProgressResolvePlaceholder validates and prepares placeholder activity messages. func obrimProgressResolvePlaceholder(config map[string]any) string { placeholder, ok := config["placeholder"].(string) if !ok { return "" } return strings.TrimSpace(placeholder) } // obrimProgressGenerateMessage generates human-readable progress messages. func obrimProgressGenerateMessage( progressType string, state string, percentage int, placeholder string, ) string { if progressType == obrimProgressTypeCountable { switch state { case obrimProgressStateStarted: return fmt.Sprintf("Progress started (%d%%).", percentage) case obrimProgressStateRunning: return fmt.Sprintf("Progress running (%d%% complete).", percentage) case obrimProgressStateCompleted: return "Progress completed successfully." case obrimProgressStateCanceled: return "Progress canceled." } } switch state { case obrimProgressStateStarted: return fmt.Sprintf("Activity started: %s.", placeholder) case obrimProgressStateRunning: return fmt.Sprintf("Activity running: %s.", placeholder) case obrimProgressStateCompleted: return fmt.Sprintf("Activity completed: %s.", placeholder) case obrimProgressStateCanceled: return fmt.Sprintf("Activity canceled: %s.", placeholder) } return "" } // obrimProgressGenerateVisual generates CLI-friendly visual progress representations. func obrimProgressGenerateVisual( progressType string, percentage int, placeholder string, ) string { if progressType == obrimProgressTypeCountable { filled := int( math.Round( (float64(percentage) / 100) * obrimProgressVisualWidth, ), ) if filled > obrimProgressVisualWidth { filled = obrimProgressVisualWidth } if filled < 0 { filled = 0 } return fmt.Sprintf( "[%s%s] %d%%", strings.Repeat("#", filled), strings.Repeat("-", obrimProgressVisualWidth-filled), percentage, ) } return fmt.Sprintf("[~] %s", placeholder) } // obrimProgressBuildResponse constructs standardized utility response payloads. func obrimProgressBuildResponse( success bool, code string, payload map[string]any, ) map[string]any { if !success { return map[string]any{ "status": false, "code": code, "payload": nil, } } return map[string]any{ "status": true, "code": code, "payload": payload, } } // obrimProgressConvertToInt safely converts supported numeric values to int. func obrimProgressConvertToInt(value any) (int, bool) { switch v := value.(type) { case int: return v, true case int8: return int(v), true case int16: return int(v), true case int32: return int(v), true case int64: return int(v), true case uint: return int(v), true case uint8: return int(v), true case uint16: return int(v), true case uint32: return int(v), true case uint64: return int(v), true case float32: return int(v), true case float64: return int(v), true default: return 0, false } }