owpengram-server/internal/rpc/stickers_creator.go
2026-07-01 21:55:55 +08:00

351 lines
11 KiB
Go

package rpc
import (
"context"
"errors"
"github.com/gotd/td/tg"
"telesrv/internal/domain"
)
func (r *Router) registerStickers(d *tg.ServerDispatcher) {
d.OnStickersCreateStickerSet(r.onStickersCreateStickerSet)
d.OnStickersCheckShortName(r.onStickersCheckShortName)
d.OnStickersSuggestShortName(r.onStickersSuggestShortName)
d.OnStickersAddStickerToSet(r.onStickersAddStickerToSet)
d.OnStickersRemoveStickerFromSet(r.onStickersRemoveStickerFromSet)
d.OnStickersChangeStickerPosition(r.onStickersChangeStickerPosition)
d.OnStickersRenameStickerSet(r.onStickersRenameStickerSet)
d.OnStickersDeleteStickerSet(r.onStickersDeleteStickerSet)
}
func (r *Router) onStickersCreateStickerSet(ctx context.Context, req *tg.StickersCreateStickerSetRequest) (tg.MessagesStickerSetClass, error) {
if req == nil {
return nil, inputRequestInvalidErr()
}
if r.deps.Files == nil {
return nil, internalErr()
}
if req.Masks && req.Emojis {
return nil, packTypeInvalidErr()
}
userID, err := r.stickerSetCreatorUserID(ctx, req.UserID)
if err != nil {
return nil, err
}
items := make([]domain.StickerSetItemInput, 0, len(req.Stickers))
for _, item := range req.Stickers {
id, accessHash, ok := inputDocumentRef(item.Document)
if !ok {
return nil, stickerFileInvalidErr()
}
items = append(items, domain.StickerSetItemInput{
DocumentID: id,
DocumentAccessHash: accessHash,
Emoji: item.Emoji,
Keywords: item.Keywords,
})
}
thumbID, thumbAccessHash, ok := inputDocumentRef(req.Thumb)
if req.Thumb != nil && !ok {
return nil, stickerFileInvalidErr()
}
kind := domain.StickerSetKindStickers
if req.Emojis {
kind = domain.StickerSetKindEmoji
} else if req.Masks {
kind = domain.StickerSetKindMasks
}
set, docs, err := r.deps.Files.CreateStickerSet(ctx, domain.CreateStickerSetRequest{
CreatorUserID: userID,
Title: req.Title,
ShortName: req.ShortName,
Kind: kind,
TextColor: req.TextColor,
ThumbDocumentID: thumbID,
ThumbAccessHash: thumbAccessHash,
Items: items,
Software: req.Software,
Date: int(r.clock.Now().Unix()),
})
if err != nil {
return nil, stickerSetCreateErr(err)
}
if svc, ok := r.userStickerSetSvc(); ok {
if err := svc.InstallUserStickerSet(ctx, userID, set.ID, userStickerSetKind(set), false, int(r.clock.Now().Unix())); err != nil {
return nil, internalErr()
}
set.Installed = true
set.InstalledDate = int(r.clock.Now().Unix())
}
r.invalidateStickerCatalog(userStickerSetKind(set))
r.pushStickerSetsUpdate(ctx, userID, userStickerSetKind(set))
return tgMessagesStickerSet(set, docs), nil
}
func (r *Router) onStickersCheckShortName(ctx context.Context, shortName string) (bool, error) {
if r.deps.Files == nil {
return false, internalErr()
}
if _, _, err := r.currentUserID(ctx); err != nil {
return false, internalErr()
}
available, err := r.deps.Files.CheckStickerSetShortName(ctx, shortName)
if err != nil {
return false, stickerSetShortNameCheckErr(err)
}
return available, nil
}
func (r *Router) onStickersSuggestShortName(ctx context.Context, title string) (*tg.StickersSuggestedShortName, error) {
if r.deps.Files == nil {
return nil, internalErr()
}
userID, _, err := r.currentUserID(ctx)
if err != nil {
return nil, internalErr()
}
shortName, err := r.deps.Files.SuggestStickerSetShortName(ctx, title, userID)
if err != nil {
return nil, stickerSetSuggestShortNameErr(err)
}
return &tg.StickersSuggestedShortName{ShortName: shortName}, nil
}
func (r *Router) onStickersAddStickerToSet(ctx context.Context, req *tg.StickersAddStickerToSetRequest) (tg.MessagesStickerSetClass, error) {
if req == nil {
return nil, inputRequestInvalidErr()
}
userID, err := r.stickerSetActorUserID(ctx)
if err != nil {
return nil, err
}
ref, ok := stickerSetRefFromInput(req.Stickerset)
if !ok {
return nil, stickersetInvalidErr()
}
documentID, accessHash, ok := inputDocumentRef(req.Sticker.Document)
if !ok {
return nil, stickerFileInvalidErr()
}
set, docs, err := r.deps.Files.AddStickerToSet(ctx, userID, ref, domain.StickerSetItemInput{
DocumentID: documentID,
DocumentAccessHash: accessHash,
Emoji: req.Sticker.Emoji,
Keywords: req.Sticker.Keywords,
})
if err != nil {
return nil, stickerSetManagementErr(err)
}
r.notifyStickerSetMutated(ctx, userID, set)
return tgMessagesStickerSet(set, docs), nil
}
func (r *Router) onStickersRemoveStickerFromSet(ctx context.Context, input tg.InputDocumentClass) (tg.MessagesStickerSetClass, error) {
userID, err := r.stickerSetActorUserID(ctx)
if err != nil {
return nil, err
}
documentID, accessHash, ok := inputDocumentRef(input)
if !ok {
return nil, stickerFileInvalidErr()
}
set, docs, err := r.deps.Files.RemoveStickerFromSet(ctx, userID, documentID, accessHash)
if err != nil {
return nil, stickerSetManagementErr(err)
}
r.notifyStickerSetMutated(ctx, userID, set)
return tgMessagesStickerSet(set, docs), nil
}
func (r *Router) onStickersChangeStickerPosition(ctx context.Context, req *tg.StickersChangeStickerPositionRequest) (tg.MessagesStickerSetClass, error) {
if req == nil {
return nil, inputRequestInvalidErr()
}
userID, err := r.stickerSetActorUserID(ctx)
if err != nil {
return nil, err
}
documentID, accessHash, ok := inputDocumentRef(req.Sticker)
if !ok {
return nil, stickerFileInvalidErr()
}
set, docs, err := r.deps.Files.ChangeStickerPosition(ctx, userID, documentID, accessHash, req.Position)
if err != nil {
return nil, stickerSetManagementErr(err)
}
r.notifyStickerSetMutated(ctx, userID, set)
return tgMessagesStickerSet(set, docs), nil
}
func (r *Router) onStickersRenameStickerSet(ctx context.Context, req *tg.StickersRenameStickerSetRequest) (tg.MessagesStickerSetClass, error) {
if req == nil {
return nil, inputRequestInvalidErr()
}
userID, err := r.stickerSetActorUserID(ctx)
if err != nil {
return nil, err
}
ref, ok := stickerSetRefFromInput(req.Stickerset)
if !ok {
return nil, stickersetInvalidErr()
}
set, docs, err := r.deps.Files.RenameStickerSet(ctx, userID, ref, req.Title)
if err != nil {
return nil, stickerSetManagementErr(err)
}
r.notifyStickerSetMutated(ctx, userID, set)
return tgMessagesStickerSet(set, docs), nil
}
func (r *Router) onStickersDeleteStickerSet(ctx context.Context, input tg.InputStickerSetClass) (bool, error) {
userID, err := r.stickerSetActorUserID(ctx)
if err != nil {
return false, err
}
ref, ok := stickerSetRefFromInput(input)
if !ok {
return false, stickersetInvalidErr()
}
kind, err := r.deps.Files.DeleteStickerSet(ctx, userID, ref)
if err != nil {
return false, stickerSetManagementErr(err)
}
r.invalidateStickerCatalog(kind)
r.pushStickerSetsUpdate(ctx, userID, kind)
return true, nil
}
func (r *Router) stickerSetActorUserID(ctx context.Context) (int64, error) {
if r.deps.Files == nil {
return 0, internalErr()
}
userID, _, err := r.currentUserID(ctx)
if err != nil {
return 0, internalErr()
}
return userID, nil
}
func (r *Router) notifyStickerSetMutated(ctx context.Context, userID int64, set domain.StickerSet) {
kind := userStickerSetKind(set)
r.invalidateStickerCatalog(kind)
r.pushStickerSetsUpdate(ctx, userID, kind)
}
func (r *Router) stickerSetCreatorUserID(ctx context.Context, input tg.InputUserClass) (int64, error) {
currentUserID, _, err := r.currentUserID(ctx)
if err != nil {
return 0, internalErr()
}
if r.deps.Users == nil {
switch v := input.(type) {
case *tg.InputUserSelf:
return currentUserID, nil
case *tg.InputUser:
if v != nil && v.UserID == currentUserID {
return currentUserID, nil
}
}
return 0, userIDInvalidErr()
}
user, found, err := r.userFromInput(ctx, currentUserID, input)
if err != nil {
return 0, internalErr()
}
if !found || user.ID != currentUserID {
return 0, userIDInvalidErr()
}
return currentUserID, nil
}
func inputDocumentRef(input tg.InputDocumentClass) (int64, int64, bool) {
doc, ok := input.(*tg.InputDocument)
if !ok || doc == nil || doc.ID == 0 || doc.AccessHash == 0 {
return 0, 0, false
}
return doc.ID, doc.AccessHash, true
}
func packShortNameInvalidErr() error { return tgerr400("PACK_SHORT_NAME_INVALID") }
func packShortNameOccupiedErr() error { return tgerr400("PACK_SHORT_NAME_OCCUPIED") }
func packTitleInvalidErr() error { return tgerr400("PACK_TITLE_INVALID") }
func packTypeInvalidErr() error { return tgerr400("PACK_TYPE_INVALID") }
func stickersEmptyErr() error { return tgerr400("STICKERS_EMPTY") }
func stickersTooMuchErr() error { return tgerr400("STICKERS_TOO_MUCH") }
func stickerEmojiInvalidErr() error { return tgerr400("STICKER_EMOJI_INVALID") }
func stickerFileInvalidErr() error { return tgerr400("STICKER_FILE_INVALID") }
func shortNameInvalidErr() error { return tgerr400("SHORT_NAME_INVALID") }
func titleInvalidErr() error { return tgerr400("TITLE_INVALID") }
func positionInvalidErr() error { return tgerr400("POSITION_INVALID") }
func stickerSetCreateErr(err error) error {
switch {
case errors.Is(err, domain.ErrStickerSetTitleInvalid):
return packTitleInvalidErr()
case errors.Is(err, domain.ErrStickerSetShortNameInvalid):
return packShortNameInvalidErr()
case errors.Is(err, domain.ErrStickerSetShortNameOccupied):
return packShortNameOccupiedErr()
case errors.Is(err, domain.ErrStickerSetTypeInvalid):
return packTypeInvalidErr()
case errors.Is(err, domain.ErrStickerSetEmpty):
return stickersEmptyErr()
case errors.Is(err, domain.ErrStickerSetTooMuch):
return stickersTooMuchErr()
case errors.Is(err, domain.ErrStickerSetEmojiInvalid):
return stickerEmojiInvalidErr()
case errors.Is(err, domain.ErrStickerSetFileInvalid), errors.Is(err, domain.ErrDocumentInvalid):
return stickerFileInvalidErr()
case errors.Is(err, domain.ErrStickerSetCreatorInvalid):
return userIDInvalidErr()
default:
return internalErr()
}
}
func stickerSetShortNameCheckErr(err error) error {
switch {
case errors.Is(err, domain.ErrStickerSetShortNameInvalid):
return shortNameInvalidErr()
default:
return internalErr()
}
}
func stickerSetSuggestShortNameErr(err error) error {
switch {
case errors.Is(err, domain.ErrStickerSetTitleInvalid):
return titleInvalidErr()
case errors.Is(err, domain.ErrStickerSetShortNameOccupied):
return packShortNameOccupiedErr()
case errors.Is(err, domain.ErrStickerSetCreatorInvalid):
return userIDInvalidErr()
default:
return internalErr()
}
}
func stickerSetManagementErr(err error) error {
switch {
case errors.Is(err, domain.ErrStickerSetTitleInvalid):
return packTitleInvalidErr()
case errors.Is(err, domain.ErrStickerSetEmpty):
return stickersEmptyErr()
case errors.Is(err, domain.ErrStickerSetTooMuch):
return stickersTooMuchErr()
case errors.Is(err, domain.ErrStickerSetEmojiInvalid):
return stickerEmojiInvalidErr()
case errors.Is(err, domain.ErrStickerSetFileInvalid), errors.Is(err, domain.ErrDocumentInvalid):
return stickerFileInvalidErr()
case errors.Is(err, domain.ErrStickerSetCreatorInvalid):
return userIDInvalidErr()
case errors.Is(err, domain.ErrStickerSetPositionInvalid):
return positionInvalidErr()
case errors.Is(err, domain.ErrStickerSetInvalid), errors.Is(err, domain.ErrStickerSetNotOwned):
return stickersetInvalidErr()
default:
return internalErr()
}
}