Files
SaveAny-Bot/core/tphtask/execute.go
Krau 900823cdb9 refactor: refactor task logic for better scalability (#76)
* refactor: a big refactor. wip

* refactor: port handle file

* refactor: place all handlers

* fix: task info nil pointer

* feat: enhance task progress tracking and context management

* feat: cancel task

* feat: stream mode

* feat: silent mode

* feat: dir cmd

* refactor: remove unused old file

* feat: rule cmd

* feat: handle silent mode

* feat: batch task

* fix: batch task progress and temp file cleanup

* refactor: update file creation and cleanup methods for better resource management

* feat: add save command with silent mode handling

* feat: message link

* feat: update message prompts to include file count in storage selection

* feat: slient save links

* refactor: reduce dup code

* feat: rule type

* feat: chose dir

* feat: refactor file handling and storage rules, improve error handling and logging

* feat: rule mode

* feat: telegraph pics

* fix: tphpics nil pointer and inaccurate dirpath

* feat: silent save telegraph

* feat: add suffix to avoid file overwrite

* feat: new storage telegram

* chore: tidy go mod
2025-06-15 23:57:49 +08:00

95 lines
2.6 KiB
Go

package tphtask
import (
"context"
"fmt"
"io"
"path"
"path/filepath"
"github.com/charmbracelet/log"
"github.com/duke-git/lancet/v2/retry"
"github.com/krau/SaveAny-Bot/common/utils/fsutil"
"github.com/krau/SaveAny-Bot/config"
"go.uber.org/multierr"
"golang.org/x/sync/errgroup"
)
func (t *Task) Execute(ctx context.Context) error {
logger := log.FromContext(ctx)
logger.Infof("Starting Telegraph task %s", t.PhPath)
t.progress.OnStart(ctx, t)
eg, gctx := errgroup.WithContext(ctx)
eg.SetLimit(config.Cfg.Workers)
for i, pic := range t.Pics {
pic := pic
i := i
eg.Go(func() error {
err := t.processPic(gctx, pic, i)
if err != nil {
logger.Errorf("Error processing picture %s: %v", pic, err)
return fmt.Errorf("failed to process picture %s: %w", pic, err)
}
t.downloaded.Add(1)
t.progress.OnProgress(gctx, t)
return nil
})
}
err := eg.Wait()
if err != nil {
logger.Errorf("Error during Telegraph task execution: %v", err)
} else {
logger.Infof("Telegraph task %s completed successfully", t.PhPath)
}
t.progress.OnDone(ctx, t, err)
return err
}
func (t *Task) processPic(ctx context.Context, picUrl string, index int) error {
retryOpts := []retry.Option{
retry.Context(ctx),
retry.RetryTimes(uint(config.Cfg.Retry)),
}
var lastErr error
err := retry.Retry(func() error {
var body io.ReadCloser
body, lastErr = t.client.Download(ctx, picUrl)
if lastErr != nil {
lastErr = fmt.Errorf("failed to download picture %s: %w", picUrl, lastErr)
return lastErr
}
defer body.Close()
filename := fmt.Sprintf("%d%s", index+1, path.Ext(picUrl))
if t.cannotStream {
cacheFile, err := fsutil.CreateFile(filepath.Join(config.Cfg.Temp.BasePath,
fmt.Sprintf("tph_%s_%s", t.TaskID(), filename),
))
if err != nil {
lastErr = fmt.Errorf("failed to create cache file for picture %s: %w", filename, err)
return lastErr
}
defer func() {
if err := cacheFile.CloseAndRemove(); err != nil {
logger := log.FromContext(ctx)
logger.Errorf("Failed to close and remove cache file for picture %s: %v", filename, err)
}
}()
_, lastErr = io.Copy(cacheFile, body)
if lastErr != nil {
lastErr = fmt.Errorf("failed to copy picture %s to cache file: %w", filename, lastErr)
return lastErr
}
lastErr = t.Stor.Save(ctx, cacheFile, path.Join(t.StorPath, filename))
} else {
lastErr = t.Stor.Save(ctx, body, path.Join(t.StorPath, filename))
}
if lastErr != nil {
lastErr = fmt.Errorf("failed to save picture %s: %w", filename, lastErr)
return lastErr
}
return nil
}, retryOpts...)
return multierr.Combine(err, lastErr)
}