84 lines
1.8 KiB
Go
84 lines
1.8 KiB
Go
|
package service
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"net/http"
|
||
|
"os"
|
||
|
"strconv"
|
||
|
)
|
||
|
|
||
|
// ProgressWriter is a custom writer to track progress and execute a callback
|
||
|
type ProgressWriter struct {
|
||
|
io.Writer
|
||
|
Total int64
|
||
|
Progress int64
|
||
|
Callback func(progress int64, total int64)
|
||
|
}
|
||
|
|
||
|
func (pw *ProgressWriter) Write(p []byte) (int, error) {
|
||
|
n, err := pw.Writer.Write(p)
|
||
|
if err != nil {
|
||
|
return n, err
|
||
|
}
|
||
|
pw.Progress += int64(n)
|
||
|
pw.Callback(pw.Progress, pw.Total)
|
||
|
return n, nil
|
||
|
}
|
||
|
|
||
|
func DownloadFile(url string, filePath string, overwrite bool, callback func(progress int64, total int64)) error {
|
||
|
// Check if the file exists
|
||
|
if _, err := os.Stat(filePath); err == nil {
|
||
|
if overwrite {
|
||
|
// Overwrite the file if it exists
|
||
|
if err := os.Remove(filePath); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
} else {
|
||
|
return fmt.Errorf("file %s already exists", filePath)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Create the file
|
||
|
out, err := os.Create(filePath)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer out.Close()
|
||
|
|
||
|
// Get the data
|
||
|
resp, err := http.Get(url)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
|
||
|
|
||
|
// Check server response
|
||
|
if resp.StatusCode != http.StatusOK {
|
||
|
return fmt.Errorf("bad status: %s", resp.Status)
|
||
|
}
|
||
|
|
||
|
// Get the size
|
||
|
size, err := strconv.Atoi(resp.Header.Get("Content-Length"))
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Create progress writer
|
||
|
pw := &ProgressWriter{
|
||
|
Writer: out,
|
||
|
Total: int64(size),
|
||
|
Callback: callback,
|
||
|
}
|
||
|
|
||
|
// Write the body to file with progress
|
||
|
_, err = io.Copy(pw, resp.Body)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
fmt.Println("\nDownload complete")
|
||
|
return nil
|
||
|
}
|