Files
browser/plugins/examples/scum-server-plugin/companion/orchestration.go
T
2026-07-20 16:42:33 +08:00

167 lines
5.8 KiB
Go

package companion
import (
"context"
"fmt"
"time"
)
const (
SmokeClaimLimit = 1
SmokeIsolationEnvironment = "SCUM_COMPANION_SMOKE_SCOPE"
SmokeIsolationValue = "isolated-non-production"
companionDiagnosticsCommandType = "companion.diagnostics"
companionHealthSnapshotType = "companion.health"
companionHealthSchemaVersion = "1"
companionHealthKeepForSeconds = 7 * 24 * 60 * 60
companionHealthMaxRecords = 1000
)
type SmokeOptions struct {
IsolatedNonProduction bool
StreamSuffix func() (string, error)
}
type SmokeResult struct {
ClaimedCount int `json:"claimedCount"`
CompletedCount int `json:"completedCount"`
UnsupportedCount int `json:"unsupportedCount"`
CompletedCommandIDs []string `json:"completedCommandIds"`
UnsupportedCommandIDs []string `json:"unsupportedCommandIds"`
SnapshotID string `json:"snapshotId,omitempty"`
}
func RunOneShotSmoke(ctx context.Context, client *Client, options SmokeOptions) (SmokeResult, error) {
result := SmokeResult{CompletedCommandIDs: []string{}, UnsupportedCommandIDs: []string{}}
if client == nil {
return result, fmt.Errorf("companion client is required")
}
if !options.IsolatedNonProduction {
return result, fmt.Errorf("one-shot smoke requires an isolated non-production queue")
}
streamSuffix := options.StreamSuffix
if streamSuffix == nil {
streamSuffix = randomNonce
}
suffix, err := streamSuffix()
if err != nil || !validNonce(suffix) {
return result, fmt.Errorf("create isolated smoke stream")
}
streamKey := "smoke-" + suffix
if len(streamKey) > 80 {
return result, fmt.Errorf("isolated smoke stream is too long")
}
if _, err := client.Register(ctx); err != nil {
return result, err
}
observedAt := client.now().UTC()
if _, err := client.Heartbeat(ctx, HealthReport{Status: "healthy", Reason: "one-shot smoke ready"}); err != nil {
return result, err
}
commands, err := client.ClaimCommands(ctx, SmokeClaimLimit)
if err != nil {
return result, err
}
result.ClaimedCount = len(commands)
if len(commands) != 1 {
return result, fmt.Errorf("one-shot smoke requires exactly one isolated command")
}
command := commands[0]
if err := validateSmokeDiagnosticsCommand(command, observedAt); err != nil {
result.UnsupportedCount = 1
if command.ID != "" {
result.UnsupportedCommandIDs = append(result.UnsupportedCommandIDs, command.ID)
}
return result, err
}
ack, err := client.AckCommand(ctx, command.ID, command.FencingToken)
if err != nil {
return result, err
}
if ack.CommandID != command.ID || ack.FencingToken != command.FencingToken || ack.State != "claimed" {
return result, fmt.Errorf("platform returned an invalid smoke acknowledgement")
}
diagnostics := map[string]any{
"status": "online",
"version": client.config.Component.Version,
"lastHeartbeatAt": observedAt.Format(time.RFC3339Nano),
}
completed, err := client.CompleteCommand(ctx, command.ID, command.FencingToken, CommandResult{Status: "succeeded", Summary: "companion diagnostics available", Payload: diagnostics})
if err != nil {
return result, err
}
if completed.CommandID != command.ID || completed.State != "succeeded" {
return result, fmt.Errorf("platform returned an invalid smoke command result")
}
result.CompletedCount = 1
result.CompletedCommandIDs = append(result.CompletedCommandIDs, command.ID)
health := map[string]any{
"status": "online",
"version": client.config.Component.Version,
"observedAt": observedAt.Format(time.RFC3339Nano),
"capabilities": append([]string(nil), client.config.Capabilities...),
}
accepted, err := client.UploadSnapshot(ctx, Snapshot{
Type: companionHealthSnapshotType,
SchemaVersion: companionHealthSchemaVersion,
StreamKey: streamKey,
Sequence: 1,
ObservedAt: observedAt,
Payload: health,
KeepForSeconds: companionHealthKeepForSeconds,
MaxRecords: companionHealthMaxRecords,
})
if err != nil {
return result, err
}
if accepted.SnapshotID == "" || accepted.ProfileKey != ProfileKey || accepted.Type != companionHealthSnapshotType || accepted.SchemaVersion != companionHealthSchemaVersion || accepted.StreamKey != streamKey || accepted.Sequence != 1 {
return result, fmt.Errorf("platform returned an invalid smoke snapshot acknowledgement")
}
result.SnapshotID = accepted.SnapshotID
return result, nil
}
func validateSmokeDiagnosticsCommand(command ClaimedCommand, stamp time.Time) error {
if command.CommandType != companionDiagnosticsCommandType {
return fmt.Errorf("isolated smoke claimed an unsupported command")
}
if command.ID == "" || command.ProfileKey != ProfileKey || command.FencingToken == 0 {
return fmt.Errorf("isolated smoke command identity is invalid")
}
if command.LeaseExpiresAt.IsZero() || command.ExpiresAt.IsZero() || !stamp.Before(command.LeaseExpiresAt) || !stamp.Before(command.ExpiresAt) {
return fmt.Errorf("isolated smoke command lease is not live")
}
if command.Payload == nil {
return fmt.Errorf("isolated smoke diagnostics payload is invalid")
}
for key, value := range command.Payload {
switch key {
case "includeWindowState":
if _, ok := value.(bool); !ok {
return fmt.Errorf("isolated smoke diagnostics payload is invalid")
}
case "maxEntries":
if !boundedDiagnosticsEntries(value) {
return fmt.Errorf("isolated smoke diagnostics payload is invalid")
}
default:
return fmt.Errorf("isolated smoke diagnostics payload is invalid")
}
}
return nil
}
func boundedDiagnosticsEntries(value any) bool {
switch typed := value.(type) {
case int:
return typed >= 1 && typed <= 20
case int64:
return typed >= 1 && typed <= 20
case float64:
return typed >= 1 && typed <= 20 && typed == float64(int(typed))
default:
return false
}
}