added multiple mirrors to round robin downloads from

This commit is contained in:
2026-04-20 22:18:22 -06:00
parent 6fdf5a4a52
commit 9fa2b93330
4 changed files with 24 additions and 10 deletions
+4 -4
View File
@@ -8,7 +8,7 @@ import (
type Config struct { type Config struct {
CacheRoot string `toml:"cache_root"` CacheRoot string `toml:"cache_root"`
MirrorURL string `toml:"mirror_url"` MirrorURLs []string `toml:"mirror_url"`
MirroredRepos []string `toml:"mirrored_repos"` MirroredRepos []string `toml:"mirrored_repos"`
Port string `toml:"port"` Port string `toml:"port"`
Auth AuthConfig `toml:"auth"` Auth AuthConfig `toml:"auth"`
@@ -22,7 +22,7 @@ type AuthConfig struct {
func NewConfig() *Config { func NewConfig() *Config {
return &Config{ return &Config{
CacheRoot: "/home/ewpt3ch/dev/pacman-cache-server/tmprepo", CacheRoot: "/home/ewpt3ch/dev/pacman-cache-server/tmprepo",
MirrorURL: "https://us.mirrors.cicku.me/archlinux/", MirrorURLs: "https://us.mirrors.cicku.me/archlinux/",
Port: "8090", Port: "8090",
Auth: AuthConfig{Token: "FakeToken"}, Auth: AuthConfig{Token: "FakeToken"},
} }
@@ -48,8 +48,8 @@ func (c *Config) validate() error {
if c.CacheRoot == "" { if c.CacheRoot == "" {
return fmt.Errorf("cache root is required") return fmt.Errorf("cache root is required")
} }
if c.MirrorURL == "" { if len(c.MirrorURLs) == 0 {
return fmt.Errorf("mirror url is required") return fmt.Errorf("at least one mirror is required")
} }
if c.Port == "" { if c.Port == "" {
c.Port = "8090" c.Port = "8090"
+3 -1
View File
@@ -1,5 +1,7 @@
cache_root = "/home/ewpt3ch/dev/pacman-cache-server/tmprepo" cache_root = "/home/ewpt3ch/dev/pacman-cache-server/tmprepo"
mirror_url = "https://us.mirrors.cicku.me/archlinux/" mirror_url = ["https://us.mirrors.cicku.me/archlinux/",
"https://losangeles.mirror.pkgbuild.com/",
"https://mirror.givebytes.net/archlinux/"]
# array of upstream repos this server caches see pacman.conf # array of upstream repos this server caches see pacman.conf
# or pacman docs for more info <core, extra, multilib> # or pacman docs for more info <core, extra, multilib>
mirrored_repos = ["core", "extra"] mirrored_repos = ["core", "extra"]
+16 -4
View File
@@ -3,11 +3,13 @@ package cache
import ( import (
"fmt" "fmt"
"io" "io"
"log"
"net" "net"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"sync" "sync"
"sync/atomic"
"time" "time"
"golang.org/x/sync/singleflight" "golang.org/x/sync/singleflight"
@@ -15,14 +17,15 @@ import (
type Cache struct { type Cache struct {
cacheRoot string cacheRoot string
mirrorURL string mirrorURLs []string
mirroredRepos []string mirroredRepos []string
mirrorIdx atomic.Uint32
sf singleflight.Group //prevents duplicate downloads sf singleflight.Group //prevents duplicate downloads
mu sync.Mutex mu sync.Mutex
client http.Client client http.Client
} }
func NewCache(cacheRoot string, mirrorURL string, mirroredRepos []string) *Cache { func NewCache(cacheRoot string, mirrorURLs []string, mirroredRepos []string) *Cache {
transport := &http.Transport{ transport := &http.Transport{
DialContext: (&net.Dialer{ DialContext: (&net.Dialer{
Timeout: 5 * time.Second, Timeout: 5 * time.Second,
@@ -32,7 +35,7 @@ func NewCache(cacheRoot string, mirrorURL string, mirroredRepos []string) *Cache
return &Cache{ return &Cache{
cacheRoot: cacheRoot, cacheRoot: cacheRoot,
mirrorURL: mirrorURL, mirrorURLs: mirrorURLs,
mirroredRepos: mirroredRepos, mirroredRepos: mirroredRepos,
client: http.Client{ client: http.Client{
Timeout: 15 * time.Second, Timeout: 15 * time.Second,
@@ -42,7 +45,9 @@ func NewCache(cacheRoot string, mirrorURL string, mirroredRepos []string) *Cache
} }
func (c *Cache) Fetch(pkgPath string) error { func (c *Cache) Fetch(pkgPath string) error {
log.Printf("pkgPath from Fetch %v", pkgPath)
_, err, _ := c.sf.Do(pkgPath, func() (any, error) { _, err, _ := c.sf.Do(pkgPath, func() (any, error) {
log.Print("calling fetch")
return nil, c.fetch(pkgPath) return nil, c.fetch(pkgPath)
}) })
return err return err
@@ -62,7 +67,9 @@ func (c *Cache) fetch(pkgName string) error {
tempPkgName := pkgName + ".tmp" tempPkgName := pkgName + ".tmp"
tempPkgPath := filepath.Join(c.cacheRoot, tempPkgName) //full tmp write path tempPkgPath := filepath.Join(c.cacheRoot, tempPkgName) //full tmp write path
outPkg := filepath.Join(c.cacheRoot, pkgName) outPkg := filepath.Join(c.cacheRoot, pkgName)
pkgURL := c.mirrorURL + pkgName pkgURL := c.nextMirror() + pkgName
log.Printf("fetching %v", pkgURL)
resp, err := c.client.Get(pkgURL) resp, err := c.client.Get(pkgURL)
if err != nil { if err != nil {
@@ -92,3 +99,8 @@ func (c *Cache) fetch(pkgName string) error {
} }
return nil return nil
} }
func (c *Cache) nextMirror() string {
idx := c.mirrorIdx.Add(1) - 1
return c.mirrorURLs[idx%uint32(len(c.mirrorURLs))]
}
+1 -1
View File
@@ -28,7 +28,7 @@ func main() {
log.Fatal(err) log.Fatal(err)
} }
c := cache.NewCache(cfg.CacheRoot, cfg.MirrorURL, cfg.MirroredRepos) c := cache.NewCache(cfg.CacheRoot, cfg.MirrorURLs, cfg.MirroredRepos)
srv := &Server{cfg: cfg, c: c} srv := &Server{cfg: cfg, c: c}
mux := http.NewServeMux() mux := http.NewServeMux()