proxy-pool/internal/domain/upstream/pool.go
youfak 4de3ffb85f
Some checks are pending
ci / test (ubuntu-latest) (push) Waiting to run
ci / test (windows-latest) (push) Waiting to run
ci / race (push) Waiting to run
feat: add ephemeral proxy activity pool
2026-07-29 12:51:18 +08:00

82 lines
1.6 KiB
Go

package upstream
import (
"time"
proxyDomain "proxy-pool/internal/domain/proxy"
)
type ProxyCapacity struct {
State proxyDomain.State
ExpiresAt time.Time
Max int64
Active int64
Reserved int64
}
type Inventory struct {
Proxies []ProxyCapacity
PendingExpected int
FetchedTotal int64
MaxSize int
MaxTotal int64
}
func (i Inventory) AvailableSlots(now time.Time, safetyMargin time.Duration) int64 {
var available int64
deadline := now.Add(safetyMargin)
for _, candidate := range i.Proxies {
if candidate.State != proxyDomain.StateAvailable {
continue
}
if !candidate.ExpiresAt.IsZero() && !candidate.ExpiresAt.After(deadline) {
continue
}
slots := candidate.Max - candidate.Active - candidate.Reserved
if slots > 0 {
available += slots
}
}
return available
}
func (i Inventory) ManagedCount() int {
count := max(i.PendingExpected, 0)
for _, candidate := range i.Proxies {
if managedState(candidate.State) {
count++
}
}
return count
}
func (i Inventory) FetchAllowance(requested int) int {
if requested <= 0 || i.MaxSize <= 0 {
return 0
}
allowed := min(requested, max(i.MaxSize-i.ManagedCount(), 0))
if i.MaxTotal > 0 {
remaining := i.MaxTotal - i.FetchedTotal
if remaining <= 0 {
return 0
}
if int64(allowed) > remaining {
allowed = int(remaining)
}
}
return allowed
}
func managedState(state proxyDomain.State) bool {
switch state {
case proxyDomain.StateFetched,
proxyDomain.StateChecking,
proxyDomain.StateAvailable,
proxyDomain.StateSuspect,
proxyDomain.StateDraining:
return true
default:
return false
}
}