You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
star/mget/redo.go

139 lines
2.7 KiB
Go

3 months ago
package mget
import (
"encoding/json"
"fmt"
"os"
"strings"
"sync"
"time"
)
type Redo struct {
Is206 bool `json:"is_206"`
OriginUri string `json:"origin_uri"`
Date time.Time `json:"date"`
Filename string `json:"filename"`
ContentLength uint64 `json:"content_length"`
Range []Range `json:"range"`
rangeUpdated bool
lastUpdate time.Time
lastTotal uint64
speed float64
total uint64
isRedo bool
sync.RWMutex
}
func (r *Redo) CacheTotal() uint64 {
return r.total
}
func (r *Redo) Total() uint64 {
var total uint64
for {
r.RLock()
for _, v := range r.Range {
total += v.Max - v.Min + 1
}
r.total = total
r.RUnlock()
if r.total > r.ContentLength && r.ContentLength > 0 {
r.reform()
continue
}
break
}
return total
}
func (r *Redo) Update(start, end int) error {
if start < 0 || end < 0 || start > end {
return fmt.Errorf("invalid range: %d-%d", start, end)
}
r.Lock()
defer r.Unlock()
r.rangeUpdated = true
r.Range = append(r.Range, Range{uint64(start), uint64(end)})
now := time.Now()
if now.Sub(r.lastUpdate) >= time.Millisecond*500 {
var total uint64
for _, v := range r.Range {
total += v.Max - v.Min + 1
}
r.total = total
r.speed = float64(total-r.lastTotal) / (float64(now.Sub(r.lastUpdate).Milliseconds()) / 1000.00)
r.lastTotal = total
r.lastUpdate = now
}
return nil
}
func (r *Redo) Percent() float64 {
return float64(r.Total()) / float64(r.ContentLength)
}
func (r *Redo) FormatPercent() string {
return fmt.Sprintf("%.2f%%", r.Percent()*100)
}
func (r *Redo) FormatSpeed(unit string) string {
switch strings.ToLower(unit) {
case "kb":
return fmt.Sprintf("%.2f KB/s", r.speed/1024)
case "mb":
return fmt.Sprintf("%.2f MB/s", r.speed/1024/1024)
case "gb":
return fmt.Sprintf("%.2f GB/s", r.speed/1024/1024/1024)
default:
return fmt.Sprintf("%.2f B/s", r.speed)
}
}
func (r *Redo) Speed() float64 {
return r.speed
}
func (r *Redo) Save() error {
var err error
err = r.reform()
if err != nil {
return err
}
if r.Filename != "" {
data, err := json.Marshal(r)
if err != nil {
return err
}
r.Lock()
defer r.Unlock()
return os.WriteFile(r.Filename+".bgrd", data, 0644)
}
return nil
}
func (r *Redo) reform() error {
r.Lock()
defer r.Unlock()
if !r.rangeUpdated {
return nil
}
tmp, err := r.uniformRange(r.Range)
if err != nil {
return err
}
r.Range = tmp
return nil
}
func (r *Redo) uniformRange(rg []Range) ([]Range, error) {
return uniformRange(rg)
}
func (r *Redo) ReverseRange() ([]Range, error) {
r.reform()
r.RLock()
defer r.RUnlock()
return r.uniformRange(subRange([]Range{{0, r.ContentLength - 1}}, r.Range))
}