Files
orbit/platform/resources/service.go

80 lines
3.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package resources 管理当前凭据所属应用的共享额度,应用管理动作需单独授权。
package resources
import (
"context"
"strings"
"unicode/utf8"
"git.yuntuo.hk/k2safe/orbit/internal/fault"
core "git.yuntuo.hk/k2safe/orbit/model"
"git.yuntuo.hk/k2safe/orbit/platform/auth"
)
// View 返回配置与当前用量;运行计数不参与配置版本。
type View struct {
// ApplicationID 所属应用标识,由凭据归属确定。
ApplicationID core.ID `json:"application_id"`
// Revision 仅配置变更增加的版本;JSON 使用十进制字符串。
Revision uint64 `json:"revision,string"`
// MaxUnfinishedTasks 跨命名空间的未终结任务上限,包含待核查任务。
MaxUnfinishedTasks uint32 `json:"max_unfinished_tasks"`
// UnfinishedTasks 当前未终结任务总数;自动重试不重复占用。
UnfinishedTasks uint64 `json:"unfinished_tasks,string"`
// MaxConcurrency 跨队列的预占及运行尝试总上限。
MaxConcurrency uint32 `json:"max_concurrency"`
// ActiveAttempts 当前预占与运行的尝试数。
ActiveAttempts uint64 `json:"active_attempts,string"`
// PendingStarts 已预占但尚未开始的尝试数,属于 ActiveAttempts。
PendingStarts uint64 `json:"pending_starts,string"`
// RatePerSecond 每秒固定窗口允许的开始授权次数。
RatePerSecond uint32 `json:"rate_per_second"`
}
// ConfigureInput 完整替换三个正整数上限;要求版本和审计原因。
type ConfigureInput struct {
// ExpectedRevision 管理命令预期配置版本,须保留原值重报。
ExpectedRevision uint64 `json:"expected_revision,string"`
// Reason 非空审计原因,最多 1024 个 Unicode 字符。
Reason string `json:"reason"`
// MaxUnfinishedTasks 跨命名空间的未终结任务上限,包含待核查任务。
MaxUnfinishedTasks uint32 `json:"max_unfinished_tasks"`
// MaxConcurrency 跨队列的预占及运行尝试总上限。
MaxConcurrency uint32 `json:"max_concurrency"`
// RatePerSecond 每秒固定窗口允许的开始授权次数。
RatePerSecond uint32 `json:"rate_per_second"`
}
type Result struct {
// Resources 配置成功时的原用量快照,重报不刷新。
Resources View `json:"resources"`
// Deduplicated 是否返回先前已提交的同身份回执。
Deduplicated bool `json:"deduplicated"`
}
type Store interface {
GetApplicationResources(context.Context, auth.Token) (View, error)
ConfigureApplicationResources(context.Context, auth.Token, string, ConfigureInput) (Result, error)
}
type Service struct{ store Store }
func New(store Store) *Service { return &Service{store: store} }
func (s *Service) Get(ctx context.Context, token auth.Token) (View, error) {
return s.store.GetApplicationResources(ctx, token)
}
func (s *Service) Configure(ctx context.Context, token auth.Token, key string, in ConfigureInput) (Result, error) {
if len(key) < 1 || len(key) > 128 {
return Result{}, fault.Invalid("invalid Idempotency-Key")
}
for _, c := range key {
if c < 33 || c > 126 {
return Result{}, fault.Invalid("invalid Idempotency-Key")
}
}
if in.ExpectedRevision == 0 || strings.TrimSpace(in.Reason) == "" || !utf8.ValidString(in.Reason) || utf8.RuneCountInString(in.Reason) > 1024 {
return Result{}, fault.Invalid("reason and nonzero expected_revision are required")
}
if in.MaxUnfinishedTasks < 1 || in.MaxUnfinishedTasks > 100000000 || in.MaxConcurrency < 1 || in.MaxConcurrency > 1000000 || in.RatePerSecond < 1 || in.RatePerSecond > 10000000 {
return Result{}, fault.Invalid("application limits are invalid")
}
return s.store.ConfigureApplicationResources(ctx, token, key, in)
}