Работая разработчиком в одной веб-студии, пришел клиент с довольно интересной работкой, ему нужен был агрегатор постов из чужих телеграм каналов, так как стек в компании был 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

Комментарии (3)


  1. PrinceKorwin
    02.08.2021 18:12
    +3

    Так как пути назад уже не было, перебрали мы всю либу и обновили методы а так же исправили ошибки и теперь все просто чудесно.

    ...

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

    Скажите, а почему вы выбрали вариант форкнуть исходную библиотеку вместо того, чтобы отправить merge request с исправлениями в оригинальный стрим?

    Ну и хорошо бы в вашем репозитории указать, что ваш код точно также наследовал и GPL лицензию.


    1. KaoriEl Автор
      02.08.2021 18:30

      Кидал я merge request, но автор либы их давненько не чекает насколько я понял. И в иссусах ему люди на ошибки указывали, исправлений так и не дождались. В моем репозитирии указано - Library for working with golang based on tdlib. his library was taken from the user Arman92 and changed for the current version of tdlib. Конечно я не пытаюсь выставить чужую работу за свою, я лишь говорю что обновил её


  1. NiceDay
    03.08.2021 00:45

    рассказать про проблемы Madeline о которых нигде не узнать

    проблем у madeline - на целый цикл материалов хватит.

    вообще в статье Telegram-клиент на %langname% ожидаешь собственно разработку этого клиента, реализацию mtproto ну или хотя бы что на этом языке напишут FFI обертку к tdlib, а не вот это вот всё "мы форкнули библиотеку".