mirror of
https://github.com/krau/SaveAny-Bot.git
synced 2026-08-30 04:36:41 +08:00
feat(core): persist tasks and recover them after restart
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
package tfile
|
||||
|
||||
import (
|
||||
"github.com/gotd/td/telegram/downloader"
|
||||
"github.com/gotd/td/tg"
|
||||
)
|
||||
|
||||
// Payloadable is implemented by TGFile implementations that can serialize
|
||||
// themselves for task recovery.
|
||||
type Payloadable interface {
|
||||
Payload() FilePayload
|
||||
}
|
||||
|
||||
// FilePayloadOf returns the serializable form of f.
|
||||
func FilePayloadOf(f TGFile) (FilePayload, bool) {
|
||||
p, ok := f.(Payloadable)
|
||||
if !ok {
|
||||
return FilePayload{}, false
|
||||
}
|
||||
return p.Payload(), true
|
||||
}
|
||||
|
||||
// FilePayload is the minimal serializable representation of a TGFile,
|
||||
// used to rebuild tasks after a process restart.
|
||||
type FilePayload struct {
|
||||
Kind string `json:"kind"` // "document" | "photo"
|
||||
ID int64 `json:"id"`
|
||||
AccessHash int64 `json:"access_hash"`
|
||||
FileReference []byte `json:"file_reference"`
|
||||
ThumbSize string `json:"thumb_size"`
|
||||
Size int64 `json:"size"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Payload returns the serializable representation of the file.
|
||||
func (f *tgFile) Payload() FilePayload {
|
||||
p := FilePayload{
|
||||
Size: f.size,
|
||||
Name: f.name,
|
||||
}
|
||||
switch loc := f.location.(type) {
|
||||
case *tg.InputDocumentFileLocation:
|
||||
p.Kind = "document"
|
||||
p.ID = loc.ID
|
||||
p.AccessHash = loc.AccessHash
|
||||
p.FileReference = loc.FileReference
|
||||
p.ThumbSize = loc.ThumbSize
|
||||
case *tg.InputPhotoFileLocation:
|
||||
p.Kind = "photo"
|
||||
p.ID = loc.ID
|
||||
p.AccessHash = loc.AccessHash
|
||||
p.FileReference = loc.FileReference
|
||||
p.ThumbSize = loc.ThumbSize
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Location rebuilds the Telegram file location from the payload.
|
||||
func (p FilePayload) Location() tg.InputFileLocationClass {
|
||||
switch p.Kind {
|
||||
case "photo":
|
||||
return &tg.InputPhotoFileLocation{
|
||||
ID: p.ID,
|
||||
AccessHash: p.AccessHash,
|
||||
FileReference: p.FileReference,
|
||||
ThumbSize: p.ThumbSize,
|
||||
}
|
||||
default:
|
||||
return &tg.InputDocumentFileLocation{
|
||||
ID: p.ID,
|
||||
AccessHash: p.AccessHash,
|
||||
FileReference: p.FileReference,
|
||||
ThumbSize: p.ThumbSize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FileFromPayload rebuilds a TGFile from its serialized payload.
|
||||
func FileFromPayload(p FilePayload, dler downloader.Client) TGFile {
|
||||
return &tgFile{
|
||||
location: p.Location(),
|
||||
dler: dler,
|
||||
size: p.Size,
|
||||
name: p.Name,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package tfile
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
)
|
||||
|
||||
func TestFilePayloadDocumentRoundTrip(t *testing.T) {
|
||||
file := NewTGFile(
|
||||
&tg.InputDocumentFileLocation{
|
||||
ID: 6287403840090150101,
|
||||
AccessHash: -8452541528324991878,
|
||||
FileReference: []byte{0x02, 0x0e, 0x80, 0xd6},
|
||||
ThumbSize: "",
|
||||
},
|
||||
nil,
|
||||
4194304000,
|
||||
"常轨脱离Creative凸.7z.001",
|
||||
)
|
||||
p, ok := FilePayloadOf(file)
|
||||
if !ok {
|
||||
t.Fatalf("FilePayloadOf failed")
|
||||
}
|
||||
rebuilt := FileFromPayload(p, nil)
|
||||
if !reflect.DeepEqual(rebuilt.Location(), file.Location()) {
|
||||
t.Fatalf("location mismatch:\n got %#v\nwant %#v", rebuilt.Location(), file.Location())
|
||||
}
|
||||
if rebuilt.Size() != file.Size() || rebuilt.Name() != file.Name() {
|
||||
t.Fatalf("size/name mismatch: got %d %q, want %d %q", rebuilt.Size(), rebuilt.Name(), file.Size(), file.Name())
|
||||
}
|
||||
if p.Kind != "document" {
|
||||
t.Fatalf("kind = %q, want document", p.Kind)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilePayloadPhotoRoundTrip(t *testing.T) {
|
||||
file := NewTGFile(
|
||||
&tg.InputPhotoFileLocation{
|
||||
ID: 123,
|
||||
AccessHash: 456,
|
||||
FileReference: []byte{0xaa, 0xbb},
|
||||
ThumbSize: "y",
|
||||
},
|
||||
nil,
|
||||
0,
|
||||
"photo_123.png",
|
||||
)
|
||||
p, ok := FilePayloadOf(file)
|
||||
if !ok {
|
||||
t.Fatalf("FilePayloadOf failed")
|
||||
}
|
||||
if p.Kind != "photo" {
|
||||
t.Fatalf("kind = %q, want photo", p.Kind)
|
||||
}
|
||||
rebuilt := FileFromPayload(p, nil)
|
||||
if !reflect.DeepEqual(rebuilt.Location(), file.Location()) {
|
||||
t.Fatalf("location mismatch:\n got %#v\nwant %#v", rebuilt.Location(), file.Location())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user