146 lines
3.8 KiB
Go
146 lines
3.8 KiB
Go
package common
|
|
|
|
import (
|
|
`math`
|
|
`time`
|
|
)
|
|
|
|
/*
|
|
CurrentTimeStep returns the current time step using the given
|
|
[time.Duration] `period`.
|
|
|
|
If `period` is equal to time.Duration(0), it will be set to [DefaultTimePeriod].
|
|
*/
|
|
func CurrentTimeStep(period time.Duration) (ts int64) {
|
|
return TimeStepFromTime(time.Now(), period)
|
|
}
|
|
|
|
/*
|
|
OffsetTimeStep is like [CurrentTimeStep] but returns the time step next/previous
|
|
to the current specified by `offset` (`offset` may be negative or positive).
|
|
*/
|
|
func OffsetTimeStep(period time.Duration, offset int64) (ts int64) {
|
|
|
|
var offsetDuration time.Duration
|
|
|
|
period = normalizePeriod(period)
|
|
|
|
offsetDuration = period * time.Duration(offset)
|
|
|
|
ts = TimeStepFromTime(time.Now().Add(offsetDuration), period)
|
|
|
|
return
|
|
}
|
|
|
|
/*
|
|
OffsetTimeStepToTime is like [TimeStepToTime] but returns the next/previous
|
|
time range in relation to time step `ts` specified by `offset` (`offset` may be negative or positive).
|
|
*/
|
|
func OffsetTimeStepToTime(ts int64, period time.Duration, offset int64) (start, end time.Time) {
|
|
return TimeStepToTime(ts+offset, period)
|
|
}
|
|
|
|
/*
|
|
TimeStepFromTime returns a time step (see [RFC 6238 § 1.2], [RFC 6238 § 5.2])
|
|
from a provided generation time `t` as a [time.Time] and a life length
|
|
`period` as a [time.Duration].
|
|
|
|
If `period` is equal to time.Duration(0), it will be set to [DefaultTimePeriod].
|
|
|
|
[RFC 6238 § 1.2]: https://datatracker.ietf.org/doc/html/rfc6238#section-1.2
|
|
[RFC 6238 § 5.2]: https://datatracker.ietf.org/doc/html/rfc6238#section-5.2
|
|
*/
|
|
func TimeStepFromTime(t time.Time, period time.Duration) (ts int64) {
|
|
|
|
period = normalizePeriod(period)
|
|
|
|
ts = int64(math.Floor(float64(t.Unix()) / period.Seconds()))
|
|
|
|
return
|
|
}
|
|
|
|
/*
|
|
TimeStepToTime returns a [time.Time] `start` and `end` from a time step `ts`
|
|
and a lifetime period `period` (as a [time.Duration]).
|
|
|
|
If `period` is equal to time.Duration(0), it will be set to [DefaultTimePeriod].
|
|
*/
|
|
func TimeStepToTime(ts int64, period time.Duration) (start, end time.Time) {
|
|
|
|
var fromEpoch time.Duration
|
|
|
|
period = normalizePeriod(period)
|
|
fromEpoch = (time.Second * time.Duration(ts*int64(period.Seconds()))).Truncate(time.Second)
|
|
|
|
start = time.Unix(0, 0).Add(fromEpoch).Truncate(time.Second)
|
|
end = start.Add(period).Truncate(time.Second)
|
|
|
|
return
|
|
}
|
|
|
|
// VaultEscape is used to normalize a string to a Vault-safe name (for e.g. secrets).
|
|
func VaultEscape(s *string) {
|
|
|
|
var c rune
|
|
var idx int
|
|
var last rune
|
|
var norm []rune
|
|
var reduced []rune = make([]rune, 0)
|
|
|
|
if s == nil {
|
|
return
|
|
}
|
|
norm = make([]rune, 0, len(*s))
|
|
|
|
// https://github.com/hashicorp/vault/issues/5645#issuecomment-434404750
|
|
// It seems they relaxed this a bit since then, as hyphens and periods are also allowed.
|
|
// https://github.com/hashicorp/vault/blob/main/sdk/framework/path.go#L26
|
|
// At time of writing, the regex is: (?P<name>\\w(([\\w-.@]+)?\\w)?)
|
|
// Per comments: "alphanumeric characters along with -, . and @."
|
|
for _, c = range *s {
|
|
// If it's "safe" chars, it's fine
|
|
if (c == '-' || c == '.') || // 0x2d, 0x2e
|
|
(c >= '0' && c <= '9') || // 0x30 to 0x39
|
|
(c == '@') || // 0x40
|
|
(c >= 'A' && c <= 'Z') || // 0x41 to 0x5a
|
|
(c == '_') || // 0x5f
|
|
(c >= 'a' && c <= 'z') { // 0x61 to 0x7a
|
|
norm = append(norm, c)
|
|
continue
|
|
}
|
|
// Otherwise normalize it to a safe char
|
|
norm = append(norm, VaultRepl)
|
|
}
|
|
|
|
// And remove repeating sequential replacers.
|
|
for idx, c = range norm[:] {
|
|
if idx == 0 {
|
|
last = c
|
|
reduced = append(reduced, c)
|
|
continue
|
|
}
|
|
if c == last && last == VaultRepl {
|
|
continue
|
|
}
|
|
reduced = append(reduced, c)
|
|
last = c
|
|
}
|
|
|
|
*s = string(reduced)
|
|
|
|
return
|
|
}
|
|
|
|
// normalizedPeriod returns `period` if non-zero, otherwise [DefaultTimePeriod].
|
|
func normalizePeriod(period time.Duration) (normalized time.Duration) {
|
|
|
|
if period != time.Duration(0) {
|
|
normalized = period
|
|
return
|
|
}
|
|
|
|
normalized = DefaultTimePeriod
|
|
|
|
return
|
|
}
|