480 lines
11 KiB
Go
480 lines
11 KiB
Go
/*
|
|
|--------------------------------------------------------------------------
|
|
| Metadata
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Name:
|
|
| - Marker
|
|
|
|
|
| Purpose:
|
|
| - Provide a unified utility for generating unique markers through
|
|
| time-based, random, and encoded generation strategies using a
|
|
| single standardized entry point.
|
|
|
|
|
| Guideline:
|
|
| - Use ObrimMarker() as the primary entry point for all marker
|
|
| generation operations.
|
|
| - Provide a supported marker type and the required configuration
|
|
| values for the selected generation strategy.
|
|
| - Consume responses through the standardized status, code, and
|
|
| payload structure.
|
|
| - Validate response status before accessing payload data.
|
|
| - Use time markers for distributed uniqueness requirements.
|
|
| - Use random markers for collision-resistant identifier generation.
|
|
| - Use encoded markers for deterministic identifier generation from
|
|
| source data.
|
|
|
|
|
| Example:
|
|
| - ObrimMarker("time", map[string]any{
|
|
| "epoch": 1704067200000,
|
|
| "instance": "NODE01",
|
|
| })
|
|
|
|
|
| - ObrimMarker("random", map[string]any{
|
|
| "length": 32,
|
|
| "charset": "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
|
|
| })
|
|
|
|
|
| - ObrimMarker("encoded", map[string]any{
|
|
| "data": "customer-1001",
|
|
| "length": 24,
|
|
| "salt": "obrim",
|
|
| })
|
|
|
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Credit
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Contributor:
|
|
| - Rajon Ahmed
|
|
| - Scionite
|
|
|
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
package marker
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
obrimMarkerTypeTime = "time"
|
|
obrimMarkerTypeRandom = "random"
|
|
obrimMarkerTypeEncoded = "encoded"
|
|
|
|
ObrimMarkerCodeSuccessTimeGenerated = "SUCCESS_TIME_GENERATED"
|
|
ObrimMarkerCodeSuccessRandomGenerated = "SUCCESS_RANDOM_GENERATED"
|
|
ObrimMarkerCodeSuccessEncodedGenerated = "SUCCESS_ENCODED_GENERATED"
|
|
|
|
ObrimMarkerCodeFailedUnsupportedType = "FAILED_UNSUPPORTED_TYPE"
|
|
ObrimMarkerCodeFailedMissingConfig = "FAILED_MISSING_CONFIGURATION"
|
|
ObrimMarkerCodeFailedInvalidConfig = "FAILED_INVALID_CONFIGURATION"
|
|
ObrimMarkerCodeFailedGeneration = "FAILED_GENERATION"
|
|
ObrimMarkerCodeFailedValidation = "FAILED_VALIDATION"
|
|
)
|
|
|
|
const (
|
|
obrimMarkerDefaultRandomLength = 16
|
|
obrimMarkerDefaultEncodedLength = 16
|
|
obrimMarkerDefaultCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
|
)
|
|
|
|
// ObrimMarkerResponse defines the standardized utility response.
|
|
type ObrimMarkerResponse struct {
|
|
Status bool `json:"status"`
|
|
Code string `json:"code"`
|
|
Payload map[string]any `json:"payload"`
|
|
}
|
|
|
|
// ObrimMarker routes marker generation requests and returns a standardized marker response.
|
|
func ObrimMarker(markerType string, config map[string]any) map[string]any {
|
|
obrimMarkerLog("initialization")
|
|
|
|
if !obrimMarkerValidateType(markerType) {
|
|
obrimMarkerLog("failure")
|
|
|
|
return obrimMarkerBuildResponse(
|
|
false,
|
|
ObrimMarkerCodeFailedUnsupportedType,
|
|
nil,
|
|
)
|
|
}
|
|
|
|
if config == nil {
|
|
config = map[string]any{}
|
|
}
|
|
|
|
response := obrimMarkerRoute(markerType, config)
|
|
|
|
if status, ok := response["status"].(bool); ok && status {
|
|
obrimMarkerLog("success")
|
|
} else {
|
|
obrimMarkerLog("failure")
|
|
}
|
|
|
|
return response
|
|
}
|
|
|
|
// obrimMarkerValidateType validates supported marker generation types.
|
|
func obrimMarkerValidateType(markerType string) bool {
|
|
switch strings.TrimSpace(markerType) {
|
|
case obrimMarkerTypeTime:
|
|
return true
|
|
|
|
case obrimMarkerTypeRandom:
|
|
return true
|
|
|
|
case obrimMarkerTypeEncoded:
|
|
return true
|
|
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// obrimMarkerRoute routes execution to the selected marker generation workflow.
|
|
func obrimMarkerRoute(
|
|
markerType string,
|
|
config map[string]any,
|
|
) map[string]any {
|
|
switch markerType {
|
|
case obrimMarkerTypeTime:
|
|
return obrimMarkerTime(config)
|
|
|
|
case obrimMarkerTypeRandom:
|
|
return obrimMarkerRandom(config)
|
|
|
|
case obrimMarkerTypeEncoded:
|
|
return obrimMarkerEncoded(config)
|
|
|
|
default:
|
|
return obrimMarkerBuildResponse(
|
|
false,
|
|
ObrimMarkerCodeFailedUnsupportedType,
|
|
nil,
|
|
)
|
|
}
|
|
}
|
|
|
|
// obrimMarkerBuildResponse builds standardized success and error responses.
|
|
func obrimMarkerBuildResponse(
|
|
status bool,
|
|
code string,
|
|
payload map[string]any,
|
|
) map[string]any {
|
|
return map[string]any{
|
|
"status": status,
|
|
"code": code,
|
|
"payload": payload,
|
|
}
|
|
}
|
|
|
|
// obrimMarkerTime generates time-based unique markers.
|
|
func obrimMarkerTime(config map[string]any) map[string]any {
|
|
epoch, instance, code := obrimMarkerValidateTime(config)
|
|
if code != "" {
|
|
return obrimMarkerBuildResponse(false, code, nil)
|
|
}
|
|
|
|
marker, err := obrimMarkerTimeGenerate(epoch, instance)
|
|
if err != nil {
|
|
return obrimMarkerBuildResponse(
|
|
false,
|
|
ObrimMarkerCodeFailedGeneration,
|
|
nil,
|
|
)
|
|
}
|
|
|
|
return obrimMarkerBuildResponse(
|
|
true,
|
|
ObrimMarkerCodeSuccessTimeGenerated,
|
|
map[string]any{
|
|
"marker": marker,
|
|
"epoch": epoch,
|
|
"instance": instance,
|
|
},
|
|
)
|
|
}
|
|
|
|
// obrimMarkerValidateTime validates time marker configuration parameters.
|
|
func obrimMarkerValidateTime(
|
|
config map[string]any,
|
|
) (int64, string, string) {
|
|
epochValue, epochExists := config["epoch"]
|
|
instanceValue, instanceExists := config["instance"]
|
|
|
|
if !epochExists {
|
|
return 0, "", ObrimMarkerCodeFailedMissingConfig
|
|
}
|
|
|
|
if !instanceExists {
|
|
return 0, "", ObrimMarkerCodeFailedMissingConfig
|
|
}
|
|
|
|
var epoch int64
|
|
|
|
switch value := epochValue.(type) {
|
|
case int64:
|
|
epoch = value
|
|
|
|
case int:
|
|
epoch = int64(value)
|
|
|
|
case float64:
|
|
epoch = int64(value)
|
|
|
|
default:
|
|
return 0, "", ObrimMarkerCodeFailedInvalidConfig
|
|
}
|
|
|
|
instance, ok := instanceValue.(string)
|
|
if !ok || strings.TrimSpace(instance) == "" {
|
|
return 0, "", ObrimMarkerCodeFailedInvalidConfig
|
|
}
|
|
|
|
if epoch < 0 {
|
|
return 0, "", ObrimMarkerCodeFailedInvalidConfig
|
|
}
|
|
|
|
return epoch, instance, ""
|
|
}
|
|
|
|
// obrimMarkerTimeGenerate produces the final time-based marker value.
|
|
func obrimMarkerTimeGenerate(
|
|
epoch int64,
|
|
instance string,
|
|
) (string, error) {
|
|
now := time.Now().UnixMilli()
|
|
|
|
if epoch > now {
|
|
return "", obrimMarkerError("invalid epoch")
|
|
}
|
|
|
|
return fmt.Sprintf(
|
|
"%X%s",
|
|
now-epoch,
|
|
strings.ToUpper(instance),
|
|
), nil
|
|
}
|
|
|
|
// obrimMarkerRandom generates random collision-resistant markers.
|
|
func obrimMarkerRandom(config map[string]any) map[string]any {
|
|
length, charset, code := obrimMarkerValidateRandom(config)
|
|
if code != "" {
|
|
return obrimMarkerBuildResponse(false, code, nil)
|
|
}
|
|
|
|
marker, err := obrimMarkerRandomGenerate(length, charset)
|
|
if err != nil {
|
|
return obrimMarkerBuildResponse(
|
|
false,
|
|
ObrimMarkerCodeFailedGeneration,
|
|
nil,
|
|
)
|
|
}
|
|
|
|
return obrimMarkerBuildResponse(
|
|
true,
|
|
ObrimMarkerCodeSuccessRandomGenerated,
|
|
map[string]any{
|
|
"marker": marker,
|
|
"length": length,
|
|
"charset": charset,
|
|
},
|
|
)
|
|
}
|
|
|
|
// obrimMarkerValidateRandom validates random marker configuration parameters.
|
|
func obrimMarkerValidateRandom(
|
|
config map[string]any,
|
|
) (int, string, string) {
|
|
var length = obrimMarkerDefaultRandomLength
|
|
var charset = obrimMarkerDefaultCharset
|
|
|
|
if value, exists := config["length"]; exists {
|
|
switch typedValue := value.(type) {
|
|
case int:
|
|
length = typedValue
|
|
|
|
case int64:
|
|
length = int(typedValue)
|
|
|
|
case float64:
|
|
length = int(typedValue)
|
|
|
|
default:
|
|
return 0, "", ObrimMarkerCodeFailedInvalidConfig
|
|
}
|
|
}
|
|
|
|
if value, exists := config["charset"]; exists {
|
|
typedValue, ok := value.(string)
|
|
if !ok {
|
|
return 0, "", ObrimMarkerCodeFailedInvalidConfig
|
|
}
|
|
|
|
charset = typedValue
|
|
}
|
|
|
|
if length <= 0 {
|
|
return 0, "", ObrimMarkerCodeFailedValidation
|
|
}
|
|
|
|
if strings.TrimSpace(charset) == "" {
|
|
return 0, "", ObrimMarkerCodeFailedValidation
|
|
}
|
|
|
|
return length, charset, ""
|
|
}
|
|
|
|
// obrimMarkerRandomGenerate produces the final random marker value.
|
|
func obrimMarkerRandomGenerate(
|
|
length int,
|
|
charset string,
|
|
) (string, error) {
|
|
var buffer = make([]byte, length)
|
|
var randomBuffer = make([]byte, length)
|
|
|
|
_, err := rand.Read(randomBuffer)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
for index := range buffer {
|
|
buffer[index] = charset[int(randomBuffer[index])%len(charset)]
|
|
}
|
|
|
|
return string(buffer), nil
|
|
}
|
|
|
|
// obrimMarkerEncoded generates deterministic encoded markers.
|
|
func obrimMarkerEncoded(config map[string]any) map[string]any {
|
|
data, length, charset, salt, code := obrimMarkerValidateEncoded(config)
|
|
if code != "" {
|
|
return obrimMarkerBuildResponse(false, code, nil)
|
|
}
|
|
|
|
marker, err := obrimMarkerEncodedGenerate(
|
|
data,
|
|
length,
|
|
charset,
|
|
salt,
|
|
)
|
|
if err != nil {
|
|
return obrimMarkerBuildResponse(
|
|
false,
|
|
ObrimMarkerCodeFailedGeneration,
|
|
nil,
|
|
)
|
|
}
|
|
|
|
return obrimMarkerBuildResponse(
|
|
true,
|
|
ObrimMarkerCodeSuccessEncodedGenerated,
|
|
map[string]any{
|
|
"marker": marker,
|
|
"source": data,
|
|
"length": length,
|
|
},
|
|
)
|
|
}
|
|
|
|
// obrimMarkerValidateEncoded validates encoded marker configuration parameters.
|
|
func obrimMarkerValidateEncoded(
|
|
config map[string]any,
|
|
) (string, int, string, string, string) {
|
|
dataValue, exists := config["data"]
|
|
if !exists {
|
|
return "", 0, "", "", ObrimMarkerCodeFailedMissingConfig
|
|
}
|
|
|
|
data, ok := dataValue.(string)
|
|
if !ok || strings.TrimSpace(data) == "" {
|
|
return "", 0, "", "", ObrimMarkerCodeFailedInvalidConfig
|
|
}
|
|
|
|
var length = obrimMarkerDefaultEncodedLength
|
|
var charset = obrimMarkerDefaultCharset
|
|
var salt string
|
|
|
|
if value, exists := config["length"]; exists {
|
|
switch typedValue := value.(type) {
|
|
case int:
|
|
length = typedValue
|
|
|
|
case int64:
|
|
length = int(typedValue)
|
|
|
|
case float64:
|
|
length = int(typedValue)
|
|
|
|
default:
|
|
return "", 0, "", "", ObrimMarkerCodeFailedInvalidConfig
|
|
}
|
|
}
|
|
|
|
if value, exists := config["charset"]; exists {
|
|
typedValue, ok := value.(string)
|
|
if !ok {
|
|
return "", 0, "", "", ObrimMarkerCodeFailedInvalidConfig
|
|
}
|
|
|
|
charset = typedValue
|
|
}
|
|
|
|
if value, exists := config["salt"]; exists {
|
|
typedValue, ok := value.(string)
|
|
if !ok {
|
|
return "", 0, "", "", ObrimMarkerCodeFailedInvalidConfig
|
|
}
|
|
|
|
salt = typedValue
|
|
}
|
|
|
|
if length <= 0 {
|
|
return "", 0, "", "", ObrimMarkerCodeFailedValidation
|
|
}
|
|
|
|
if strings.TrimSpace(charset) == "" {
|
|
return "", 0, "", "", ObrimMarkerCodeFailedValidation
|
|
}
|
|
|
|
return data, length, charset, salt, ""
|
|
}
|
|
|
|
// obrimMarkerEncodedGenerate produces the final encoded marker value.
|
|
func obrimMarkerEncodedGenerate(
|
|
data string,
|
|
length int,
|
|
charset string,
|
|
salt string,
|
|
) (string, error) {
|
|
var hash = sha256.Sum256([]byte(data + salt))
|
|
var output = make([]byte, length)
|
|
|
|
for index := 0; index < length; index++ {
|
|
output[index] = charset[int(hash[index%len(hash)])%len(charset)]
|
|
}
|
|
|
|
return string(output), nil
|
|
}
|
|
|
|
// obrimMarkerLog logs utility lifecycle events.
|
|
func obrimMarkerLog(event string) {
|
|
_ = event
|
|
}
|
|
|
|
// obrimMarkerError formats internal errors.
|
|
func obrimMarkerError(message string) error {
|
|
return fmt.Errorf("%s", message)
|
|
}
|