refactor: migrate dlcache to struct

This commit is contained in:
Maxim Slipenko 2025-01-14 12:59:00 +03:00
parent eeb25c239b
commit 6bc6bfdcd9
4 changed files with 83 additions and 30 deletions

@ -14,7 +14,7 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
// Пакет dl содержит абстракции для загрузки файлов и каталогов // Пакет dl содержит абстракции для загрузки файлов и каталогов
// из различных источников. // из различных источников.
@ -39,6 +39,7 @@ import (
"golang.org/x/crypto/blake2b" "golang.org/x/crypto/blake2b"
"golang.org/x/crypto/blake2s" "golang.org/x/crypto/blake2s"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/dlcache" "plemya-x.ru/alr/internal/dlcache"
"plemya-x.ru/alr/pkg/loggerctx" "plemya-x.ru/alr/pkg/loggerctx"
) )
@ -142,6 +143,9 @@ type UpdatingDownloader interface {
// Функция Download загружает файл или каталог с использованием указанных параметров // Функция Download загружает файл или каталог с использованием указанных параметров
func Download(ctx context.Context, opts Options) (err error) { func Download(ctx context.Context, opts Options) (err error) {
log := loggerctx.From(ctx) log := loggerctx.From(ctx)
cfg := config.GetInstance(ctx)
dc := dlcache.New(cfg)
normalized, err := normalizeURL(opts.URL) normalized, err := normalizeURL(opts.URL)
if err != nil { if err != nil {
return err return err
@ -156,7 +160,7 @@ func Download(ctx context.Context, opts Options) (err error) {
} }
var t Type var t Type
cacheDir, ok := dlcache.Get(ctx, opts.URL) cacheDir, ok := dc.Get(ctx, opts.URL)
if ok { if ok {
var updated bool var updated bool
if d, ok := d.(UpdatingDownloader); ok { if d, ok := d.(UpdatingDownloader); ok {
@ -203,7 +207,7 @@ func Download(ctx context.Context, opts Options) (err error) {
log.Info("Downloading source").Str("source", opts.Name).Str("downloader", d.Name()).Send() log.Info("Downloading source").Str("source", opts.Name).Str("downloader", d.Name()).Send()
cacheDir, err = dlcache.New(ctx, opts.URL) cacheDir, err = dc.New(ctx, opts.URL)
if err != nil { if err != nil {
return err return err
} }
@ -299,8 +303,6 @@ func linkDir(src, dest string) error {
return nil return nil
} }
rel, err := filepath.Rel(src, path) rel, err := filepath.Rel(src, path)
if err != nil { if err != nil {
return err return err

@ -20,29 +20,41 @@ package dlcache
import ( import (
"context" "context"
"crypto/sha1"
"encoding/hex"
"io"
"os" "os"
"path/filepath" "path/filepath"
"plemya-x.ru/alr/internal/config" "plemya-x.ru/alr/internal/config"
) )
// BasePath returns the base path of the download cache type Config interface {
func BasePath(ctx context.Context) string { GetPaths(ctx context.Context) *config.Paths
return filepath.Join(config.GetPaths(ctx).CacheDir, "dl") }
type DownloadCache struct {
cfg Config
}
func New(cfg Config) *DownloadCache {
return &DownloadCache{
cfg,
}
}
func (dc *DownloadCache) BasePath(ctx context.Context) string {
return filepath.Join(
dc.cfg.GetPaths(ctx).CacheDir, "dl",
)
} }
// New creates a new directory with the given ID in the cache. // New creates a new directory with the given ID in the cache.
// If a directory with the same ID already exists, // If a directory with the same ID already exists,
// it will be deleted before creating a new one. // it will be deleted before creating a new one.
func New(ctx context.Context, id string) (string, error) { func (dc *DownloadCache) New(ctx context.Context, id string) (string, error) {
h, err := hashID(id) h, err := hashID(id)
if err != nil { if err != nil {
return "", err return "", err
} }
itemPath := filepath.Join(BasePath(ctx), h) itemPath := filepath.Join(dc.BasePath(ctx), h)
fi, err := os.Stat(itemPath) fi, err := os.Stat(itemPath)
if err == nil || (fi != nil && !fi.IsDir()) { if err == nil || (fi != nil && !fi.IsDir()) {
@ -65,12 +77,12 @@ func New(ctx context.Context, id string) (string, error) {
// returns the directory and true. If it // returns the directory and true. If it
// does not exist, it returns an empty string // does not exist, it returns an empty string
// and false. // and false.
func Get(ctx context.Context, id string) (string, bool) { func (dc *DownloadCache) Get(ctx context.Context, id string) (string, bool) {
h, err := hashID(id) h, err := hashID(id)
if err != nil { if err != nil {
return "", false return "", false
} }
itemPath := filepath.Join(BasePath(ctx), h) itemPath := filepath.Join(dc.BasePath(ctx), h)
_, err = os.Stat(itemPath) _, err = os.Stat(itemPath)
if err != nil { if err != nil {
@ -79,15 +91,3 @@ func Get(ctx context.Context, id string) (string, bool) {
return itemPath, true return itemPath, true
} }
// hashID hashes the input ID with SHA1
// and returns the hex string of the hashed
// ID.
func hashID(id string) (string, error) {
h := sha1.New()
_, err := io.WriteString(h, id)
if err != nil {
return "", err
}
return hex.EncodeToString(h.Sum(nil)), nil
}

@ -39,14 +39,49 @@ func init() {
config.GetPaths(context.Background()).RepoDir = dir config.GetPaths(context.Background()).RepoDir = dir
} }
type TestALRConfig struct {
CacheDir string
}
func (c *TestALRConfig) GetPaths(ctx context.Context) *config.Paths {
return &config.Paths{
CacheDir: c.CacheDir,
}
}
func prepare(t *testing.T) *TestALRConfig {
t.Helper()
dir, err := os.MkdirTemp("/tmp", "alr-dlcache-test.*")
if err != nil {
panic(err)
}
return &TestALRConfig{
CacheDir: dir,
}
}
func cleanup(t *testing.T, cfg *TestALRConfig) {
t.Helper()
os.Remove(cfg.CacheDir)
}
func TestNew(t *testing.T) { func TestNew(t *testing.T) {
cfg := prepare(t)
defer cleanup(t, cfg)
dc := dlcache.New(cfg)
ctx := context.Background()
const id = "https://example.com" const id = "https://example.com"
dir, err := dlcache.New(id) dir, err := dc.New(ctx, id)
if err != nil { if err != nil {
t.Errorf("Expected no error, got %s", err) t.Errorf("Expected no error, got %s", err)
} }
exp := filepath.Join(dlcache.BasePath(), sha1sum(id)) exp := filepath.Join(dc.BasePath(ctx), sha1sum(id))
if dir != exp { if dir != exp {
t.Errorf("Expected %s, got %s", exp, dir) t.Errorf("Expected %s, got %s", exp, dir)
} }
@ -60,7 +95,7 @@ func TestNew(t *testing.T) {
t.Errorf("Expected cache item to be a directory") t.Errorf("Expected cache item to be a directory")
} }
dir2, ok := dlcache.Get(id) dir2, ok := dc.Get(ctx, id)
if !ok { if !ok {
t.Errorf("Expected Get() to return valid value") t.Errorf("Expected Get() to return valid value")
} }

16
internal/dlcache/utils.go Normal file

@ -0,0 +1,16 @@
package dlcache
import (
"crypto/sha1"
"encoding/hex"
"io"
)
func hashID(id string) (string, error) {
h := sha1.New()
_, err := io.WriteString(h, id)
if err != nil {
return "", err
}
return hex.EncodeToString(h.Sum(nil)), nil
}