| package repository |
|
|
| import ( |
| "context" |
| "strconv" |
| "time" |
|
|
| "github.com/chenyme/grok2api/backend/internal/domain/account" |
| ) |
|
|
| |
| |
| func AccountConcurrencyKey(accountID uint64) string { |
| return "account:" + strconv.FormatUint(accountID, 10) |
| } |
|
|
| |
| type RateLimiter interface { |
| Allow(ctx context.Context, key string, limit int, now time.Time) (bool, error) |
| } |
|
|
| |
| type ConcurrencyLimiter interface { |
| Acquire(ctx context.Context, key string, limit int) (release func(), acquired bool, err error) |
| Current(ctx context.Context, key string) (int, error) |
| } |
|
|
| |
| type ConcurrencySnapshotReader interface { |
| CurrentMany(ctx context.Context, keys []string) (map[string]int, error) |
| } |
|
|
| |
| type StickySessionRepository interface { |
| Get(ctx context.Context, affinityKey string, now time.Time) (uint64, bool, error) |
| |
| Bind(ctx context.Context, affinityKey string, proposedAccountID uint64, now, expiresAt time.Time) (accountID uint64, err error) |
| |
| Set(ctx context.Context, affinityKey string, accountID uint64, expiresAt time.Time) error |
| DeleteByAccount(ctx context.Context, accountID uint64) error |
| } |
|
|
| |
| |
| type StickySessionBatchDeleter interface { |
| DeleteByAccounts(ctx context.Context, accountIDs []uint64) error |
| } |
|
|
| |
| |
| type ReasoningReplayRepository interface { |
| Get(ctx context.Context, model, sessionKey string, now time.Time, ttl time.Duration) (items [][]byte, ok bool, err error) |
| Set(ctx context.Context, model, sessionKey string, items [][]byte, expiresAt time.Time) error |
| Delete(ctx context.Context, model, sessionKey string) error |
| } |
|
|
| |
| type ObservedModelState struct { |
| Model string |
| ObservedAt time.Time |
| } |
|
|
| |
| |
| type ObservedModelStateRepository interface { |
| GetObservedModelState(ctx context.Context, accountID uint64) (ObservedModelState, bool, error) |
| SetObservedModelState(ctx context.Context, accountID uint64, value ObservedModelState, ttl time.Duration) error |
| } |
|
|
| |
| type DeviceSessionRepository interface { |
| Create(ctx context.Context, value account.DeviceSession) error |
| Get(ctx context.Context, id string, now time.Time) (account.DeviceSession, error) |
| Update(ctx context.Context, value account.DeviceSession) error |
| Delete(ctx context.Context, id string) error |
| } |
|
|
| |
| type DistributedLock interface { |
| Acquire(ctx context.Context, key string, ttl time.Duration) (release func(), acquired bool, err error) |
| } |
|
|
| |
| type SettingsChangeBus interface { |
| PublishSettingsChanged(ctx context.Context) error |
| ListenSettingsChanges(ctx context.Context, handler func(context.Context) error) error |
| } |
|
|
| type InvalidationKind string |
|
|
| const ( |
| InvalidationRouteChanged InvalidationKind = "route_changed" |
| InvalidationModelBindingChanged InvalidationKind = "model_binding_changed" |
| InvalidationAccountStateChanged InvalidationKind = "account_state_changed" |
| InvalidationAccountCredentialChanged InvalidationKind = "account_credential_changed" |
| InvalidationAccountCapabilityChanged InvalidationKind = "account_capability_changed" |
| InvalidationAccountBillingChanged InvalidationKind = "account_billing_changed" |
| InvalidationAccountQuotaChanged InvalidationKind = "account_quota_changed" |
| InvalidationAccountRecoveryChanged InvalidationKind = "account_recovery_changed" |
| InvalidationAccountModelQuotaChanged InvalidationKind = "account_model_quota_changed" |
| InvalidationClientKeyChanged InvalidationKind = "client_key_changed" |
| ) |
|
|
| type InvalidationLayer string |
|
|
| const ( |
| InvalidationLayerRoute InvalidationLayer = "route" |
| InvalidationLayerBase InvalidationLayer = "account_base" |
| InvalidationLayerOverlay InvalidationLayer = "account_overlay" |
| InvalidationLayerClientKey InvalidationLayer = "client_key" |
| ) |
|
|
| type InvalidationEvent struct { |
| Kind InvalidationKind `json:"kind"` |
| Provider account.Provider `json:"provider,omitempty"` |
| AccountID uint64 `json:"accountId,omitempty"` |
| ClientKeyID uint64 `json:"clientKeyId,omitempty"` |
| UpstreamModel string `json:"upstreamModel,omitempty"` |
| Revision uint64 `json:"revision,omitempty"` |
| SourceInstance string `json:"sourceInstance,omitempty"` |
| PublishedAt time.Time `json:"publishedAt,omitempty"` |
| } |
|
|
| func (e InvalidationEvent) Layer() InvalidationLayer { |
| switch e.Kind { |
| case InvalidationRouteChanged: |
| return InvalidationLayerRoute |
| case InvalidationModelBindingChanged, InvalidationAccountCapabilityChanged, InvalidationAccountModelQuotaChanged: |
| return InvalidationLayerOverlay |
| case InvalidationAccountStateChanged, InvalidationAccountCredentialChanged, InvalidationAccountBillingChanged, InvalidationAccountQuotaChanged, InvalidationAccountRecoveryChanged: |
| return InvalidationLayerBase |
| case InvalidationClientKeyChanged: |
| return InvalidationLayerClientKey |
| default: |
| return "" |
| } |
| } |
|
|
| func (e InvalidationEvent) Valid() bool { |
| layer := e.Layer() |
| if layer == "" { |
| return false |
| } |
| if layer == InvalidationLayerClientKey { |
| return e.Provider == "" && e.AccountID == 0 && e.UpstreamModel == "" |
| } |
| switch e.Provider { |
| case "", account.ProviderBuild, account.ProviderWeb, account.ProviderConsole: |
| return true |
| default: |
| return false |
| } |
| } |
|
|
| type InvalidationObserver func(context.Context, InvalidationEvent) |
|
|
| |
| |
| type InvalidationBus interface { |
| PublishInvalidation(ctx context.Context, event InvalidationEvent) error |
| ListenInvalidations(ctx context.Context, handler func(context.Context, InvalidationEvent) error) error |
| } |
|
|
| |
| type QuotaRecoveryQueue interface { |
| ScheduleQuotaRecovery(ctx context.Context, value account.QuotaRecoveryEvent) error |
| EnsureQuotaRecovery(ctx context.Context, value account.QuotaRecoveryEvent) error |
| ClaimDueQuotaRecoveries(ctx context.Context, now time.Time, limit int, lease time.Duration) ([]account.QuotaRecoveryEvent, error) |
| AckQuotaRecovery(ctx context.Context, value account.QuotaRecoveryEvent) error |
| RescheduleQuotaRecovery(ctx context.Context, value account.QuotaRecoveryEvent) error |
| } |
|
|
| type QuotaRefreshDirty struct { |
| AccountID uint64 |
| Mode string |
| Generation uint64 |
| } |
|
|
| |
| |
| type QuotaRefreshCoordinator interface { |
| MarkQuotaRefreshDirty(ctx context.Context, accountID uint64, mode string, ttl time.Duration) (uint64, error) |
| QuotaRefreshGeneration(ctx context.Context, accountID uint64, mode string) (generation uint64, dirty bool, err error) |
| ClearQuotaRefreshDirty(ctx context.Context, accountID uint64, mode string, generation uint64) (bool, error) |
| ListQuotaRefreshDirty(ctx context.Context, now time.Time, limit int) ([]QuotaRefreshDirty, error) |
| } |
|
|