package engine import ( "errors" "fmt" "os" "path/filepath" "strings" ) // seedMarkerFile names the file, in the flat dictionary directory, that records the // version the directory was first seeded as. It is dot-prefixed so OpenWithVersions' // version scan skips it (like the .staging upload area). const seedMarkerFile = ".seed_version" // resolveSeedVersion returns the version label the flat dictionary directory is // addressed by, recording it on first use. // // The contour's dictionary lives on a named volume seeded from the image once and // never re-seeded (deploy/docker-compose.yml). The flat DAWGs carry no embedded // version, so the version a volume was first seeded as is recorded in a // .seed_version marker and is **authoritative** from then on: // // - fresh directory (no marker): record bootVersion (the build's // BACKEND_DICT_VERSION) and return it — the seed of a fresh volume; // - already-seeded directory: return the recorded marker and ignore bootVersion. // // So a later build seed never relabels the already-seeded flat bytes — which would void // games pinned to the prior label and mis-serve new ones. The new build version is instead // delivered as a NEW subdirectory (DeliverVersion) and made active (Service.InitActiveVersion), // so a redeploy still moves new games to it while old games keep the flat label. New games // pin the active version (DB-persisted); a console upload can also set it out-of-band. // // A directory that cannot be written makes the first record fail; that also breaks // the admin console (which writes version subdirectories here), so the error is // returned rather than swallowed, matching the package's fail-loud dictionary setup. func resolveSeedVersion(dir, bootVersion string) (string, error) { path := filepath.Join(dir, seedMarkerFile) data, err := os.ReadFile(path) if err != nil && !errors.Is(err, os.ErrNotExist) { return "", fmt.Errorf("engine: read dictionary seed marker %s: %w", path, err) } if err == nil { if recorded := strings.TrimSpace(string(data)); recorded != "" { return recorded, nil } // An empty/corrupt marker falls through and is rewritten from bootVersion. } if werr := os.WriteFile(path, []byte(bootVersion+"\n"), 0o644); werr != nil { return "", fmt.Errorf("engine: record dictionary seed marker %s: %w", path, werr) } return bootVersion, nil }