97 lines
2.9 KiB
Go
97 lines
2.9 KiB
Go
package artifacts
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"gitea.maximumdirect.net/eric/narratio/internal/adapters/storage"
|
|
"gitea.maximumdirect.net/eric/narratio/internal/manifest"
|
|
)
|
|
|
|
const (
|
|
// MaxLegacyCurrentRunPointerBytes bounds the compatibility run selector.
|
|
MaxLegacyCurrentRunPointerBytes int64 = 4 << 10
|
|
// MaxLegacyCurrentManifestBytes bounds the compatibility session manifest.
|
|
MaxLegacyCurrentManifestBytes int64 = MaxRemoteSessionManifestBytes
|
|
)
|
|
|
|
// This file is temporary compatibility support for sessions published before
|
|
// immutable current commits. It can be removed after legacy remote state is migrated.
|
|
|
|
func loadLegacyCurrentState(
|
|
ctx context.Context,
|
|
store storage.ObjectStore,
|
|
sessionPrefix string,
|
|
validation CurrentStateValidation,
|
|
) (*CurrentState, error) {
|
|
currentManifestKey, currentRunIDKey := ResolveCurrentStateKeys(sessionPrefix)
|
|
runID, err := loadLegacyCurrentRunPointer(ctx, store, currentRunIDKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
m, err := loadLegacyCurrentManifest(ctx, store, currentManifestKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
state := &CurrentState{
|
|
SessionPrefix: sessionPrefix,
|
|
CurrentRunIDKey: currentRunIDKey,
|
|
CurrentManifestKey: currentManifestKey,
|
|
RunID: runID,
|
|
Manifest: m,
|
|
}
|
|
if err := ValidateCurrentStateIdentity(state, validation); err != nil {
|
|
return nil, err
|
|
}
|
|
return state, nil
|
|
}
|
|
|
|
func loadLegacyCurrentRunPointer(ctx context.Context, store storage.ObjectStore, currentRunIDKey string) (string, error) {
|
|
key := strings.TrimSpace(currentRunIDKey)
|
|
if key == "" {
|
|
return "", fmt.Errorf("current run pointer key is required")
|
|
}
|
|
|
|
_, data, err := readCurrentStateControlObject(ctx, store, key, "legacy current run pointer", MaxLegacyCurrentRunPointerBytes)
|
|
if err != nil {
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
return "", &CurrentRunPointerMissingError{Key: key}
|
|
}
|
|
return "", err
|
|
}
|
|
runID := strings.TrimSpace(string(data))
|
|
if runID == "" {
|
|
return "", fmt.Errorf("current run pointer %q is empty", key)
|
|
}
|
|
if err := ValidateRunIdentity(runID); err != nil {
|
|
return "", fmt.Errorf("current run pointer %q contains an unsafe legacy run id; migrate remote state before use: %w", key, err)
|
|
}
|
|
return runID, nil
|
|
}
|
|
|
|
func loadLegacyCurrentManifest(ctx context.Context, store storage.ObjectStore, currentManifestKey string) (*manifest.Manifest, error) {
|
|
key := strings.TrimSpace(currentManifestKey)
|
|
if key == "" {
|
|
return nil, fmt.Errorf("current manifest key is required")
|
|
}
|
|
|
|
_, data, err := readCurrentStateControlObject(ctx, store, key, "legacy current manifest", MaxLegacyCurrentManifestBytes)
|
|
if err != nil {
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
return nil, &CurrentManifestMissingError{Key: key}
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
m, err := (&manifest.LocalStore{}).LoadReader(ctx, bytes.NewReader(data))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("current manifest decode failed: %w", err)
|
|
}
|
|
return m, nil
|
|
}
|