97 lines
3.7 KiB
Go
97 lines
3.7 KiB
Go
package continuityexecutor
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
|
|
commitcontract "git.cin.su/m/Assistant/contracts/commit"
|
|
"git.cin.su/m/Assistant/contracts/continuity"
|
|
"git.cin.su/m/Assistant/modules/commit/ports"
|
|
)
|
|
|
|
type Adapter struct {
|
|
baseURL string
|
|
token string
|
|
client *http.Client
|
|
}
|
|
|
|
func New(baseURL, token string, client *http.Client) (*Adapter, error) {
|
|
baseURL = strings.TrimRight(baseURL, "/")
|
|
if baseURL == "" || token == "" || client == nil {
|
|
return nil, fmt.Errorf("continuity executor requires base URL, token, and HTTP client")
|
|
}
|
|
if _, err := url.ParseRequestURI(baseURL); err != nil {
|
|
return nil, fmt.Errorf("invalid continuity executor URL: %w", err)
|
|
}
|
|
return &Adapter{baseURL: baseURL, token: token, client: client}, nil
|
|
}
|
|
|
|
func (a *Adapter) Execute(action commitcontract.AuthorizedAction) ports.ExecutionResult {
|
|
if action.Proposal.CapabilityID != commitcontract.CapabilityContinuityTransition || action.Proposal.Operation != commitcontract.OperationSatisfyDelivered {
|
|
return ports.ExecutionResult{Known: true, Succeeded: false}
|
|
}
|
|
command := continuity.SatisfyDeliveredCommand{
|
|
ActionIntentID: continuity.CommittedActionIntentID(action.Proposal.IntentID),
|
|
AuthorizedActionID: continuity.CommittedAuthorizedActionID(action.ID),
|
|
OwnerPrincipalID: action.PrincipalID,
|
|
Subject: action.Proposal.ContinuitySubject,
|
|
}
|
|
body, err := json.Marshal(command)
|
|
if err != nil {
|
|
return ports.ExecutionResult{Known: true, Succeeded: false}
|
|
}
|
|
request, err := http.NewRequest(http.MethodPost, a.baseURL+"/v1/internal/executor/satisfy-delivered", bytes.NewReader(body))
|
|
if err != nil {
|
|
return ports.ExecutionResult{Known: true, Succeeded: false}
|
|
}
|
|
request.Header.Set("Authorization", "Bearer "+a.token)
|
|
request.Header.Set("Content-Type", "application/json")
|
|
response, err := a.client.Do(request)
|
|
if err != nil {
|
|
return ports.ExecutionResult{Known: false}
|
|
}
|
|
defer response.Body.Close()
|
|
if response.StatusCode == http.StatusOK {
|
|
var receipt continuity.ActionReceipt
|
|
if json.NewDecoder(response.Body).Decode(&receipt) != nil ||
|
|
receipt.ActionIntentID != command.ActionIntentID || receipt.AuthorizedActionID != command.AuthorizedActionID ||
|
|
receipt.ResultState != continuity.ProspectiveSatisfied {
|
|
return ports.ExecutionResult{Known: false}
|
|
}
|
|
return ports.ExecutionResult{Known: true, Succeeded: true}
|
|
}
|
|
if response.StatusCode >= 400 && response.StatusCode < 500 {
|
|
return ports.ExecutionResult{Known: true, Succeeded: false}
|
|
}
|
|
return ports.ExecutionResult{Known: false}
|
|
}
|
|
|
|
func (a *Adapter) Reconcile(action commitcontract.AuthorizedAction) ports.ExecutionResult {
|
|
endpoint := a.baseURL + "/v1/internal/executor/receipts/" + url.PathEscape(string(action.Proposal.IntentID))
|
|
request, err := http.NewRequest(http.MethodGet, endpoint, nil)
|
|
if err != nil {
|
|
return ports.ExecutionResult{Known: false}
|
|
}
|
|
request.Header.Set("Authorization", "Bearer "+a.token)
|
|
response, err := a.client.Do(request)
|
|
if err != nil {
|
|
return ports.ExecutionResult{Known: false}
|
|
}
|
|
defer response.Body.Close()
|
|
if response.StatusCode != http.StatusOK {
|
|
return ports.ExecutionResult{Known: false}
|
|
}
|
|
var receipt continuity.ActionReceipt
|
|
if json.NewDecoder(response.Body).Decode(&receipt) != nil ||
|
|
receipt.ActionIntentID != continuity.CommittedActionIntentID(action.Proposal.IntentID) ||
|
|
receipt.AuthorizedActionID != continuity.CommittedAuthorizedActionID(action.ID) ||
|
|
receipt.OwnerPrincipalID != action.PrincipalID || receipt.Subject != action.Proposal.ContinuitySubject {
|
|
return ports.ExecutionResult{Known: false}
|
|
}
|
|
return ports.ExecutionResult{Known: true, Succeeded: receipt.ResultState == continuity.ProspectiveSatisfied}
|
|
}
|