teldrive/services/common.go

271 lines
6.2 KiB
Go
Raw Normal View History

2023-09-20 03:20:44 +08:00
package services
import (
"bytes"
"context"
"fmt"
"strconv"
"github.com/divyam234/teldrive/database"
"github.com/divyam234/teldrive/models"
"github.com/divyam234/teldrive/schemas"
"github.com/divyam234/teldrive/types"
2023-11-02 21:51:30 +08:00
"github.com/divyam234/teldrive/utils/cache"
2023-09-20 03:20:44 +08:00
"github.com/divyam234/teldrive/utils/tgc"
"github.com/gin-gonic/gin"
"github.com/gotd/td/telegram"
"github.com/gotd/td/tg"
"github.com/pkg/errors"
"github.com/thoas/go-funk"
)
func getChunk(ctx context.Context, tgClient *telegram.Client, location tg.InputFileLocationClass, offset int64, limit int64) ([]byte, error) {
req := &tg.UploadGetFileRequest{
Offset: offset,
Limit: int(limit),
Location: location,
}
r, err := tgClient.API().UploadGetFile(ctx, req)
if err != nil {
return nil, err
}
switch result := r.(type) {
case *tg.UploadFile:
return result.Bytes, nil
default:
return nil, fmt.Errorf("unexpected type %T", r)
}
}
func iterContent(ctx context.Context, tgClient *telegram.Client, location tg.InputFileLocationClass) (*bytes.Buffer, error) {
offset := int64(0)
limit := int64(1024 * 1024)
buff := &bytes.Buffer{}
for {
r, err := getChunk(ctx, tgClient, location, offset, limit)
if err != nil {
return buff, err
}
if len(r) == 0 {
break
}
buff.Write(r)
offset += int64(limit)
}
return buff, nil
}
func getUserAuth(c *gin.Context) (int64, string) {
val, _ := c.Get("jwtUser")
jwtUser := val.(*types.JWTClaims)
userId, _ := strconv.ParseInt(jwtUser.Subject, 10, 64)
return userId, jwtUser.TgSession
}
func getBotInfo(ctx context.Context, token string) (*BotInfo, error) {
client, _ := tgc.BotLogin(token)
var user *tg.User
err := tgc.RunWithAuth(ctx, client, token, func(ctx context.Context) error {
user, _ = client.Self(ctx)
return nil
})
if err != nil {
return nil, err
}
return &BotInfo{Id: user.ID, UserName: user.Username, Token: token}, nil
}
func getParts(ctx context.Context, client *telegram.Client, file *schemas.FileOutFull, userID string) ([]types.Part, error) {
2023-11-02 21:51:30 +08:00
parts := []types.Part{}
key := fmt.Sprintf("messages:%s:%s", file.ID, userID)
err := cache.GetCache().Get(key, &parts)
if err == nil {
return parts, nil
}
2023-09-20 03:20:44 +08:00
ids := funk.Map(*file.Parts, func(part models.Part) tg.InputMessageClass {
return tg.InputMessageClass(&tg.InputMessageID{ID: int(part.ID)})
})
channel, err := GetChannelById(ctx, client, *file.ChannelID, userID)
if err != nil {
return nil, err
}
messageRequest := tg.ChannelsGetMessagesRequest{Channel: channel, ID: ids.([]tg.InputMessageClass)}
res, err := client.API().ChannelsGetMessages(ctx, &messageRequest)
if err != nil {
return nil, err
}
messages := res.(*tg.MessagesChannelMessages)
for _, message := range messages.Messages {
item := message.(*tg.Message)
media := item.Media.(*tg.MessageMediaDocument)
document := media.Document.(*tg.Document)
location := document.AsInputDocumentFileLocation()
2023-11-06 02:08:18 +08:00
parts = append(parts, types.Part{Location: location, Start: 0, End: document.Size - 1})
2023-09-20 03:20:44 +08:00
}
2023-11-02 21:51:30 +08:00
cache.GetCache().Set(key, &parts, 3600)
2023-09-20 03:20:44 +08:00
return parts, nil
}
2023-11-06 02:08:18 +08:00
func rangedParts(parts []types.Part, startByte, endByte int64) []types.Part {
chunkSize := parts[0].End + 1
numParts := int64(len(parts))
2023-09-20 03:20:44 +08:00
2023-11-06 02:08:18 +08:00
validParts := []types.Part{}
2023-09-20 03:20:44 +08:00
2023-11-06 02:08:18 +08:00
firstChunk := max(startByte/chunkSize, 0)
2023-09-20 03:20:44 +08:00
2023-11-06 02:08:18 +08:00
lastChunk := min(endByte/chunkSize, numParts)
2023-09-20 03:20:44 +08:00
2023-11-06 02:08:18 +08:00
startInFirstChunk := startByte % chunkSize
endInLastChunk := endByte % chunkSize
if firstChunk == lastChunk {
validParts = append(validParts, types.Part{
Location: parts[firstChunk].Location,
Start: startInFirstChunk,
End: endInLastChunk,
})
} else {
validParts = append(validParts, types.Part{
Location: parts[firstChunk].Location,
Start: startInFirstChunk,
End: parts[firstChunk].End,
})
// Add valid parts from any chunks in between.
for i := firstChunk + 1; i < lastChunk; i++ {
validParts = append(validParts, types.Part{
2023-11-08 17:04:18 +08:00
Location: parts[i].Location,
2023-11-06 02:08:18 +08:00
Start: 0,
2023-11-08 17:04:18 +08:00
End: parts[i].End,
2023-11-06 02:08:18 +08:00
})
}
2023-09-20 03:20:44 +08:00
2023-11-06 02:08:18 +08:00
// Add valid parts from the last chunk.
validParts = append(validParts, types.Part{
2023-11-08 17:04:18 +08:00
Location: parts[lastChunk].Location,
2023-11-06 02:08:18 +08:00
Start: 0,
End: endInLastChunk,
})
2023-09-20 03:20:44 +08:00
}
2023-11-06 02:08:18 +08:00
return validParts
2023-09-20 03:20:44 +08:00
}
func GetChannelById(ctx context.Context, client *telegram.Client, channelID int64, userID string) (*tg.InputChannel, error) {
channel := &tg.InputChannel{}
2023-09-24 04:26:04 +08:00
inputChannel := &tg.InputChannel{
ChannelID: channelID,
}
channels, err := client.API().ChannelsGetChannels(ctx, []tg.InputChannelClass{inputChannel})
2023-09-20 03:20:44 +08:00
if err != nil {
2023-09-24 04:26:04 +08:00
return nil, err
}
2023-09-20 03:20:44 +08:00
2023-09-24 04:26:04 +08:00
if len(channels.GetChats()) == 0 {
return nil, errors.New("no channels found")
2023-09-20 03:20:44 +08:00
}
2023-09-24 04:26:04 +08:00
channel = channels.GetChats()[0].(*tg.Channel).AsInput()
2023-09-20 03:20:44 +08:00
return channel, nil
}
func GetDefaultChannel(ctx context.Context, userID int64) (int64, error) {
var channelID int64
2023-11-02 21:51:30 +08:00
key := fmt.Sprintf("users:channel:%d", userID)
2023-09-20 03:20:44 +08:00
2023-11-02 21:51:30 +08:00
err := cache.GetCache().Get(key, &channelID)
2023-09-20 03:20:44 +08:00
2023-11-02 21:51:30 +08:00
if err == nil {
return channelID, nil
}
2023-09-20 03:20:44 +08:00
2023-11-02 21:51:30 +08:00
var channelIds []int64
database.DB.Model(&models.Channel{}).Where("user_id = ?", userID).Where("selected = ?", true).
Pluck("channel_id", &channelIds)
if len(channelIds) == 1 {
channelID = channelIds[0]
cache.GetCache().Set(key, channelID, 0)
2023-09-20 03:20:44 +08:00
}
if channelID == 0 {
return channelID, errors.New("default channel not set")
}
return channelID, nil
}
func GetBotsToken(ctx context.Context, userID int64) ([]string, error) {
2023-09-20 03:20:44 +08:00
var bots []string
channelId, err := GetDefaultChannel(ctx, userID)
2023-09-20 03:20:44 +08:00
if err != nil {
return nil, err
}
2023-11-02 21:51:30 +08:00
key := fmt.Sprintf("users:bots:%d:%d", userID, channelId)
2023-11-02 21:51:30 +08:00
err = cache.GetCache().Get(key, &bots)
2023-09-20 03:20:44 +08:00
2023-11-02 21:51:30 +08:00
if err == nil {
return bots, nil
2023-09-20 03:20:44 +08:00
}
2023-11-02 21:51:30 +08:00
if err := database.DB.Model(&models.Bot{}).Where("user_id = ?", userID).
Where("channel_id = ?", channelId).Pluck("token", &bots).Error; err != nil {
return nil, err
}
cache.GetCache().Set(key, &bots, 0)
2023-09-20 03:20:44 +08:00
return bots, nil
}
2023-11-02 21:51:30 +08:00
func GetSessionByHash(hash string) (*models.Session, error) {
var session models.Session
key := fmt.Sprintf("sessions:%s", hash)
err := cache.GetCache().Get(key, &session)
if err == nil {
return &session, nil
}
if err := database.DB.Model(&models.Session{}).Where("hash = ?", hash).First(&session).Error; err != nil {
return nil, err
}
cache.GetCache().Set(key, &session, 0)
return &session, nil
}