277 lines
7.0 KiB
Go
277 lines
7.0 KiB
Go
/*
|
|
|--------------------------------------------------------------------------
|
|
| Manifest
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Name:
|
|
| - datetime
|
|
|
|
|
| Purpose:
|
|
| - Retrieve and format the current date and time from either the host
|
|
| system clock or a trusted framework-managed NTP source.
|
|
|
|
|
| Guideline:
|
|
| - Use local for host system clock retrieval.
|
|
| - Use trusted for framework-managed NTP retrieval.
|
|
| - Only use supported framework date/time format patterns.
|
|
| - All responses must be returned as standardized JSON objects.
|
|
|
|
|
| Example:
|
|
| - ObrimDatetime("local", map[string]any{"format":"yyyy-MM-dd"})
|
|
| - ObrimDatetime("trusted", map[string]any{"format":"timestampsec"})
|
|
|
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Credit
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Contributor:
|
|
| - Rajon Ahmed
|
|
| - Scionite
|
|
|
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
package datetime
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net"
|
|
"time"
|
|
|
|
"go/module/essential/visible/service/helper/log"
|
|
"go/module/essential/visible/service/helper/status"
|
|
)
|
|
|
|
// ObrimDatetimePayload represents datetime payload data.
|
|
type ObrimDatetimePayload struct {
|
|
Value string `json:"value"`
|
|
}
|
|
|
|
// ObrimDatetimeOutput represents utility output structure.
|
|
type ObrimDatetimeOutput struct {
|
|
Status bool `json:"status"`
|
|
Code string `json:"code"`
|
|
Payload *ObrimDatetimePayload `json:"payload"`
|
|
}
|
|
|
|
// obrimDatetimePatternMap stores framework-supported format mappings.
|
|
var obrimDatetimePatternMap = map[string]string{
|
|
"yyyy-MM-dd": "2006-01-02",
|
|
"MMM dd, yyyy": "Jan 02, 2006",
|
|
"MMMM dd, yyyy": "January 02, 2006",
|
|
"EEE, MMM dd, yyyy": "Mon, Jan 02, 2006",
|
|
"EEE, MMMM dd, yyyy": "Mon, January 02, 2006",
|
|
"EEEE, MMM dd, yyyy": "Monday, Jan 02, 2006",
|
|
"EEEE, MMMM dd, yyyy": "Monday, January 02, 2006",
|
|
"HH:mm:ss": "15:04:05",
|
|
"hh:mm:ss a": "03:04:05 PM",
|
|
"yyyy-MM-dd HH:mm:ss": "2006-01-02 15:04:05",
|
|
"yyyy-MM-dd HH:mm:ss z": "2006-01-02 15:04:05 MST",
|
|
"yyyy-MM-dd'T'HH:mm:ssXXX": "2006-01-02T15:04:05Z07:00",
|
|
}
|
|
|
|
// ObrimDatetime retrieves and formats current date and time.
|
|
func ObrimDatetime(datetimeType string, config map[string]any) string {
|
|
status.ObrimStatus("INFO", "Initializing datetime utility.")
|
|
log.ObrimLog("INIT", "Datetime utility initialized.")
|
|
|
|
if err := obrimDatetimeValidate(datetimeType, config); err != nil {
|
|
status.ObrimStatus("ERROR", err.Error())
|
|
log.ObrimLog("ERROR", err.Error())
|
|
|
|
response := obrimDatetimeResponse(false, "FAILED_"+err.Error(), nil)
|
|
return response
|
|
}
|
|
|
|
format := config["format"].(string)
|
|
|
|
var currentTime time.Time
|
|
var err error
|
|
|
|
switch datetimeType {
|
|
case "local":
|
|
currentTime, err = obrimDatetimeLocal()
|
|
|
|
case "trusted":
|
|
currentTime, err = obrimDatetimeTrusted()
|
|
|
|
default:
|
|
err = errors.New("INVALID_TYPE")
|
|
}
|
|
|
|
if err != nil {
|
|
status.ObrimStatus("ERROR", err.Error())
|
|
log.ObrimLog("ERROR", err.Error())
|
|
|
|
response := obrimDatetimeResponse(false, "FAILED_"+err.Error(), nil)
|
|
return response
|
|
}
|
|
|
|
value, err := obrimDatetimeFormatApply(currentTime, format)
|
|
if err != nil {
|
|
status.ObrimStatus("ERROR", err.Error())
|
|
log.ObrimLog("ERROR", err.Error())
|
|
|
|
response := obrimDatetimeResponse(false, "FAILED_"+err.Error(), nil)
|
|
return response
|
|
}
|
|
|
|
payload := &ObrimDatetimePayload{
|
|
Value: value,
|
|
}
|
|
|
|
status.ObrimStatus("SUCCESS", "Datetime retrieved successfully.")
|
|
log.ObrimLog("SUCCESS", "Datetime retrieved successfully.")
|
|
|
|
return obrimDatetimeResponse(
|
|
true,
|
|
"SUCCESS_DATETIME_RETRIEVED",
|
|
payload,
|
|
)
|
|
}
|
|
|
|
// obrimDatetimeValidate validates utility inputs.
|
|
func obrimDatetimeValidate(datetimeType string, config map[string]any) error {
|
|
if datetimeType != "local" && datetimeType != "trusted" {
|
|
return errors.New("INVALID_TYPE")
|
|
}
|
|
|
|
formatValue, exists := config["format"]
|
|
if !exists {
|
|
return errors.New("INVALID_FORMAT")
|
|
}
|
|
|
|
format, ok := formatValue.(string)
|
|
if !ok {
|
|
return errors.New("INVALID_FORMAT")
|
|
}
|
|
|
|
if !obrimDatetimePatternValidate(format) {
|
|
return errors.New("INVALID_FORMAT")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// obrimDatetimePatternValidate validates supported patterns.
|
|
func obrimDatetimePatternValidate(pattern string) bool {
|
|
_, exists := obrimDatetimePatternMap[pattern]
|
|
return exists || pattern == "timestampsec" || pattern == "timestampmil"
|
|
}
|
|
|
|
// obrimDatetimePatternResolve resolves framework patterns.
|
|
func obrimDatetimePatternResolve(pattern string) (string, error) {
|
|
if pattern == "timestampsec" || pattern == "timestampmil" {
|
|
return pattern, nil
|
|
}
|
|
|
|
layout, exists := obrimDatetimePatternMap[pattern]
|
|
if !exists {
|
|
return "", errors.New("INVALID_FORMAT")
|
|
}
|
|
|
|
return layout, nil
|
|
}
|
|
|
|
// obrimDatetimeFormatApply applies formatting.
|
|
func obrimDatetimeFormatApply(value time.Time, pattern string) (string, error) {
|
|
layout, err := obrimDatetimePatternResolve(pattern)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
switch pattern {
|
|
case "timestampsec":
|
|
return time.Unix(value.Unix(), 0).Format("1136239445"), nil
|
|
|
|
case "timestampmil":
|
|
return time.UnixMilli(value.UnixMilli()).Format("1136239445000"), nil
|
|
|
|
default:
|
|
return value.Format(layout), nil
|
|
}
|
|
}
|
|
|
|
// obrimDatetimeLocal retrieves local system time.
|
|
func obrimDatetimeLocal() (time.Time, error) {
|
|
return time.Now(), nil
|
|
}
|
|
|
|
// obrimDatetimeTrusted retrieves trusted time.
|
|
func obrimDatetimeTrusted() (time.Time, error) {
|
|
return obrimDatetimeTrustedSync()
|
|
}
|
|
|
|
// obrimDatetimeTrustedSync synchronizes trusted NTP time.
|
|
func obrimDatetimeTrustedSync() (time.Time, error) {
|
|
connection, err := net.DialTimeout(
|
|
"udp",
|
|
"time.google.com:123",
|
|
5*time.Second,
|
|
)
|
|
if err != nil {
|
|
return time.Time{}, errors.New("TRUSTED_TIME_RETRIEVAL")
|
|
}
|
|
|
|
defer connection.Close()
|
|
|
|
request := make([]byte, 48)
|
|
request[0] = 0x1B
|
|
|
|
if _, err = connection.Write(request); err != nil {
|
|
return time.Time{}, errors.New("TRUSTED_TIME_RETRIEVAL")
|
|
}
|
|
|
|
if err = connection.SetDeadline(time.Now().Add(5 * time.Second)); err != nil {
|
|
return time.Time{}, errors.New("TRUSTED_TIME_RETRIEVAL")
|
|
}
|
|
|
|
response := make([]byte, 48)
|
|
|
|
if _, err = connection.Read(response); err != nil {
|
|
return time.Time{}, errors.New("TRUSTED_TIME_RETRIEVAL")
|
|
}
|
|
|
|
seconds := uint64(response[40])<<24 |
|
|
uint64(response[41])<<16 |
|
|
uint64(response[42])<<8 |
|
|
uint64(response[43])
|
|
|
|
const ntpEpochOffset = 2208988800
|
|
|
|
unixSeconds := int64(seconds) - ntpEpochOffset
|
|
|
|
return time.Unix(unixSeconds, 0).UTC(), nil
|
|
}
|
|
|
|
// obrimDatetimeResponse builds standardized responses.
|
|
func obrimDatetimeResponse(
|
|
statusValue bool,
|
|
code string,
|
|
payload *ObrimDatetimePayload,
|
|
) string {
|
|
response := ObrimDatetimeOutput{
|
|
Status: statusValue,
|
|
Code: code,
|
|
Payload: payload,
|
|
}
|
|
|
|
data, err := json.Marshal(response)
|
|
if err != nil {
|
|
fallback := ObrimDatetimeOutput{
|
|
Status: false,
|
|
Code: "FAILED_RESPONSE_BUILD",
|
|
Payload: nil,
|
|
}
|
|
|
|
data, _ = json.Marshal(fallback)
|
|
}
|
|
|
|
return string(data)
|
|
}
|