forked from Plemya-x/ALR
		
	Небольшие переводы и комментарии
This commit is contained in:
		@@ -16,8 +16,8 @@
 | 
				
			|||||||
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					* along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Package dl contains abstractions for downloadingfiles and directories
 | 
					// Пакет dl содержит абстракции для загрузки файлов и каталогов
 | 
				
			||||||
// from various sources.
 | 
					// из различных источников.
 | 
				
			||||||
package dl
 | 
					package dl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
@@ -43,31 +43,32 @@ import (
 | 
				
			|||||||
	"plemya-x.ru/alr/pkg/loggerctx"
 | 
						"plemya-x.ru/alr/pkg/loggerctx"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Константа для имени файла манифеста кэша
 | 
				
			||||||
const manifestFileName = ".alr_cache_manifest"
 | 
					const manifestFileName = ".alr_cache_manifest"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ErrChecksumMismatch occurs when the checksum of a downloaded file
 | 
					// Объявление ошибок для несоответствия контрольной суммы и отсутствия алгоритма хеширования
 | 
				
			||||||
// does not match the expected checksum provided in the Options struct.
 | 
					 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	ErrChecksumMismatch = errors.New("dl: checksums did not match")
 | 
						ErrChecksumMismatch = errors.New("dl: checksums did not match")
 | 
				
			||||||
	ErrNoSuchHashAlgo   = errors.New("dl: invalid hashing algorithm")
 | 
						ErrNoSuchHashAlgo   = errors.New("dl: invalid hashing algorithm")
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Downloaders contains all the downloaders in the order in which
 | 
					// Массив доступных загрузчиков в порядке их проверки
 | 
				
			||||||
// they should be checked
 | 
					 | 
				
			||||||
var Downloaders = []Downloader{
 | 
					var Downloaders = []Downloader{
 | 
				
			||||||
	GitDownloader{},
 | 
						GitDownloader{},
 | 
				
			||||||
	TorrentDownloader{},
 | 
						TorrentDownloader{},
 | 
				
			||||||
	FileDownloader{},
 | 
						FileDownloader{},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Type represents the type of download (file or directory)
 | 
					// Тип данных, представляющий тип загрузки (файл или каталог)
 | 
				
			||||||
type Type uint8
 | 
					type Type uint8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Объявление констант для типов загрузки
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	TypeFile Type = iota
 | 
						TypeFile Type = iota
 | 
				
			||||||
	TypeDir
 | 
						TypeDir
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Метод для получения строки, представляющей тип загрузки
 | 
				
			||||||
func (t Type) String() string {
 | 
					func (t Type) String() string {
 | 
				
			||||||
	switch t {
 | 
						switch t {
 | 
				
			||||||
	case TypeFile:
 | 
						case TypeFile:
 | 
				
			||||||
@@ -78,8 +79,7 @@ func (t Type) String() string {
 | 
				
			|||||||
	return "<unknown>"
 | 
						return "<unknown>"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Options contains the options for downloading
 | 
					// Структура Options содержит параметры для загрузки файлов и каталогов
 | 
				
			||||||
// files and directories
 | 
					 | 
				
			||||||
type Options struct {
 | 
					type Options struct {
 | 
				
			||||||
	Hash             []byte
 | 
						Hash             []byte
 | 
				
			||||||
	HashAlgorithm    string
 | 
						HashAlgorithm    string
 | 
				
			||||||
@@ -92,6 +92,7 @@ type Options struct {
 | 
				
			|||||||
	LocalDir         string
 | 
						LocalDir         string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Метод для создания нового хеша на основе указанного алгоритма хеширования
 | 
				
			||||||
func (opts Options) NewHash() (hash.Hash, error) {
 | 
					func (opts Options) NewHash() (hash.Hash, error) {
 | 
				
			||||||
	switch opts.HashAlgorithm {
 | 
						switch opts.HashAlgorithm {
 | 
				
			||||||
	case "", "sha256":
 | 
						case "", "sha256":
 | 
				
			||||||
@@ -119,49 +120,26 @@ func (opts Options) NewHash() (hash.Hash, error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Manifest holds information about the type and name
 | 
					// Структура Manifest хранит информацию о типе и имени загруженного файла или каталога
 | 
				
			||||||
// of a downloaded file or directory. It is stored inside
 | 
					 | 
				
			||||||
// each cache directory for later use.
 | 
					 | 
				
			||||||
type Manifest struct {
 | 
					type Manifest struct {
 | 
				
			||||||
	Type Type
 | 
						Type Type
 | 
				
			||||||
	Name string
 | 
						Name string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Интерфейс Downloader для реализации различных загрузчиков
 | 
				
			||||||
type Downloader interface {
 | 
					type Downloader interface {
 | 
				
			||||||
	// Name returns the name of the downloader
 | 
					 | 
				
			||||||
	Name() string
 | 
						Name() string
 | 
				
			||||||
	// MatchURL checks if the given URL matches
 | 
					 | 
				
			||||||
	// the downloader.
 | 
					 | 
				
			||||||
	MatchURL(string) bool
 | 
						MatchURL(string) bool
 | 
				
			||||||
	// Download downloads the object at the URL
 | 
					 | 
				
			||||||
	// provided in the options, to the destination
 | 
					 | 
				
			||||||
	// given in the options. It returns a type,
 | 
					 | 
				
			||||||
	// a name for the downloaded object (this may be empty),
 | 
					 | 
				
			||||||
	// and an error.
 | 
					 | 
				
			||||||
	Download(Options) (Type, string, error)
 | 
						Download(Options) (Type, string, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UpdatingDownloader extends the Downloader interface
 | 
					// Интерфейс UpdatingDownloader расширяет Downloader методом Update
 | 
				
			||||||
// with an Update method for protocols such as git, which
 | 
					 | 
				
			||||||
// allow for incremental updates without changing the URL.
 | 
					 | 
				
			||||||
type UpdatingDownloader interface {
 | 
					type UpdatingDownloader interface {
 | 
				
			||||||
	Downloader
 | 
						Downloader
 | 
				
			||||||
	// Update checks for and performs any
 | 
					 | 
				
			||||||
	// available updates for the object
 | 
					 | 
				
			||||||
	// described in the options. It returns
 | 
					 | 
				
			||||||
	// true if an update was performed, or
 | 
					 | 
				
			||||||
	// false if no update was required.
 | 
					 | 
				
			||||||
	Update(Options) (bool, error)
 | 
						Update(Options) (bool, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Download downloads a file or directory using the specified options.
 | 
					// Функция Download загружает файл или каталог с использованием указанных параметров
 | 
				
			||||||
// It first gets the appropriate downloader for the URL, then checks
 | 
					 | 
				
			||||||
// if caching is enabled. If caching is enabled, it attempts to get
 | 
					 | 
				
			||||||
// the cache directory for the URL and update it if necessary.
 | 
					 | 
				
			||||||
// If the source is found in the cache, it links it to the destination
 | 
					 | 
				
			||||||
// using hard links. If the source is not found in the cache,
 | 
					 | 
				
			||||||
// it downloads the source to a new cache directory and links it
 | 
					 | 
				
			||||||
// to the destination.
 | 
					 | 
				
			||||||
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)
 | 
				
			||||||
	normalized, err := normalizeURL(opts.URL)
 | 
						normalized, err := normalizeURL(opts.URL)
 | 
				
			||||||
@@ -216,9 +194,6 @@ func Download(ctx context.Context, opts Options) (err error) {
 | 
				
			|||||||
				return nil
 | 
									return nil
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			// If we cannot read the manifest,
 | 
					 | 
				
			||||||
			// this cache entry is invalid and
 | 
					 | 
				
			||||||
			// the source must be re-downloaded.
 | 
					 | 
				
			||||||
			err = os.RemoveAll(cacheDir)
 | 
								err = os.RemoveAll(cacheDir)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
@@ -256,7 +231,7 @@ func Download(ctx context.Context, opts Options) (err error) {
 | 
				
			|||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// writeManifest writes the manifest to the specified cache directory.
 | 
					// Функция writeManifest записывает манифест в указанный каталог кэша
 | 
				
			||||||
func writeManifest(cacheDir string, m Manifest) error {
 | 
					func writeManifest(cacheDir string, m Manifest) error {
 | 
				
			||||||
	fl, err := os.Create(filepath.Join(cacheDir, manifestFileName))
 | 
						fl, err := os.Create(filepath.Join(cacheDir, manifestFileName))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -266,7 +241,7 @@ func writeManifest(cacheDir string, m Manifest) error {
 | 
				
			|||||||
	return msgpack.NewEncoder(fl).Encode(m)
 | 
						return msgpack.NewEncoder(fl).Encode(m)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// getManifest reads the manifest from the specified cache directory.
 | 
					// Функция getManifest считывает манифест из указанного каталога кэша
 | 
				
			||||||
func getManifest(cacheDir string) (m Manifest, err error) {
 | 
					func getManifest(cacheDir string) (m Manifest, err error) {
 | 
				
			||||||
	fl, err := os.Open(filepath.Join(cacheDir, manifestFileName))
 | 
						fl, err := os.Open(filepath.Join(cacheDir, manifestFileName))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -278,7 +253,7 @@ func getManifest(cacheDir string) (m Manifest, err error) {
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// handleCache links the cache directory or a file within it to the destination
 | 
					// Функция handleCache создает жесткие ссылки для файлов из каталога кэша в каталог назначения
 | 
				
			||||||
func handleCache(cacheDir, dest, name string, t Type) (bool, error) {
 | 
					func handleCache(cacheDir, dest, name string, t Type) (bool, error) {
 | 
				
			||||||
	switch t {
 | 
						switch t {
 | 
				
			||||||
	case TypeFile:
 | 
						case TypeFile:
 | 
				
			||||||
@@ -313,12 +288,7 @@ func handleCache(cacheDir, dest, name string, t Type) (bool, error) {
 | 
				
			|||||||
	return false, nil
 | 
						return false, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// linkDir recursively walks through a directory, creating
 | 
					// Функция linkDir рекурсивно создает жесткие ссылки для файлов из каталога src в каталог dest
 | 
				
			||||||
// hard links for each file from the src directory to the
 | 
					 | 
				
			||||||
// dest directory. If it encounters a directory, it will
 | 
					 | 
				
			||||||
// create a directory with the same name and permissions
 | 
					 | 
				
			||||||
// in the dest directory, because hard links cannot be
 | 
					 | 
				
			||||||
// created for directories.
 | 
					 | 
				
			||||||
func linkDir(src, dest string) error {
 | 
					func linkDir(src, dest string) error {
 | 
				
			||||||
	return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
 | 
						return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -329,6 +299,8 @@ 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
 | 
				
			||||||
@@ -343,6 +315,7 @@ func linkDir(src, dest string) error {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Функция getDownloader возвращает загрузчик, соответствующий URL
 | 
				
			||||||
func getDownloader(u string) Downloader {
 | 
					func getDownloader(u string) Downloader {
 | 
				
			||||||
	for _, d := range Downloaders {
 | 
						for _, d := range Downloaders {
 | 
				
			||||||
		if d.MatchURL(u) {
 | 
							if d.MatchURL(u) {
 | 
				
			||||||
@@ -352,8 +325,7 @@ func getDownloader(u string) Downloader {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// normalizeURL normalizes a URL string, so that insignificant
 | 
					// Функция normalizeURL нормализует строку URL, чтобы незначительные различия не изменяли хеш
 | 
				
			||||||
// differences don't change the hash.
 | 
					 | 
				
			||||||
func normalizeURL(u string) (string, error) {
 | 
					func normalizeURL(u string) (string, error) {
 | 
				
			||||||
	const normalizationFlags = purell.FlagRemoveTrailingSlash |
 | 
						const normalizationFlags = purell.FlagRemoveTrailingSlash |
 | 
				
			||||||
		purell.FlagRemoveDefaultPort |
 | 
							purell.FlagRemoveDefaultPort |
 | 
				
			||||||
@@ -373,7 +345,7 @@ func normalizeURL(u string) (string, error) {
 | 
				
			|||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Fix magnet URLs after normalization
 | 
						// Исправление URL-адресов magnet после нормализации
 | 
				
			||||||
	u = strings.Replace(u, "magnet://", "magnet:", 1)
 | 
						u = strings.Replace(u, "magnet://", "magnet:", 1)
 | 
				
			||||||
	return u, nil
 | 
						return u, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,40 +36,47 @@ import (
 | 
				
			|||||||
	"plemya-x.ru/alr/internal/shutils/handlers"
 | 
						"plemya-x.ru/alr/internal/shutils/handlers"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FileDownloader downloads files using HTTP
 | 
					// FileDownloader загружает файлы с использованием HTTP
 | 
				
			||||||
type FileDownloader struct{}
 | 
					type FileDownloader struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Name always returns "file"
 | 
					// Name всегда возвращает "file"
 | 
				
			||||||
func (FileDownloader) Name() string {
 | 
					func (FileDownloader) Name() string {
 | 
				
			||||||
	return "file"
 | 
						return "file"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// MatchURL always returns true, as FileDownloader
 | 
					// MatchURL всегда возвращает true, так как FileDownloader
 | 
				
			||||||
// is used as a fallback if nothing else matches
 | 
					// используется как резерв, если ничего другого не соответствует
 | 
				
			||||||
func (FileDownloader) MatchURL(string) bool {
 | 
					func (FileDownloader) MatchURL(string) bool {
 | 
				
			||||||
	return true
 | 
						return true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Download downloads a file using HTTP. If the file is
 | 
					// Download загружает файл с использованием HTTP. Если файл
 | 
				
			||||||
// compressed using a supported format, it will be extracted
 | 
					// сжат в поддерживаемом формате, он будет распакован
 | 
				
			||||||
func (FileDownloader) Download(opts Options) (Type, string, error) {
 | 
					func (FileDownloader) Download(opts Options) (Type, string, error) {
 | 
				
			||||||
 | 
						// Разбор URL
 | 
				
			||||||
	u, err := url.Parse(opts.URL)
 | 
						u, err := url.Parse(opts.URL)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return 0, "", err
 | 
							return 0, "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Получение параметров запроса
 | 
				
			||||||
	query := u.Query()
 | 
						query := u.Query()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Получение имени файла из параметров запроса
 | 
				
			||||||
	name := query.Get("~name")
 | 
						name := query.Get("~name")
 | 
				
			||||||
	query.Del("~name")
 | 
						query.Del("~name")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Получение параметра архивации
 | 
				
			||||||
	archive := query.Get("~archive")
 | 
						archive := query.Get("~archive")
 | 
				
			||||||
	query.Del("~archive")
 | 
						query.Del("~archive")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Кодирование измененных параметров запроса обратно в URL
 | 
				
			||||||
	u.RawQuery = query.Encode()
 | 
						u.RawQuery = query.Encode()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var r io.ReadCloser
 | 
						var r io.ReadCloser
 | 
				
			||||||
	var size int64
 | 
						var size int64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Проверка схемы URL на "local"
 | 
				
			||||||
	if u.Scheme == "local" {
 | 
						if u.Scheme == "local" {
 | 
				
			||||||
		localFl, err := os.Open(filepath.Join(opts.LocalDir, u.Path))
 | 
							localFl, err := os.Open(filepath.Join(opts.LocalDir, u.Path))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -85,6 +92,7 @@ func (FileDownloader) Download(opts Options) (Type, string, error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		r = localFl
 | 
							r = localFl
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
 | 
							// Выполнение HTTP GET запроса
 | 
				
			||||||
		res, err := http.Get(u.String())
 | 
							res, err := http.Get(u.String())
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return 0, "", err
 | 
								return 0, "", err
 | 
				
			||||||
@@ -107,6 +115,7 @@ func (FileDownloader) Download(opts Options) (Type, string, error) {
 | 
				
			|||||||
	defer fl.Close()
 | 
						defer fl.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var bar io.WriteCloser
 | 
						var bar io.WriteCloser
 | 
				
			||||||
 | 
						// Настройка индикатора прогресса
 | 
				
			||||||
	if opts.Progress != nil {
 | 
						if opts.Progress != nil {
 | 
				
			||||||
		bar = progressbar.NewOptions64(
 | 
							bar = progressbar.NewOptions64(
 | 
				
			||||||
			size,
 | 
								size,
 | 
				
			||||||
@@ -134,18 +143,21 @@ func (FileDownloader) Download(opts Options) (Type, string, error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var w io.Writer
 | 
						var w io.Writer
 | 
				
			||||||
 | 
						// Настройка MultiWriter для записи в файл, хеш и индикатор прогресса
 | 
				
			||||||
	if opts.Hash != nil {
 | 
						if opts.Hash != nil {
 | 
				
			||||||
		w = io.MultiWriter(fl, h, bar)
 | 
							w = io.MultiWriter(fl, h, bar)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		w = io.MultiWriter(fl, bar)
 | 
							w = io.MultiWriter(fl, bar)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Копирование содержимого из источника в файл назначения
 | 
				
			||||||
	_, err = io.Copy(w, r)
 | 
						_, err = io.Copy(w, r)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return 0, "", err
 | 
							return 0, "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	r.Close()
 | 
						r.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Проверка контрольной суммы
 | 
				
			||||||
	if opts.Hash != nil {
 | 
						if opts.Hash != nil {
 | 
				
			||||||
		sum := h.Sum(nil)
 | 
							sum := h.Sum(nil)
 | 
				
			||||||
		if !bytes.Equal(sum, opts.Hash) {
 | 
							if !bytes.Equal(sum, opts.Hash) {
 | 
				
			||||||
@@ -153,6 +165,7 @@ func (FileDownloader) Download(opts Options) (Type, string, error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Проверка необходимости постобработки
 | 
				
			||||||
	if opts.PostprocDisabled {
 | 
						if opts.PostprocDisabled {
 | 
				
			||||||
		return TypeFile, name, nil
 | 
							return TypeFile, name, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -162,6 +175,7 @@ func (FileDownloader) Download(opts Options) (Type, string, error) {
 | 
				
			|||||||
		return 0, "", err
 | 
							return 0, "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Идентификация формата архива
 | 
				
			||||||
	format, ar, err := archiver.Identify(name, fl)
 | 
						format, ar, err := archiver.Identify(name, fl)
 | 
				
			||||||
	if err == archiver.ErrNoMatch {
 | 
						if err == archiver.ErrNoMatch {
 | 
				
			||||||
		return TypeFile, name, nil
 | 
							return TypeFile, name, nil
 | 
				
			||||||
@@ -169,21 +183,25 @@ func (FileDownloader) Download(opts Options) (Type, string, error) {
 | 
				
			|||||||
		return 0, "", err
 | 
							return 0, "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Распаковка архива
 | 
				
			||||||
	err = extractFile(ar, format, name, opts)
 | 
						err = extractFile(ar, format, name, opts)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return 0, "", err
 | 
							return 0, "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Удаление исходного архива
 | 
				
			||||||
	err = os.Remove(path)
 | 
						err = os.Remove(path)
 | 
				
			||||||
	return TypeDir, "", err
 | 
						return TypeDir, "", err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// extractFile extracts an archive or decompresses a file
 | 
					// extractFile извлекает архив или распаковывает файл
 | 
				
			||||||
func extractFile(r io.Reader, format archiver.Format, name string, opts Options) (err error) {
 | 
					func extractFile(r io.Reader, format archiver.Format, name string, opts Options) (err error) {
 | 
				
			||||||
	fname := format.Name()
 | 
						fname := format.Name()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Проверка типа формата архива
 | 
				
			||||||
	switch format := format.(type) {
 | 
						switch format := format.(type) {
 | 
				
			||||||
	case archiver.Extractor:
 | 
						case archiver.Extractor:
 | 
				
			||||||
 | 
							// Извлечение файлов из архива
 | 
				
			||||||
		err = format.Extract(context.Background(), r, nil, func(ctx context.Context, f archiver.File) error {
 | 
							err = format.Extract(context.Background(), r, nil, func(ctx context.Context, f archiver.File) error {
 | 
				
			||||||
			fr, err := f.Open()
 | 
								fr, err := f.Open()
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
@@ -224,6 +242,7 @@ func extractFile(r io.Reader, format archiver.Format, name string, opts Options)
 | 
				
			|||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case archiver.Decompressor:
 | 
						case archiver.Decompressor:
 | 
				
			||||||
 | 
							// Распаковка сжатого файла
 | 
				
			||||||
		rc, err := format.OpenReader(r)
 | 
							rc, err := format.OpenReader(r)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
@@ -247,10 +266,9 @@ func extractFile(r io.Reader, format archiver.Format, name string, opts Options)
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// getFilename attempts to parse the Content-Disposition
 | 
					// getFilename пытается разобрать заголовок Content-Disposition
 | 
				
			||||||
// HTTP response header and extract a filename. If the
 | 
					// HTTP-ответа и извлечь имя файла. Если заголовок отсутствует,
 | 
				
			||||||
// header does not exist, it will use the last element
 | 
					// используется последний элемент пути.
 | 
				
			||||||
// of the path.
 | 
					 | 
				
			||||||
func getFilename(res *http.Response) (name string) {
 | 
					func getFilename(res *http.Response) (name string) {
 | 
				
			||||||
	_, params, err := mime.ParseMediaType(res.Header.Get("Content-Disposition"))
 | 
						_, params, err := mime.ParseMediaType(res.Header.Get("Content-Disposition"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user