s3 support
This commit is contained in:
parent
fa5cfaf14d
commit
03f10b66ee
53 changed files with 2796 additions and 102 deletions
|
|
@ -18,6 +18,8 @@ type MediaBackend string
|
|||
const (
|
||||
// MediaBackendLocalFS 表示 blob 字节存在本地磁盘(object_key 为相对路径)。
|
||||
MediaBackendLocalFS MediaBackend = "localfs"
|
||||
// MediaBackendS3 表示 blob 字节存在 S3 兼容对象存储(MinIO 或 AWS S3)。
|
||||
MediaBackendS3 MediaBackend = "s3"
|
||||
)
|
||||
|
||||
// FileBlob 是一个可下载的二进制对象的索引项:location_key → 后端/对象键/大小/mime。
|
||||
|
|
@ -233,6 +235,10 @@ type Document struct {
|
|||
DCID int `json:"dc_id,omitempty"`
|
||||
Attributes []DocumentAttribute `json:"attributes,omitempty"`
|
||||
Thumbs []PhotoSize `json:"thumbs,omitempty"`
|
||||
// OwnerUserID is who uploaded this document; 0 for rows predating storage
|
||||
// accounting or for system-originated documents. Used for per-account
|
||||
// storage usage reporting, not part of the tg wire protocol.
|
||||
OwnerUserID int64 `json:"owner_user_id,omitempty"`
|
||||
}
|
||||
|
||||
// StickerSetRef 返回该文档归属的贴纸集引用(若有 sticker/custom_emoji 属性)。
|
||||
|
|
@ -384,6 +390,9 @@ type Photo struct {
|
|||
DCID int `json:"dc_id,omitempty"`
|
||||
HasStickers bool `json:"has_stickers,omitempty"`
|
||||
Sizes []PhotoSize `json:"sizes,omitempty"`
|
||||
// OwnerUserID is who uploaded this photo; 0 for rows predating storage
|
||||
// accounting or for system-originated photos (e.g. webpage previews).
|
||||
OwnerUserID int64 `json:"owner_user_id,omitempty"`
|
||||
}
|
||||
|
||||
func ClonePhotoPtr(photo *Photo) *Photo {
|
||||
|
|
|
|||
|
|
@ -11,4 +11,8 @@ var (
|
|||
ErrUploadQuotaExceeded = errors.New("upload quota exceeded")
|
||||
ErrPhotoInvalid = errors.New("photo invalid")
|
||||
ErrDocumentInvalid = errors.New("document invalid")
|
||||
// ErrStorageFull is returned when the configured low-space guard rejects a
|
||||
// write: local disk free bytes (or, on the s3 backend, the configured
|
||||
// total-bytes budget) has fallen below the configured threshold.
|
||||
ErrStorageFull = errors.New("storage full")
|
||||
)
|
||||
|
|
|
|||
90
internal/domain/media_refs.go
Normal file
90
internal/domain/media_refs.go
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
package domain
|
||||
|
||||
// MediaKind identifies which table a media_references row points into.
|
||||
type MediaKind string
|
||||
|
||||
const (
|
||||
MediaKindDocument MediaKind = "document"
|
||||
MediaKindPhoto MediaKind = "photo"
|
||||
)
|
||||
|
||||
// MediaRefKind identifies why a document/photo is still considered "live" --
|
||||
// each distinct kind of place that can hold a durable pointer to media gets
|
||||
// its own ref_kind, so removing one kind of reference (e.g. a deleted
|
||||
// message) doesn't accidentally drop a still-live reference of another kind
|
||||
// (e.g. the same document also set as someone's profile photo).
|
||||
type MediaRefKind string
|
||||
|
||||
const (
|
||||
MediaRefKindMessageBox MediaRefKind = "message_box"
|
||||
MediaRefKindChannelMessage MediaRefKind = "channel_message"
|
||||
MediaRefKindProfilePhoto MediaRefKind = "profile_photo"
|
||||
MediaRefKindStickerSet MediaRefKind = "sticker_set"
|
||||
MediaRefKindGift MediaRefKind = "gift"
|
||||
)
|
||||
|
||||
// MediaReference is one live pointer to a document/photo. GC (the storage
|
||||
// retention sweep) only considers a document/photo eligible for deletion
|
||||
// once every reference to it has been removed.
|
||||
type MediaReference struct {
|
||||
Kind MediaKind
|
||||
MediaID int64
|
||||
RefKind MediaRefKind
|
||||
RefKey string
|
||||
}
|
||||
|
||||
// OrphanCandidate is a document/photo whose last reference has been removed
|
||||
// (orphaned_at is set) and is old enough to be considered for the storage
|
||||
// retention sweep.
|
||||
type OrphanCandidate struct {
|
||||
Kind MediaKind
|
||||
MediaID int64
|
||||
Backend MediaBackend
|
||||
ObjectKey string
|
||||
Size int64
|
||||
OrphanedAt int64 // unix seconds
|
||||
}
|
||||
|
||||
// MediaRefTarget identifies one document/photo embedded in a message's media
|
||||
// snapshot.
|
||||
type MediaRefTarget struct {
|
||||
Kind MediaKind
|
||||
ID int64
|
||||
}
|
||||
|
||||
// ExtractMediaRefTargets returns every document/photo id embedded in a
|
||||
// message's media snapshot (including nested ones -- a live photo's video
|
||||
// document, a webpage preview's photo), deduplicated. Used to register/drop
|
||||
// media_references rows when a message carrying this media is
|
||||
// created/edited/deleted.
|
||||
func ExtractMediaRefTargets(media *MessageMedia) []MediaRefTarget {
|
||||
if media == nil {
|
||||
return nil
|
||||
}
|
||||
seen := make(map[MediaRefTarget]struct{}, 2)
|
||||
var out []MediaRefTarget
|
||||
add := func(kind MediaKind, id int64) {
|
||||
if id == 0 {
|
||||
return
|
||||
}
|
||||
t := MediaRefTarget{Kind: kind, ID: id}
|
||||
if _, ok := seen[t]; ok {
|
||||
return
|
||||
}
|
||||
seen[t] = struct{}{}
|
||||
out = append(out, t)
|
||||
}
|
||||
if media.Photo != nil {
|
||||
add(MediaKindPhoto, media.Photo.ID)
|
||||
}
|
||||
if media.Document != nil {
|
||||
add(MediaKindDocument, media.Document.ID)
|
||||
}
|
||||
if media.LivePhotoVideo != nil {
|
||||
add(MediaKindDocument, media.LivePhotoVideo.ID)
|
||||
}
|
||||
if media.WebPage != nil && media.WebPage.Photo != nil {
|
||||
add(MediaKindPhoto, media.WebPage.Photo.ID)
|
||||
}
|
||||
return out
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue