Как стать автором
Обновить

Telegram-клиент на Golang

Время на прочтение 3 мин
Количество просмотров 11K

Работая разработчиком в одной веб-студии, пришел клиент с довольно интересной работкой, ему нужен был агрегатор постов из чужих телеграм каналов, так как стек в компании был PHP то решили писать на нем, а конкретно на библиотеке MadelineProto о которой уже есть статья от крутого парня (более подробно об этой либе можете почитать в его статье), вот и началось мучительно создание этого сервиса...

Madeline в общей массе свой очень хорошо, полностью асинхронный и имет под капотом кучу методов для работы как с ботами так и с клиентом, но есть у него одна маленькая проблема (а может и не одна ¯\_(ツ)_/¯) , встроенный EventHandler получает не все новые сообщения из постов (и да я понимаю что есть getHistory, но если бы мы брали сообщения через этот метод, все вышло бы очень медленно работающим и высоконагруженным) Долгие часы и даже дни поиска решения этой проблемы не привели к желаемому результату, все так же процент постов которые пропускались именно Madeline был слишком большим.

Ок, было принято волевое решение забить на данную библиотеку и попробовать найти что-то другое на известном нам стеке, взгляд упал на go-tdlib. Развернули либу и поехали пыхтеть в разработку, и о чудо все посты собираются и все стало чудесно, за исключением одного но... Данная библиотека от пользователя Arman92 сильно отстает от офф методов tdlib и имеет внутри несколько логических ошибок, в общем начали у нас сыпаться паники и другие неприятные вещи. Так как пути назад уже не было, перебрали всю либу и обновили методы, а так же исправили ошибки автора.

Цель статьи — в первую очередь привлечь внимание к работе с телеграмм на Golang и рассказать про проблемы Madeline о которых нигде не узнать. Ну и соответственно приведу кусочек кода EventHandler'а для большей ясности.

func restoreSessions(client *tdlib.Client) {
	log.Println("<<<<<<<<<<<<<<<<<<<<<<<<<<RestoreSessionLog>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
	rdb := redis.NewClient(&redis.Options{
		Addr:     "redis:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})

	pong, err := rdb.Ping().Result()
	if err == nil {
		log.Println("1.Redis connections:" + pong + " - Redis ready")
		log.Println("1.1 redis connections successful")
	}
	log.Println("2. authorization client tdlib ")
	go func() {
		log.Println("2.1 timeout 6 sec")
		time.Sleep(6 * time.Second)
		currentState, err := client.Authorize()
		if err != nil {
			log.Println("2.2 err client authorization ")
			log.Println(err)
		}
		for ; currentState.GetAuthorizationStateEnum() != tdlib.AuthorizationStateReadyType; currentState, _ = client.Authorize() {
			time.Sleep(300 * time.Millisecond)
		}

		eventFilter := func(msg *tdlib.TdMessage) bool {
			return true
		}
		log.Println("2.2 authorization client successful ")
		log.Println("2.3 get info session client ")
		//cid - ID юзера в тг
		user, err := client.GetMe()
		if err == nil {
			log.Println("2.4 get info session client successful")
		}else {
			log.Println("2.4 get info session client finished with error:")
			log.Println(err)
		}
		cid := user.ID

		/**
		Выписываю редис лист, если что можно позырить записывает ли он
		*/
		log.Println("2.5 redis list for message:")
		log.Println("2.5 Redis List ---- " + "gotdlibMessage-" + strconv.Itoa(int(cid)) + " ---- Redis List")

		receiver := client.AddEventReceiver(&tdlib.UpdateNewMessage{}, eventFilter, 5)
		log.Println("2.6 handle message")
		for newMsg := range receiver.Chan {
			updateMsg := (newMsg).(*tdlib.UpdateNewMessage)

			if updateMsg.Message.Content.GetMessageContentEnum() == "messagePhoto" {
				log.Println("2.7 new message with type: messagePhoto")
				go messagePhoto(updateMsg, newMsg, rdb, cid,client)
			}

			if updateMsg.Message.Content.GetMessageContentEnum() == "messageText" {
				log.Println("2.7 new message with type: messageText")
				go messageText(updateMsg, rdb, cid,client)
			}

			if updateMsg.Message.Content.GetMessageContentEnum() == "messageVideo" {
				log.Println("2.7 new message with type: messageVideo")
				go messageVideo(updateMsg, rdb, cid,client)
			}

			if updateMsg.Message.Content.GetMessageContentEnum() == "messageDocument" {
				log.Println("2.7 new message with type: messageDocument")
				go messageDocument(updateMsg, rdb, cid,client)
			}
		}
	}()
}

P.S: Доработанную и актуальную либу на 01.08.2021 (Может и дальше буду обновлять) вы можете взять у меня на гите — git

Теги:
Хабы:
-5
Комментарии 3
Комментарии Комментарии 3

Публикации

Истории

Работа

Go разработчик
124 вакансии
PHP программист
175 вакансий

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн
PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн