refactor(db, config, repos): migrate from functions to struct #9
| @@ -14,7 +14,7 @@ | ||||
| * | ||||
| * You should have received a copy of the GNU General Public License | ||||
| * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
| */ | ||||
|  */ | ||||
|  | ||||
| // Пакет dl содержит абстракции для загрузки файлов и каталогов | ||||
| // из различных источников. | ||||
| @@ -39,6 +39,7 @@ import ( | ||||
| 	"golang.org/x/crypto/blake2b" | ||||
| 	"golang.org/x/crypto/blake2s" | ||||
| 	"golang.org/x/exp/slices" | ||||
| 	"plemya-x.ru/alr/internal/config" | ||||
| 	"plemya-x.ru/alr/internal/dlcache" | ||||
| 	"plemya-x.ru/alr/pkg/loggerctx" | ||||
| ) | ||||
| @@ -142,6 +143,9 @@ type UpdatingDownloader interface { | ||||
| // Функция Download загружает файл или каталог с использованием указанных параметров | ||||
| func Download(ctx context.Context, opts Options) (err error) { | ||||
| 	log := loggerctx.From(ctx) | ||||
| 	cfg := config.GetInstance(ctx) | ||||
| 	dc := dlcache.New(cfg) | ||||
|  | ||||
| 	normalized, err := normalizeURL(opts.URL) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| @@ -156,7 +160,7 @@ func Download(ctx context.Context, opts Options) (err error) { | ||||
| 	} | ||||
|  | ||||
| 	var t Type | ||||
| 	cacheDir, ok := dlcache.Get(ctx, opts.URL) | ||||
| 	cacheDir, ok := dc.Get(ctx, opts.URL) | ||||
| 	if ok { | ||||
| 		var updated bool | ||||
| 		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() | ||||
|  | ||||
| 	cacheDir, err = dlcache.New(ctx, opts.URL) | ||||
| 	cacheDir, err = dc.New(ctx, opts.URL) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -299,8 +303,6 @@ func linkDir(src, dest string) error { | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
|  | ||||
|  | ||||
| 		rel, err := filepath.Rel(src, path) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
|   | ||||
| @@ -20,29 +20,41 @@ package dlcache | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto/sha1" | ||||
| 	"encoding/hex" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"plemya-x.ru/alr/internal/config" | ||||
| ) | ||||
|  | ||||
| // BasePath returns the base path of the download cache | ||||
| func BasePath(ctx context.Context) string { | ||||
| 	return filepath.Join(config.GetPaths(ctx).CacheDir, "dl") | ||||
| type Config interface { | ||||
| 	GetPaths(ctx context.Context) *config.Paths | ||||
| } | ||||
|  | ||||
| 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. | ||||
| // If a directory with the same ID already exists, | ||||
| // 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) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	itemPath := filepath.Join(BasePath(ctx), h) | ||||
| 	itemPath := filepath.Join(dc.BasePath(ctx), h) | ||||
|  | ||||
| 	fi, err := os.Stat(itemPath) | ||||
| 	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 | ||||
| // does not exist, it returns an empty string | ||||
| // 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) | ||||
| 	if err != nil { | ||||
| 		return "", false | ||||
| 	} | ||||
| 	itemPath := filepath.Join(BasePath(ctx), h) | ||||
| 	itemPath := filepath.Join(dc.BasePath(ctx), h) | ||||
|  | ||||
| 	_, err = os.Stat(itemPath) | ||||
| 	if err != nil { | ||||
| @@ -79,15 +91,3 @@ func Get(ctx context.Context, id string) (string, bool) { | ||||
|  | ||||
| 	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 | ||||
| } | ||||
|  | ||||
| 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) { | ||||
| 	cfg := prepare(t) | ||||
| 	defer cleanup(t, cfg) | ||||
|  | ||||
| 	dc := dlcache.New(cfg) | ||||
|  | ||||
| 	ctx := context.Background() | ||||
|  | ||||
| 	const id = "https://example.com" | ||||
| 	dir, err := dlcache.New(id) | ||||
| 	dir, err := dc.New(ctx, id) | ||||
| 	if err != nil { | ||||
| 		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 { | ||||
| 		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") | ||||
| 	} | ||||
|  | ||||
| 	dir2, ok := dlcache.Get(id) | ||||
| 	dir2, ok := dc.Get(ctx, id) | ||||
| 	if !ok { | ||||
| 		t.Errorf("Expected Get() to return valid value") | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										16
									
								
								internal/dlcache/utils.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										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 | ||||
| } | ||||
		Reference in New Issue
	
	Block a user