136 lines
2.9 KiB
Go
136 lines
2.9 KiB
Go
package backend
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// Global progress tracker
|
|
var (
|
|
currentProgress float64
|
|
currentProgressLock sync.RWMutex
|
|
isDownloading bool
|
|
downloadingLock sync.RWMutex
|
|
currentSpeed float64
|
|
speedLock sync.RWMutex
|
|
)
|
|
|
|
// ProgressInfo represents download progress information
|
|
type ProgressInfo struct {
|
|
IsDownloading bool `json:"is_downloading"`
|
|
MBDownloaded float64 `json:"mb_downloaded"`
|
|
SpeedMBps float64 `json:"speed_mbps"`
|
|
}
|
|
|
|
// GetDownloadProgress returns current download progress
|
|
func GetDownloadProgress() ProgressInfo {
|
|
downloadingLock.RLock()
|
|
downloading := isDownloading
|
|
downloadingLock.RUnlock()
|
|
|
|
currentProgressLock.RLock()
|
|
progress := currentProgress
|
|
currentProgressLock.RUnlock()
|
|
|
|
speedLock.RLock()
|
|
speed := currentSpeed
|
|
speedLock.RUnlock()
|
|
|
|
return ProgressInfo{
|
|
IsDownloading: downloading,
|
|
MBDownloaded: progress,
|
|
SpeedMBps: speed,
|
|
}
|
|
}
|
|
|
|
// SetDownloadSpeed updates the current download speed
|
|
func SetDownloadSpeed(mbps float64) {
|
|
speedLock.Lock()
|
|
currentSpeed = mbps
|
|
speedLock.Unlock()
|
|
}
|
|
|
|
// SetDownloadProgress updates the current download progress
|
|
func SetDownloadProgress(mbDownloaded float64) {
|
|
currentProgressLock.Lock()
|
|
currentProgress = mbDownloaded
|
|
currentProgressLock.Unlock()
|
|
}
|
|
|
|
// SetDownloading sets the downloading state
|
|
func SetDownloading(downloading bool) {
|
|
downloadingLock.Lock()
|
|
isDownloading = downloading
|
|
downloadingLock.Unlock()
|
|
|
|
if !downloading {
|
|
// Reset progress when download completes
|
|
SetDownloadProgress(0)
|
|
SetDownloadSpeed(0)
|
|
}
|
|
}
|
|
|
|
// ProgressWriter wraps an io.Writer and reports download progress
|
|
type ProgressWriter struct {
|
|
writer io.Writer
|
|
total int64
|
|
lastPrinted int64
|
|
startTime int64
|
|
lastTime int64
|
|
lastBytes int64
|
|
}
|
|
|
|
func NewProgressWriter(writer io.Writer) *ProgressWriter {
|
|
now := getCurrentTimeMillis()
|
|
return &ProgressWriter{
|
|
writer: writer,
|
|
total: 0,
|
|
lastPrinted: 0,
|
|
startTime: now,
|
|
lastTime: now,
|
|
lastBytes: 0,
|
|
}
|
|
}
|
|
|
|
func getCurrentTimeMillis() int64 {
|
|
return time.Now().UnixMilli()
|
|
}
|
|
|
|
func (pw *ProgressWriter) Write(p []byte) (int, error) {
|
|
n, err := pw.writer.Write(p)
|
|
pw.total += int64(n)
|
|
|
|
// Report progress every 256KB for smoother updates
|
|
if pw.total-pw.lastPrinted >= 256*1024 {
|
|
mbDownloaded := float64(pw.total) / (1024 * 1024)
|
|
|
|
// Calculate speed (MB/s)
|
|
now := getCurrentTimeMillis()
|
|
timeDiff := float64(now-pw.lastTime) / 1000.0 // seconds
|
|
bytesDiff := float64(pw.total - pw.lastBytes)
|
|
|
|
if timeDiff > 0 {
|
|
speedMBps := (bytesDiff / (1024 * 1024)) / timeDiff
|
|
SetDownloadSpeed(speedMBps)
|
|
fmt.Printf("\rDownloaded: %.2f MB (%.2f MB/s)", mbDownloaded, speedMBps)
|
|
} else {
|
|
fmt.Printf("\rDownloaded: %.2f MB", mbDownloaded)
|
|
}
|
|
|
|
// Update global progress
|
|
SetDownloadProgress(mbDownloaded)
|
|
|
|
pw.lastPrinted = pw.total
|
|
pw.lastTime = now
|
|
pw.lastBytes = pw.total
|
|
}
|
|
|
|
return n, err
|
|
}
|
|
|
|
func (pw *ProgressWriter) GetTotal() int64 {
|
|
return pw.total
|
|
}
|