444 lines
10 KiB
Go
444 lines
10 KiB
Go
/*
|
|
|--------------------------------------------------------------------------
|
|
| 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
|
|
}
|
|
}
|