feat: expose bounded workflow activation and signal history
This commit is contained in:
91
weave/signal/history.go
Normal file
91
weave/signal/history.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package signal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"git.yuntuo.hk/k2safe/orbit/internal/fault"
|
||||
core "git.yuntuo.hk/k2safe/orbit/model"
|
||||
"git.yuntuo.hk/k2safe/orbit/platform/auth"
|
||||
"git.yuntuo.hk/k2safe/orbit/pulse/service"
|
||||
)
|
||||
|
||||
const AuditAction = "workflows:audit:read"
|
||||
|
||||
// Summary 不聚合信号正文、关联键或证据;单条Get用于读取完整原始信号。
|
||||
type Summary struct {
|
||||
ID core.ID `json:"id"` // ID 持久信号身份。
|
||||
WorkflowID core.ID `json:"workflow_id"` // WorkflowID 所属实例。
|
||||
Revision uint64 `json:"revision,string"` // Revision 该信号当前记录版本。
|
||||
Name string `json:"name"` // Name 原信号类型名称。
|
||||
PayloadVersion string `json:"payload_version"` // PayloadVersion 固定内容契约;未核验旧数据可能为空。
|
||||
TargetStepKey string `json:"target_step_key"` // TargetStepKey 原目标步骤名称,不跟随当前步骤变更。
|
||||
TargetActivationSequence uint32 `json:"target_activation_sequence"` // TargetActivationSequence 原指定代次,未核验旧数据可能为0。
|
||||
State string `json:"state"` // State 当前PENDING、CONSUMED、EXPIRED或REJECTED。
|
||||
Disposition string `json:"disposition,omitempty"` // Disposition 已记录的消费或拒绝原因。
|
||||
AcceptedAt time.Time `json:"accepted_at"` // AcceptedAt 原受理时间,也是分页排序依据。
|
||||
ExpiresAt time.Time `json:"expires_at"` // ExpiresAt 原固定截止,不因读取或重报延长。
|
||||
}
|
||||
type Page struct {
|
||||
WorkflowID core.ID `json:"workflow_id"` // WorkflowID 已授权实例。
|
||||
Revision uint64 `json:"revision,string"` // Revision 本页读取时的实例版本;跨页状态可变化。
|
||||
Items []Summary `json:"items"` // Items 按受理时间及ID倒序的摘要,空页为[]。
|
||||
NextCursor string `json:"next_cursor,omitempty"` // NextCursor 绑定命名空间及实例的后续位置。
|
||||
}
|
||||
type OperationSummary struct {
|
||||
ID core.ID `json:"id"` // ID 不可改写的操作审计身份。
|
||||
WorkflowID core.ID `json:"workflow_id"` // WorkflowID 经信号归属验证的实例。
|
||||
SignalID core.ID `json:"signal_id"` // SignalID 本次操作对应的信号资源。
|
||||
OperationID core.ID `json:"operation_id"` // OperationID 服务端操作身份,不是原始幂等键。
|
||||
ActorID string `json:"actor_id"` // ActorID 已认证的实际操作主体。
|
||||
Action string `json:"action"` // Action 操作种类,如workflow.signal。
|
||||
CreatedAt time.Time `json:"created_at"` // CreatedAt 原操作创建时间。
|
||||
}
|
||||
type OperationView struct {
|
||||
OperationSummary
|
||||
Reason string `json:"reason"` // Reason 原操作原因。
|
||||
EvidenceRef string `json:"evidence_ref,omitempty"` // EvidenceRef 原证据引用,不保存外部秘密。
|
||||
Before json.RawMessage `json:"before"` // Before 操作前摘要,首次受理可为null。
|
||||
After json.RawMessage `json:"after"` // After 原受理身份、摘要、时间和当时状态,不替代当前消费状态。
|
||||
}
|
||||
type OperationPage struct {
|
||||
Items []OperationSummary `json:"items"` // Items 按创建时间和ID倒序的有界审计摘要。
|
||||
NextCursor string `json:"next_cursor,omitempty"` // NextCursor 绑定实例、信号及查询类型的后续位置。
|
||||
}
|
||||
|
||||
func historyPage(in service.HistoryPageInput) (service.HistoryPageInput, error) {
|
||||
if in.Limit == 0 {
|
||||
in.Limit = 20
|
||||
}
|
||||
if in.Limit < 1 || in.Limit > 100 || len(in.Cursor) > 1024 {
|
||||
return in, fault.Invalid("invalid workflow signal history page")
|
||||
}
|
||||
return in, nil
|
||||
}
|
||||
func (s *Service) List(ctx context.Context, t auth.Token, workflow core.ID, in service.HistoryPageInput) (Page, error) {
|
||||
if workflow.Validate() != nil {
|
||||
return Page{}, fault.Invalid("invalid workflow id")
|
||||
}
|
||||
in, err := historyPage(in)
|
||||
if err != nil {
|
||||
return Page{}, err
|
||||
}
|
||||
return s.store.List(ctx, t, workflow, in)
|
||||
}
|
||||
func (s *Service) ListOperations(ctx context.Context, t auth.Token, workflow, id core.ID, in service.HistoryPageInput) (OperationPage, error) {
|
||||
if workflow.Validate() != nil || id.Validate() != nil {
|
||||
return OperationPage{}, fault.Invalid("invalid workflow signal identity")
|
||||
}
|
||||
in, err := historyPage(in)
|
||||
if err != nil {
|
||||
return OperationPage{}, err
|
||||
}
|
||||
return s.store.ListOperations(ctx, t, workflow, id, in)
|
||||
}
|
||||
func (s *Service) GetOperation(ctx context.Context, t auth.Token, workflow, id, operation core.ID) (OperationView, error) {
|
||||
if workflow.Validate() != nil || id.Validate() != nil || operation.Validate() != nil {
|
||||
return OperationView{}, fault.Invalid("invalid signal operation identity")
|
||||
}
|
||||
return s.store.GetOperation(ctx, t, workflow, id, operation)
|
||||
}
|
||||
@@ -56,6 +56,9 @@ type Result struct {
|
||||
Deduplicated bool `json:"deduplicated"` // Deduplicated 原身份恢复,不重报新事件或重新计时。
|
||||
}
|
||||
type Store interface {
|
||||
List(context.Context, auth.Token, core.ID, service.HistoryPageInput) (Page, error)
|
||||
ListOperations(context.Context, auth.Token, core.ID, core.ID, service.HistoryPageInput) (OperationPage, error)
|
||||
GetOperation(context.Context, auth.Token, core.ID, core.ID, core.ID) (OperationView, error)
|
||||
Send(context.Context, auth.Token, core.ID, string, Input) (Result, error)
|
||||
Get(context.Context, auth.Token, core.ID, core.ID) (View, error)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
core "git.yuntuo.hk/k2safe/orbit/model"
|
||||
"git.yuntuo.hk/k2safe/orbit/platform/auth"
|
||||
"git.yuntuo.hk/k2safe/orbit/pulse/service"
|
||||
)
|
||||
|
||||
type captureStore struct {
|
||||
@@ -53,3 +54,16 @@ func TestSignalInputBoundary(t *testing.T) {
|
||||
t.Fatal("missing identity accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *captureStore) List(context.Context, auth.Token, core.ID, service.HistoryPageInput) (Page, error) {
|
||||
s.calls++
|
||||
return Page{}, nil
|
||||
}
|
||||
func (s *captureStore) ListOperations(context.Context, auth.Token, core.ID, core.ID, service.HistoryPageInput) (OperationPage, error) {
|
||||
s.calls++
|
||||
return OperationPage{}, nil
|
||||
}
|
||||
func (s *captureStore) GetOperation(context.Context, auth.Token, core.ID, core.ID, core.ID) (OperationView, error) {
|
||||
s.calls++
|
||||
return OperationView{}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user