mirror of
https://github.com/krau/SaveAny-Bot.git
synced 2026-08-21 16:22:36 +08:00
refactor: share progress throttling helpers
Move size-tiered and count-based throttling into progressutil. Localize hardcoded Chinese progress strings. Drop five duplicated implementations and dead local copies.
This commit is contained in:
53
common/utils/progressutil/progress.go
Normal file
53
common/utils/progressutil/progress.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// Package progressutil provides shared progress-update throttling used by
|
||||||
|
// task progress trackers. All task packages must use these helpers instead
|
||||||
|
// of re-implementing throttle logic.
|
||||||
|
package progressutil
|
||||||
|
|
||||||
|
// updatesLevels sizes files by their total size and picks how often the
|
||||||
|
// progress percent may be reported: smaller files report less often.
|
||||||
|
var updatesLevels = []struct {
|
||||||
|
size int64 // file size threshold
|
||||||
|
stepPercent int // minimum percent step between updates
|
||||||
|
}{
|
||||||
|
{10 << 20, 100},
|
||||||
|
{50 << 20, 20},
|
||||||
|
{200 << 20, 10},
|
||||||
|
{500 << 20, 5},
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShouldUpdate reports whether a byte-based progress update should be shown,
|
||||||
|
// throttled by a minimum percent step that shrinks as the total grows.
|
||||||
|
func ShouldUpdate(total, downloaded int64, lastUpdatePercent int) bool {
|
||||||
|
if total <= 0 || downloaded <= 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
percent := int((downloaded * 100) / total)
|
||||||
|
if percent <= lastUpdatePercent {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
step := updatesLevels[len(updatesLevels)-1].stepPercent
|
||||||
|
for _, lvl := range updatesLevels {
|
||||||
|
if total < lvl.size {
|
||||||
|
step = lvl.stepPercent
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return percent >= lastUpdatePercent+step
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShouldUpdateCount reports whether a count-based progress update (e.g. files
|
||||||
|
// downloaded so far) should be shown: every 10 units, or when finished.
|
||||||
|
func ShouldUpdateCount(downloaded, total int64) bool {
|
||||||
|
if total <= 0 || downloaded <= 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const step = int64(10)
|
||||||
|
if downloaded < step {
|
||||||
|
return downloaded == total
|
||||||
|
}
|
||||||
|
return downloaded%step == 0 || downloaded == total
|
||||||
|
}
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package batchtfile
|
|
||||||
|
|
||||||
var progressUpdatesLevels = []struct {
|
|
||||||
size int64 // 文件大小阈值
|
|
||||||
stepPercent int // 每多少 % 更新一次
|
|
||||||
}{
|
|
||||||
{10 << 20, 100},
|
|
||||||
{50 << 20, 20},
|
|
||||||
{200 << 20, 10},
|
|
||||||
{500 << 20, 5},
|
|
||||||
}
|
|
||||||
|
|
||||||
func shouldUpdateProgress(total, downloaded int64, lastUpdatePercent int) bool {
|
|
||||||
if total <= 0 || downloaded <= 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
percent := int((downloaded * 100) / total)
|
|
||||||
if percent <= lastUpdatePercent {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
step := progressUpdatesLevels[len(progressUpdatesLevels)-1].stepPercent
|
|
||||||
for _, lvl := range progressUpdatesLevels {
|
|
||||||
if total < lvl.size {
|
|
||||||
step = lvl.stepPercent
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return percent >= lastUpdatePercent+step
|
|
||||||
}
|
|
||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/krau/SaveAny-Bot/common/i18n"
|
"github.com/krau/SaveAny-Bot/common/i18n"
|
||||||
"github.com/krau/SaveAny-Bot/common/i18n/i18nk"
|
"github.com/krau/SaveAny-Bot/common/i18n/i18nk"
|
||||||
"github.com/krau/SaveAny-Bot/common/utils/dlutil"
|
"github.com/krau/SaveAny-Bot/common/utils/dlutil"
|
||||||
|
"github.com/krau/SaveAny-Bot/common/utils/progressutil"
|
||||||
"github.com/krau/SaveAny-Bot/common/utils/tgutil"
|
"github.com/krau/SaveAny-Bot/common/utils/tgutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -102,7 +103,7 @@ func (p *Progress) OnDone(ctx context.Context, info TaskInfo, err error) {
|
|||||||
|
|
||||||
// OnProgress implements ProgressTracker.
|
// OnProgress implements ProgressTracker.
|
||||||
func (p *Progress) OnProgress(ctx context.Context, info TaskInfo) {
|
func (p *Progress) OnProgress(ctx context.Context, info TaskInfo) {
|
||||||
if !shouldUpdateProgress(info.TotalBytes(), info.DownloadedBytes(), int(p.lastUpdatePercent.Load())) {
|
if !progressutil.ShouldUpdate(info.TotalBytes(), info.DownloadedBytes(), int(p.lastUpdatePercent.Load())) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
percent := int((info.DownloadedBytes() * 100) / info.TotalBytes())
|
percent := int((info.DownloadedBytes() * 100) / info.TotalBytes())
|
||||||
@@ -115,7 +116,10 @@ func (p *Progress) OnProgress(ctx context.Context, info TaskInfo) {
|
|||||||
var entities []tg.MessageEntityClass
|
var entities []tg.MessageEntityClass
|
||||||
if err := styling.Perform(&entityBuilder,
|
if err := styling.Perform(&entityBuilder,
|
||||||
styling.Plain(i18n.T(i18nk.BotMsgProgressDownloadingPrefix, nil)),
|
styling.Plain(i18n.T(i18nk.BotMsgProgressDownloadingPrefix, nil)),
|
||||||
styling.Code(fmt.Sprintf("%.2f MB (%d个文件)", float64(info.TotalBytes())/(1024*1024), info.TotalFiles())),
|
styling.Code(i18n.T(i18nk.BotMsgProgressSizeWithFiles, map[string]any{
|
||||||
|
"Size": fmt.Sprintf("%.2f MB", float64(info.TotalBytes())/(1024*1024)),
|
||||||
|
"Count": info.TotalFiles(),
|
||||||
|
})),
|
||||||
styling.Plain(i18n.T(i18nk.BotMsgProgressProcessingListPrefix, nil)),
|
styling.Plain(i18n.T(i18nk.BotMsgProgressProcessingListPrefix, nil)),
|
||||||
func() styling.StyledTextOption {
|
func() styling.StyledTextOption {
|
||||||
var lines []string
|
var lines []string
|
||||||
|
|||||||
@@ -207,34 +207,3 @@ func parseFilenameFallback(cd string) string {
|
|||||||
|
|
||||||
return decodeFilenameParam(value)
|
return decodeFilenameParam(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
var progressUpdatesLevels = []struct {
|
|
||||||
size int64 // 文件大小阈值
|
|
||||||
stepPercent int // 每多少 % 更新一次
|
|
||||||
}{
|
|
||||||
{10 << 20, 100},
|
|
||||||
{50 << 20, 50},
|
|
||||||
{200 << 20, 20},
|
|
||||||
{500 << 20, 10},
|
|
||||||
}
|
|
||||||
|
|
||||||
func shouldUpdateProgress(total, downloaded int64, lastUpdatePercent int) bool {
|
|
||||||
if total <= 0 || downloaded <= 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
percent := int((downloaded * 100) / total)
|
|
||||||
if percent <= lastUpdatePercent {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
step := progressUpdatesLevels[len(progressUpdatesLevels)-1].stepPercent
|
|
||||||
for _, lvl := range progressUpdatesLevels {
|
|
||||||
if total < lvl.size {
|
|
||||||
step = lvl.stepPercent
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return percent >= lastUpdatePercent+step
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -15,40 +15,10 @@ import (
|
|||||||
"github.com/krau/SaveAny-Bot/common/i18n"
|
"github.com/krau/SaveAny-Bot/common/i18n"
|
||||||
"github.com/krau/SaveAny-Bot/common/i18n/i18nk"
|
"github.com/krau/SaveAny-Bot/common/i18n/i18nk"
|
||||||
"github.com/krau/SaveAny-Bot/common/utils/dlutil"
|
"github.com/krau/SaveAny-Bot/common/utils/dlutil"
|
||||||
|
"github.com/krau/SaveAny-Bot/common/utils/progressutil"
|
||||||
"github.com/krau/SaveAny-Bot/common/utils/tgutil"
|
"github.com/krau/SaveAny-Bot/common/utils/tgutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
var progressUpdatesLevels = []struct {
|
|
||||||
size int64 // 文件大小阈值
|
|
||||||
stepPercent int // 每多少 % 更新一次
|
|
||||||
}{
|
|
||||||
{10 << 20, 100},
|
|
||||||
{50 << 20, 50},
|
|
||||||
{200 << 20, 20},
|
|
||||||
{500 << 20, 10},
|
|
||||||
}
|
|
||||||
|
|
||||||
func shouldUpdateProgress(total, downloaded int64, lastUpdatePercent int) bool {
|
|
||||||
if total <= 0 || downloaded <= 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
percent := int((downloaded * 100) / total)
|
|
||||||
if percent <= lastUpdatePercent {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
step := progressUpdatesLevels[len(progressUpdatesLevels)-1].stepPercent
|
|
||||||
for _, lvl := range progressUpdatesLevels {
|
|
||||||
if total < lvl.size {
|
|
||||||
step = lvl.stepPercent
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return percent >= lastUpdatePercent+step
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProgressTracker interface {
|
type ProgressTracker interface {
|
||||||
OnStart(ctx context.Context, info TaskInfo)
|
OnStart(ctx context.Context, info TaskInfo)
|
||||||
OnProgress(ctx context.Context, info TaskInfo)
|
OnProgress(ctx context.Context, info TaskInfo)
|
||||||
@@ -73,7 +43,10 @@ func (p *Progress) OnStart(ctx context.Context, info TaskInfo) {
|
|||||||
styling.Plain(i18n.T(i18nk.BotMsgProgressParsedStartPrefix, map[string]any{
|
styling.Plain(i18n.T(i18nk.BotMsgProgressParsedStartPrefix, map[string]any{
|
||||||
"Site": info.Site(),
|
"Site": info.Site(),
|
||||||
})),
|
})),
|
||||||
styling.Code(fmt.Sprintf("%.2f MB (%d个资源)", float64(info.TotalBytes())/(1024*1024), info.TotalResources())),
|
styling.Code(i18n.T(i18nk.BotMsgProgressSizeWithResources, map[string]any{
|
||||||
|
"Size": fmt.Sprintf("%.2f MB", float64(info.TotalBytes())/(1024*1024)),
|
||||||
|
"Count": info.TotalResources(),
|
||||||
|
})),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
log.FromContext(ctx).Errorf("Failed to build entities: %s", err)
|
log.FromContext(ctx).Errorf("Failed to build entities: %s", err)
|
||||||
return
|
return
|
||||||
@@ -101,7 +74,7 @@ func (p *Progress) OnStart(ctx context.Context, info TaskInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Progress) OnProgress(ctx context.Context, info TaskInfo) {
|
func (p *Progress) OnProgress(ctx context.Context, info TaskInfo) {
|
||||||
if !shouldUpdateProgress(info.TotalBytes(), info.DownloadedBytes(), int(p.lastUpdatePercent.Load())) {
|
if !progressutil.ShouldUpdate(info.TotalBytes(), info.DownloadedBytes(), int(p.lastUpdatePercent.Load())) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
percent := int((info.DownloadedBytes() * 100) / info.TotalBytes())
|
percent := int((info.DownloadedBytes() * 100) / info.TotalBytes())
|
||||||
@@ -114,7 +87,10 @@ func (p *Progress) OnProgress(ctx context.Context, info TaskInfo) {
|
|||||||
var entities []tg.MessageEntityClass
|
var entities []tg.MessageEntityClass
|
||||||
if err := styling.Perform(&entityBuilder,
|
if err := styling.Perform(&entityBuilder,
|
||||||
styling.Plain(i18n.T(i18nk.BotMsgProgressDownloadingPrefix, nil)),
|
styling.Plain(i18n.T(i18nk.BotMsgProgressDownloadingPrefix, nil)),
|
||||||
styling.Code(fmt.Sprintf("%.2f MB (%d个文件)", float64(info.TotalBytes())/(1024*1024), info.TotalResources())),
|
styling.Code(i18n.T(i18nk.BotMsgProgressSizeWithFiles, map[string]any{
|
||||||
|
"Size": fmt.Sprintf("%.2f MB", float64(info.TotalBytes())/(1024*1024)),
|
||||||
|
"Count": info.TotalResources(),
|
||||||
|
})),
|
||||||
styling.Plain(i18n.T(i18nk.BotMsgProgressProcessingListPrefix, nil)),
|
styling.Plain(i18n.T(i18nk.BotMsgProgressProcessingListPrefix, nil)),
|
||||||
func() styling.StyledTextOption {
|
func() styling.StyledTextOption {
|
||||||
var lines []string
|
var lines []string
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/gotd/td/tg"
|
"github.com/gotd/td/tg"
|
||||||
"github.com/krau/SaveAny-Bot/common/i18n"
|
"github.com/krau/SaveAny-Bot/common/i18n"
|
||||||
"github.com/krau/SaveAny-Bot/common/i18n/i18nk"
|
"github.com/krau/SaveAny-Bot/common/i18n/i18nk"
|
||||||
|
"github.com/krau/SaveAny-Bot/common/utils/progressutil"
|
||||||
"github.com/krau/SaveAny-Bot/common/utils/tgutil"
|
"github.com/krau/SaveAny-Bot/common/utils/tgutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -60,7 +61,7 @@ func (p *Progress) OnStart(ctx context.Context, info TaskInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Progress) OnProgress(ctx context.Context, info TaskInfo) {
|
func (p *Progress) OnProgress(ctx context.Context, info TaskInfo) {
|
||||||
if !shouldUpdateProgress(info.Downloaded(), int64(info.TotalPics())) {
|
if !progressutil.ShouldUpdateCount(info.Downloaded(), int64(info.TotalPics())) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.FromContext(ctx).Debugf("Progress update: %s, %d/%d", info.TaskID(), info.Downloaded(), info.TotalPics())
|
log.FromContext(ctx).Debugf("Progress update: %s, %d/%d", info.TaskID(), info.Downloaded(), info.TotalPics())
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
package telegraph
|
|
||||||
|
|
||||||
func shouldUpdateProgress(downloaded int64, total int64) bool {
|
|
||||||
if total <= 0 || downloaded <= 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
step := int64(10)
|
|
||||||
if downloaded < step {
|
|
||||||
return downloaded == total
|
|
||||||
}
|
|
||||||
return downloaded%step == 0 || downloaded == total
|
|
||||||
}
|
|
||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/krau/SaveAny-Bot/common/i18n"
|
"github.com/krau/SaveAny-Bot/common/i18n"
|
||||||
"github.com/krau/SaveAny-Bot/common/i18n/i18nk"
|
"github.com/krau/SaveAny-Bot/common/i18n/i18nk"
|
||||||
"github.com/krau/SaveAny-Bot/common/utils/dlutil"
|
"github.com/krau/SaveAny-Bot/common/utils/dlutil"
|
||||||
|
"github.com/krau/SaveAny-Bot/common/utils/progressutil"
|
||||||
"github.com/krau/SaveAny-Bot/common/utils/tgutil"
|
"github.com/krau/SaveAny-Bot/common/utils/tgutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -111,7 +112,7 @@ func (p *Progress) OnProgress(ctx context.Context, info TaskInfo, downloaded, to
|
|||||||
|
|
||||||
func shouldUpdateSingleDownloadProgress(total, downloaded int64, lastPercent int, elapsed time.Duration) bool {
|
func shouldUpdateSingleDownloadProgress(total, downloaded int64, lastPercent int, elapsed time.Duration) bool {
|
||||||
if total > 0 {
|
if total > 0 {
|
||||||
return shouldUpdateProgress(total, downloaded, lastPercent)
|
return progressutil.ShouldUpdate(total, downloaded, lastPercent)
|
||||||
}
|
}
|
||||||
return downloaded > 0 && elapsed >= uploadProgressMaxInterval
|
return downloaded > 0 && elapsed >= uploadProgressMaxInterval
|
||||||
}
|
}
|
||||||
@@ -183,7 +184,7 @@ func shouldUpdateUploadProgress(total, uploaded int64, lastPercent int, elapsed
|
|||||||
if percent == lastPercent {
|
if percent == lastPercent {
|
||||||
return elapsed >= uploadProgressMaxInterval
|
return elapsed >= uploadProgressMaxInterval
|
||||||
}
|
}
|
||||||
return shouldUpdateProgress(total, uploaded, lastPercent) || elapsed >= uploadProgressMaxInterval
|
return progressutil.ShouldUpdate(total, uploaded, lastPercent) || elapsed >= uploadProgressMaxInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
func singleUploadPhase(attempt int) singleProgressPhase {
|
func singleUploadPhase(attempt int) singleProgressPhase {
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
package tfile
|
|
||||||
|
|
||||||
var progressUpdatesLevels = []struct {
|
|
||||||
size int64 // 文件大小阈值
|
|
||||||
stepPercent int // 每多少 % 更新一次
|
|
||||||
}{
|
|
||||||
{10 << 20, 100},
|
|
||||||
{50 << 20, 20},
|
|
||||||
{200 << 20, 10},
|
|
||||||
{500 << 20, 5},
|
|
||||||
}
|
|
||||||
|
|
||||||
func shouldUpdateProgress(total, downloaded int64, lastUpdatePercent int) bool {
|
|
||||||
if total <= 0 || downloaded <= 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
percent := int((downloaded * 100) / total)
|
|
||||||
if percent <= lastUpdatePercent {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
step := progressUpdatesLevels[len(progressUpdatesLevels)-1].stepPercent
|
|
||||||
for _, lvl := range progressUpdatesLevels {
|
|
||||||
if total < lvl.size {
|
|
||||||
step = lvl.stepPercent
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return percent >= lastUpdatePercent+step
|
|
||||||
}
|
|
||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/krau/SaveAny-Bot/common/i18n"
|
"github.com/krau/SaveAny-Bot/common/i18n"
|
||||||
"github.com/krau/SaveAny-Bot/common/i18n/i18nk"
|
"github.com/krau/SaveAny-Bot/common/i18n/i18nk"
|
||||||
"github.com/krau/SaveAny-Bot/common/utils/dlutil"
|
"github.com/krau/SaveAny-Bot/common/utils/dlutil"
|
||||||
|
"github.com/krau/SaveAny-Bot/common/utils/progressutil"
|
||||||
"github.com/krau/SaveAny-Bot/common/utils/tgutil"
|
"github.com/krau/SaveAny-Bot/common/utils/tgutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -83,7 +84,7 @@ func (p *Progress) OnStart(ctx context.Context, info TaskInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Progress) OnProgress(ctx context.Context, info TaskInfo) {
|
func (p *Progress) OnProgress(ctx context.Context, info TaskInfo) {
|
||||||
if !shouldUpdateProgress(info.TotalSize(), info.Uploaded(), int(p.lastUpdatePercent.Load())) {
|
if !progressutil.ShouldUpdate(info.TotalSize(), info.Uploaded(), int(p.lastUpdatePercent.Load())) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
percent := int((info.Uploaded() * 100) / info.TotalSize())
|
percent := int((info.Uploaded() * 100) / info.TotalSize())
|
||||||
@@ -221,14 +222,6 @@ func (p *Progress) OnDone(ctx context.Context, info TaskInfo, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func shouldUpdateProgress(total, current int64, lastPercent int) bool {
|
|
||||||
if total == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
currentPercent := int((current * 100) / total)
|
|
||||||
return currentPercent > lastPercent && currentPercent%5 == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatDuration(d time.Duration) string {
|
func formatDuration(d time.Duration) string {
|
||||||
d = d.Round(time.Second)
|
d = d.Round(time.Second)
|
||||||
h := d / time.Hour
|
h := d / time.Hour
|
||||||
|
|||||||
Reference in New Issue
Block a user