Compare commits
No commits in common. "51ad54c48eb7f9f6ba1185bb0da08a16651acc23" and "747d848a7bbf15c40ac665644d7af42be8949d0d" have entirely different histories.
51ad54c48e
...
747d848a7b
@ -1,344 +0,0 @@
|
|||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Description
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Name:
|
|
||||||
| - Datetime
|
|
||||||
|
|
|
||||||
| Purpose:
|
|
||||||
| - Retrieve the current date and time from the host system clock or
|
|
||||||
| trusted clock state and return the formatted result using a supported
|
|
||||||
| framework date/time pattern.
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Instruction
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Guideline:
|
|
||||||
| - Use local to retrieve the current date and time while preserving the
|
|
||||||
| host system timezone.
|
|
||||||
| - Use cloud to retrieve the current trusted UTC date and time using the
|
|
||||||
| resolved clock state.
|
|
||||||
| - Provide the format configuration when a specific supported date/time
|
|
||||||
| representation is required.
|
|
||||||
| - Use the utility through ObrimDatetime(type string, config map[string]any).
|
|
||||||
|
|
|
||||||
| Example:
|
|
||||||
| - ObrimDatetime("local", map[string]any{
|
|
||||||
| "format": "yyyy-MM-dd",
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
| - ObrimDatetime("local", map[string]any{
|
|
||||||
| "format": "HH:mm:ss",
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
| - ObrimDatetime("cloud", map[string]any{
|
|
||||||
| "format": "yyyy-MM-dd HH:mm:ss z",
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
| - ObrimDatetime("cloud", map[string]any{
|
|
||||||
| "format": "yyyy-MM-dd'T'HH:mm:ssXXX",
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Credit
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Contributor:
|
|
||||||
| - Rajon Ahmed
|
|
||||||
| - Blockonite
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
package datetime
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"go/module/essential/hidden/service/worker/clock"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Reusable datetime input and result constants.
|
|
||||||
const (
|
|
||||||
obrimDatetimeTypeLocal = "local"
|
|
||||||
obrimDatetimeTypeCloud = "cloud"
|
|
||||||
|
|
||||||
obrimDatetimeFormatTimestampSec = "timestampsec"
|
|
||||||
obrimDatetimeFormatTimestampMil = "timestampmil"
|
|
||||||
obrimDatetimeFormatYearMonthDay = "yyyy-MM-dd"
|
|
||||||
obrimDatetimeFormatMonthDayYear = "MMM dd, yyyy"
|
|
||||||
obrimDatetimeFormatFullMonthDayYear = "MMMM dd, yyyy"
|
|
||||||
obrimDatetimeFormatWeekdayMonthDayYear = "EEE, MMM dd, yyyy"
|
|
||||||
obrimDatetimeFormatWeekdayFullMonthDayYear = "EEE, MMMM dd, yyyy"
|
|
||||||
obrimDatetimeFormatFullWeekdayMonthDayYear = "EEEE, MMM dd, yyyy"
|
|
||||||
obrimDatetimeFormatFullWeekdayFullMonthDayYear = "EEEE, MMMM dd, yyyy"
|
|
||||||
obrimDatetimeFormatTime = "HH:mm:ss"
|
|
||||||
obrimDatetimeFormatTime12 = "hh:mm:ss a"
|
|
||||||
obrimDatetimeFormatDateTime = "yyyy-MM-dd HH:mm:ss"
|
|
||||||
obrimDatetimeFormatDateTimeZone = "yyyy-MM-dd HH:mm:ss z"
|
|
||||||
obrimDatetimeFormatISO8601 = "yyyy-MM-dd'T'HH:mm:ssXXX"
|
|
||||||
|
|
||||||
obrimDatetimeSuccessRetrieved = "SUCCESS_DATETIME_RETRIEVED"
|
|
||||||
obrimDatetimeFailureInvalidType = "FAILURE_INVALID_TYPE"
|
|
||||||
obrimDatetimeFailureInvalidFormat = "FAILURE_INVALID_FORMAT"
|
|
||||||
obrimDatetimeFailureTrustedTimeSource = "FAILURE_TRUSTED_TIME_SOURCE_ERROR"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Datetime clock state contains the resolved synchronization information.
|
|
||||||
type obrimDatetimeClockState struct {
|
|
||||||
clockOffset int64
|
|
||||||
lastSync int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Datetime output contains the standardized utility response.
|
|
||||||
type obrimDatetimeOutput struct {
|
|
||||||
Status bool `json:"status"`
|
|
||||||
Code string `json:"code"`
|
|
||||||
Payload any `json:"payload"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Datetime payload contains the formatted datetime result.
|
|
||||||
type obrimDatetimePayload struct {
|
|
||||||
Value string `json:"value"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ObrimDatetime retrieves and formats the current date and time.
|
|
||||||
func ObrimDatetime(datetimeType string, config map[string]any) map[string]any {
|
|
||||||
format, code := obrimDatetimeValidateInput(datetimeType, config)
|
|
||||||
if code != "" {
|
|
||||||
return obrimDatetimeBuildOutput(false, code, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
state, available := obrimDatetimeResolveState()
|
|
||||||
|
|
||||||
switch datetimeType {
|
|
||||||
case obrimDatetimeTypeLocal:
|
|
||||||
value := obrimDatetimeLocal(format, state, available)
|
|
||||||
return obrimDatetimeBuildOutput(
|
|
||||||
true,
|
|
||||||
obrimDatetimeSuccessRetrieved,
|
|
||||||
&obrimDatetimePayload{Value: value},
|
|
||||||
)
|
|
||||||
|
|
||||||
case obrimDatetimeTypeCloud:
|
|
||||||
if !available {
|
|
||||||
return obrimDatetimeBuildOutput(
|
|
||||||
false,
|
|
||||||
obrimDatetimeFailureTrustedTimeSource,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
value := obrimDatetimeCloud(format, state)
|
|
||||||
return obrimDatetimeBuildOutput(
|
|
||||||
true,
|
|
||||||
obrimDatetimeSuccessRetrieved,
|
|
||||||
&obrimDatetimePayload{Value: value},
|
|
||||||
)
|
|
||||||
|
|
||||||
default:
|
|
||||||
return obrimDatetimeBuildOutput(false, obrimDatetimeFailureInvalidType, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimDatetimeValidateInput validates the requested datetime type and format.
|
|
||||||
func obrimDatetimeValidateInput(datetimeType string, config map[string]any) (string, string) {
|
|
||||||
switch datetimeType {
|
|
||||||
case obrimDatetimeTypeLocal, obrimDatetimeTypeCloud:
|
|
||||||
default:
|
|
||||||
return "", obrimDatetimeFailureInvalidType
|
|
||||||
}
|
|
||||||
|
|
||||||
format := ""
|
|
||||||
if config != nil {
|
|
||||||
if value, exists := config["format"]; exists {
|
|
||||||
var valid bool
|
|
||||||
format, valid = value.(string)
|
|
||||||
if !valid || format == "" {
|
|
||||||
return "", obrimDatetimeFailureInvalidFormat
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if format == "" {
|
|
||||||
format = obrimDatetimeFormatDateTime
|
|
||||||
}
|
|
||||||
|
|
||||||
switch format {
|
|
||||||
case obrimDatetimeFormatTimestampSec,
|
|
||||||
obrimDatetimeFormatTimestampMil,
|
|
||||||
obrimDatetimeFormatYearMonthDay,
|
|
||||||
obrimDatetimeFormatMonthDayYear,
|
|
||||||
obrimDatetimeFormatFullMonthDayYear,
|
|
||||||
obrimDatetimeFormatWeekdayMonthDayYear,
|
|
||||||
obrimDatetimeFormatWeekdayFullMonthDayYear,
|
|
||||||
obrimDatetimeFormatFullWeekdayMonthDayYear,
|
|
||||||
obrimDatetimeFormatFullWeekdayFullMonthDayYear,
|
|
||||||
obrimDatetimeFormatTime,
|
|
||||||
obrimDatetimeFormatTime12,
|
|
||||||
obrimDatetimeFormatDateTime,
|
|
||||||
obrimDatetimeFormatDateTimeZone,
|
|
||||||
obrimDatetimeFormatISO8601:
|
|
||||||
return format, ""
|
|
||||||
default:
|
|
||||||
return "", obrimDatetimeFailureInvalidFormat
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimDatetimeRouteRequest routes the request to its type-specific operation.
|
|
||||||
func obrimDatetimeRouteRequest(
|
|
||||||
datetimeType string,
|
|
||||||
format string,
|
|
||||||
state obrimDatetimeClockState,
|
|
||||||
available bool,
|
|
||||||
) (string, string) {
|
|
||||||
switch datetimeType {
|
|
||||||
case obrimDatetimeTypeLocal:
|
|
||||||
return obrimDatetimeLocal(format, state, available), ""
|
|
||||||
case obrimDatetimeTypeCloud:
|
|
||||||
if !available {
|
|
||||||
return "", obrimDatetimeFailureTrustedTimeSource
|
|
||||||
}
|
|
||||||
return obrimDatetimeCloud(format, state), ""
|
|
||||||
default:
|
|
||||||
return "", obrimDatetimeFailureInvalidType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimDatetimeBuildOutput builds the standardized utility output.
|
|
||||||
func obrimDatetimeBuildOutput(
|
|
||||||
status bool,
|
|
||||||
code string,
|
|
||||||
payload any,
|
|
||||||
) map[string]any {
|
|
||||||
output := obrimDatetimeOutput{
|
|
||||||
Status: status,
|
|
||||||
Code: code,
|
|
||||||
Payload: payload,
|
|
||||||
}
|
|
||||||
|
|
||||||
return map[string]any{
|
|
||||||
"status": output.Status,
|
|
||||||
"code": output.Code,
|
|
||||||
"payload": output.Payload,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimDatetimeResolveState resolves trusted clock state through the clock service.
|
|
||||||
func obrimDatetimeResolveState() (obrimDatetimeClockState, bool) {
|
|
||||||
now := time.Now()
|
|
||||||
trusted := clock.ObrimClockCurrentClock()
|
|
||||||
|
|
||||||
offset := trusted.Sub(now.UTC())
|
|
||||||
|
|
||||||
if offset == 0 {
|
|
||||||
return obrimDatetimeClockState{
|
|
||||||
clockOffset: 0,
|
|
||||||
lastSync: 0,
|
|
||||||
}, false
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimDatetimeClockState{
|
|
||||||
clockOffset: offset.Nanoseconds(),
|
|
||||||
lastSync: trusted.UnixNano(),
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimDatetimeApplyOffset applies the resolved clock offset to system time.
|
|
||||||
func obrimDatetimeApplyOffset(value time.Time, state obrimDatetimeClockState) time.Time {
|
|
||||||
return value.Add(time.Duration(state.clockOffset))
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimDatetimeFormat formats a datetime using a framework-supported pattern.
|
|
||||||
func obrimDatetimeFormat(value time.Time, format string) string {
|
|
||||||
switch format {
|
|
||||||
case obrimDatetimeFormatTimestampSec:
|
|
||||||
return formatTimestampSeconds(value)
|
|
||||||
|
|
||||||
case obrimDatetimeFormatTimestampMil:
|
|
||||||
return formatTimestampMilliseconds(value)
|
|
||||||
|
|
||||||
case obrimDatetimeFormatYearMonthDay:
|
|
||||||
return value.Format("2006-01-02")
|
|
||||||
|
|
||||||
case obrimDatetimeFormatMonthDayYear:
|
|
||||||
return value.Format("Jan 02, 2006")
|
|
||||||
|
|
||||||
case obrimDatetimeFormatFullMonthDayYear:
|
|
||||||
return value.Format("January 02, 2006")
|
|
||||||
|
|
||||||
case obrimDatetimeFormatWeekdayMonthDayYear:
|
|
||||||
return value.Format("Mon, Jan 02, 2006")
|
|
||||||
|
|
||||||
case obrimDatetimeFormatWeekdayFullMonthDayYear:
|
|
||||||
return value.Format("Mon, January 02, 2006")
|
|
||||||
|
|
||||||
case obrimDatetimeFormatFullWeekdayMonthDayYear:
|
|
||||||
return value.Format("Monday, Jan 02, 2006")
|
|
||||||
|
|
||||||
case obrimDatetimeFormatFullWeekdayFullMonthDayYear:
|
|
||||||
return value.Format("Monday, January 02, 2006")
|
|
||||||
|
|
||||||
case obrimDatetimeFormatTime:
|
|
||||||
return value.Format("15:04:05")
|
|
||||||
|
|
||||||
case obrimDatetimeFormatTime12:
|
|
||||||
return value.Format("03:04:05 PM")
|
|
||||||
|
|
||||||
case obrimDatetimeFormatDateTime:
|
|
||||||
return value.Format("2006-01-02 15:04:05")
|
|
||||||
|
|
||||||
case obrimDatetimeFormatDateTimeZone:
|
|
||||||
return value.Format("2006-01-02 15:04:05 MST")
|
|
||||||
|
|
||||||
case obrimDatetimeFormatISO8601:
|
|
||||||
return value.Format("2006-01-02T15:04:05Z07:00")
|
|
||||||
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// formatTimestampSeconds formats a datetime as a Unix timestamp in seconds.
|
|
||||||
func formatTimestampSeconds(value time.Time) string {
|
|
||||||
return value.Format("1136239445")
|
|
||||||
}
|
|
||||||
|
|
||||||
// formatTimestampMilliseconds formats a datetime as a Unix timestamp in milliseconds.
|
|
||||||
func formatTimestampMilliseconds(value time.Time) string {
|
|
||||||
return value.Format("1136239445123")
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimDatetimeLocal retrieves and formats corrected local system time.
|
|
||||||
func obrimDatetimeLocal(
|
|
||||||
format string,
|
|
||||||
state obrimDatetimeClockState,
|
|
||||||
available bool,
|
|
||||||
) string {
|
|
||||||
value := time.Now()
|
|
||||||
|
|
||||||
if available {
|
|
||||||
value = obrimDatetimeApplyOffset(value, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimDatetimeFormat(value, format)
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimDatetimeCloud retrieves and formats corrected trusted UTC time.
|
|
||||||
func obrimDatetimeCloud(
|
|
||||||
format string,
|
|
||||||
state obrimDatetimeClockState,
|
|
||||||
) string {
|
|
||||||
value := obrimDatetimeApplyOffset(time.Now().UTC(), state).UTC()
|
|
||||||
return obrimDatetimeFormat(value, format)
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,396 +0,0 @@
|
|||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Description
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Name:
|
|
||||||
| - Hash
|
|
||||||
|
|
|
||||||
| Purpose:
|
|
||||||
| - Generate and verify cryptographic hash values using standard or
|
|
||||||
| salted hashing methods for integrity verification, canonical
|
|
||||||
| fingerprinting, resource identification, comparison workflows,
|
|
||||||
| and security-oriented hashing requirements.
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Instruction
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Guideline:
|
|
||||||
| - Use to generate deterministic hashes in standard mode.
|
|
||||||
| - Use to generate salted hashes when salted hashing is required.
|
|
||||||
| - Use to verify supplied hash values against input values.
|
|
||||||
| - Use standard mode when deterministic hashing without a salt is
|
|
||||||
| required.
|
|
||||||
| - Use salted mode when a supplied or cryptographically secure
|
|
||||||
| generated salt is required.
|
|
||||||
|
|
|
||||||
| Example:
|
|
||||||
| - ObrimHash("calculate", map[string]any{
|
|
||||||
| "mode": "standard",
|
|
||||||
| "algorithm": "...",
|
|
||||||
| "value": "...",
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
| - ObrimHash("calculate", map[string]any{
|
|
||||||
| "mode": "salted",
|
|
||||||
| "algorithm": "...",
|
|
||||||
| "value": "...",
|
|
||||||
| "salt": "...",
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
| - ObrimHash("compare", map[string]any{
|
|
||||||
| "mode": "standard",
|
|
||||||
| "algorithm": "...",
|
|
||||||
| "value": "...",
|
|
||||||
| "hash": "...",
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
| - ObrimHash("compare", map[string]any{
|
|
||||||
| "mode": "salted",
|
|
||||||
| "algorithm": "...",
|
|
||||||
| "value": "...",
|
|
||||||
| "hash": "...",
|
|
||||||
| "salt": "...",
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Credit
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Contributor:
|
|
||||||
| - Rajon Ahmed
|
|
||||||
| - Blockonite
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hash
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/sha256"
|
|
||||||
"crypto/sha512"
|
|
||||||
"encoding/hex"
|
|
||||||
"errors"
|
|
||||||
"hash"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hash result codes.
|
|
||||||
const (
|
|
||||||
ObrimHashSuccessCalculated = "SUCCESS_CALCULATED"
|
|
||||||
ObrimHashSuccessCompared = "SUCCESS_COMPARED"
|
|
||||||
ObrimHashFailureInvalidType = "FAILURE_INVALID_TYPE"
|
|
||||||
ObrimHashFailureInvalidConfig = "FAILURE_INVALID_CONFIG"
|
|
||||||
ObrimHashFailureInvalidMode = "FAILURE_INVALID_MODE"
|
|
||||||
ObrimHashFailureInvalidAlgorithm = "FAILURE_INVALID_ALGORITHM"
|
|
||||||
ObrimHashFailureInvalidValue = "FAILURE_INVALID_VALUE"
|
|
||||||
ObrimHashFailureInvalidHash = "FAILURE_INVALID_HASH"
|
|
||||||
ObrimHashFailureInvalidSalt = "FAILURE_INVALID_SALT"
|
|
||||||
ObrimHashFailureProcessing = "FAILURE_PROCESSING"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hash utility modes.
|
|
||||||
const (
|
|
||||||
obrimHashModeStandard = "standard"
|
|
||||||
obrimHashModeSalted = "salted"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hash utility algorithms.
|
|
||||||
const (
|
|
||||||
obrimHashAlgorithmSHA256 = "sha256"
|
|
||||||
obrimHashAlgorithmSHA512 = "sha512"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hash utility configuration keys.
|
|
||||||
const (
|
|
||||||
obrimHashConfigMode = "mode"
|
|
||||||
obrimHashConfigAlgorithm = "algorithm"
|
|
||||||
obrimHashConfigValue = "value"
|
|
||||||
obrimHashConfigHash = "hash"
|
|
||||||
obrimHashConfigSalt = "salt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hash utility operation types.
|
|
||||||
const (
|
|
||||||
obrimHashTypeCalculate = "calculate"
|
|
||||||
obrimHashTypeCompare = "compare"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hash utility output structure.
|
|
||||||
type obrimHashOutput struct {
|
|
||||||
Status bool `json:"status"`
|
|
||||||
Code string `json:"code"`
|
|
||||||
Payload map[string]any `json:"payload"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash utility request configuration.
|
|
||||||
type obrimHashConfig struct {
|
|
||||||
Mode string
|
|
||||||
Algorithm string
|
|
||||||
Value string
|
|
||||||
Hash string
|
|
||||||
Salt string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash utility execution function.
|
|
||||||
func ObrimHash(Type string, Config map[string]any) map[string]any {
|
|
||||||
ConfigData, Code := obrimHashValidateInput(Type, Config)
|
|
||||||
if Code != "" {
|
|
||||||
return obrimHashBuildOutput(false, Code, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimHashRouteRequest(Type, ConfigData)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate hash utility input.
|
|
||||||
func obrimHashValidateInput(Type string, Config map[string]any) (obrimHashConfig, string) {
|
|
||||||
var ConfigData obrimHashConfig
|
|
||||||
|
|
||||||
switch Type {
|
|
||||||
case obrimHashTypeCalculate, obrimHashTypeCompare:
|
|
||||||
default:
|
|
||||||
return ConfigData, ObrimHashFailureInvalidType
|
|
||||||
}
|
|
||||||
|
|
||||||
if Config == nil {
|
|
||||||
return ConfigData, ObrimHashFailureInvalidConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
ConfigData.Mode = obrimHashReadStringConfig(Config, obrimHashConfigMode)
|
|
||||||
ConfigData.Algorithm = obrimHashReadStringConfig(Config, obrimHashConfigAlgorithm)
|
|
||||||
ConfigData.Value = obrimHashReadStringConfig(Config, obrimHashConfigValue)
|
|
||||||
ConfigData.Hash = obrimHashReadStringConfig(Config, obrimHashConfigHash)
|
|
||||||
ConfigData.Salt = obrimHashReadStringConfig(Config, obrimHashConfigSalt)
|
|
||||||
|
|
||||||
switch ConfigData.Mode {
|
|
||||||
case obrimHashModeStandard, obrimHashModeSalted:
|
|
||||||
default:
|
|
||||||
return ConfigData, ObrimHashFailureInvalidMode
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ConfigData.Algorithm {
|
|
||||||
case obrimHashAlgorithmSHA256, obrimHashAlgorithmSHA512:
|
|
||||||
default:
|
|
||||||
return ConfigData, ObrimHashFailureInvalidAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
if ConfigData.Value == "" {
|
|
||||||
return ConfigData, ObrimHashFailureInvalidValue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch Type {
|
|
||||||
case obrimHashTypeCalculate:
|
|
||||||
if ConfigData.Mode == obrimHashModeStandard && ConfigData.Salt != "" {
|
|
||||||
return ConfigData, ObrimHashFailureInvalidSalt
|
|
||||||
}
|
|
||||||
case obrimHashTypeCompare:
|
|
||||||
if ConfigData.Hash == "" {
|
|
||||||
return ConfigData, ObrimHashFailureInvalidHash
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ConfigData.Mode {
|
|
||||||
case obrimHashModeStandard:
|
|
||||||
if ConfigData.Salt != "" {
|
|
||||||
return ConfigData, ObrimHashFailureInvalidSalt
|
|
||||||
}
|
|
||||||
case obrimHashModeSalted:
|
|
||||||
if ConfigData.Salt == "" {
|
|
||||||
return ConfigData, ObrimHashFailureInvalidSalt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ConfigData, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Route the hash utility request.
|
|
||||||
func obrimHashRouteRequest(Type string, Config obrimHashConfig) map[string]any {
|
|
||||||
switch Type {
|
|
||||||
case obrimHashTypeCalculate:
|
|
||||||
return obrimHashCalculate(Config)
|
|
||||||
case obrimHashTypeCompare:
|
|
||||||
return obrimHashCompare(Config)
|
|
||||||
default:
|
|
||||||
return obrimHashBuildOutput(false, ObrimHashFailureInvalidType, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build standardized hash utility output.
|
|
||||||
func obrimHashBuildOutput(Status bool, Code string, Payload map[string]any) map[string]any {
|
|
||||||
Output := obrimHashOutput{
|
|
||||||
Status: Status,
|
|
||||||
Code: Code,
|
|
||||||
Payload: Payload,
|
|
||||||
}
|
|
||||||
|
|
||||||
return map[string]any{
|
|
||||||
"status": Output.Status,
|
|
||||||
"code": Output.Code,
|
|
||||||
"payload": Output.Payload,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process hash generation.
|
|
||||||
func obrimHashCalculate(Config obrimHashConfig) map[string]any {
|
|
||||||
switch Config.Mode {
|
|
||||||
case obrimHashModeStandard:
|
|
||||||
return obrimHashCalculateStandard(Config)
|
|
||||||
case obrimHashModeSalted:
|
|
||||||
return obrimHashCalculateSalted(Config)
|
|
||||||
default:
|
|
||||||
return obrimHashBuildOutput(false, ObrimHashFailureInvalidMode, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate deterministic standard hash.
|
|
||||||
func obrimHashCalculateStandard(Config obrimHashConfig) map[string]any {
|
|
||||||
HashValue, Error := obrimHashGenerate(Config.Algorithm, Config.Value)
|
|
||||||
if Error != nil {
|
|
||||||
return obrimHashBuildOutput(false, ObrimHashFailureProcessing, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
Payload := map[string]any{
|
|
||||||
"algorithm": Config.Algorithm,
|
|
||||||
"hash": HashValue,
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimHashBuildOutput(true, ObrimHashSuccessCalculated, Payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate salted hash.
|
|
||||||
func obrimHashCalculateSalted(Config obrimHashConfig) map[string]any {
|
|
||||||
Salt := Config.Salt
|
|
||||||
|
|
||||||
if Salt == "" {
|
|
||||||
var Error error
|
|
||||||
|
|
||||||
Salt, Error = obrimHashGenerateSalt()
|
|
||||||
if Error != nil {
|
|
||||||
return obrimHashBuildOutput(false, ObrimHashFailureProcessing, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HashValue, Error := obrimHashGenerate(Config.Algorithm, Salt+Config.Value)
|
|
||||||
if Error != nil {
|
|
||||||
return obrimHashBuildOutput(false, ObrimHashFailureProcessing, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
Payload := map[string]any{
|
|
||||||
"algorithm": Config.Algorithm,
|
|
||||||
"hash": HashValue,
|
|
||||||
"salt": Salt,
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimHashBuildOutput(true, ObrimHashSuccessCalculated, Payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a cryptographically secure random salt.
|
|
||||||
func obrimHashGenerateSalt() (string, error) {
|
|
||||||
Salt := make([]byte, 32)
|
|
||||||
|
|
||||||
if _, Error := rand.Read(Salt); Error != nil {
|
|
||||||
return "", Error
|
|
||||||
}
|
|
||||||
|
|
||||||
return hex.EncodeToString(Salt), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process hash verification.
|
|
||||||
func obrimHashCompare(Config obrimHashConfig) map[string]any {
|
|
||||||
switch Config.Mode {
|
|
||||||
case obrimHashModeStandard:
|
|
||||||
return obrimHashCompareStandard(Config)
|
|
||||||
case obrimHashModeSalted:
|
|
||||||
return obrimHashCompareSalted(Config)
|
|
||||||
default:
|
|
||||||
return obrimHashBuildOutput(false, ObrimHashFailureInvalidMode, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify standard hash.
|
|
||||||
func obrimHashCompareStandard(Config obrimHashConfig) map[string]any {
|
|
||||||
HashValue, Error := obrimHashGenerate(Config.Algorithm, Config.Value)
|
|
||||||
if Error != nil {
|
|
||||||
return obrimHashBuildOutput(false, ObrimHashFailureProcessing, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
Matched := obrimHashVerify(HashValue, Config.Hash)
|
|
||||||
|
|
||||||
Payload := map[string]any{
|
|
||||||
"algorithm": Config.Algorithm,
|
|
||||||
"matched": Matched,
|
|
||||||
"hash": Config.Hash,
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimHashBuildOutput(true, ObrimHashSuccessCompared, Payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify salted hash.
|
|
||||||
func obrimHashCompareSalted(Config obrimHashConfig) map[string]any {
|
|
||||||
HashValue, Error := obrimHashGenerate(Config.Algorithm, Config.Salt+Config.Value)
|
|
||||||
if Error != nil {
|
|
||||||
return obrimHashBuildOutput(false, ObrimHashFailureProcessing, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
Matched := obrimHashVerify(HashValue, Config.Hash)
|
|
||||||
|
|
||||||
Payload := map[string]any{
|
|
||||||
"algorithm": Config.Algorithm,
|
|
||||||
"matched": Matched,
|
|
||||||
"hash": Config.Hash,
|
|
||||||
"salt": Config.Salt,
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimHashBuildOutput(true, ObrimHashSuccessCompared, Payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify regenerated and supplied hashes using strict byte comparison.
|
|
||||||
func obrimHashVerify(Expected string, Supplied string) bool {
|
|
||||||
return string([]byte(Expected)) == string([]byte(Supplied))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a hash using the selected algorithm.
|
|
||||||
func obrimHashGenerate(Algorithm string, Value string) (string, error) {
|
|
||||||
var HashFunction func() hash.Hash
|
|
||||||
|
|
||||||
switch Algorithm {
|
|
||||||
case obrimHashAlgorithmSHA256:
|
|
||||||
HashFunction = sha256.New
|
|
||||||
case obrimHashAlgorithmSHA512:
|
|
||||||
HashFunction = sha512.New
|
|
||||||
default:
|
|
||||||
return "", errors.New("unsupported hashing algorithm")
|
|
||||||
}
|
|
||||||
|
|
||||||
Hasher := HashFunction()
|
|
||||||
|
|
||||||
if _, Error := Hasher.Write([]byte(Value)); Error != nil {
|
|
||||||
return "", Error
|
|
||||||
}
|
|
||||||
|
|
||||||
return hex.EncodeToString(Hasher.Sum(nil)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read a string configuration value.
|
|
||||||
func obrimHashReadStringConfig(Config map[string]any, Key string) string {
|
|
||||||
Value, Exists := Config[Key]
|
|
||||||
if !Exists || Value == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
StringValue, Valid := Value.(string)
|
|
||||||
if !Valid {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return StringValue
|
|
||||||
}
|
|
||||||
@ -1,445 +0,0 @@
|
|||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Description
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Name:
|
|
||||||
| - Key
|
|
||||||
|
|
|
||||||
| Purpose:
|
|
||||||
| - Generate cryptographic key material through a type-driven dispatch
|
|
||||||
| model supporting symmetric and asymmetric key generation.
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Instruction
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Guideline:
|
|
||||||
| - Use the utility to generate cryptographically secure symmetric or
|
|
||||||
| asymmetric key material.
|
|
||||||
| - Use the "symmetric" type with the supported AES algorithm and
|
|
||||||
| 128, 192, or 256 bit key sizes.
|
|
||||||
| - Use the "asymmetric" type with the supported ECC algorithm using
|
|
||||||
| the EdDSA curve.
|
|
||||||
| - Provide the type-specific configuration required for the selected
|
|
||||||
| key generation workflow.
|
|
||||||
|
|
|
||||||
| Example:
|
|
||||||
| - ObrimKey("symmetric", map[string]any{
|
|
||||||
| "algorithm": "aes",
|
|
||||||
| "key_size": 256,
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
| - ObrimKey("asymmetric", map[string]any{
|
|
||||||
| "algorithm": "ecc",
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Credit
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Contributor:
|
|
||||||
| - Rajon Ahmed
|
|
||||||
| - Blockonite
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
package key
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/aes"
|
|
||||||
"crypto/ed25519"
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/base64"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
obrimKeyTypeSymmetric = "symmetric"
|
|
||||||
obrimKeyTypeAsymmetric = "asymmetric"
|
|
||||||
|
|
||||||
obrimKeyAlgorithmAES = "aes"
|
|
||||||
obrimKeyAlgorithmECC = "ecc"
|
|
||||||
obrimKeyCurveEdDSA = "eddsa"
|
|
||||||
|
|
||||||
obrimKeySize128 = 128
|
|
||||||
obrimKeySize192 = 192
|
|
||||||
obrimKeySize256 = 256
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
obrimKeySuccessSymmetricGenerated = "SUCCESS_SYMMETRIC_KEY_GENERATED"
|
|
||||||
obrimKeySuccessAsymmetricGenerated = "SUCCESS_ASYMMETRIC_KEY_GENERATED"
|
|
||||||
|
|
||||||
obrimKeyFailureInvalidType = "FAILURE_INVALID_TYPE"
|
|
||||||
obrimKeyFailureInvalidConfig = "FAILURE_INVALID_CONFIG"
|
|
||||||
obrimKeyFailureMissingAlgorithm = "FAILURE_MISSING_ALGORITHM"
|
|
||||||
obrimKeyFailureInvalidAlgorithm = "FAILURE_INVALID_ALGORITHM"
|
|
||||||
obrimKeyFailureMissingKeySize = "FAILURE_MISSING_KEY_SIZE"
|
|
||||||
obrimKeyFailureInvalidKeySize = "FAILURE_INVALID_KEY_SIZE"
|
|
||||||
obrimKeyFailureKeyGeneration = "FAILURE_KEY_GENERATION"
|
|
||||||
obrimKeyFailureAsymmetricKeyGeneration = "FAILURE_ASYMMETRIC_KEY_GENERATION"
|
|
||||||
obrimKeyFailureUnsupportedOperation = "FAILURE_UNSUPPORTED_OPERATION"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
obrimKeyConfigAlgorithm = "algorithm"
|
|
||||||
obrimKeyConfigKeySize = "key_size"
|
|
||||||
)
|
|
||||||
|
|
||||||
type obrimKeySymmetricConfig struct {
|
|
||||||
algorithm string
|
|
||||||
keySize int
|
|
||||||
}
|
|
||||||
|
|
||||||
type obrimKeyAsymmetricConfig struct {
|
|
||||||
algorithm string
|
|
||||||
}
|
|
||||||
|
|
||||||
type obrimKeySymmetricPayload struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Algorithm string `json:"algorithm"`
|
|
||||||
KeySize int `json:"key_size"`
|
|
||||||
KeyMaterial string `json:"key_material"`
|
|
||||||
GeneratedAt string `json:"generated_at"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type obrimKeyAsymmetricPayload struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Algorithm string `json:"algorithm"`
|
|
||||||
Curve string `json:"curve"`
|
|
||||||
PublicKey string `json:"public_key"`
|
|
||||||
PrivateKey string `json:"private_key"`
|
|
||||||
GeneratedAt string `json:"generated_at"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type obrimKeyOutput struct {
|
|
||||||
Status bool `json:"status"`
|
|
||||||
Code string `json:"code"`
|
|
||||||
Payload any `json:"payload"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func ObrimKey(keyType string, config map[string]any) map[string]any {
|
|
||||||
if code := obrimKeyValidateInput(keyType, config); code != "" {
|
|
||||||
return obrimKeyBuildOutput(false, code, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimKeyRouteRequest(keyType, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func obrimKeyValidateInput(keyType string, config map[string]any) string {
|
|
||||||
switch keyType {
|
|
||||||
case obrimKeyTypeSymmetric:
|
|
||||||
if config == nil {
|
|
||||||
return obrimKeyFailureInvalidConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
algorithm, ok := config[obrimKeyConfigAlgorithm]
|
|
||||||
if !ok {
|
|
||||||
return obrimKeyFailureMissingAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
algorithmValue, ok := algorithm.(string)
|
|
||||||
if !ok || algorithmValue == "" {
|
|
||||||
return obrimKeyFailureInvalidAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
switch algorithmValue {
|
|
||||||
case obrimKeyAlgorithmAES:
|
|
||||||
default:
|
|
||||||
return obrimKeyFailureInvalidAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
keySize, ok := config[obrimKeyConfigKeySize]
|
|
||||||
if !ok {
|
|
||||||
return obrimKeyFailureMissingKeySize
|
|
||||||
}
|
|
||||||
|
|
||||||
switch value := keySize.(type) {
|
|
||||||
case int:
|
|
||||||
switch value {
|
|
||||||
case obrimKeySize128, obrimKeySize192, obrimKeySize256:
|
|
||||||
default:
|
|
||||||
return obrimKeyFailureInvalidKeySize
|
|
||||||
}
|
|
||||||
case int8:
|
|
||||||
switch value {
|
|
||||||
case obrimKeySize128, obrimKeySize192, obrimKeySize256:
|
|
||||||
default:
|
|
||||||
return obrimKeyFailureInvalidKeySize
|
|
||||||
}
|
|
||||||
case int16:
|
|
||||||
switch value {
|
|
||||||
case obrimKeySize128, obrimKeySize192, obrimKeySize256:
|
|
||||||
default:
|
|
||||||
return obrimKeyFailureInvalidKeySize
|
|
||||||
}
|
|
||||||
case int32:
|
|
||||||
switch value {
|
|
||||||
case obrimKeySize128, obrimKeySize192, obrimKeySize256:
|
|
||||||
default:
|
|
||||||
return obrimKeyFailureInvalidKeySize
|
|
||||||
}
|
|
||||||
case int64:
|
|
||||||
switch value {
|
|
||||||
case obrimKeySize128, obrimKeySize192, obrimKeySize256:
|
|
||||||
default:
|
|
||||||
return obrimKeyFailureInvalidKeySize
|
|
||||||
}
|
|
||||||
case uint:
|
|
||||||
switch value {
|
|
||||||
case obrimKeySize128, obrimKeySize192, obrimKeySize256:
|
|
||||||
default:
|
|
||||||
return obrimKeyFailureInvalidKeySize
|
|
||||||
}
|
|
||||||
case uint8:
|
|
||||||
switch value {
|
|
||||||
case obrimKeySize128, obrimKeySize192, obrimKeySize256:
|
|
||||||
default:
|
|
||||||
return obrimKeyFailureInvalidKeySize
|
|
||||||
}
|
|
||||||
case uint16:
|
|
||||||
switch value {
|
|
||||||
case obrimKeySize128, obrimKeySize192, obrimKeySize256:
|
|
||||||
default:
|
|
||||||
return obrimKeyFailureInvalidKeySize
|
|
||||||
}
|
|
||||||
case uint32:
|
|
||||||
switch value {
|
|
||||||
case obrimKeySize128, obrimKeySize192, obrimKeySize256:
|
|
||||||
default:
|
|
||||||
return obrimKeyFailureInvalidKeySize
|
|
||||||
}
|
|
||||||
case uint64:
|
|
||||||
switch value {
|
|
||||||
case obrimKeySize128, obrimKeySize192, obrimKeySize256:
|
|
||||||
default:
|
|
||||||
return obrimKeyFailureInvalidKeySize
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return obrimKeyFailureInvalidKeySize
|
|
||||||
}
|
|
||||||
|
|
||||||
case obrimKeyTypeAsymmetric:
|
|
||||||
if config == nil {
|
|
||||||
return obrimKeyFailureInvalidConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
algorithm, ok := config[obrimKeyConfigAlgorithm]
|
|
||||||
if !ok {
|
|
||||||
return obrimKeyFailureMissingAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
algorithmValue, ok := algorithm.(string)
|
|
||||||
if !ok || algorithmValue == "" {
|
|
||||||
return obrimKeyFailureInvalidAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
switch algorithmValue {
|
|
||||||
case obrimKeyAlgorithmECC:
|
|
||||||
default:
|
|
||||||
return obrimKeyFailureInvalidAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return obrimKeyFailureInvalidType
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func obrimKeyRouteRequest(keyType string, config map[string]any) map[string]any {
|
|
||||||
switch keyType {
|
|
||||||
case obrimKeyTypeSymmetric:
|
|
||||||
normalized, code := obrimKeyNormalizeSymmetricConfig(config)
|
|
||||||
if code != "" {
|
|
||||||
return obrimKeyBuildOutput(false, code, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
payload, code := obrimKeyGenerateSymmetric(normalized)
|
|
||||||
if code != "" {
|
|
||||||
return obrimKeyBuildOutput(false, code, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimKeyBuildOutput(
|
|
||||||
true,
|
|
||||||
obrimKeySuccessSymmetricGenerated,
|
|
||||||
payload,
|
|
||||||
)
|
|
||||||
|
|
||||||
case obrimKeyTypeAsymmetric:
|
|
||||||
normalized, code := obrimKeyNormalizeAsymmetricConfig(config)
|
|
||||||
if code != "" {
|
|
||||||
return obrimKeyBuildOutput(false, code, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
payload, code := obrimKeyGenerateAsymmetric(normalized)
|
|
||||||
if code != "" {
|
|
||||||
return obrimKeyBuildOutput(false, code, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimKeyBuildOutput(
|
|
||||||
true,
|
|
||||||
obrimKeySuccessAsymmetricGenerated,
|
|
||||||
payload,
|
|
||||||
)
|
|
||||||
|
|
||||||
default:
|
|
||||||
return obrimKeyBuildOutput(false, obrimKeyFailureUnsupportedOperation, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func obrimKeyBuildOutput(status bool, code string, payload any) map[string]any {
|
|
||||||
output := obrimKeyOutput{
|
|
||||||
Status: status,
|
|
||||||
Code: code,
|
|
||||||
Payload: payload,
|
|
||||||
}
|
|
||||||
|
|
||||||
return map[string]any{
|
|
||||||
"status": output.Status,
|
|
||||||
"code": output.Code,
|
|
||||||
"payload": output.Payload,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func obrimKeyNormalizeSymmetricConfig(config map[string]any) (obrimKeySymmetricConfig, string) {
|
|
||||||
algorithm, ok := config[obrimKeyConfigAlgorithm].(string)
|
|
||||||
if !ok || algorithm == "" {
|
|
||||||
return obrimKeySymmetricConfig{}, obrimKeyFailureInvalidAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
keySizeValue, ok := config[obrimKeyConfigKeySize]
|
|
||||||
if !ok {
|
|
||||||
return obrimKeySymmetricConfig{}, obrimKeyFailureMissingKeySize
|
|
||||||
}
|
|
||||||
|
|
||||||
keySize, ok := obrimKeyNormalizeKeySize(keySizeValue)
|
|
||||||
if !ok {
|
|
||||||
return obrimKeySymmetricConfig{}, obrimKeyFailureInvalidKeySize
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimKeySymmetricConfig{
|
|
||||||
algorithm: algorithm,
|
|
||||||
keySize: keySize,
|
|
||||||
}, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func obrimKeyNormalizeKeySize(value any) (int, bool) {
|
|
||||||
switch keySize := value.(type) {
|
|
||||||
case int:
|
|
||||||
return keySize, true
|
|
||||||
case int8:
|
|
||||||
return int(keySize), true
|
|
||||||
case int16:
|
|
||||||
return int(keySize), true
|
|
||||||
case int32:
|
|
||||||
return int(keySize), true
|
|
||||||
case int64:
|
|
||||||
return int(keySize), true
|
|
||||||
case uint:
|
|
||||||
return int(keySize), true
|
|
||||||
case uint8:
|
|
||||||
return int(keySize), true
|
|
||||||
case uint16:
|
|
||||||
return int(keySize), true
|
|
||||||
case uint32:
|
|
||||||
return int(keySize), true
|
|
||||||
case uint64:
|
|
||||||
return int(keySize), true
|
|
||||||
default:
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func obrimKeyGenerateSymmetric(config obrimKeySymmetricConfig) (map[string]any, string) {
|
|
||||||
switch config.algorithm {
|
|
||||||
case obrimKeyAlgorithmAES:
|
|
||||||
return obrimKeyGenerateAES(config.keySize)
|
|
||||||
default:
|
|
||||||
return nil, obrimKeyFailureInvalidAlgorithm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func obrimKeyGenerateAES(keySize int) (map[string]any, string) {
|
|
||||||
keyLength := keySize / 8
|
|
||||||
|
|
||||||
keyMaterial := make([]byte, keyLength)
|
|
||||||
if _, err := rand.Read(keyMaterial); err != nil {
|
|
||||||
return nil, obrimKeyFailureKeyGeneration
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := aes.NewCipher(keyMaterial); err != nil {
|
|
||||||
return nil, obrimKeyFailureKeyGeneration
|
|
||||||
}
|
|
||||||
|
|
||||||
payload := obrimKeySymmetricPayload{
|
|
||||||
Type: obrimKeyTypeSymmetric,
|
|
||||||
Algorithm: obrimKeyAlgorithmAES,
|
|
||||||
KeySize: keySize,
|
|
||||||
KeyMaterial: base64.StdEncoding.EncodeToString(keyMaterial),
|
|
||||||
GeneratedAt: time.Now().UTC().Format(time.RFC3339Nano),
|
|
||||||
}
|
|
||||||
|
|
||||||
return map[string]any{
|
|
||||||
"type": payload.Type,
|
|
||||||
"algorithm": payload.Algorithm,
|
|
||||||
"key_size": payload.KeySize,
|
|
||||||
"key_material": payload.KeyMaterial,
|
|
||||||
"generated_at": payload.GeneratedAt,
|
|
||||||
}, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func obrimKeyNormalizeAsymmetricConfig(config map[string]any) (obrimKeyAsymmetricConfig, string) {
|
|
||||||
algorithm, ok := config[obrimKeyConfigAlgorithm].(string)
|
|
||||||
if !ok || algorithm == "" {
|
|
||||||
return obrimKeyAsymmetricConfig{}, obrimKeyFailureInvalidAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimKeyAsymmetricConfig{
|
|
||||||
algorithm: algorithm,
|
|
||||||
}, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func obrimKeyGenerateAsymmetric(config obrimKeyAsymmetricConfig) (map[string]any, string) {
|
|
||||||
switch config.algorithm {
|
|
||||||
case obrimKeyAlgorithmECC:
|
|
||||||
return obrimKeyGenerateECC()
|
|
||||||
default:
|
|
||||||
return nil, obrimKeyFailureInvalidAlgorithm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func obrimKeyGenerateECC() (map[string]any, string) {
|
|
||||||
publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, obrimKeyFailureAsymmetricKeyGeneration
|
|
||||||
}
|
|
||||||
|
|
||||||
payload := obrimKeyAsymmetricPayload{
|
|
||||||
Type: obrimKeyTypeAsymmetric,
|
|
||||||
Algorithm: obrimKeyAlgorithmECC,
|
|
||||||
Curve: obrimKeyCurveEdDSA,
|
|
||||||
PublicKey: base64.StdEncoding.EncodeToString(publicKey),
|
|
||||||
PrivateKey: base64.StdEncoding.EncodeToString(privateKey),
|
|
||||||
GeneratedAt: time.Now().UTC().Format(time.RFC3339Nano),
|
|
||||||
}
|
|
||||||
|
|
||||||
return map[string]any{
|
|
||||||
"type": payload.Type,
|
|
||||||
"algorithm": payload.Algorithm,
|
|
||||||
"curve": payload.Curve,
|
|
||||||
"public_key": payload.PublicKey,
|
|
||||||
"private_key": payload.PrivateKey,
|
|
||||||
"generated_at": payload.GeneratedAt,
|
|
||||||
}, ""
|
|
||||||
}
|
|
||||||
@ -1,225 +0,0 @@
|
|||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Description
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Name:
|
|
||||||
| - Log
|
|
||||||
|
|
|
||||||
| Purpose:
|
|
||||||
| - Provide a framework-level logging utility that records structured
|
|
||||||
| plaintext log entries to a persistent filesystem location using a
|
|
||||||
| deterministic and platform-aware storage strategy.
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Instruction
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Guideline:
|
|
||||||
| - Use to write standardized log messages from framework services and
|
|
||||||
| software features.
|
|
||||||
| - Provide a logical source identifier using the SERVICENAME/UTILITYNAME
|
|
||||||
| or SERVICENAME/FEATURENAME format.
|
|
||||||
| - Provide the human-readable log message as plain, formatted, or any
|
|
||||||
| UTF-8 string.
|
|
||||||
| - Log entries are stored in the platform-specific persistent log
|
|
||||||
| directory using the software name as the directory name.
|
|
||||||
| - Log entries are appended as complete UTF-8 plaintext lines without
|
|
||||||
| overwriting existing content.
|
|
||||||
|
|
|
||||||
| Example:
|
|
||||||
| - ObrimLog(
|
|
||||||
| "SERVICENAME/UTILITYNAME",
|
|
||||||
| "Utility operation completed",
|
|
||||||
| )
|
|
||||||
| - ObrimLog(
|
|
||||||
| "SERVICENAME/FEATURENAME",
|
|
||||||
| "Feature execution started",
|
|
||||||
| )
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Credit
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Contributor:
|
|
||||||
| - Rajon Ahmed
|
|
||||||
| - Blockonite
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// obrimLogSoftwareName identifies the software owning the log directory.
|
|
||||||
const obrimLogSoftwareName = "software"
|
|
||||||
|
|
||||||
// ObrimLog writes a standardized log message.
|
|
||||||
func ObrimLog(label, message string) {
|
|
||||||
obrimLogLabel, obrimLogMessage, obrimLogValid := obrimLogValidateInput(label, message)
|
|
||||||
if !obrimLogValid {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
obrimLogName := obrimLogResolveName()
|
|
||||||
if obrimLogName == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
obrimLogDirectory, obrimLogDirectoryValid := obrimLogResolveDirectory(obrimLogName)
|
|
||||||
if !obrimLogDirectoryValid {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
obrimLogFile, obrimLogFileValid := obrimLogResolveFile(obrimLogDirectory)
|
|
||||||
if !obrimLogFileValid {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
obrimLogTimestamp := obrimLogGetTimestamp()
|
|
||||||
obrimLogEntry := obrimLogBuildEntry(obrimLogTimestamp, obrimLogLabel, obrimLogMessage)
|
|
||||||
|
|
||||||
obrimLogWriteEntry(obrimLogFile, obrimLogEntry)
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimLogValidateInput normalizes and validates the log input.
|
|
||||||
func obrimLogValidateInput(label, message string) (string, string, bool) {
|
|
||||||
label = strings.TrimSpace(label)
|
|
||||||
message = strings.ReplaceAll(message, "\r\n", "\n")
|
|
||||||
message = strings.ReplaceAll(message, "\r", "\n")
|
|
||||||
message = strings.ReplaceAll(message, "\n", " ")
|
|
||||||
|
|
||||||
if label == "" || message == "" {
|
|
||||||
return "", "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
return label, message, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimLogResolveName retrieves the software name from the local constant.
|
|
||||||
func obrimLogResolveName() string {
|
|
||||||
return strings.TrimSpace(obrimLogSoftwareName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimLogResolveDirectory resolves and creates the platform-specific log directory.
|
|
||||||
func obrimLogResolveDirectory(softwareName string) (string, bool) {
|
|
||||||
var obrimLogDirectory string
|
|
||||||
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "linux":
|
|
||||||
obrimLogHome, obrimLogHomeError := os.UserHomeDir()
|
|
||||||
if obrimLogHomeError != nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
obrimLogDirectory = filepath.Join(
|
|
||||||
obrimLogHome,
|
|
||||||
".local",
|
|
||||||
"state",
|
|
||||||
softwareName,
|
|
||||||
"log",
|
|
||||||
"main",
|
|
||||||
)
|
|
||||||
|
|
||||||
case "windows":
|
|
||||||
obrimLogLocalAppData := strings.TrimSpace(os.Getenv("LOCALAPPDATA"))
|
|
||||||
if obrimLogLocalAppData == "" {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
obrimLogDirectory = filepath.Join(
|
|
||||||
obrimLogLocalAppData,
|
|
||||||
softwareName,
|
|
||||||
"log",
|
|
||||||
"main",
|
|
||||||
)
|
|
||||||
|
|
||||||
case "darwin":
|
|
||||||
obrimLogHome, obrimLogHomeError := os.UserHomeDir()
|
|
||||||
if obrimLogHomeError != nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
obrimLogDirectory = filepath.Join(
|
|
||||||
obrimLogHome,
|
|
||||||
"Library",
|
|
||||||
"Logs",
|
|
||||||
softwareName,
|
|
||||||
"log",
|
|
||||||
"main",
|
|
||||||
)
|
|
||||||
|
|
||||||
default:
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
if obrimLogDirectory == "" {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
if obrimLogMkdirError := os.MkdirAll(obrimLogDirectory, 0o755); obrimLogMkdirError != nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimLogDirectory, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimLogResolveFile resolves and creates the main log file.
|
|
||||||
func obrimLogResolveFile(directory string) (string, bool) {
|
|
||||||
obrimLogFile := filepath.Join(directory, "main.log")
|
|
||||||
|
|
||||||
obrimLogHandle, obrimLogOpenError := os.OpenFile(
|
|
||||||
obrimLogFile,
|
|
||||||
os.O_CREATE|os.O_APPEND|os.O_WRONLY,
|
|
||||||
0o644,
|
|
||||||
)
|
|
||||||
if obrimLogOpenError != nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
if obrimLogCloseError := obrimLogHandle.Close(); obrimLogCloseError != nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimLogFile, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimLogGetTimestamp gets the timestamp for a log entry.
|
|
||||||
func obrimLogGetTimestamp() string {
|
|
||||||
return time.Now().Format(time.RFC3339Nano)
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimLogBuildEntry builds a complete formatted log entry.
|
|
||||||
func obrimLogBuildEntry(timestamp, label, message string) string {
|
|
||||||
return "[" + timestamp + "] [" + label + "] " + message + "\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimLogWriteEntry appends a complete log entry to the log file.
|
|
||||||
func obrimLogWriteEntry(file, entry string) {
|
|
||||||
obrimLogHandle, obrimLogOpenError := os.OpenFile(
|
|
||||||
file,
|
|
||||||
os.O_APPEND|os.O_WRONLY,
|
|
||||||
0o644,
|
|
||||||
)
|
|
||||||
if obrimLogOpenError != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer obrimLogHandle.Close()
|
|
||||||
|
|
||||||
_, _ = obrimLogHandle.WriteString(entry)
|
|
||||||
}
|
|
||||||
@ -1,627 +0,0 @@
|
|||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Description
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Name:
|
|
||||||
| - Marker
|
|
||||||
|
|
|
||||||
| Purpose:
|
|
||||||
| - Provide a unified utility for generating unique markers through
|
|
||||||
| multiple generation strategies using a single entry point.
|
|
||||||
| - Support time-based, random, and encoded marker generation while
|
|
||||||
| maintaining a consistent output structure, deterministic routing,
|
|
||||||
| and extensible architecture.
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Instruction
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Guideline:
|
|
||||||
| - Use the time type with an epoch timestamp and instance identifier
|
|
||||||
| to generate distributed time-based markers.
|
|
||||||
| - Use the random type with a desired length and character set to
|
|
||||||
| generate collision-resistant random markers.
|
|
||||||
| - Use the encoded type with source data, output length, character
|
|
||||||
| set, and optional salt to generate deterministic encoded markers.
|
|
||||||
| - Validate the marker type and all type-specific configuration
|
|
||||||
| values before processing.
|
|
||||||
| - Use the unified ObrimMarker entry point to execute marker
|
|
||||||
| generation.
|
|
||||||
|
|
|
||||||
| Example:
|
|
||||||
| - ObrimMarker("time", map[string]any{
|
|
||||||
| "epoch": int64(0),
|
|
||||||
| "instance": "instance-01",
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
| - ObrimMarker("random", map[string]any{
|
|
||||||
| "length": 32,
|
|
||||||
| "charset": "abcdefghijklmnopqrstuvwxyz0123456789",
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
| - ObrimMarker("encoded", map[string]any{
|
|
||||||
| "data": "source-data",
|
|
||||||
| "length": 32,
|
|
||||||
| "charset": "abcdefghijklmnopqrstuvwxyz0123456789",
|
|
||||||
| "salt": "optional-salt",
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Credit
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Contributor:
|
|
||||||
| - Rajon Ahmed
|
|
||||||
| - Blockonite
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
package marker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Marker type identifiers.
|
|
||||||
obrimMarkerTypeTime = "time"
|
|
||||||
obrimMarkerTypeRandom = "random"
|
|
||||||
obrimMarkerTypeEncoded = "encoded"
|
|
||||||
|
|
||||||
// Default marker configuration values.
|
|
||||||
obrimMarkerDefaultEpoch int64 = 0
|
|
||||||
obrimMarkerDefaultCharset string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
|
||||||
obrimMarkerDefaultLength int = 32
|
|
||||||
|
|
||||||
// Marker result codes.
|
|
||||||
obrimMarkerSuccessTime = "SUCCESS_TIME_MARKER_GENERATED"
|
|
||||||
obrimMarkerSuccessRandom = "SUCCESS_RANDOM_MARKER_GENERATED"
|
|
||||||
obrimMarkerSuccessEncoded = "SUCCESS_ENCODED_MARKER_GENERATED"
|
|
||||||
|
|
||||||
// Marker failure codes.
|
|
||||||
obrimMarkerFailureInvalidType = "FAILURE_INVALID_TYPE"
|
|
||||||
obrimMarkerFailureInvalidConfig = "FAILURE_INVALID_CONFIG"
|
|
||||||
obrimMarkerFailureInvalidEpoch = "FAILURE_INVALID_EPOCH"
|
|
||||||
obrimMarkerFailureInvalidInstance = "FAILURE_INVALID_INSTANCE"
|
|
||||||
obrimMarkerFailureInvalidLength = "FAILURE_INVALID_LENGTH"
|
|
||||||
obrimMarkerFailureInvalidCharset = "FAILURE_INVALID_CHARSET"
|
|
||||||
obrimMarkerFailureEmptySource = "FAILURE_EMPTY_SOURCE"
|
|
||||||
obrimMarkerFailureInvalidEncodingConfig = "FAILURE_INVALID_ENCODING_CONFIG"
|
|
||||||
obrimMarkerFailureGenerationError = "FAILURE_GENERATION_ERROR"
|
|
||||||
)
|
|
||||||
|
|
||||||
type obrimMarkerOutput struct {
|
|
||||||
Status bool `json:"status"`
|
|
||||||
Code string `json:"code"`
|
|
||||||
Payload any `json:"payload"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type obrimMarkerTimePayload struct {
|
|
||||||
Marker string `json:"marker"`
|
|
||||||
Epoch int64 `json:"epoch"`
|
|
||||||
Instance string `json:"instance"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type obrimMarkerRandomPayload struct {
|
|
||||||
Marker string `json:"marker"`
|
|
||||||
Length int `json:"length"`
|
|
||||||
Charset string `json:"charset"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type obrimMarkerEncodedPayload struct {
|
|
||||||
Marker string `json:"marker"`
|
|
||||||
Source string `json:"source"`
|
|
||||||
Length int `json:"length"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type obrimMarkerTimeConfig struct {
|
|
||||||
Epoch int64
|
|
||||||
Instance string
|
|
||||||
}
|
|
||||||
|
|
||||||
type obrimMarkerRandomConfig struct {
|
|
||||||
Length int
|
|
||||||
Charset string
|
|
||||||
}
|
|
||||||
|
|
||||||
type obrimMarkerEncodedConfig struct {
|
|
||||||
Data string
|
|
||||||
Length int
|
|
||||||
Charset string
|
|
||||||
Salt string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ObrimMarker generates a marker using the requested generation strategy.
|
|
||||||
func ObrimMarker(typeName string, config map[string]any) map[string]any {
|
|
||||||
if code := obrimMarkerValidateInput(typeName, config); code != "" {
|
|
||||||
return obrimMarkerBuildOutput(false, code, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
payload, code := obrimMarkerRouteRequest(typeName, config)
|
|
||||||
if code != "" {
|
|
||||||
return obrimMarkerBuildOutput(false, code, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimMarkerBuildOutput(true, code, payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerValidateInput validates the requested marker type and configuration.
|
|
||||||
func obrimMarkerValidateInput(typeName string, config map[string]any) string {
|
|
||||||
if config == nil {
|
|
||||||
return obrimMarkerFailureInvalidConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
switch typeName {
|
|
||||||
case obrimMarkerTypeTime:
|
|
||||||
if code := obrimMarkerValidateTime(config); code != "" {
|
|
||||||
return code
|
|
||||||
}
|
|
||||||
case obrimMarkerTypeRandom:
|
|
||||||
if code := obrimMarkerValidateRandom(config); code != "" {
|
|
||||||
return code
|
|
||||||
}
|
|
||||||
case obrimMarkerTypeEncoded:
|
|
||||||
if code := obrimMarkerValidateEncoded(config); code != "" {
|
|
||||||
return code
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return obrimMarkerFailureInvalidType
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerRouteRequest routes the request to its type-specific workflow.
|
|
||||||
func obrimMarkerRouteRequest(typeName string, config map[string]any) (any, string) {
|
|
||||||
switch typeName {
|
|
||||||
case obrimMarkerTypeTime:
|
|
||||||
return obrimMarkerTime(config)
|
|
||||||
case obrimMarkerTypeRandom:
|
|
||||||
return obrimMarkerRandom(config)
|
|
||||||
case obrimMarkerTypeEncoded:
|
|
||||||
return obrimMarkerEncoded(config)
|
|
||||||
default:
|
|
||||||
return nil, obrimMarkerFailureInvalidType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerBuildOutput builds the standardized utility output.
|
|
||||||
func obrimMarkerBuildOutput(status bool, code string, payload any) map[string]any {
|
|
||||||
return map[string]any{
|
|
||||||
"status": status,
|
|
||||||
"code": code,
|
|
||||||
"payload": payload,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerTime executes the time marker workflow.
|
|
||||||
func obrimMarkerTime(config map[string]any) (any, string) {
|
|
||||||
markerConfig, code := obrimMarkerTimeConfig(config)
|
|
||||||
if code != "" {
|
|
||||||
return nil, code
|
|
||||||
}
|
|
||||||
|
|
||||||
marker, code := obrimMarkerTimeGenerate(markerConfig)
|
|
||||||
if code != "" {
|
|
||||||
return nil, code
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimMarkerTimePayload{
|
|
||||||
Marker: marker,
|
|
||||||
Epoch: markerConfig.Epoch,
|
|
||||||
Instance: markerConfig.Instance,
|
|
||||||
}, obrimMarkerSuccessTime
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerValidateTime validates time marker configuration.
|
|
||||||
func obrimMarkerValidateTime(config map[string]any) string {
|
|
||||||
epoch := obrimMarkerDefaultEpoch
|
|
||||||
if value, exists := config["epoch"]; exists {
|
|
||||||
parsed, ok := obrimMarkerInt64(value)
|
|
||||||
if !ok || parsed < 0 {
|
|
||||||
return obrimMarkerFailureInvalidEpoch
|
|
||||||
}
|
|
||||||
epoch = parsed
|
|
||||||
}
|
|
||||||
|
|
||||||
if epoch > time.Now().UnixNano() {
|
|
||||||
return obrimMarkerFailureInvalidEpoch
|
|
||||||
}
|
|
||||||
|
|
||||||
instance, exists := config["instance"]
|
|
||||||
if !exists {
|
|
||||||
return obrimMarkerFailureInvalidInstance
|
|
||||||
}
|
|
||||||
|
|
||||||
instanceValue, ok := instance.(string)
|
|
||||||
if !ok || strings.TrimSpace(instanceValue) == "" {
|
|
||||||
return obrimMarkerFailureInvalidInstance
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerTimeConfig builds the normalized time marker configuration.
|
|
||||||
func obrimMarkerTimeConfig(config map[string]any) (obrimMarkerTimeConfig, string) {
|
|
||||||
epoch := obrimMarkerDefaultEpoch
|
|
||||||
if value, exists := config["epoch"]; exists {
|
|
||||||
parsed, ok := obrimMarkerInt64(value)
|
|
||||||
if !ok || parsed < 0 || parsed > time.Now().UnixNano() {
|
|
||||||
return obrimMarkerTimeConfig{}, obrimMarkerFailureInvalidEpoch
|
|
||||||
}
|
|
||||||
epoch = parsed
|
|
||||||
}
|
|
||||||
|
|
||||||
instance, ok := config["instance"].(string)
|
|
||||||
if !ok || strings.TrimSpace(instance) == "" {
|
|
||||||
return obrimMarkerTimeConfig{}, obrimMarkerFailureInvalidInstance
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimMarkerTimeConfig{
|
|
||||||
Epoch: epoch,
|
|
||||||
Instance: strings.TrimSpace(instance),
|
|
||||||
}, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerTimeGenerate generates a distributed time-based marker.
|
|
||||||
func obrimMarkerTimeGenerate(config obrimMarkerTimeConfig) (string, string) {
|
|
||||||
now := time.Now().UnixNano()
|
|
||||||
elapsed := now - config.Epoch
|
|
||||||
|
|
||||||
if elapsed < 0 {
|
|
||||||
return "", obrimMarkerFailureInvalidEpoch
|
|
||||||
}
|
|
||||||
|
|
||||||
marker := fmt.Sprintf(
|
|
||||||
"%x-%s",
|
|
||||||
elapsed,
|
|
||||||
config.Instance,
|
|
||||||
)
|
|
||||||
|
|
||||||
return marker, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerRandom executes the random marker workflow.
|
|
||||||
func obrimMarkerRandom(config map[string]any) (any, string) {
|
|
||||||
markerConfig, code := obrimMarkerRandomConfig(config)
|
|
||||||
if code != "" {
|
|
||||||
return nil, code
|
|
||||||
}
|
|
||||||
|
|
||||||
marker, code := obrimMarkerRandomGenerate(markerConfig)
|
|
||||||
if code != "" {
|
|
||||||
return nil, code
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimMarkerRandomPayload{
|
|
||||||
Marker: marker,
|
|
||||||
Length: markerConfig.Length,
|
|
||||||
Charset: markerConfig.Charset,
|
|
||||||
}, obrimMarkerSuccessRandom
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerValidateRandom validates random marker configuration.
|
|
||||||
func obrimMarkerValidateRandom(config map[string]any) string {
|
|
||||||
length := obrimMarkerDefaultLength
|
|
||||||
if value, exists := config["length"]; exists {
|
|
||||||
parsed, ok := obrimMarkerInt(value)
|
|
||||||
if !ok || parsed <= 0 {
|
|
||||||
return obrimMarkerFailureInvalidLength
|
|
||||||
}
|
|
||||||
length = parsed
|
|
||||||
}
|
|
||||||
|
|
||||||
if length <= 0 {
|
|
||||||
return obrimMarkerFailureInvalidLength
|
|
||||||
}
|
|
||||||
|
|
||||||
charset := obrimMarkerDefaultCharset
|
|
||||||
if value, exists := config["charset"]; exists {
|
|
||||||
parsed, ok := value.(string)
|
|
||||||
if !ok || parsed == "" {
|
|
||||||
return obrimMarkerFailureInvalidCharset
|
|
||||||
}
|
|
||||||
charset = parsed
|
|
||||||
}
|
|
||||||
|
|
||||||
if charset == "" {
|
|
||||||
return obrimMarkerFailureInvalidCharset
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerRandomConfig builds the normalized random marker configuration.
|
|
||||||
func obrimMarkerRandomConfig(config map[string]any) (obrimMarkerRandomConfig, string) {
|
|
||||||
length := obrimMarkerDefaultLength
|
|
||||||
if value, exists := config["length"]; exists {
|
|
||||||
parsed, ok := obrimMarkerInt(value)
|
|
||||||
if !ok || parsed <= 0 {
|
|
||||||
return obrimMarkerRandomConfig{}, obrimMarkerFailureInvalidLength
|
|
||||||
}
|
|
||||||
length = parsed
|
|
||||||
}
|
|
||||||
|
|
||||||
charset := obrimMarkerDefaultCharset
|
|
||||||
if value, exists := config["charset"]; exists {
|
|
||||||
parsed, ok := value.(string)
|
|
||||||
if !ok || parsed == "" {
|
|
||||||
return obrimMarkerRandomConfig{}, obrimMarkerFailureInvalidCharset
|
|
||||||
}
|
|
||||||
charset = parsed
|
|
||||||
}
|
|
||||||
|
|
||||||
if charset == "" {
|
|
||||||
return obrimMarkerRandomConfig{}, obrimMarkerFailureInvalidCharset
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimMarkerRandomConfig{
|
|
||||||
Length: length,
|
|
||||||
Charset: charset,
|
|
||||||
}, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerRandomGenerate generates a cryptographically secure random marker.
|
|
||||||
func obrimMarkerRandomGenerate(config obrimMarkerRandomConfig) (string, string) {
|
|
||||||
characters := []rune(config.Charset)
|
|
||||||
if len(characters) == 0 {
|
|
||||||
return "", obrimMarkerFailureInvalidCharset
|
|
||||||
}
|
|
||||||
|
|
||||||
randomBytes := make([]byte, config.Length)
|
|
||||||
if _, err := rand.Read(randomBytes); err != nil {
|
|
||||||
return "", obrimMarkerFailureGenerationError
|
|
||||||
}
|
|
||||||
|
|
||||||
marker := make([]rune, config.Length)
|
|
||||||
for index := range marker {
|
|
||||||
marker[index] = characters[int(randomBytes[index])%len(characters)]
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(marker), ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerEncoded executes the encoded marker workflow.
|
|
||||||
func obrimMarkerEncoded(config map[string]any) (any, string) {
|
|
||||||
markerConfig, code := obrimMarkerEncodedConfig(config)
|
|
||||||
if code != "" {
|
|
||||||
return nil, code
|
|
||||||
}
|
|
||||||
|
|
||||||
marker, code := obrimMarkerEncodedGenerate(markerConfig)
|
|
||||||
if code != "" {
|
|
||||||
return nil, code
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimMarkerEncodedPayload{
|
|
||||||
Marker: marker,
|
|
||||||
Source: markerConfig.Data,
|
|
||||||
Length: markerConfig.Length,
|
|
||||||
}, obrimMarkerSuccessEncoded
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerValidateEncoded validates encoded marker configuration.
|
|
||||||
func obrimMarkerValidateEncoded(config map[string]any) string {
|
|
||||||
data, exists := config["data"]
|
|
||||||
if !exists {
|
|
||||||
return obrimMarkerFailureEmptySource
|
|
||||||
}
|
|
||||||
|
|
||||||
dataValue, ok := data.(string)
|
|
||||||
if !ok || strings.TrimSpace(dataValue) == "" {
|
|
||||||
return obrimMarkerFailureEmptySource
|
|
||||||
}
|
|
||||||
|
|
||||||
length := obrimMarkerDefaultLength
|
|
||||||
if value, exists := config["length"]; exists {
|
|
||||||
parsed, ok := obrimMarkerInt(value)
|
|
||||||
if !ok || parsed <= 0 {
|
|
||||||
return obrimMarkerFailureInvalidEncodingConfig
|
|
||||||
}
|
|
||||||
length = parsed
|
|
||||||
}
|
|
||||||
|
|
||||||
if length <= 0 {
|
|
||||||
return obrimMarkerFailureInvalidEncodingConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
charset := obrimMarkerDefaultCharset
|
|
||||||
if value, exists := config["charset"]; exists {
|
|
||||||
parsed, ok := value.(string)
|
|
||||||
if !ok || parsed == "" {
|
|
||||||
return obrimMarkerFailureInvalidEncodingConfig
|
|
||||||
}
|
|
||||||
charset = parsed
|
|
||||||
}
|
|
||||||
|
|
||||||
if charset == "" {
|
|
||||||
return obrimMarkerFailureInvalidEncodingConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
if value, exists := config["salt"]; exists {
|
|
||||||
if _, ok := value.(string); !ok {
|
|
||||||
return obrimMarkerFailureInvalidEncodingConfig
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = length
|
|
||||||
_ = charset
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerEncodedConfig builds the normalized encoded marker configuration.
|
|
||||||
func obrimMarkerEncodedConfig(config map[string]any) (obrimMarkerEncodedConfig, string) {
|
|
||||||
data, ok := config["data"].(string)
|
|
||||||
if !ok || strings.TrimSpace(data) == "" {
|
|
||||||
return obrimMarkerEncodedConfig{}, obrimMarkerFailureEmptySource
|
|
||||||
}
|
|
||||||
|
|
||||||
length := obrimMarkerDefaultLength
|
|
||||||
if value, exists := config["length"]; exists {
|
|
||||||
parsed, valid := obrimMarkerInt(value)
|
|
||||||
if !valid || parsed <= 0 {
|
|
||||||
return obrimMarkerEncodedConfig{}, obrimMarkerFailureInvalidEncodingConfig
|
|
||||||
}
|
|
||||||
length = parsed
|
|
||||||
}
|
|
||||||
|
|
||||||
charset := obrimMarkerDefaultCharset
|
|
||||||
if value, exists := config["charset"]; exists {
|
|
||||||
parsed, valid := value.(string)
|
|
||||||
if !valid || parsed == "" {
|
|
||||||
return obrimMarkerEncodedConfig{}, obrimMarkerFailureInvalidEncodingConfig
|
|
||||||
}
|
|
||||||
charset = parsed
|
|
||||||
}
|
|
||||||
|
|
||||||
salt := ""
|
|
||||||
if value, exists := config["salt"]; exists {
|
|
||||||
parsed, valid := value.(string)
|
|
||||||
if !valid {
|
|
||||||
return obrimMarkerEncodedConfig{}, obrimMarkerFailureInvalidEncodingConfig
|
|
||||||
}
|
|
||||||
salt = parsed
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimMarkerEncodedConfig{
|
|
||||||
Data: data,
|
|
||||||
Length: length,
|
|
||||||
Charset: charset,
|
|
||||||
Salt: salt,
|
|
||||||
}, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerEncodedGenerate generates a deterministic encoded marker.
|
|
||||||
func obrimMarkerEncodedGenerate(config obrimMarkerEncodedConfig) (string, string) {
|
|
||||||
characters := []rune(config.Charset)
|
|
||||||
if len(characters) == 0 {
|
|
||||||
return "", obrimMarkerFailureInvalidEncodingConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
source := config.Data + config.Salt
|
|
||||||
digest := sha256.Sum256([]byte(source))
|
|
||||||
|
|
||||||
seed := binary.BigEndian.Uint64(digest[:8])
|
|
||||||
marker := make([]rune, config.Length)
|
|
||||||
|
|
||||||
for index := range marker {
|
|
||||||
seed = seed*6364136223846793005 + 1442695040888963407
|
|
||||||
marker[index] = characters[int(seed%uint64(len(characters)))]
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(marker), ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerInt converts a supported value to int.
|
|
||||||
func obrimMarkerInt(value any) (int, bool) {
|
|
||||||
switch parsed := value.(type) {
|
|
||||||
case int:
|
|
||||||
return parsed, true
|
|
||||||
case int8:
|
|
||||||
return int(parsed), true
|
|
||||||
case int16:
|
|
||||||
return int(parsed), true
|
|
||||||
case int32:
|
|
||||||
return int(parsed), true
|
|
||||||
case int64:
|
|
||||||
return int(parsed), true
|
|
||||||
case uint:
|
|
||||||
return int(parsed), true
|
|
||||||
case uint8:
|
|
||||||
return int(parsed), true
|
|
||||||
case uint16:
|
|
||||||
return int(parsed), true
|
|
||||||
case uint32:
|
|
||||||
return int(parsed), true
|
|
||||||
case uint64:
|
|
||||||
if uint64(int(parsed)) != parsed {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
return int(parsed), true
|
|
||||||
case float32:
|
|
||||||
if float32(int(parsed)) != parsed {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
return int(parsed), true
|
|
||||||
case float64:
|
|
||||||
if float64(int(parsed)) != parsed {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
return int(parsed), true
|
|
||||||
case string:
|
|
||||||
converted, err := strconv.Atoi(parsed)
|
|
||||||
if err != nil {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
return converted, true
|
|
||||||
default:
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimMarkerInt64 converts a supported value to int64.
|
|
||||||
func obrimMarkerInt64(value any) (int64, bool) {
|
|
||||||
switch parsed := value.(type) {
|
|
||||||
case int:
|
|
||||||
return int64(parsed), true
|
|
||||||
case int8:
|
|
||||||
return int64(parsed), true
|
|
||||||
case int16:
|
|
||||||
return int64(parsed), true
|
|
||||||
case int32:
|
|
||||||
return int64(parsed), true
|
|
||||||
case int64:
|
|
||||||
return parsed, true
|
|
||||||
case uint:
|
|
||||||
if uint64(int64(parsed)) != uint64(parsed) {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
return int64(parsed), true
|
|
||||||
case uint8:
|
|
||||||
return int64(parsed), true
|
|
||||||
case uint16:
|
|
||||||
return int64(parsed), true
|
|
||||||
case uint32:
|
|
||||||
return int64(parsed), true
|
|
||||||
case uint64:
|
|
||||||
if parsed > uint64(^uint64(0)>>1) {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
return int64(parsed), true
|
|
||||||
case float32:
|
|
||||||
if float32(int64(parsed)) != parsed {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
return int64(parsed), true
|
|
||||||
case float64:
|
|
||||||
if float64(int64(parsed)) != parsed {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
return int64(parsed), true
|
|
||||||
case string:
|
|
||||||
converted, err := strconv.ParseInt(parsed, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
return converted, true
|
|
||||||
default:
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,375 +0,0 @@
|
|||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| 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,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@ -1,400 +0,0 @@
|
|||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Description
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Name:
|
|
||||||
| - Retriever
|
|
||||||
|
|
|
||||||
| Purpose:
|
|
||||||
| - Retrieve data from supported resource handlers through a unified
|
|
||||||
| retrieval interface.
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Instruction
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Guideline:
|
|
||||||
| - Use for retrieving data from registered JSON resource handlers.
|
|
||||||
| - Use type-based dispatching to route retrieval requests.
|
|
||||||
| - Use resource retrieval to obtain a complete JSON resource.
|
|
||||||
| - Use path retrieval to obtain a specific nested value.
|
|
||||||
| - Use fields retrieval to obtain multiple nested values.
|
|
||||||
| - Do not use path and fields retrieval together.
|
|
||||||
|
|
|
||||||
| Example:
|
|
||||||
| - ObrimRetriever("json", map[string]any{
|
|
||||||
| "resource": "metadata",
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
| - ObrimRetriever("json", map[string]any{
|
|
||||||
| "resource": "metadata",
|
|
||||||
| "path": "app.name",
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
| - ObrimRetriever("json", map[string]any{
|
|
||||||
| "resource": "metadata",
|
|
||||||
| "fields": []any{"app.name", "app.version"},
|
|
||||||
| })
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Credit
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Contributor:
|
|
||||||
| - Rajon Ahmed
|
|
||||||
| - Blockonite
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
package retriever
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Utility type identifiers define supported retriever input types.
|
|
||||||
obrimRetrieverTypeJSON = "json"
|
|
||||||
|
|
||||||
// Retriever result codes define successful execution outcomes.
|
|
||||||
obrimRetrieverSuccessResource = "SUCCESS_RESOURCE_RETRIEVED"
|
|
||||||
obrimRetrieverSuccessPath = "SUCCESS_PATH_RETRIEVED"
|
|
||||||
obrimRetrieverSuccessFields = "SUCCESS_FIELDS_RETRIEVED"
|
|
||||||
|
|
||||||
// Retriever result codes define failed execution outcomes.
|
|
||||||
obrimRetrieverFailureInvalidType = "FAILURE_INVALID_TYPE"
|
|
||||||
obrimRetrieverFailureInvalidConfig = "FAILURE_INVALID_CONFIG"
|
|
||||||
obrimRetrieverFailureResourceRequired = "FAILURE_RESOURCE_REQUIRED"
|
|
||||||
obrimRetrieverFailurePathAndFields = "FAILURE_PATH_AND_FIELDS"
|
|
||||||
obrimRetrieverFailureInvalidPath = "FAILURE_INVALID_PATH"
|
|
||||||
obrimRetrieverFailureInvalidFields = "FAILURE_INVALID_FIELDS"
|
|
||||||
obrimRetrieverFailureResourceNotFound = "FAILURE_RESOURCE_NOT_FOUND"
|
|
||||||
obrimRetrieverFailureHandlerFailed = "FAILURE_HANDLER_FAILED"
|
|
||||||
obrimRetrieverFailurePathNotFound = "FAILURE_PATH_NOT_FOUND"
|
|
||||||
obrimRetrieverFailureFieldNotFound = "FAILURE_FIELD_NOT_FOUND"
|
|
||||||
obrimRetrieverFailureUnsupportedConfig = "FAILURE_UNSUPPORTED_CONFIG"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// obrimRetrieverJsonHandlers stores registered JSON resource handlers.
|
|
||||||
obrimRetrieverJsonHandlers = map[string]func() map[string]any{}
|
|
||||||
|
|
||||||
// obrimRetrieverJsonHandlersMutex protects the JSON handler registry.
|
|
||||||
obrimRetrieverJsonHandlersMutex sync.RWMutex
|
|
||||||
)
|
|
||||||
|
|
||||||
// ObrimRetrieverResult represents the standardized retriever execution output.
|
|
||||||
type ObrimRetrieverResult struct {
|
|
||||||
Status bool `json:"status"`
|
|
||||||
Code string `json:"code"`
|
|
||||||
Payload map[string]any `json:"payload"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ObrimRetriever retrieves data from a supported resource handler.
|
|
||||||
func ObrimRetriever(
|
|
||||||
typ string,
|
|
||||||
config map[string]any,
|
|
||||||
) map[string]any {
|
|
||||||
if code := obrimRetrieverValidateInput(typ, config); code != "" {
|
|
||||||
return obrimRetrieverBuildOutput(false, code, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimRetrieverRouteRequest(typ, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ObrimRetrieverJsonRegister registers a JSON resource handler.
|
|
||||||
func ObrimRetrieverJsonRegister(
|
|
||||||
resource string,
|
|
||||||
handler func() map[string]any,
|
|
||||||
) {
|
|
||||||
if strings.TrimSpace(resource) == "" || handler == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
obrimRetrieverJsonHandlersMutex.Lock()
|
|
||||||
defer obrimRetrieverJsonHandlersMutex.Unlock()
|
|
||||||
|
|
||||||
obrimRetrieverJsonHandlers[resource] = handler
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimRetrieverValidateInput validates the retriever type and configuration.
|
|
||||||
func obrimRetrieverValidateInput(
|
|
||||||
typ string,
|
|
||||||
config map[string]any,
|
|
||||||
) string {
|
|
||||||
switch typ {
|
|
||||||
case obrimRetrieverTypeJSON:
|
|
||||||
return obrimRetrieverValidateJSONConfig(config)
|
|
||||||
default:
|
|
||||||
return obrimRetrieverFailureInvalidType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimRetrieverValidateJSONConfig validates JSON retriever configuration.
|
|
||||||
func obrimRetrieverValidateJSONConfig(config map[string]any) string {
|
|
||||||
if config == nil {
|
|
||||||
return obrimRetrieverFailureInvalidConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
resourceValue, exists := config["resource"]
|
|
||||||
if !exists {
|
|
||||||
return obrimRetrieverFailureResourceRequired
|
|
||||||
}
|
|
||||||
|
|
||||||
resource, ok := resourceValue.(string)
|
|
||||||
if !ok || strings.TrimSpace(resource) == "" {
|
|
||||||
return obrimRetrieverFailureResourceRequired
|
|
||||||
}
|
|
||||||
|
|
||||||
_, hasPath := config["path"]
|
|
||||||
_, hasFields := config["fields"]
|
|
||||||
|
|
||||||
if hasPath && hasFields {
|
|
||||||
return obrimRetrieverFailurePathAndFields
|
|
||||||
}
|
|
||||||
|
|
||||||
for key := range config {
|
|
||||||
switch key {
|
|
||||||
case "resource", "path", "fields":
|
|
||||||
default:
|
|
||||||
return obrimRetrieverFailureUnsupportedConfig
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if hasPath {
|
|
||||||
path, ok := config["path"].(string)
|
|
||||||
if !ok || strings.TrimSpace(path) == "" {
|
|
||||||
return obrimRetrieverFailureInvalidPath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if hasFields {
|
|
||||||
fields, ok := config["fields"].([]string)
|
|
||||||
if !ok || len(fields) == 0 {
|
|
||||||
return obrimRetrieverFailureInvalidFields
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, field := range fields {
|
|
||||||
if strings.TrimSpace(field) == "" {
|
|
||||||
return obrimRetrieverFailureInvalidFields
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimRetrieverRouteRequest routes the request to its type-specific entry function.
|
|
||||||
func obrimRetrieverRouteRequest(
|
|
||||||
typ string,
|
|
||||||
config map[string]any,
|
|
||||||
) map[string]any {
|
|
||||||
switch typ {
|
|
||||||
case obrimRetrieverTypeJSON:
|
|
||||||
return obrimRetrieverJson(config)
|
|
||||||
default:
|
|
||||||
return obrimRetrieverBuildOutput(
|
|
||||||
false,
|
|
||||||
obrimRetrieverFailureInvalidType,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimRetrieverBuildOutput builds the standardized retriever output.
|
|
||||||
func obrimRetrieverBuildOutput(
|
|
||||||
status bool,
|
|
||||||
code string,
|
|
||||||
payload map[string]any,
|
|
||||||
) map[string]any {
|
|
||||||
if !status {
|
|
||||||
payload = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return map[string]any{
|
|
||||||
"status": status,
|
|
||||||
"code": code,
|
|
||||||
"payload": payload,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimRetrieverJson processes a JSON retrieval request.
|
|
||||||
func obrimRetrieverJson(config map[string]any) map[string]any {
|
|
||||||
resource := config["resource"].(string)
|
|
||||||
|
|
||||||
data, ok := obrimRetrieverJsonHandler(resource)
|
|
||||||
if !ok {
|
|
||||||
return obrimRetrieverBuildOutput(
|
|
||||||
false,
|
|
||||||
obrimRetrieverFailureResourceNotFound,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if pathValue, exists := config["path"]; exists {
|
|
||||||
path := pathValue.(string)
|
|
||||||
|
|
||||||
value, ok := obrimRetrieverJsonPath(data, path)
|
|
||||||
if !ok {
|
|
||||||
return obrimRetrieverBuildOutput(
|
|
||||||
false,
|
|
||||||
obrimRetrieverFailurePathNotFound,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimRetrieverBuildOutput(
|
|
||||||
true,
|
|
||||||
obrimRetrieverSuccessPath,
|
|
||||||
map[string]any{
|
|
||||||
"data": value,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if fieldsValue, exists := config["fields"]; exists {
|
|
||||||
fields := fieldsValue.([]string)
|
|
||||||
|
|
||||||
values, ok := obrimRetrieverJsonFields(data, fields)
|
|
||||||
if !ok {
|
|
||||||
return obrimRetrieverBuildOutput(
|
|
||||||
false,
|
|
||||||
obrimRetrieverFailureFieldNotFound,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimRetrieverBuildOutput(
|
|
||||||
true,
|
|
||||||
obrimRetrieverSuccessFields,
|
|
||||||
map[string]any{
|
|
||||||
"data": values,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return obrimRetrieverBuildOutput(
|
|
||||||
true,
|
|
||||||
obrimRetrieverSuccessResource,
|
|
||||||
map[string]any{
|
|
||||||
"data": obrimRetrieverJsonResource(data),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimRetrieverJsonHandler locates and invokes a registered JSON handler.
|
|
||||||
func obrimRetrieverJsonHandler(
|
|
||||||
resource string,
|
|
||||||
) (map[string]any, bool) {
|
|
||||||
obrimRetrieverJsonHandlersMutex.RLock()
|
|
||||||
handler, exists := obrimRetrieverJsonHandlers[resource]
|
|
||||||
obrimRetrieverJsonHandlersMutex.RUnlock()
|
|
||||||
|
|
||||||
if !exists || handler == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
data := handler()
|
|
||||||
if data == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
return data, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimRetrieverJsonResource returns the complete JSON resource payload.
|
|
||||||
func obrimRetrieverJsonResource(
|
|
||||||
resource map[string]any,
|
|
||||||
) map[string]any {
|
|
||||||
return resource
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimRetrieverJsonPath retrieves a value using a dot-notation path.
|
|
||||||
func obrimRetrieverJsonPath(
|
|
||||||
resource map[string]any,
|
|
||||||
path string,
|
|
||||||
) (any, bool) {
|
|
||||||
parts := strings.Split(path, ".")
|
|
||||||
if len(parts) == 0 {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
var current any = resource
|
|
||||||
|
|
||||||
for _, part := range parts {
|
|
||||||
if part == "" {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
switch value := current.(type) {
|
|
||||||
case map[string]any:
|
|
||||||
next, exists := value[part]
|
|
||||||
if !exists {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
current = next
|
|
||||||
|
|
||||||
case []any:
|
|
||||||
index := -1
|
|
||||||
|
|
||||||
for i, item := range value {
|
|
||||||
if part == strings.TrimSpace(part) {
|
|
||||||
var parsed int
|
|
||||||
if _, err := fmt.Sscanf(part, "%d", &parsed); err == nil {
|
|
||||||
index = parsed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if index >= 0 {
|
|
||||||
_ = item
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if index < 0 || index >= len(value) {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
current = value[index]
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return current, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimRetrieverJsonFields retrieves multiple values using field selection.
|
|
||||||
func obrimRetrieverJsonFields(
|
|
||||||
resource map[string]any,
|
|
||||||
fields []string,
|
|
||||||
) (map[string]any, bool) {
|
|
||||||
values := make(map[string]any, len(fields))
|
|
||||||
|
|
||||||
for _, field := range fields {
|
|
||||||
value, ok := obrimRetrieverJsonPath(resource, field)
|
|
||||||
if !ok {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
values[field] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
return values, true
|
|
||||||
}
|
|
||||||
@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Description
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Name:
|
|
||||||
| - Status
|
|
||||||
|
|
|
||||||
| Purpose:
|
|
||||||
| - Provide a framework-level CLI status utility that standardizes
|
|
||||||
| terminal message presentation using semantic labels and visual
|
|
||||||
| indicators to ensure consistent output across all softwares.
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Instruction
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Guideline:
|
|
||||||
| - Accept a semantic status category and human-readable message.
|
|
||||||
| - Use INFO, WARNING, SUCCESS, and ERROR as supported status labels.
|
|
||||||
| - Treat unsupported, empty, or invalid labels as INFO.
|
|
||||||
| - Emit exactly one standardized terminal message per invocation.
|
|
||||||
|
|
|
||||||
| Example:
|
|
||||||
| - ObrimStatus(
|
|
||||||
| "INFO",
|
|
||||||
| "Application started successfully.",
|
|
||||||
| )
|
|
||||||
|
|
|
||||||
| - ObrimStatus(
|
|
||||||
| "WARNING",
|
|
||||||
| "Configuration file not found.",
|
|
||||||
| )
|
|
||||||
|
|
|
||||||
| - ObrimStatus(
|
|
||||||
| "SUCCESS",
|
|
||||||
| "Installation completed.",
|
|
||||||
| )
|
|
||||||
|
|
|
||||||
| - ObrimStatus(
|
|
||||||
| "ERROR",
|
|
||||||
| "Unable to connect to the server.",
|
|
||||||
| )
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Credit
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Contributor:
|
|
||||||
| - Rajon Ahmed
|
|
||||||
| - Blockonite
|
|
||||||
|
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
package status
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ObrimStatus emits a standardized terminal message.
|
|
||||||
func ObrimStatus(label, message string) {
|
|
||||||
normalizedLabel, normalizedMessage := obrimStatusValidateInput(label, message)
|
|
||||||
output := obrimStatusBuildOutput(obrimStatusFormatMessage(normalizedLabel, normalizedMessage))
|
|
||||||
|
|
||||||
fmt.Print(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimStatusValidateInput normalizes and validates the status label and message.
|
|
||||||
func obrimStatusValidateInput(label, message string) (string, string) {
|
|
||||||
normalizedLabel := strings.ToUpper(strings.TrimSpace(label))
|
|
||||||
normalizedMessage := strings.TrimSpace(message)
|
|
||||||
|
|
||||||
switch normalizedLabel {
|
|
||||||
case "INFO", "WARNING", "SUCCESS", "ERROR":
|
|
||||||
default:
|
|
||||||
normalizedLabel = "INFO"
|
|
||||||
}
|
|
||||||
|
|
||||||
return normalizedLabel, normalizedMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimStatusFormatMessage formats the status label and message with its visual indicator.
|
|
||||||
func obrimStatusFormatMessage(label, message string) string {
|
|
||||||
var indicator string
|
|
||||||
|
|
||||||
switch label {
|
|
||||||
case "WARNING":
|
|
||||||
indicator = "!"
|
|
||||||
case "SUCCESS":
|
|
||||||
indicator = "✓"
|
|
||||||
case "ERROR":
|
|
||||||
indicator = "✗"
|
|
||||||
default:
|
|
||||||
indicator = "ℹ"
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("[%s %s] %s\n", indicator, label, message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// obrimStatusBuildOutput builds the final terminal message.
|
|
||||||
func obrimStatusBuildOutput(message string) string {
|
|
||||||
return message
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user