chore: gocyclo fixes

This commit is contained in:
jamesread 2026-01-11 01:29:27 +00:00
parent 6493f7bee7
commit 84bd405ca9
3 changed files with 137 additions and 79 deletions

View File

@ -276,41 +276,43 @@ func (api *oliveTinAPI) StartActionByGetAndWait(ctx ctx.Context, req *connect.Re
} }
} }
func calculateRateLimitExpires(api *oliveTinAPI, logEntry *executor.InternalLogEntry) string {
if logEntry.Binding == nil || logEntry.Binding.Action == nil {
return ""
}
expiryUnix := api.executor.GetTimeUntilAvailable(logEntry.Binding)
if expiryUnix <= 0 {
return ""
}
return time.Unix(expiryUnix, 0).Format("2006-01-02 15:04:05")
}
func (api *oliveTinAPI) internalLogEntryToPb(logEntry *executor.InternalLogEntry, authenticatedUser *authpublic.AuthenticatedUser) *apiv1.LogEntry { func (api *oliveTinAPI) internalLogEntryToPb(logEntry *executor.InternalLogEntry, authenticatedUser *authpublic.AuthenticatedUser) *apiv1.LogEntry {
pble := &apiv1.LogEntry{ pble := &apiv1.LogEntry{
ActionTitle: logEntry.ActionTitle, ActionTitle: logEntry.ActionTitle,
ActionIcon: logEntry.ActionIcon, ActionIcon: logEntry.ActionIcon,
DatetimeStarted: logEntry.DatetimeStarted.Format("2006-01-02 15:04:05"), DatetimeStarted: logEntry.DatetimeStarted.Format("2006-01-02 15:04:05"),
DatetimeFinished: logEntry.DatetimeFinished.Format("2006-01-02 15:04:05"), DatetimeFinished: logEntry.DatetimeFinished.Format("2006-01-02 15:04:05"),
DatetimeIndex: logEntry.Index, DatetimeIndex: logEntry.Index,
Output: logEntry.Output, Output: logEntry.Output,
TimedOut: logEntry.TimedOut, TimedOut: logEntry.TimedOut,
Blocked: logEntry.Blocked, Blocked: logEntry.Blocked,
ExitCode: logEntry.ExitCode, ExitCode: logEntry.ExitCode,
Tags: logEntry.Tags, Tags: logEntry.Tags,
ExecutionTrackingId: logEntry.ExecutionTrackingID, ExecutionTrackingId: logEntry.ExecutionTrackingID,
ExecutionStarted: logEntry.ExecutionStarted, ExecutionStarted: logEntry.ExecutionStarted,
ExecutionFinished: logEntry.ExecutionFinished, ExecutionFinished: logEntry.ExecutionFinished,
User: logEntry.Username, User: logEntry.Username,
BindingId: logEntry.Binding.ID,
DatetimeRateLimitExpires: calculateRateLimitExpires(api, logEntry),
} }
if !pble.ExecutionFinished { if !pble.ExecutionFinished {
pble.CanKill = acl.IsAllowedKill(api.cfg, authenticatedUser, logEntry.Binding.Action) pble.CanKill = acl.IsAllowedKill(api.cfg, authenticatedUser, logEntry.Binding.Action)
} }
// Calculate rate limit expiry for the action
if logEntry.Binding != nil && logEntry.Binding.Action != nil {
pble.BindingId = logEntry.Binding.ID
expiryUnix := api.executor.GetTimeUntilAvailable(logEntry.Binding)
if expiryUnix > 0 {
pble.DatetimeRateLimitExpires = time.Unix(expiryUnix, 0).Format("2006-01-02 15:04:05")
} else {
pble.DatetimeRateLimitExpires = ""
}
}
return pble return pble
} }

View File

