Skip to content

Instantly share code, notes, and snippets.

@shelomentsevd
Created May 3, 2017 18:10
Show Gist options
  • Select an option

  • Save shelomentsevd/a9f8d12bdb0a05b4644350cf73f09a58 to your computer and use it in GitHub Desktop.

Select an option

Save shelomentsevd/a9f8d12bdb0a05b4644350cf73f09a58 to your computer and use it in GitHub Desktop.
package main
import (
"os"
"os/signal"
"syscall"
"fmt"
"time"
"reflect"
"mtproto"
)
func findUserById(id int32, users []mtproto.TL) mtproto.TL {
// TODO: Refactoring needed
for i:=0; i<len(users); i+=1 {
user := users[i]
switch user.(type) {
case mtproto.TL_userEmpty:
user, _ := user.(mtproto.TL_userEmpty)
if user.Id == id {
return user
}
case mtproto.TL_user:
user, _ := user.(mtproto.TL_user)
if user.Id == id {
return user
}
}
}
return mtproto.TL_null{}
}
func getUsername(user mtproto.TL) (username string) {
switch user.(type) {
case mtproto.TL_userEmpty:
user, _ := user.(mtproto.TL_userEmpty)
username = fmt.Sprintf("%d", user.Id)
case mtproto.TL_user:
user, _ := user.(mtproto.TL_user)
username = fmt.Sprintf("%s @%s %s", user.First_name, user.Username, user.Last_name)
default:
username = "Unknow username"
}
return
}
func findChatById(id int32, chats []mtproto.TL) mtproto.TL {
// TODO: Refactoring needed
for i:=0;i<len(chats);i+=1 {
chat := chats[i]
switch chat.(type) {
case mtproto.TL_chatEmpty:
chat, _ := chat.(mtproto.TL_chatEmpty)
if chat.Id == id {
return chat
}
case mtproto.TL_chat:
chat, _ := chat.(mtproto.TL_chat)
if chat.Id == id {
return chat
}
case mtproto.TL_chatForbidden:
chat, _ := chat.(mtproto.TL_chatForbidden)
if chat.Id == id {
return chat
}
case mtproto.TL_channel:
chat, _ := chat.(mtproto.TL_channel)
if chat.Id == id {
return chat
}
case mtproto.TL_channelForbidden:
chat, _ := chat.(mtproto.TL_channelForbidden)
if chat.Id == id {
return chat
}
}
}
return mtproto.TL_null{}
}
func getChatname(chat mtproto.TL) (chatname string) {
switch chat.(type) {
case mtproto.TL_chatEmpty:
chat, _ := chat.(mtproto.TL_chatEmpty)
chatname = fmt.Sprintf("%d", chat.Id)
case mtproto.TL_chat:
chat, _ := chat.(mtproto.TL_chat)
chatname = chat.Title
case mtproto.TL_chatForbidden:
chat, _ := chat.(mtproto.TL_chatForbidden)
chatname = chat.Title
case mtproto.TL_channel:
chat, _ := chat.(mtproto.TL_channel)
chatname = chat.Title
case mtproto.TL_channelForbidden:
chat, _ := chat.(mtproto.TL_channelForbidden)
chatname = chat.Title
default:
chatname = "Unknow chat"
}
return
}
func processMessage(users, chats []mtproto.TL, message mtproto.TL) {
switch message.(type) {
case mtproto.TL_messageEmpty:
message, _ := message.(mtproto.TL_messageEmpty)
fmt.Println("Empty message", message)
case mtproto.TL_message:
message, _ := message.(mtproto.TL_message)
var id int32
var to string
var from string
fromUser := findUserById(message.From_id, users)
from = getUsername(fromUser)
switch message.To_id.(type) {
case mtproto.TL_peerChannel:
peer, _ := message.To_id.(mtproto.TL_peerChannel)
id = peer.Channel_id
chat := findChatById(id, chats)
to = getChatname(chat)
case mtproto.TL_peerChat:
peer, _ := message.To_id.(mtproto.TL_peerChat)
id = peer.Chat_id
chat := findChatById(id, chats)
to = getChatname(chat)
case mtproto.TL_peerUser:
peer, _ := message.To_id.(mtproto.TL_peerUser)
id = peer.User_id
user := findUserById(id, users)
to = getUsername(user)
}
fmt.Printf("%s to %s: %s\n", from, to, message.Message)
case mtproto.TL_messageService:
message, _ := message.(mtproto.TL_messageService)
fmt.Println("Service message", message)
}
}
func process(users, messages, chats, updates []mtproto.TL, state * mtproto.TL_updates_state) error {
for i:=0;i<len(updates);i+=1 {
update := updates[i]
switch update.(type) {
case mtproto.TL_updateNewMessage:
update, _ := update.(mtproto.TL_updateNewMessage)
fmt.Println("New message: ")
processMessage(users, chats, update.Message)
case mtproto.TL_updateMessageID:
update, _ := update.(mtproto.TL_updateMessageID)
fmt.Println("Update message id", update)
case mtproto.TL_updateDeleteMessages:
update, _ := update.(mtproto.TL_updateDeleteMessages)
fmt.Println("Delete message", update)
case mtproto.TL_updateUserTyping:
update, _ := update.(mtproto.TL_updateUserTyping)
fmt.Println("User is typing", update)
case mtproto.TL_updateChatParticipants:
update, _ := update.(mtproto.TL_updateChatParticipants)
fmt.Println("Update chat participants", update)
case mtproto.TL_updateUserStatus:
update, _ := update.(mtproto.TL_updateUserStatus)
fmt.Println("User update status", update)
case mtproto.TL_updateEditMessage:
update, _ := update.(mtproto.TL_updateEditMessage)
fmt.Println("Message edited")
processMessage(users, chats, update.Message)
case mtproto.TL_updateNewChannelMessage:
update, _ := update.(mtproto.TL_updateNewChannelMessage)
fmt.Println("Message from channel")
processMessage(users, chats, update.Message)
case mtproto.TL_updateChannelTooLong:
update, _ := update.(mtproto.TL_updateChannelTooLong)
fmt.Println("Update channel too long", update)
res := findChatById(update.Channel_id, chats)
channel, ok := res.(mtproto.TL_channel)
fmt.Printf("Update %s too long\n", channel.Username)
if !ok {
fmt.Println("error")
fmt.Println(res)
return nil
}
_, result := m.UpdatesGetChannelDifference(false, mtproto.TL_inputChannel{
Channel_id: channel.Id,
Access_hash: channel.Access_hash,
}, mtproto.TL_channelMessagesFilterEmpty{}, state.Pts, 50)
switch (*result).(type) {
case mtproto.TL_updates_channelDifferenceEmpty:
diff, _ := (*result).(mtproto.TL_updates_channelDifferenceEmpty)
state.Pts = diff.Pts
case mtproto.TL_updates_channelDifference:
diff, _ := (*result).(mtproto.TL_updates_channelDifference)
state.Pts = diff.Pts
process(diff.Users, diff.New_messages, diff.Chats, diff.Other_updates, state)
}
default:
fmt.Println(reflect.TypeOf(update))
fmt.Println("Unknow type", update)
}
}
return nil
}
var m *mtproto.MTProto
func main() {
fmt.Println("Started")
// Signals
stop := make(chan struct{}, 1)
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
go func() {
s := <-sigc
fmt.Println(s)
stop <- struct{}{}
}()
// Telegram
appConfig, err := mtproto.NewConfiguration(41994,
"269069e15c81241f5670c397941016a2",
"0.0.1",
"",
"",
"")
if err != nil {
fmt.Printf("Create failed: %s\n", err)
os.Exit(2)
}
const telegramAddr = "149.154.167.50:443"
m, err = mtproto.NewMTProto(false, telegramAddr, os.Getenv("HOME")+"/.telegram_go", *appConfig)
if err != nil {
fmt.Printf("Create failed: %s\n", err)
os.Exit(2)
}
err = m.Connect()
if err != nil {
fmt.Printf("Connect failed: %s\n", err)
os.Exit(2)
}
err, tl := m.UpdatesGetState()
if err != nil {
fmt.Println("Failed to get state", err)
return
}
state, ok := (*tl).(mtproto.TL_updates_state)
if !ok {
fmt.Println("Wrong state type", ok)
return
}
// Life cycle
LifeCycle:
for {
select {
case <-stop:
break LifeCycle;
case <-time.After(time.Second * 2):
}
//fmt.Println("Next state")
err, news := m.UpdatesGetDifference(state.Pts, state.Unread_count, state.Date, state.Qts)
if err != nil {
fmt.Println("Failed to get state difference", err)
}
switch (*news).(type) {
case mtproto.TL_updates_differenceEmpty:
//fmt.Println("Difference is empty")
diff, _ := (*news).(mtproto.TL_updates_differenceEmpty)
state.Date = diff.Date
state.Seq = diff.Seq
case mtproto.TL_updates_difference:
//fmt.Println("Difference")
diff, _ := (*news).(mtproto.TL_updates_difference)
state, ok = diff.State.(mtproto.TL_updates_state)
if !ok {
fmt.Println("Wrong state type", ok)
break LifeCycle
}
//fmt.Println(diff)
process(diff.Users, diff.New_messages, diff.Chats ,diff.Other_updates, &state)
//fmt.Println("Chats: ")
//fmt.Println(diff.Chats)
//fmt.Println("Users: ")
//fmt.Println(diff.Users)
//fmt.Println("Other updates: ")
//fmt.Println(diff.Other_updates)
//fmt.Println("New messages: ")
//fmt.Println(diff.New_messages)
//for i:=0; i < len(diff.New_messages); i+=1 {
// fmt.Println(reflect.TypeOf(diff.New_messages[i]))
//}
//for message := range diff.New_messages {
// fmt.Println(reflect.TypeOf(message))
//}
case mtproto.TL_updates_differenceSlice:
//fmt.Println("Difference slice")
diff, _ := (*news).(mtproto.TL_updates_differenceSlice)
state, ok = diff.Intermediate_state.(mtproto.TL_updates_state)
if !ok {
fmt.Println("Wrong state type", ok)
break LifeCycle
}
process(diff.Users, diff.New_messages, diff.Chats ,diff.Other_updates, &state)
//fmt.Println(diff)
//fmt.Println("Chats: ")
//fmt.Println(diff.Chats)
//fmt.Println("Users: ")
//fmt.Println(diff.Users)
//fmt.Println("Other updates: ")
//fmt.Println(diff.Other_updates)
//fmt.Println("New messages: ")
//fmt.Println(diff.New_messages)
//for i:=0; i < len(diff.New_messages); i+=1 {
// fmt.Println(reflect.TypeOf(diff.New_messages[i]))
//}
//for message := range diff.New_messages {
// fmt.Println(reflect.TypeOf(message))
//}
case mtproto.TL_updates_differenceTooLong:
//fmt.Println("Difference is too long")
diff, _ := (*news).(mtproto.TL_updates_differenceTooLong)
state.Pts = diff.Pts
//err, tl := m.UpdatesGetState()
//if err != nil {
// fmt.Println("Failed to get state", err)
// return
//}
//state, ok = (*tl).(mtproto.TL_updates_state)
//if !ok {
// fmt.Println("Wrong state type", ok)
// return
//}
}
}
fmt.Println("Finished")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment