RWKV-Runner/backend-golang/download.go
2024-02-02 22:00:01 +08:00

135 lines
3.1 KiB
Go

package backend_golang
import (
"context"
"path/filepath"
"time"
"github.com/cavaliergopher/grab/v3"
"github.com/wailsapp/wails/v2/pkg/runtime"
)
func (a *App) DownloadFile(path string, url string) error {
absPath, err := a.GetAbsPath(path)
if err != nil {
return err
}
_, err = grab.Get(absPath, url)
if err != nil {
return err
}
return nil
}
type DownloadStatus struct {
resp *grab.Response
cancel context.CancelFunc
Name string `json:"name"`
Path string `json:"path"`
Url string `json:"url"`
Transferred int64 `json:"transferred"`
Size int64 `json:"size"`
Speed float64 `json:"speed"`
Progress float64 `json:"progress"`
Downloading bool `json:"downloading"`
Done bool `json:"done"`
}
var downloadList []*DownloadStatus
func existsInDownloadList(path string, url string) bool {
for _, ds := range downloadList {
if ds.Path == path || ds.Url == url {
return true
}
}
return false
}
func (a *App) PauseDownload(url string) {
for _, ds := range downloadList {
if ds.Url == url {
if ds.cancel != nil {
ds.cancel()
}
ds.resp = nil
ds.Downloading = false
ds.Speed = 0
break
}
}
}
func (a *App) ContinueDownload(url string) {
for _, ds := range downloadList {
if ds.Url == url {
if !ds.Downloading && ds.resp == nil && !ds.Done {
ds.Downloading = true
req, err := grab.NewRequest(ds.Path, ds.Url)
if err != nil {
ds.Downloading = false
break
}
// if PauseDownload() is called before the request finished, ds.Downloading will be false
// if the user keeps clicking pause and resume, it may result in multiple requests being successfully downloaded at the same time
// so we have to create a context and cancel it when PauseDownload() is called
ctx, cancel := context.WithCancel(context.Background())
ds.cancel = cancel
req = req.WithContext(ctx)
resp := grab.DefaultClient.Do(req)
if resp != nil && resp.HTTPResponse != nil &&
resp.HTTPResponse.StatusCode >= 200 && resp.HTTPResponse.StatusCode < 300 {
ds.resp = resp
} else {
ds.Downloading = false
}
}
break
}
}
}
func (a *App) AddToDownloadList(path string, url string) {
absPath, err := a.GetAbsPath(path)
if err != nil {
return
}
if !existsInDownloadList(absPath, url) {
downloadList = append(downloadList, &DownloadStatus{
resp: nil,
Name: filepath.Base(path),
Path: absPath,
Url: url,
Downloading: false,
})
a.ContinueDownload(url)
} else {
a.ContinueDownload(url)
}
}
func (a *App) downloadLoop() {
ticker := time.NewTicker(500 * time.Millisecond)
go func() {
for {
<-ticker.C
for _, ds := range downloadList {
if ds.resp != nil {
ds.Transferred = ds.resp.BytesComplete()
ds.Size = ds.resp.Size()
ds.Speed = ds.resp.BytesPerSecond()
ds.Progress = 100 * ds.resp.Progress()
ds.Downloading = !ds.resp.IsComplete()
ds.Done = ds.resp.Progress() == 1
if !ds.Downloading {
ds.resp = nil
}
}
}
runtime.EventsEmit(a.ctx, "downloadList", downloadList)
}
}()
}