package httpapi import ( "context" "errors" "git.5iot.com/iotlcm-public/iotlcm-worker-svr/internal/fullsync/contract" "github.com/gogf/gf/v2/errors/gerror" ) type runReader struct { live contract.LiveRunReader archive contract.ArchivedRunReader rounds contract.RoundStatsReader } // NewRunReader composes live-first run queries without knowing either storage // implementation. Archive and rounds are optional (nil disables that lookup). // Only absent live metadata permits archive fallback; live round errors do not. func NewRunReader(live contract.LiveRunReader, archive contract.ArchivedRunReader, rounds contract.RoundStatsReader) (contract.RunReader, error) { if live == nil { return nil, gerror.New("full-sync run reader requires a live reader") } return &runReader{live: live, archive: archive, rounds: rounds}, nil } func (r *runReader) GetRun(ctx context.Context, runID string) (contract.RunView, error) { if err := contract.ValidateID(runID); err != nil { return contract.RunView{}, err } meta, err := r.live.GetRunMeta(ctx, runID) if err == nil { view := contract.RunView{Source: contract.SourceLive, Run: meta} if r.rounds != nil { view.Rounds, err = r.rounds.GetRoundStats(ctx, runID) } return view, err } if !errors.Is(err, contract.ErrNotFound) || r.archive == nil { return contract.RunView{}, err } archive, err := r.archive.GetArchivedRun(ctx, runID) if err != nil { return contract.RunView{}, err } return contract.RunView{Source: contract.SourceArchive, Run: archive.Run, Rounds: archive.Rounds}, nil }