2024-06-25 14:37:26 +00:00
package telegram
import (
2024-06-30 18:02:23 +00:00
"context"
2024-07-01 11:15:15 +00:00
"errors"
2024-06-25 14:37:26 +00:00
"fmt"
2024-07-01 11:15:15 +00:00
"path/filepath"
2024-06-30 18:02:23 +00:00
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
2024-07-01 11:15:15 +00:00
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
2024-07-01 13:21:15 +00:00
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/pj_errors"
2024-06-30 18:02:23 +00:00
"penahub.gitlab.yandexcloud.net/backend/tdlib/client"
2024-07-01 11:15:15 +00:00
"sync"
"time"
2024-06-25 14:37:26 +00:00
)
type TelegramClient struct {
2024-06-30 18:02:23 +00:00
repo * dal . DAL
2024-07-01 13:02:26 +00:00
TgClients map [ int64 ] * client . Client
2024-06-30 18:02:23 +00:00
WaitingClients map [ string ] WaitingClient
2024-07-01 11:15:15 +00:00
mu sync . Mutex
2024-06-30 18:02:23 +00:00
}
2024-06-25 14:37:26 +00:00
2024-06-30 18:02:23 +00:00
type WaitingClient struct {
PreviousReq AuthTgUserReq
Authorizer * client . ClientAuthorizer
}
2024-06-27 09:24:23 +00:00
2024-07-09 20:07:44 +00:00
func NewTelegramClient ( ctx context . Context , repo * dal . DAL ) ( * TelegramClient , error ) {
2024-07-01 11:15:15 +00:00
tgClient := & TelegramClient {
2024-06-30 18:02:23 +00:00
repo : repo ,
2024-07-01 13:02:26 +00:00
TgClients : make ( map [ int64 ] * client . Client ) ,
2024-06-30 18:02:23 +00:00
WaitingClients : make ( map [ string ] WaitingClient ) ,
2024-07-01 11:15:15 +00:00
}
allTgAccounts , err := repo . TgRepo . GetAllTgAccounts ( ctx )
if err != nil {
2024-07-01 13:21:15 +00:00
if errors . Is ( err , pj_errors . ErrNotFound ) {
2024-07-01 11:15:15 +00:00
return tgClient , nil
}
return nil , err
}
for _ , account := range allTgAccounts {
2024-07-01 13:02:26 +00:00
if account . Status == model . ActiveTg {
authorizer := client . ClientAuthorizerr ( )
authorizer . TdlibParameters <- & client . SetTdlibParametersRequest {
UseTestDc : false ,
DatabaseDirectory : filepath . Join ( ".tdlib" , "database" ) ,
FilesDirectory : filepath . Join ( ".tdlib" , "files" ) ,
2024-07-02 21:04:07 +00:00
UseFileDatabase : true ,
UseChatInfoDatabase : true ,
UseMessageDatabase : true ,
UseSecretChats : true ,
2024-07-01 13:02:26 +00:00
ApiId : account . ApiID ,
ApiHash : account . ApiHash ,
SystemLanguageCode : "en" ,
DeviceModel : "Server" ,
SystemVersion : "1.0.0" ,
ApplicationVersion : "1.0.0" ,
}
2024-07-01 11:15:15 +00:00
2024-07-01 13:02:26 +00:00
_ , err := client . SetLogVerbosityLevel ( & client . SetLogVerbosityLevelRequest {
NewVerbosityLevel : 1 ,
} )
if err != nil {
return nil , err
2024-07-01 11:15:15 +00:00
}
2024-07-01 13:02:26 +00:00
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
2024-07-01 11:15:15 +00:00
}
2024-07-01 13:02:26 +00:00
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
2024-07-01 11:15:15 +00:00
}
}
}
}
return tgClient , nil
2024-06-30 18:02:23 +00:00
}
2024-06-25 14:37:26 +00:00
2024-06-30 18:02:23 +00:00
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" )
2024-07-01 11:15:15 +00:00
tg . mu . Lock ( )
defer tg . mu . Unlock ( )
2024-06-30 18:02:23 +00:00
tg . WaitingClients [ id ] = data
}
func ( tg * TelegramClient ) GetFromMap ( id string ) ( WaitingClient , bool ) {
fmt . Println ( "GetFromMap" )
2024-07-01 11:15:15 +00:00
tg . mu . Lock ( )
defer tg . mu . Unlock ( )
2024-06-30 18:02:23 +00:00
if data , ok := tg . WaitingClients [ id ] ; ok {
2024-07-01 13:21:15 +00:00
delete ( tg . WaitingClients , id )
2024-06-30 18:02:23 +00:00
return data , true
2024-06-25 14:37:26 +00:00
}
2024-06-30 18:02:23 +00:00
return WaitingClient { } , false
}
2024-07-02 21:04:07 +00:00
func ( tg * TelegramClient ) SaveTgAccount ( appID int32 , appHash string , tdLibClient * client . Client ) {
account , err := tg . repo . TgRepo . SearchIDByAppIDanAppHash ( context . Background ( ) , appID , appHash )
2024-07-01 11:15:15 +00:00
if err != nil {
2024-07-02 21:04:07 +00:00
fmt . Println ( "err SaveTgAccount" , err )
return
}
if account . Status == model . ActiveTg {
tg . mu . Lock ( )
defer tg . mu . Unlock ( )
tg . TgClients [ account . ID ] = tdLibClient
2024-07-01 11:15:15 +00:00
}
2024-06-25 14:37:26 +00:00
}
2024-07-05 07:49:42 +00:00
func ( tg * TelegramClient ) CreateChannel ( channelName string , botID int64 ) ( string , int64 , error ) {
2024-07-02 11:29:36 +00:00
tg . mu . Lock ( )
defer tg . mu . Unlock ( )
2024-07-05 07:49:42 +00:00
if len ( tg . TgClients ) == 0 {
return "" , 0 , errors . New ( "no active Telegram clients" )
2024-07-03 11:04:29 +00:00
}
2024-07-05 07:49:42 +00:00
var lastError error
var inviteLink string
var channelId int64
for _ , activeClient := range tg . TgClients {
2024-07-11 15:10:16 +00:00
// todo пока не понимаю это какой то рандом? в один день бот норм находится в другой уже не находится хотя абсолютно с точки зрения тг кода этой функции и бота не менялось
2024-07-05 07:49:42 +00:00
_ , err := activeClient . GetUser ( & client . GetUserRequest {
UserId : botID ,
} )
if err != nil {
lastError = fmt . Errorf ( "not found this bot, make privacy off: %v" , err )
continue
}
2024-07-03 11:04:29 +00:00
2024-07-05 07:49:42 +00:00
// todo нужно поймать ошибку, при которой либо бан либо медленный редим включается для того чтобы прервать
// исполнение клиента текущего аккаунта и дать задачу следующему пока поймал 1 раз и не запомнил больше не получается
channel , err := activeClient . CreateNewSupergroupChat ( & client . CreateNewSupergroupChatRequest {
2024-07-10 11:46:45 +00:00
Title : channelName ,
IsChannel : true ,
2024-07-05 07:49:42 +00:00
Description : "private channel" ,
} )
if err != nil {
lastError = fmt . Errorf ( "failed to create channel: %s" , err . Error ( ) )
continue
}
2024-07-02 11:29:36 +00:00
2024-07-05 07:49:42 +00:00
_ , err = activeClient . SetChatMemberStatus ( & client . SetChatMemberStatusRequest {
ChatId : channel . Id ,
MemberId : & client . MessageSenderUser { UserId : botID } ,
Status : & client . ChatMemberStatusAdministrator {
CustomTitle : "bot" ,
Rights : & client . ChatAdministratorRights {
2024-07-09 20:07:44 +00:00
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 ,
2024-07-05 07:49:42 +00:00
} ,
2024-07-02 21:04:07 +00:00
} ,
2024-07-05 07:49:42 +00:00
} )
if err != nil {
lastError = fmt . Errorf ( "failed to make bot admin: %s" , err . Error ( ) )
continue
}
2024-07-02 11:29:36 +00:00
2024-07-05 07:49:42 +00:00
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
}
2024-07-02 11:29:36 +00:00
2024-07-05 07:49:42 +00:00
_ , 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
2024-07-03 11:04:29 +00:00
}
2024-07-05 07:49:42 +00:00
return "" , 0 , lastError
2024-06-25 14:37:26 +00:00
}