core/internal/clients/telegram/tg.go

247 lines
7.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package telegram
import (
"context"
"errors"
"fmt"
"path/filepath"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/pj_errors"
"penahub.gitlab.yandexcloud.net/backend/tdlib/client"
"sync"
"time"
)
type TelegramClient struct {
repo *dal.DAL
TgClients map[int64]*client.Client
WaitingClients map[string]WaitingClient
mu sync.Mutex
}
type WaitingClient struct {
PreviousReq AuthTgUserReq
Authorizer *client.ClientAuthorizer
}
func NewTelegramClient(ctx context.Context, repo *dal.DAL) (*TelegramClient, error) {
tgClient := &TelegramClient{
repo: repo,
TgClients: make(map[int64]*client.Client),
WaitingClients: make(map[string]WaitingClient),
}
allTgAccounts, err := repo.TgRepo.GetAllTgAccounts(ctx)
if err != nil {
if errors.Is(err, pj_errors.ErrNotFound) {
return tgClient, nil
}
return nil, err
}
for _, account := range allTgAccounts {
if account.Status == model.ActiveTg {
authorizer := client.ClientAuthorizerr()
authorizer.TdlibParameters <- &client.SetTdlibParametersRequest{
UseTestDc: false,
DatabaseDirectory: filepath.Join(".tdlib", "database"),
FilesDirectory: filepath.Join(".tdlib", "files"),
UseFileDatabase: true,
UseChatInfoDatabase: true,
UseMessageDatabase: true,
UseSecretChats: true,
ApiId: account.ApiID,
ApiHash: account.ApiHash,
SystemLanguageCode: "en",
DeviceModel: "Server",
SystemVersion: "1.0.0",
ApplicationVersion: "1.0.0",
}
_, err := client.SetLogVerbosityLevel(&client.SetLogVerbosityLevelRequest{
NewVerbosityLevel: 1,
})
if err != nil {
return nil, err
}
var tdlibClient *client.Client
var goErr error
go func() {
tdlibClient, goErr = client.NewClient(authorizer)
if goErr != nil {
fmt.Println("new client failed", err)
return
}
fmt.Println("i am down")
}()
if goErr != nil {
return nil, goErr
}
for {
state, ok := <-authorizer.State
if !ok {
break
}
fmt.Println("currnet state:", state)
switch state.AuthorizationStateType() {
case client.TypeAuthorizationStateWaitPhoneNumber:
authorizer.PhoneNumber <- account.PhoneNumber
case client.TypeAuthorizationStateWaitCode:
err := tgClient.repo.TgRepo.UpdateStatusTg(ctx, account.ID, model.InactiveTg)
if err != nil {
return nil, err
}
case client.TypeAuthorizationStateLoggingOut, client.TypeAuthorizationStateClosing, client.TypeAuthorizationStateClosed:
err := tgClient.repo.TgRepo.UpdateStatusTg(ctx, account.ID, model.InactiveTg)
if err != nil {
return nil, err
}
case client.TypeAuthorizationStateReady:
// костыль так как в либе тож костыль стоит пока там ьд обновиться будет ниловый всегда клиент
time.Sleep(3 * time.Second)
me, err := tdlibClient.GetMe()
if err != nil {
return nil, err
}
fmt.Printf("Me: %s %s [%v]", me.FirstName, me.LastName, me.Usernames)
tgClient.mu.Lock()
tgClient.TgClients[account.ID] = tdlibClient
tgClient.mu.Unlock()
break
case client.TypeAuthorizationStateWaitPassword:
authorizer.Password <- account.Password
}
}
}
}
return tgClient, nil
}
type AuthTgUserReq struct {
ApiID int32 `json:"api_id"`
ApiHash string `json:"api_hash"`
PhoneNumber string `json:"phone_number"`
Password string `json:"password"`
}
func (tg *TelegramClient) AddedToMap(data WaitingClient, id string) {
fmt.Println("AddedToMap")
tg.mu.Lock()
defer tg.mu.Unlock()
tg.WaitingClients[id] = data
}
func (tg *TelegramClient) GetFromMap(id string) (WaitingClient, bool) {
fmt.Println("GetFromMap")
tg.mu.Lock()
defer tg.mu.Unlock()
if data, ok := tg.WaitingClients[id]; ok {
delete(tg.WaitingClients, id)
return data, true
}
return WaitingClient{}, false
}
func (tg *TelegramClient) SaveTgAccount(appID int32, appHash string, tdLibClient *client.Client) {
account, err := tg.repo.TgRepo.SearchIDByAppIDanAppHash(context.Background(), appID, appHash)
if err != nil {
fmt.Println("err SaveTgAccount", err)
return
}
if account.Status == model.ActiveTg {
tg.mu.Lock()
defer tg.mu.Unlock()
tg.TgClients[account.ID] = tdLibClient
}
}
func (tg *TelegramClient) CreateChannel(channelName string, botID int64) (string, int64, error) {
tg.mu.Lock()
defer tg.mu.Unlock()
if len(tg.TgClients) == 0 {
return "", 0, errors.New("no active Telegram clients")
}
var lastError error
var inviteLink string
var channelId int64
for _, activeClient := range tg.TgClients {
// todo пока не понимаю это какой то рандом? в один день бот норм находится в другой уже не находится хотя абсолютно с точки зрения тг кода этой функции и бота не менялось
_, err := activeClient.GetUser(&client.GetUserRequest{
UserId: botID,
})
if err != nil {
lastError = fmt.Errorf("not found this bot, make privacy off: %v", err)
continue
}
// todo нужно поймать ошибку, при которой либо бан либо медленный редим включается для того чтобы прервать
// исполнение клиента текущего аккаунта и дать задачу следующему пока поймал 1 раз и не запомнил больше не получается
channel, err := activeClient.CreateNewSupergroupChat(&client.CreateNewSupergroupChatRequest{
Title: channelName,
IsChannel: true,
Description: "private channel",
})
if err != nil {
lastError = fmt.Errorf("failed to create channel: %s", err.Error())
continue
}
_, err = activeClient.SetChatMemberStatus(&client.SetChatMemberStatusRequest{
ChatId: channel.Id,
MemberId: &client.MessageSenderUser{UserId: botID},
Status: &client.ChatMemberStatusAdministrator{
CustomTitle: "bot",
Rights: &client.ChatAdministratorRights{
CanManageChat: true,
CanChangeInfo: true,
CanPostMessages: true,
CanEditMessages: true,
CanDeleteMessages: true,
CanInviteUsers: true,
CanRestrictMembers: true,
CanPinMessages: true,
CanManageTopics: true,
CanPromoteMembers: true,
CanManageVideoChats: true,
CanPostStories: true,
CanEditStories: true,
CanDeleteStories: true,
},
},
})
if err != nil {
lastError = fmt.Errorf("failed to make bot admin: %s", err.Error())
continue
}
inviteLinkResp, err := activeClient.CreateChatInviteLink(&client.CreateChatInviteLinkRequest{
ChatId: channel.Id,
Name: channelName,
ExpirationDate: 0,
MemberLimit: 0,
CreatesJoinRequest: false,
})
if err != nil {
lastError = fmt.Errorf("failed to get invite link: %s", err.Error())
continue
}
_, err = activeClient.LeaveChat(&client.LeaveChatRequest{
ChatId: channel.Id,
})
if err != nil {
lastError = fmt.Errorf("failed to leave the channel: %s", err.Error())
continue
}
inviteLink = inviteLinkResp.InviteLink
channelId = channel.Id
return inviteLink, channelId, nil
}
return "", 0, lastError
}