108 lines
2.5 KiB
Go
108 lines
2.5 KiB
Go
package state
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
legacyOwnerSchema = 2
|
|
legacyMultiOwnerSchema = 3
|
|
CatalogSchemaVersion = 4
|
|
legacySchemaVersion = 1
|
|
StateModeCatalog = "catalog"
|
|
OutputKindSource = "source"
|
|
OutputKindGenerated = "generated"
|
|
)
|
|
|
|
type StateDocument struct {
|
|
Catalog *CatalogState
|
|
SupersededLegacy *SupersededLegacyState
|
|
}
|
|
|
|
type DestinationStatus struct {
|
|
Catalog *CatalogState
|
|
SupersededLegacy *SupersededLegacyState
|
|
StateErr error
|
|
HasContents bool
|
|
}
|
|
|
|
type SupersededLegacyState struct {
|
|
SchemaVersion int
|
|
}
|
|
|
|
type StatePolicy struct {
|
|
Mode string
|
|
}
|
|
|
|
type OwnerScope struct {
|
|
PipelineID string
|
|
DestinationID string
|
|
}
|
|
|
|
type rawStatePolicy struct {
|
|
Mode string `json:"mode"`
|
|
}
|
|
|
|
func ParseDocument(data []byte) (StateDocument, error) {
|
|
schemaVersion, err := parseSchemaVersion(data)
|
|
if err != nil {
|
|
return StateDocument{}, err
|
|
}
|
|
switch schemaVersion {
|
|
case legacySchemaVersion, legacyOwnerSchema, legacyMultiOwnerSchema:
|
|
return StateDocument{SupersededLegacy: &SupersededLegacyState{SchemaVersion: schemaVersion}}, nil
|
|
case CatalogSchemaVersion:
|
|
catalog, err := ParseCatalog(data)
|
|
if err != nil {
|
|
return StateDocument{}, err
|
|
}
|
|
return StateDocument{Catalog: &catalog}, nil
|
|
default:
|
|
return StateDocument{}, fmt.Errorf("state schema_version %d is unsupported", schemaVersion)
|
|
}
|
|
}
|
|
|
|
func parseSchemaVersion(data []byte) (int, error) {
|
|
decoder := json.NewDecoder(bytes.NewReader(data))
|
|
var raw struct {
|
|
SchemaVersion *int `json:"schema_version"`
|
|
}
|
|
if err := decoder.Decode(&raw); err != nil {
|
|
return 0, fmt.Errorf("parse distributor state: %w", err)
|
|
}
|
|
var extra any
|
|
if err := decoder.Decode(&extra); err != io.EOF {
|
|
return 0, fmt.Errorf("parse distributor state: trailing data")
|
|
}
|
|
if raw.SchemaVersion == nil {
|
|
return 0, fmt.Errorf("state schema_version is required")
|
|
}
|
|
return *raw.SchemaVersion, nil
|
|
}
|
|
|
|
func (p StatePolicy) MarshalJSON() ([]byte, error) {
|
|
type policyJSON struct {
|
|
Mode string `json:"mode"`
|
|
}
|
|
return json.Marshal(policyJSON{Mode: p.Mode})
|
|
}
|
|
|
|
func CurrentOwnerScope(pipelineID, destinationID string) OwnerScope {
|
|
return OwnerScope{PipelineID: pipelineID, DestinationID: destinationID}
|
|
}
|
|
|
|
func parseRequiredTime(field string, raw *string) (time.Time, error) {
|
|
if raw == nil || *raw == "" {
|
|
return time.Time{}, fmt.Errorf("%s is required", field)
|
|
}
|
|
parsed, err := time.Parse(time.RFC3339, *raw)
|
|
if err != nil {
|
|
return time.Time{}, fmt.Errorf("%s must be RFC3339: %w", field, err)
|
|
}
|
|
return parsed.UTC(), nil
|
|
}
|