mirror of
https://github.com/therootcompany/golib.git
synced 2026-04-24 20:58:00 +00:00
refactor: remove callbacks from gitshallow and httpcache
Top-layer callers (IPFilter) now drive all reloads directly after Sync/Fetch return. gitshallow.Init now returns (bool, error). httpcache drops Init and Sync — callers just call Fetch.
This commit is contained in:
parent
5f48a9beaa
commit
e2236aa09b
@ -16,8 +16,7 @@ type Repo struct {
|
|||||||
Depth int // 0 defaults to 1, -1 for all
|
Depth int // 0 defaults to 1, -1 for all
|
||||||
Branch string // Optional: specific branch to clone/pull
|
Branch string // Optional: specific branch to clone/pull
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
callbacks []func() error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new Repo instance.
|
// New creates a new Repo instance.
|
||||||
@ -33,27 +32,18 @@ func New(url, path string, depth int, branch string) *Repo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register adds a callback invoked after each successful clone or pull.
|
// Init clones the repo if missing, then syncs once.
|
||||||
// Use this to reload files and update atomic pointers when the repo changes.
|
// Returns whether anything new was fetched.
|
||||||
func (r *Repo) Register(fn func() error) {
|
func (r *Repo) Init(lightGC bool) (bool, error) {
|
||||||
r.callbacks = append(r.callbacks, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init clones the repo if missing, syncs once, then invokes all callbacks
|
|
||||||
// regardless of whether git had new commits — ensuring files are loaded on startup.
|
|
||||||
func (r *Repo) Init(lightGC bool) error {
|
|
||||||
gitDir := filepath.Join(r.Path, ".git")
|
gitDir := filepath.Join(r.Path, ".git")
|
||||||
if _, err := os.Stat(gitDir); err != nil {
|
if _, err := os.Stat(gitDir); err != nil {
|
||||||
if _, err := r.Clone(); err != nil {
|
if _, err := r.Clone(); err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := r.syncGit(lightGC); err != nil {
|
updated, err := r.syncGit(lightGC)
|
||||||
return err
|
return updated, err
|
||||||
}
|
|
||||||
|
|
||||||
return r.invokeCallbacks()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone performs a shallow clone (--depth N --single-branch --no-tags).
|
// Clone performs a shallow clone (--depth N --single-branch --no-tags).
|
||||||
@ -182,16 +172,10 @@ func (r *Repo) gc(aggressiveGC, pruneNow bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync clones if missing, pulls, runs GC, and invokes callbacks if HEAD changed.
|
// Sync clones if missing, pulls, and runs GC. Returns whether HEAD changed.
|
||||||
// Returns whether HEAD changed.
|
// lightGC=false runs aggressive GC with --prune=now to minimize disk use.
|
||||||
// lightGC=false (zero value) runs aggressive GC with --prune=now to minimize disk use.
|
func (r *Repo) Sync(lightGC bool) (bool, error) {
|
||||||
func (r *Repo) Sync(lightGC bool) (updated bool, err error) {
|
return r.syncGit(lightGC)
|
||||||
updated, err = r.syncGit(lightGC)
|
|
||||||
if err != nil || !updated {
|
|
||||||
return updated, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, r.invokeCallbacks()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repo) syncGit(lightGC bool) (updated bool, err error) {
|
func (r *Repo) syncGit(lightGC bool) (updated bool, err error) {
|
||||||
@ -211,12 +195,3 @@ func (r *Repo) syncGit(lightGC bool) (updated bool, err error) {
|
|||||||
|
|
||||||
return true, r.gc(!lightGC, !lightGC)
|
return true, r.gc(!lightGC, !lightGC)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repo) invokeCallbacks() error {
|
|
||||||
for _, fn := range r.callbacks {
|
|
||||||
if err := fn(); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "error: reload callback: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@ -12,16 +12,15 @@ import (
|
|||||||
const defaultTimeout = 30 * time.Second
|
const defaultTimeout = 30 * time.Second
|
||||||
|
|
||||||
// Cacher fetches a URL to a local file, using ETag/Last-Modified to skip
|
// Cacher fetches a URL to a local file, using ETag/Last-Modified to skip
|
||||||
// unchanged responses. Calls registered callbacks when the file changes.
|
// unchanged responses.
|
||||||
type Cacher struct {
|
type Cacher struct {
|
||||||
URL string
|
URL string
|
||||||
Path string
|
Path string
|
||||||
Timeout time.Duration // 0 uses 30s
|
Timeout time.Duration // 0 uses 30s
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
etag string
|
etag string
|
||||||
lastMod string
|
lastMod string
|
||||||
callbacks []func() error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a Cacher that fetches URL and writes it to path.
|
// New creates a Cacher that fetches URL and writes it to path.
|
||||||
@ -29,34 +28,8 @@ func New(url, path string) *Cacher {
|
|||||||
return &Cacher{URL: url, Path: path}
|
return &Cacher{URL: url, Path: path}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register adds a callback invoked after each successful fetch.
|
|
||||||
func (c *Cacher) Register(fn func() error) {
|
|
||||||
c.callbacks = append(c.callbacks, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init fetches the URL unconditionally (no cached headers yet) and invokes
|
|
||||||
// all callbacks, ensuring files are loaded on startup.
|
|
||||||
func (c *Cacher) Init() error {
|
|
||||||
if _, err := c.Fetch(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.invokeCallbacks()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync sends a conditional GET, writes updated content, and invokes callbacks.
|
|
||||||
// Returns whether the file was updated.
|
|
||||||
func (c *Cacher) Sync() (updated bool, err error) {
|
|
||||||
updated, err = c.Fetch()
|
|
||||||
if err != nil || !updated {
|
|
||||||
return updated, err
|
|
||||||
}
|
|
||||||
return true, c.invokeCallbacks()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch sends a conditional GET and writes new content to Path if the server
|
// Fetch sends a conditional GET and writes new content to Path if the server
|
||||||
// responds with 200. Returns whether the file was updated. Does not invoke
|
// responds with 200. Returns whether the file was updated.
|
||||||
// callbacks — use Sync for the single-cacher case, or call Fetch across
|
|
||||||
// multiple cachers and handle the reload yourself.
|
|
||||||
func (c *Cacher) Fetch() (updated bool, err error) {
|
func (c *Cacher) Fetch() (updated bool, err error) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
@ -118,12 +91,3 @@ func (c *Cacher) Fetch() (updated bool, err error) {
|
|||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cacher) invokeCallbacks() error {
|
|
||||||
for _, fn := range c.callbacks {
|
|
||||||
if err := fn(); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "error: reload callback: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@ -30,8 +30,8 @@ type IPFilter struct {
|
|||||||
inboundPaths []string
|
inboundPaths []string
|
||||||
outboundPaths []string
|
outboundPaths []string
|
||||||
|
|
||||||
git *gitshallow.Repo
|
git *gitshallow.Repo
|
||||||
httpInbound []*httpcache.Cacher
|
httpInbound []*httpcache.Cacher
|
||||||
httpOutbound []*httpcache.Cacher
|
httpOutbound []*httpcache.Cacher
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +47,6 @@ func NewFileFilter(whitelist, inbound, outbound []string) *IPFilter {
|
|||||||
// NewGitFilter clones/pulls gitURL into repoDir and loads the given relative
|
// NewGitFilter clones/pulls gitURL into repoDir and loads the given relative
|
||||||
// paths for each cohort on each update.
|
// paths for each cohort on each update.
|
||||||
func NewGitFilter(gitURL, repoDir string, whitelist, inboundRel, outboundRel []string) *IPFilter {
|
func NewGitFilter(gitURL, repoDir string, whitelist, inboundRel, outboundRel []string) *IPFilter {
|
||||||
repo := gitshallow.New(gitURL, repoDir, 1, "")
|
|
||||||
abs := func(rel []string) []string {
|
abs := func(rel []string) []string {
|
||||||
out := make([]string, len(rel))
|
out := make([]string, len(rel))
|
||||||
for i, p := range rel {
|
for i, p := range rel {
|
||||||
@ -55,14 +54,12 @@ func NewGitFilter(gitURL, repoDir string, whitelist, inboundRel, outboundRel []s
|
|||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
f := &IPFilter{
|
return &IPFilter{
|
||||||
whitelistPaths: whitelist,
|
whitelistPaths: whitelist,
|
||||||
inboundPaths: abs(inboundRel),
|
inboundPaths: abs(inboundRel),
|
||||||
outboundPaths: abs(outboundRel),
|
outboundPaths: abs(outboundRel),
|
||||||
git: repo,
|
git: gitshallow.New(gitURL, repoDir, 1, ""),
|
||||||
}
|
}
|
||||||
repo.Register(f.reloadAll)
|
|
||||||
return f
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHTTPFilter fetches inbound and outbound sources via HTTP;
|
// NewHTTPFilter fetches inbound and outbound sources via HTTP;
|
||||||
@ -83,7 +80,9 @@ func NewHTTPFilter(whitelist []string, inbound, outbound []HTTPSource) *IPFilter
|
|||||||
func (f *IPFilter) Init(lightGC bool) error {
|
func (f *IPFilter) Init(lightGC bool) error {
|
||||||
switch {
|
switch {
|
||||||
case f.git != nil:
|
case f.git != nil:
|
||||||
return f.git.Init(lightGC)
|
if _, err := f.git.Init(lightGC); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
case len(f.httpInbound) > 0 || len(f.httpOutbound) > 0:
|
case len(f.httpInbound) > 0 || len(f.httpOutbound) > 0:
|
||||||
for _, c := range f.httpInbound {
|
for _, c := range f.httpInbound {
|
||||||
if _, err := c.Fetch(); err != nil {
|
if _, err := c.Fetch(); err != nil {
|
||||||
@ -95,10 +94,8 @@ func (f *IPFilter) Init(lightGC bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return f.reloadAll()
|
|
||||||
default:
|
|
||||||
return f.reloadAll()
|
|
||||||
}
|
}
|
||||||
|
return f.reloadAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *IPFilter) Run(ctx context.Context, lightGC bool) {
|
func (f *IPFilter) Run(ctx context.Context, lightGC bool) {
|
||||||
@ -124,7 +121,11 @@ func (f *IPFilter) Run(ctx context.Context, lightGC bool) {
|
|||||||
func (f *IPFilter) sync(lightGC bool) (bool, error) {
|
func (f *IPFilter) sync(lightGC bool) (bool, error) {
|
||||||
switch {
|
switch {
|
||||||
case f.git != nil:
|
case f.git != nil:
|
||||||
return f.git.Sync(lightGC)
|
updated, err := f.git.Sync(lightGC)
|
||||||
|
if err != nil || !updated {
|
||||||
|
return updated, err
|
||||||
|
}
|
||||||
|
return true, f.reloadAll()
|
||||||
case len(f.httpInbound) > 0 || len(f.httpOutbound) > 0:
|
case len(f.httpInbound) > 0 || len(f.httpOutbound) > 0:
|
||||||
var anyUpdated bool
|
var anyUpdated bool
|
||||||
for _, c := range f.httpInbound {
|
for _, c := range f.httpInbound {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user