cjongseok / mtproto

Telegram MTProto and its proxy (over gRPC) in Go (golang). API Layer: 71
Apache License 2.0
151 stars 20 forks source link

PredUpdateShortChatMessage not working? #12

Closed astravexton closed 6 years ago

astravexton commented 6 years ago

Stripped down code:

func newSubscriber(mconn *mtproto.Conn) *subscriber {
    s := new(subscriber)
    s.mconn = mconn
    return s
}

type subscriber struct {
    mconn *mtproto.Conn
}

func (s *subscriber) OnUpdate(u mtproto.Update) {
    switch u.(type) {
        case *mtproto.PredUpdateShortChatMessage:
            fmt.Println("PredUpdateShortChatMessage")
        case *mtproto.PredUpdateShortMessage:
            fmt.Println("PredUpdateShortMessage")
    }
}

func main() {
    mconn, _= manager.LoadAuthentication(phoneNumber)
    mconn.AddUpdateCallback(newSubscriber(mconn))
    for {
        time.Sleep(time.Second)
    }
}

PredUpdateShortMessage works fine, but PredUpdateShortChatMessage doesn't, it's called when there is a message to a group/channel, is there something i'm missing/doing wrong?

Output of u:

Updates:<
  Updates:<
    UpdateNewChannelMessage:<
      Message:<
        Message:<
          Flags:264
          Id:-
          FromId:-ToId:<
            PeerChannel:<
              ChannelId:-
            >
          >
          ReplyToMsgId:-
          Date:1527894767
          Message:"Some Message"
        >
      >
      Pts:41234
      PtsCount:1
    >
  >
  Users:<
    User:<
      Flags:107
      Id:-
      AccessHash:-
      FirstName:"Some"
      Username:"User"
      Photo:<
        UserProfilePhoto:<
          PhotoId:-
          PhotoSmall:<
            FileLocation:<
              DcId:1
              VolumeId:-
              LocalId:- Secret:-
            >
          >
          PhotoBig:<
            FileLocation:<
              DcId:1 VolumeId:-
              LocalId:-
              Secret:-
            >
          >
        >
      >
      Status:<
        UserStatusRecently:<>
      >
    >
  >
  Chats:<
    Channel:<
      Flags:24904
      Id:-
      AccessHash:-
      Title:"Group Name"
      Username:"groupusername"
      Photo:<
        ChatPhoto:<
          PhotoSmall:<
            FileLocation:<
              DcId:4
              VolumeId:-
              LocalId:-
              Secret:-
            >
          >
          PhotoBig:<
            FileLocation:<
              DcId:4
              VolumeId:-
              LocalId:-
              Secret:-
            >
          >
        >
      >
      Date:1506520301
      AdminRights:<
        Value:<
          Flags:121
        >
      >
    >
  >
  Date:1527894766
>
cjongseok commented 6 years ago

@nathan0 Thanks for the good question. You can filter the messages by 'mtproto.PredUpdates'. It has a field 'Updates' which is a slice of '*mtproto.TypeUpdate', and 'mtproto.TypeUpdate.Value' is one of

// types.tl.pb.go:8131
*TypeUpdate_UpdateNewMessage
*TypeUpdate_UpdateMessageID
*TypeUpdate_UpdateDeleteMessages
*TypeUpdate_UpdateUserTyping
*TypeUpdate_UpdateChatUserTyping
...

Among them, what you want would be 'mtproto.TypeUpdate_UpdateNewChannelMessage'. It contains a field 'UpdateNewChannelMessage' whose type is 'mtproto.PredUpdateNewChannelMessage'. The Output of 'u' you commented shows well this data structure. The outter 'updates' is 'mtproto.PredUpdates' which consists of fields 'Updates', 'Users', 'Chats', 'Date, and 'Seq', and inner 'updates' is a slice of 'mtproto.TypeUpdate' whose first item is 'mtproto.PredUpdateNewChannelMessage'.

Quite complicated! The reason is that Telegram mtproto has a type hierarchy. Telegram's mtproto has three kinds of types, Type, Predicate, and Method. A Type is a kind of a data structure interface which has no fields, and a Predicate implements a Type. In the above case, mtproto.PredUpdateNewChannelMessage is a Predicate of a Type mtproto.TypeUpdate. gRPC recommends to implement this kind of polymorphism with Oneof, so cjongseok/mtproto defines TypeUpdate in protobuf as below:

// types.tl.proto:360
message TypeUpdate {
    oneof Value {
        PredUpdateNewMessage UpdateNewMessage = 1;
        PredUpdateMessageID UpdateMessageID = 2;
        PredUpdateDeleteMessages UpdateDeleteMessages = 3;
        PredUpdateUserTyping UpdateUserTyping = 4;
        PredUpdateChatUserTyping UpdateChatUserTyping = 5;
        PredUpdateChatParticipants UpdateChatParticipants = 6;
                 ...
                PredUpdateChannelReadMessagesContents UpdateChannelReadMessagesContents = 65;
        }
}

The use of gRPC Oneof in Go is complex, because Go does not allow hierarchical relations among types, e.g., inheritance. I believe, however, gRPC guys did their best and it would be the best implementation of such polymorphism in Go with RPC. This document will help you use Oneof in Go.

cjongseok commented 6 years ago

re-open it, if the comment does not work.