@ -34,16 +34,16 @@ type Action struct {
// ActionArgument objects appear on Actions. // ActionArgument objects appear on Actions.
type ActionArgument struct { type ActionArgument struct {
Name string `koanf:"name"` Name string `koanf:"name"`
Title string `koanf:"title"` Title string `koanf:"title"`
Description string `koanf:"description"` Description string `koanf:"description"`
Type string `koanf:"type"` Type string `koanf:"type"`
Default string `koanf:"default"` Default string `koanf:"default"`
Choices []ActionArgumentChoice `koanf:"choices"` Choices []ActionArgumentChoice `koanf:"choices"`
Entity string `koanf:"entity"` Entity string `koanf:"entity"`
RejectNull bool `koanf:"rejectNull"` RejectNull bool `koanf:"rejectNull"`
Suggestions map[string]string `koanf:"suggestions"` Suggestions map[string]string `koanf:"suggestions"`
SuggestionsBrowserKey string `koanf:"suggestionsBrowserKey"` SuggestionsBrowserKey string `koanf:"suggestionsBrowserKey"`
} }
// ActionArgumentChoice represents a predefined choice for an argument. // ActionArgumentChoice represents a predefined choice for an argument.

View File

@ -309,6 +309,101 @@ func (e *Executor) GetLogsByBindingId(bindingId string) []*InternalLogEntry {
return logs return logs
} }
// shouldCountExecution checks if a log entry should be counted for rate limiting.
func shouldCountExecution(logEntry *InternalLogEntry, windowStart time.Time) bool {
return !logEntry.Blocked && logEntry.DatetimeStarted.After(windowStart)
}
// updateOldestExecution updates the oldest execution time if this entry is older.
func updateOldestExecution(oldestExecutionTime **time.Time, logEntry *InternalLogEntry) {
if *oldestExecutionTime == nil {
*oldestExecutionTime = &logEntry.DatetimeStarted
} else if logEntry.DatetimeStarted.Before(**oldestExecutionTime) {
*oldestExecutionTime = &logEntry.DatetimeStarted
}
}
// findOldestExecutionInWindow finds the oldest execution within the time window and counts executions.
// Returns the count of executions and the oldest execution time, or nil if none found.
func findOldestExecutionInWindow(logs []*InternalLogEntry, windowStart time.Time) (int, *time.Time) {
executions := 0
var oldestExecutionTime *time.Time
for _, logEntry := range logs {
if !shouldCountExecution(logEntry, windowStart) {
continue
}
executions++
updateOldestExecution(&oldestExecutionTime, logEntry)
}
return executions, oldestExecutionTime
}
// calculateExpiryTime calculates when the oldest execution will fall outside the rate limit window.
func calculateExpiryTime(oldestExecutionTime time.Time, duration time.Duration, now time.Time) time.Time {
expiryTime := oldestExecutionTime.Add(duration)
if !expiryTime.After(now) {
return time.Time{}
}
return expiryTime
}
// updateMaxExpiryTime updates maxExpiryTime if expiryTime is later.
func updateMaxExpiryTime(maxExpiryTime *time.Time, expiryTime time.Time) {
if expiryTime.IsZero() {
return
}
if maxExpiryTime.IsZero() || expiryTime.After(*maxExpiryTime) {
*maxExpiryTime = expiryTime
}
}
// calculateExpiryForRate calculates the expiry time for a single rate limit rule.
// Returns the expiry time if the rate limit is exceeded, or zero time if not.
func calculateExpiryForRate(rate config.RateSpec, logs []*InternalLogEntry, now time.Time) time.Time {
duration := parseDuration(rate)
if duration <= 0 {
return time.Time{}
}
windowStart := now.Add(-duration)
executions, oldestExecutionTime := findOldestExecutionInWindow(logs, windowStart)
if executions < rate.Limit || oldestExecutionTime == nil {
return time.Time{}
}
return calculateExpiryTime(*oldestExecutionTime, duration, now)
}
// getLogsForBinding retrieves logs for a binding ID.
func (e *Executor) getLogsForBinding(bindingId string) []*InternalLogEntry {
e.logmutex.RLock()
logs, found := e.LogsByBindingId[bindingId]
e.logmutex.RUnlock()
if !found || len(logs) == 0 {
return nil
}
return logs
}
// calculateMaxExpiryTimeFromRates calculates the maximum expiry time across all rate limit rules.
func calculateMaxExpiryTimeFromRates(rates []config.RateSpec, logs []*InternalLogEntry, now time.Time) time.Time {
var maxExpiryTime time.Time
for _, rate := range rates {
expiryTime := calculateExpiryForRate(rate, logs, now)
updateMaxExpiryTime(&maxExpiryTime, expiryTime)
}
return maxExpiryTime
}
// GetTimeUntilAvailable calculates when an action will be available again based on rate limits. // GetTimeUntilAvailable calculates when an action will be available again based on rate limits.
// Returns the Unix timestamp in seconds when the rate limit expires, or 0 if the action is available now. // Returns the Unix timestamp in seconds when the rate limit expires, or 0 if the action is available now.
func (e *Executor) GetTimeUntilAvailable(binding *ActionBinding) int64 { func (e *Executor) GetTimeUntilAvailable(binding *ActionBinding) int64 {
@ -316,51 +411,12 @@ func (e *Executor) GetTimeUntilAvailable(binding *ActionBinding) int64 {
return 0 return 0
} }
e.logmutex.RLock() logs := e.getLogsForBinding(binding.ID)
defer e.logmutex.RUnlock() if logs == nil {
logs, found := e.LogsByBindingId[binding.ID]
if !found || len(logs) == 0 {
return 0 return 0
} }
now := time.Now() maxExpiryTime := calculateMaxExpiryTimeFromRates(binding.Action.MaxRate, logs, time.Now())
var maxExpiryTime time.Time
for _, rate := range binding.Action.MaxRate {
duration := parseDuration(rate)
if duration <= 0 {
continue
}
then := now.Add(-duration)
executions := 0
var oldestExecutionTime *time.Time
for _, logEntry := range logs {
if logEntry.Blocked {
continue
}
if logEntry.DatetimeStarted.After(then) {
executions++
if oldestExecutionTime == nil || logEntry.DatetimeStarted.Before(*oldestExecutionTime) {
oldestExecutionTime = &logEntry.DatetimeStarted
}
}
}
// If we're at or over the limit, calculate when the oldest execution will fall outside the window
// Note: getExecutionsCount uses -1 because it counts the current execution, but we're checking
// availability before execution, so we compare directly to rate.Limit
if executions >= rate.Limit && oldestExecutionTime != nil {
// The oldest execution will fall outside the window at: oldestExecutionTime + duration
expiryTime := oldestExecutionTime.Add(duration)
if expiryTime.After(now) && (maxExpiryTime.IsZero() || expiryTime.After(maxExpiryTime)) {
maxExpiryTime = expiryTime
}
}
}
if maxExpiryTime.IsZero() { if maxExpiryTime.IsZero() {
return 0 return 0