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

panic: runtime error: invalid memory address or nil pointer dereference #20

Open amir3code opened 5 years ago

amir3code commented 5 years ago

The code that I am writing is this:
What I am trying to do is to get a list of dialogs. But sometime panic error happens due to some network error.

package main

import (
    "github.com/cjongseok/mtproto"
    "context"
    "os"
    "fmt"
    "github.com/cjongseok/slog"
    "math/rand"
    "reflect"
)

func main() {
    // the acc we are using is: (telegram acc new three)
    caller := setUpLoggingNConnectNGetCaller()
    getDialogs(caller)                                                        // === line 16 ===
}

func getDialogs(caller *mtproto.RPCaller) *mtproto.PredMessagesDialogs {
    emptyPeer := &mtproto.TypeInputPeer{Value: &mtproto.TypeInputPeer_InputPeerEmpty{InputPeerEmpty: &mtproto.PredInputPeerEmpty{}}}
    var response *mtproto.TypeMessagesDialogs
    r, err := caller.MessagesGetDialogs(context.Background(), &mtproto.ReqMessagesGetDialogs{       //  === line 22 ===
        OffsetDate: 0, OffsetId: 0, OffsetPeer: emptyPeer,
    })
    if err != nil {
        fmt.Println("Can not get dialogs due to error:", err)
    }
    response = r

    dialogs := response.GetMessagesDialogs().GetDialogs()
    for _, item := range dialogs {
        fmt.Println(reflect.TypeOf(item.GetValue()))
        fmt.Println()
    }

    return response.GetMessagesDialogs()
}

func setUpLoggingNConnectNGetCaller() *mtproto.RPCaller {
    // set up logging
    logf, err := os.OpenFile("ss.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        fmt.Printf("error opening file: %v", err)
    }
    defer logf.Close()
    slog.SetLogOutput(logf)

    appVersion := "0.1"
    deviceModel := "SHIT"
    systemVersion := "0.2"
    language := "en"
    config, _ := mtproto.NewConfiguration(appVersion, deviceModel, systemVersion, language, 0, 0, "credentials.json")
    manager, _ := mtproto.NewManager(config)

    // Sign-in by key
    mconn, _ := manager.LoadAuthentication()
    caller := mtproto.RPCaller{RPC: mconn}
    return &caller
}

The error that happens is this:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x7a61be]

goroutine 1 [running]:
kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto.(*Conn).LogPrefix(0x0, 0xc49d80, 0x0)
        /home/kasra/go/src/kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto/conn.go:363 +0x2e
kasra/doingstuff_on_tg/vendor/github.com/cjongseok/slog.logprefix(0xc49d80, 0x0, 0x0, 0x12bc180)
        /home/kasra/go/src/kasra/doingstuff_on_tg/vendor/github.com/cjongseok/slog/slog.go:128 +0x29a
kasra/doingstuff_on_tg/vendor/github.com/cjongseok/slog.Logln(0xc49d80, 0x0, 0xc420093860, 0x2, 0x2)
        /home/kasra/go/src/kasra/doingstuff_on_tg/vendor/github.com/cjongseok/slog/slog.go:165 +0x6d
kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto.(*Conn).Session(0x0, 0x1)
        /home/kasra/go/src/kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto/conn.go:151 +0xdc
kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto.(*Conn).InvokeNonBlocked(0x0, 0xd09ac0, 0xc420250580, 0xc420093d70)
        /home/kasra/go/src/kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto/conn.go:130 +0x90
kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto.(*Conn).InvokeBlocked(0x0, 0xd09ac0, 0xc420250580, 0x7f1b32e68d90, 0x0, 0x2, 0xdf8475800)
        /home/kasra/go/src/kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto/conn.go:114 +0x5d
kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto.RPCaller.MessagesGetDialogs(0xd04060, 0x0, 0xd25760, 0xc4200d4050, 0xc420250580, 0xc88ace, 0x2, 0xdf8475800)
        /home/kasra/go/src/kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto/procs.tl.go:424 +0x57
main.getDialogs(0xc4202482f0, 0xc4200b8058)
        /home/kasra/go/src/kasra/doingstuff_on_tg/_accounts_/main.go:22 +0x127
main.main()
        /home/kasra/go/src/kasra/doingstuff_on_tg/_accounts_/main.go:16 +0x27
exit status 2

How can I handle this kind of error? (I have put comment after line 22 and 16 of my code to make it clear) As you can see I have received the error in err variable and checked it but I still get this panic.
Not to mention that I dont ALWAYS get this panic, It just happens sometimes due to network errors, How can I handle this one?

cjongseok commented 5 years ago

@amir3code Thanks for your interest in this repository. It seems sometimes manager.LoadAuthentication() returns nil conn. Can you check it with

mconn, err := manager.LoadAuthentication()
if err != nil {
  fmt.Println(err)
}

instead of

mconn, _ := manager.LoadAuthentication()

For more evidences please share the log file ss.log after removing your credentials.

cjongseok commented 5 years ago

For your information, if you want to fetch the list of all the channels and chat groups, I recommend to use MessagesGetAllChats() instead of MessagesGetDialogs(). Please check this simple shell command for the usage.

amir3code commented 5 years ago

I now have a ss.log file but it is crowded and over 1 megabyte! I will try to incorporate your change and post the log file in the next two days. BTW, one question. Is there any way to distinguish between a Super Group and a Channel? because they are both returned with the type Channel.

cjongseok commented 5 years ago

Actually I have no idea for the problem. Although I checked responses from not only MessagesGetAllChats() but ChannelsGetFullChannel(), I couldn't get any difference between channel and group. So in my case I'm doing that manually, since I'm joined a couple of groups.

amir3code commented 5 years ago

Yeah yeah they are both the same unfortunately.
I have another question, How should I tell that for example MessagesGetAllChats method wants nothing in its arguments, how can I know that?
For example I have written the same as the simple shell file you told me:

func getDialogsAllTest(caller *mtproto.RPCaller) *mtproto.TypeMessagesDialogs {
    r, _ := caller.MessagesGetAllChats(context.Background(), &mtproto.ReqMessagesGetAllChats{})
    return r
}

The struct ReqMessagesGetAllChats should have nothing as argument for creation, right? but I see that It accepts one argument (assuming that XXX* are not necessary) ...

func getDialogsAllTest(caller *mtproto.RPCaller) *mtproto.TypeMessagesDialogs {
    r, _ := caller.MessagesGetAllChats(context.Background(), &mtproto.ReqMessagesGetAllChats{
        ExceptIds:            nil,
        XXX_NoUnkeyedLiteral: struct{}{},
        XXX_unrecognized:     nil,
        XXX_sizecache:        0,
    })
    return r
}

And that is ExceptIds. How should I tell that I do not have to fill this parameter. Is it all try and error or there is a documentation? How did you figured these out? Thanks for your time.

cjongseok commented 5 years ago

Right it is all try and error. You can find some old methods in Telegram API document, but its version is too old (document: 23, cjongseok/mtproto: 71, latest: 91). Another documentation source is tdlib document. It is quite recent, but you know there is a interface gap between tdlib and tl-schema.