package orbit import ( "context" "errors" ) func workflowActivationPath(id, key string, activation ...string) (string, error) { if !validID(id) || !workflowVersionName(key) { return "", errors.New("invalid workflow step identity") } path := "/v1/workflows/" + id + "/steps/" + key + "/activations" for _, v := range activation { if !validID(v) { return "", errors.New("invalid activation id") } path += "/" + v } return path, nil } func workflowSignalPath(id string, signal ...string) (string, error) { if !validID(id) { return "", errors.New("invalid workflow id") } path := "/v1/workflows/" + id + "/signals" for _, v := range signal { if !validID(v) { return "", errors.New("invalid signal id") } path += "/" + v } return path, nil } func historyResponseSize(n int, in HistoryPageRequest) bool { limit := in.Limit if limit == 0 { limit = 20 } return n <= limit } // ListWorkflowActivations 返回指定逻辑步骤的各次激活摘要,代次倒序;跨页状态可继续变化。 func (c *Client) ListWorkflowActivations(ctx context.Context, id, key string, in HistoryPageRequest) (WorkflowActivationPage, error) { var out WorkflowActivationPage path, err := workflowActivationPath(id, key) if err != nil { return out, err } query, err := historyPageQuery(in) if err != nil { return out, err } if err = c.call(ctx, "GET", path+query, "", nil, &out); err != nil { return WorkflowActivationPage{}, err } if out.InstanceID != id || !validID(out.StepID) || out.Revision == 0 || out.Items == nil || !historyResponseSize(len(out.Items), in) { return WorkflowActivationPage{}, errors.New("invalid activation page") } for i, a := range out.Items { if !validID(a.ID) || a.StepID != out.StepID || a.Sequence == 0 || a.Revision == 0 || i > 0 && a.Sequence >= out.Items[i-1].Sequence { return WorkflowActivationPage{}, errors.New("invalid activation summary") } } return out, nil } // GetWorkflowActivation 明确读取给定历史激活,Step仍为逻辑步骤当前视图,不能用它替代历史Activation。 func (c *Client) GetWorkflowActivation(ctx context.Context, id, key, activation string) (WorkflowActivationDetail, error) { var out WorkflowActivationDetail path, err := workflowActivationPath(id, key, activation) if err != nil { return out, err } if err = c.call(ctx, "GET", path, "", nil, &out); err != nil { return WorkflowActivationDetail{}, err } if out.InstanceID != id || out.Step.Key != key || out.Activation.ID != activation || !validID(out.Step.ID) || out.Activation.StepID != out.Step.ID || out.Activation.Sequence == 0 || out.Revision == 0 { return WorkflowActivationDetail{}, errors.New("activation detail identity mismatch") } return out, nil } // ListWorkflowPollRounds 只读取一个激活内的查询轮次;人工恢复的同一业务轮可分属不同激活。 func (c *Client) ListWorkflowPollRounds(ctx context.Context, id, key, activation string, in HistoryPageRequest) (WorkflowPollRoundPage, error) { var out WorkflowPollRoundPage path, err := workflowActivationPath(id, key, activation) if err != nil { return out, err } query, err := historyPageQuery(in) if err != nil { return out, err } if err = c.call(ctx, "GET", path+"/rounds"+query, "", nil, &out); err != nil { return WorkflowPollRoundPage{}, err } if out.InstanceID != id || out.ActivationID != activation || out.Revision == 0 || out.Items == nil || !historyResponseSize(len(out.Items), in) { return WorkflowPollRoundPage{}, errors.New("invalid poll round page") } for i, r := range out.Items { if !validID(r.ID) || !validID(r.TaskID) || r.ActivationID != activation || r.Round == 0 || i > 0 && r.Round >= out.Items[i-1].Round { return WorkflowPollRoundPage{}, errors.New("invalid poll round summary") } } return out, nil } // ListWorkflowSignals 不携带信号正文;单条原始内容用GetWorkflowSignal读取。 func (c *Client) ListWorkflowSignals(ctx context.Context, id string, in HistoryPageRequest) (WorkflowSignalPage, error) { var out WorkflowSignalPage path, err := workflowSignalPath(id) if err != nil { return out, err } query, err := historyPageQuery(in) if err != nil { return out, err } if err = c.call(ctx, "GET", path+query, "", nil, &out); err != nil { return WorkflowSignalPage{}, err } if out.WorkflowID != id || out.Revision == 0 || out.Items == nil || !historyResponseSize(len(out.Items), in) { return WorkflowSignalPage{}, errors.New("invalid signal page") } for _, v := range out.Items { if !validID(v.ID) || v.WorkflowID != id { return WorkflowSignalPage{}, errors.New("signal summary identity mismatch") } } return out, nil } // ListWorkflowSignalOperations 需要独立workflows:audit:read权限,只返回信号资源的操作审计摘要。 func (c *Client) ListWorkflowSignalOperations(ctx context.Context, id, signal string, in HistoryPageRequest) (WorkflowSignalOperationPage, error) { var out WorkflowSignalOperationPage path, err := workflowSignalPath(id, signal) if err != nil { return out, err } query, err := historyPageQuery(in) if err != nil { return out, err } if err = c.call(ctx, "GET", path+"/operations"+query, "", nil, &out); err != nil { return WorkflowSignalOperationPage{}, err } if out.Items == nil || !historyResponseSize(len(out.Items), in) { return WorkflowSignalOperationPage{}, errors.New("invalid signal operation page") } for _, v := range out.Items { if !validID(v.ID) || v.WorkflowID != id || v.SignalID != signal { return WorkflowSignalOperationPage{}, errors.New("signal operation identity mismatch") } } return out, nil } func (c *Client) GetWorkflowSignalOperation(ctx context.Context, id, signal, operation string) (WorkflowSignalOperation, error) { var out WorkflowSignalOperation path, err := workflowSignalPath(id, signal) if err != nil { return out, err } if !validID(operation) { return out, errors.New("invalid signal operation id") } if err = c.call(ctx, "GET", path+"/operations/"+operation, "", nil, &out); err != nil { return WorkflowSignalOperation{}, err } if out.ID != operation || out.WorkflowID != id || out.SignalID != signal { return WorkflowSignalOperation{}, errors.New("signal operation detail identity mismatch") } return out, nil }