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, error) { tg.mu.Lock() defer tg.mu.Unlock() var activeClient *client.Client for _, c := range tg.TgClients { activeClient = c break } if activeClient == nil { return "", errors.New("no active Telegram clients") } _, err := activeClient.GetUser(&client.GetUserRequest{ UserId: botID, }) if err != nil { return "", errors.New("not found this bot, make privacy off") } channel, err := activeClient.CreateNewSupergroupChat(&client.CreateNewSupergroupChatRequest{ Title: channelName, IsChannel: true, Description: "private channel", }) if err != nil { return "", fmt.Errorf("failed to create channel: %s", err.Error()) } _, 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, CanInviteUsers: true, CanRestrictMembers: true, CanPromoteMembers: true, }, }, }) if err != nil { return "", fmt.Errorf("failed to make bot admin: %s", err.Error()) } inviteLink, err := activeClient.CreateChatInviteLink(&client.CreateChatInviteLinkRequest{ ChatId: channel.Id, Name: channelName, ExpirationDate: 0, MemberLimit: 0, CreatesJoinRequest: false, }) if err != nil { return "", fmt.Errorf("failed to get invite link: %s", err.Error()) } _, err = activeClient.LeaveChat(&client.LeaveChatRequest{ ChatId: channel.Id, }) if err != nil { return "", fmt.Errorf("failed to leave the channel: %s", err.Error()) } return inviteLink.InviteLink, nil }