From 5687f7f992a2d85e1060d58a667ee8735ab16e1a Mon Sep 17 00:00:00 2001 From: Eric Phillips Date: Tue, 14 Apr 2026 22:46:23 -0600 Subject: [PATCH] added refresh db capability and did some refactoring --- config.go | 10 ++++++---- handlerPkgs.go | 10 +++++----- internal/cache/cache.go | 37 ++++++++++++++++++++----------------- internal/cache/refresh.go | 27 +++++++++++++++++++++++++++ main.go | 19 ++++++++++++------- 5 files changed, 70 insertions(+), 33 deletions(-) create mode 100644 internal/cache/refresh.go diff --git a/config.go b/config.go index 1778b52..adef269 100644 --- a/config.go +++ b/config.go @@ -1,13 +1,15 @@ package main type Config struct { - RepoPath string - MirrorURL string + MirrorRoot string + MirrorURL string + Port string } func NewConfig() *Config { return &Config{ - RepoPath: "/home/ewpt3ch/dev/pacman-cache-server/tmprepo", - MirrorURL: "https://us.mirrors.cicku.me/archlinux/", + MirrorRoot: "/home/ewpt3ch/dev/pacman-cache-server/tmprepo", + MirrorURL: "https://us.mirrors.cicku.me/archlinux/", + Port: "8090", } } diff --git a/handlerPkgs.go b/handlerPkgs.go index a8ced60..bf2c467 100644 --- a/handlerPkgs.go +++ b/handlerPkgs.go @@ -9,17 +9,17 @@ import ( "gitea.ewpt3ch.dev/ewpt3ch/pkgstash/internal/cache" ) -func handlePackage(w http.ResponseWriter, req *http.Request, c *cache.Cache) { +func (s *Server) handlePackage(w http.ResponseWriter, req *http.Request) { // build file paths from the request, they follow archlinux repo - // /[core, extra, etc]/os/[x86_64, arm, etc]/package.pkg.tar.zst[.sig] + // /[core, extra, etc]/os/[x86_64, arm, etc]/package.pkg.tar.zst[.sig] repo := req.PathValue("repo") arch := req.PathValue("arch") file := req.PathValue("file") - relPath := filepath.Join(repo, "os", arch, file) //path from repo root to pkg or db file - pkgPath := filepath.Join(repoRoot, relPath) //path for local read of the file + repoPath := filepath.Join(repo, "os", arch, file) //path from mirror root to pkg or db file + pkgPath := filepath.Join(s.cfg.MirrorRoot, repoPath) //absolute path for local read of the file if _, err := os.Stat(pkgPath); err != nil { - err = c.Fetch(relPath) + err = s.c.Fetch(repoPath) if err != nil { var upstreamErr *cache.UpstreamError if errors.As(err, &upstreamErr) { diff --git a/internal/cache/cache.go b/internal/cache/cache.go index 849f647..92c33d7 100644 --- a/internal/cache/cache.go +++ b/internal/cache/cache.go @@ -3,24 +3,27 @@ package cache import ( "fmt" "io" - "log" "net/http" "os" "path/filepath" + "sync" "golang.org/x/sync/singleflight" ) type Cache struct { - repo string - mirrorURL string - sf singleflight.Group + localRoot string + mirrorURL string + mirroredRepos []string + sf singleflight.Group //prevents duplicate downloads + mu sync.Mutex } -func NewCache(repo string, mirrorURL string) *Cache { +func NewCache(localRoot string, mirrorURL string) *Cache { return &Cache{ - repo: repo, - mirrorURL: mirrorURL, + localRoot: localRoot, + mirrorURL: mirrorURL, + mirroredRepos: []string{"core", "extra"}, } } @@ -39,12 +42,12 @@ func (e *UpstreamError) Error() string { return fmt.Sprintf("upstream returned %d", e.StatusCode) } -func (c *Cache) fetch(pkgPath string) error { - // pkgPath is relative to the repo or mirror root - tempPkgPath := pkgPath + ".tmp" - tempPkgName := filepath.Join(c.repo, tempPkgPath) //full tmp write path - outPkg := filepath.Join(c.repo, pkgPath) - pkgURL := c.mirrorURL + pkgPath +func (c *Cache) fetch(pkgName string) error { + // pkgName is relative to the localRoot + tempPkgName := pkgName + ".tmp" + tempPkgPath := filepath.Join(c.localRoot, tempPkgName) //full tmp write path + outPkg := filepath.Join(c.localRoot, pkgName) + pkgURL := c.mirrorURL + pkgName resp, err := http.Get(pkgURL) if err != nil { @@ -56,7 +59,7 @@ func (c *Cache) fetch(pkgPath string) error { return &UpstreamError{StatusCode: resp.StatusCode} } - outFile, err := os.Create(tempPkgName) + outFile, err := os.Create(tempPkgPath) if err != nil { return err } @@ -64,12 +67,12 @@ func (c *Cache) fetch(pkgPath string) error { _, err = io.Copy(outFile, resp.Body) if err != nil { - os.Remove(tempPkgName) + os.Remove(tempPkgPath) return err } - if err := os.Rename(tempPkgName, outPkg); err != nil { - os.Remove(tempPkgName) + if err := os.Rename(tempPkgPath, outPkg); err != nil { + os.Remove(tempPkgPath) return err } return nil diff --git a/internal/cache/refresh.go b/internal/cache/refresh.go new file mode 100644 index 0000000..b5bc4bc --- /dev/null +++ b/internal/cache/refresh.go @@ -0,0 +1,27 @@ +package cache + +import "path/filepath" + +func (c *Cache) Refresh() error { + if !c.mu.TryLock() { + return nil + } + defer c.mu.Unlock() + + for _, repo := range c.mirroredRepos { + if err := c.refreshDB(repo); err != nil { + return err + } + } + return nil +} + +func (c *Cache) refreshDB(repo string) error { + dbFile := repo + ".db.tar.gz" + dbPath := filepath.Join(repo, "os/x86_64", dbFile) + err := c.Fetch(dbPath) + if err != nil { + return err + } + return nil +} diff --git a/main.go b/main.go index ee95b9f..e0b913a 100644 --- a/main.go +++ b/main.go @@ -7,20 +7,25 @@ import ( "gitea.ewpt3ch.dev/ewpt3ch/pkgstash/internal/cache" ) -const repoRoot = "/home/ewpt3ch/dev/pacman-cache-server/tmprepo" +type Server struct { + cfg *Config + c *cache.Cache +} func main() { - const port = "8090" cfg := NewConfig() - c := cache.NewCache(cfg.RepoPath, cfg.MirrorURL) + c := cache.NewCache(cfg.MirrorRoot, cfg.MirrorURL) + srv := &Server{cfg: cfg, c: c} mux := http.NewServeMux() - mux.HandleFunc("GET /{repo}/os/{arch}/{file}", func(w http.ResponseWriter, req *http.Request) { - handlePackage(w, req, c) - }) + mux.HandleFunc("GET /{repo}/os/{arch}/{file}", srv.handlePackage) + + if err := srv.c.Refresh(); err != nil { + log.Fatal(err) + } httpServe := &http.Server{ - Addr: ":" + port, + Addr: ":" + srv.cfg.Port, Handler: mux, }