/* |-------------------------------------------------------------------------- | Description |-------------------------------------------------------------------------- | | Name: | - Progress | | Purpose: | - Manage, monitor, and report lifecycle-aware task progress through | standardized progress tracking for countable and uncountable workflows. | |-------------------------------------------------------------------------- */ /* |-------------------------------------------------------------------------- | Instruction |-------------------------------------------------------------------------- | | Guideline: | - Use countable progress when tracking numeric progress using current | and target values. | - Use uncountable progress when tracking activity-based progress | without percentage calculation. | - Provide the lifecycle state through the state configuration value. | - Provide current and target values when using countable progress. | | Example: | - ObrimProgress("countable", map[string]any{ | "state": "running", | "current": 50, | "target": 100, | }) | | - ObrimProgress("uncountable", map[string]any{ | "state": "running", | }) | |-------------------------------------------------------------------------- */ /* |-------------------------------------------------------------------------- | Credit |-------------------------------------------------------------------------- | | Contributor: | - Rajon Ahmed | - Blockonite | |-------------------------------------------------------------------------- */ package progress import ( "math" ) const ( obrimProgressTypeCountable = "countable" obrimProgressTypeUncountable = "uncountable" obrimProgressStateStarted = "started" obrimProgressStateRunning = "running" obrimProgressStateCompleted = "completed" obrimProgressStateCanceled = "canceled" obrimProgressSuccessStarted = "SUCCESS_STARTED" obrimProgressSuccessRunning = "SUCCESS_RUNNING" obrimProgressSuccessCompleted = "SUCCESS_COMPLETED" obrimProgressSuccessCanceled = "SUCCESS_CANCELED" obrimProgressFailureInvalidType = "FAILURE_INVALID_TYPE" obrimProgressFailureMissingState = "FAILURE_MISSING_STATE" obrimProgressFailureInvalidState = "FAILURE_INVALID_STATE" obrimProgressFailureMissingCurrent = "FAILURE_MISSING_CURRENT" obrimProgressFailureInvalidCurrent = "FAILURE_INVALID_CURRENT" obrimProgressFailureMissingTarget = "FAILURE_MISSING_TARGET" obrimProgressFailureInvalidTarget = "FAILURE_INVALID_TARGET" obrimProgressFailureNonPositiveTarget = "FAILURE_NON_POSITIVE_TARGET" ) type obrimProgressPayload struct { Type string State string Current any Target any Percentage any } type obrimProgressOutput struct { Status bool Code string Payload any } // ObrimProgress manages lifecycle-aware countable and uncountable progress. func ObrimProgress(progressType string, config map[string]any) map[string]any { if code := obrimProgressValidateInput(progressType, config); code != "" { return obrimProgressBuildOutput(false, code, nil) } return obrimProgressRouteRequest(progressType, config) } // obrimProgressValidateInput validates the requested progress type and configuration. func obrimProgressValidateInput(progressType string, config map[string]any) string { switch progressType { case obrimProgressTypeCountable: state, exists := config["state"] if !exists { return obrimProgressFailureMissingState } stateValue, ok := state.(string) if !ok { return obrimProgressFailureInvalidState } switch stateValue { case obrimProgressStateStarted, obrimProgressStateRunning, obrimProgressStateCompleted, obrimProgressStateCanceled: default: return obrimProgressFailureInvalidState } if _, exists := config["current"]; !exists { return obrimProgressFailureMissingCurrent } switch config["current"].(type) { case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64: default: return obrimProgressFailureInvalidCurrent } if _, exists := config["target"]; !exists { return obrimProgressFailureMissingTarget } switch config["target"].(type) { case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64: default: return obrimProgressFailureInvalidTarget } target := 0.0 switch value := config["target"].(type) { case int: target = float64(value) case int8: target = float64(value) case int16: target = float64(value) case int32: target = float64(value) case int64: target = float64(value) case uint: target = float64(value) case uint8: target = float64(value) case uint16: target = float64(value) case uint32: target = float64(value) case uint64: target = float64(value) case float32: target = float64(value) case float64: target = value } if target <= 0 { return obrimProgressFailureNonPositiveTarget } case obrimProgressTypeUncountable: state, exists := config["state"] if !exists { return obrimProgressFailureMissingState } stateValue, ok := state.(string) if !ok { return obrimProgressFailureInvalidState } switch stateValue { case obrimProgressStateStarted, obrimProgressStateRunning, obrimProgressStateCompleted, obrimProgressStateCanceled: default: return obrimProgressFailureInvalidState } default: return obrimProgressFailureInvalidType } return "" } // obrimProgressRouteRequest routes progress processing to its type-specific entry function. func obrimProgressRouteRequest(progressType string, config map[string]any) map[string]any { switch progressType { case obrimProgressTypeCountable: return obrimProgressCountable(config) case obrimProgressTypeUncountable: return obrimProgressUncountable(config) default: return obrimProgressBuildOutput(false, obrimProgressFailureInvalidType, nil) } } // obrimProgressBuildOutput builds the standardized progress utility output. func obrimProgressBuildOutput(status bool, code string, payload *obrimProgressPayload) map[string]any { output := map[string]any{ "status": status, "code": code, "payload": nil, } if payload == nil { return output } output["payload"] = map[string]any{ "type": payload.Type, "state": payload.State, "current": payload.Current, "target": payload.Target, "percentage": payload.Percentage, } return output } // obrimProgressCountable processes countable progress workflows. func obrimProgressCountable(config map[string]any) map[string]any { state := config["state"].(string) var current float64 var target float64 switch value := config["current"].(type) { case int: current = float64(value) case int8: current = float64(value) case int16: current = float64(value) case int32: current = float64(value) case int64: current = float64(value) case uint: current = float64(value) case uint8: current = float64(value) case uint16: current = float64(value) case uint32: current = float64(value) case uint64: current = float64(value) case float32: current = float64(value) case float64: current = value } switch value := config["target"].(type) { case int: target = float64(value) case int8: target = float64(value) case int16: target = float64(value) case int32: target = float64(value) case int64: target = float64(value) case uint: target = float64(value) case uint8: target = float64(value) case uint16: target = float64(value) case uint32: target = float64(value) case uint64: target = float64(value) case float32: target = float64(value) case float64: target = value } percentage := int(math.Round((current / target) * 100)) if percentage < 0 { percentage = 0 } if percentage > 100 { percentage = 100 } code := obrimProgressSuccessRunning switch state { case obrimProgressStateStarted: code = obrimProgressSuccessStarted case obrimProgressStateRunning: code = obrimProgressSuccessRunning case obrimProgressStateCompleted: code = obrimProgressSuccessCompleted case obrimProgressStateCanceled: code = obrimProgressSuccessCanceled } return obrimProgressBuildOutput( true, code, &obrimProgressPayload{ Type: obrimProgressTypeCountable, State: state, Current: current, Target: target, Percentage: percentage, }, ) } // obrimProgressUncountable processes uncountable progress workflows. func obrimProgressUncountable(config map[string]any) map[string]any { state := config["state"].(string) code := obrimProgressSuccessRunning switch state { case obrimProgressStateStarted: code = obrimProgressSuccessStarted case obrimProgressStateRunning: code = obrimProgressSuccessRunning case obrimProgressStateCompleted: code = obrimProgressSuccessCompleted case obrimProgressStateCanceled: code = obrimProgressSuccessCanceled } return obrimProgressBuildOutput( true, code, &obrimProgressPayload{ Type: obrimProgressTypeUncountable, State: state, Current: nil, Target: nil, Percentage: nil, }, ) }