alexander-akhmetov / python-telegram

Python client for the Telegram's tdlib
MIT License
610 stars 122 forks source link

Posix Error : Network is unreachable; How to send a file #152

Closed rohittp0 closed 3 years ago

rohittp0 commented 3 years ago

I have a reliable network connection but still, I am getting this error,

[ConnectionCreator.cpp:896][#1][!ConnectionCreator] [[2001:b28:f23f:f005::a]:443] to DcId{5}: [PosixError : Network is unreachable : 101 : Failed to connect to [[2001:b28:f23f:f005::a]:443]]

Method To Reproduce

Login using tg.login() and entering code. Wait for login to end then wait for running to finish.

Now restart the program and call tg.login(). Call, param= { '@type': 'sendMessage', 'chat_id': chat_id, 'input_message_content': { '@type':'inputMessageDocument', 'document': { '@type':'inputFileLocal', 'path': file_path } } tg.call_method("sendMessage",param).wait()

The complete output : `[ 2][t 4][1612541454.562263250][Timer.cpp:67][#1][!Td][&duration > maxduration] SLOW: [name:change key][duration:2973.3us] [ 2][t 4][1612541454.562390089][TdDb.cpp:323][#1][!Td] Got PRAGMA user_version = 13 [ 2][t 4][1612541454.564440011][AuthDataShared.cpp:109][#1][!Td] DcId{5} [auth_key_id:12701291553040611538][state:OK][created_at:1612541131.000000] [ 2][t 4][1612541454.565639734][Session.cpp:167][#1][!SessionProxy:5:main] Generate new session_id 7671406197548583323 for auth key 12701291553040611538 for main DC5

alexander-akhmetov commented 3 years ago

Hi,

tdlib tries to connect to IPv6 network. Can you try to call tdlib's setOption with prefer_ipv6=False? python-telegram does not support setOption, so you need to call it directly:

    tg = Telegram(...)

    tg.call_method(
        'setOption',
        {
            'name': 'prefer_ipv6',
            'value': {'@type': 'optionValueBoolean', 'value': False},
        },
    )

    tg.login()
rohittp0 commented 3 years ago

Hi,

tdlib tries to connect to IPv6 network. Can you try to call tdlib's setOption with prefer_ipv6=False? python-telegram does not support setOption, so you need to call it directly:

    tg = Telegram(...)

    tg.call_method(
        'setOption',
        {
            'name': 'prefer_ipv6',
            'value': {'@type': 'optionValueBoolean', 'value': False},
        },
    )

    tg.login()

YesI tried this and nothing changed. I can still send text messages but can't send files. This is how I am trying to send files :

def sendFile(tg,chat_id,file_path,parent_folder="/") :
        param= {
            '@type': 'sendMessageAlbum',
            'chat_id': chat_id,
            'input_message_content': {
                '@type':'inputMessageDocument',
                'document': {
                    '@type':'inputFileLocal',
                    'path': file_path
                },
                'caption' : {
                    'text': {
                        '@type': 'formattedText', 
                        'text': str(path.relpath(file_path,parent_folder))
                    }
                }
            },
            '@extra': {
                'path': file_path
            }
        }
        return tg.call_method("sendMessage",param)

sendFile(tg,123,"/some/real/path.png","/some").wait()  # This returns none

Calling wait on tg.send_message() also returns none ( even when it had succeeded ) I am pretty new to Python so sorry in advance if it is something I am doing wrong 🙏

alexander-akhmetov commented 3 years ago

According to this issue PosixError : Network is unreachable : 101 is not an error but a warning.

Calling wait on tg.send_message() also returns none ( even when it had succeeded )

Yes, wait() does not return anything. call_mehod returns instance of telegram.utils.AsyncResult. AsyncResult.wait() is a blocking call which waits for the response. To get the actual response (update attribute) you need to change your code:

result = sendFile(tg,123,"/some/real/path.png","/some")
result.wait()
print(result.update)  
# or
# print(result.error_info)
rohittp0 commented 3 years ago

Yes, wait() does not return anything. call_mehod returns instance of telegram.utils.AsyncResult. AsyncResult.wait() is a blocking call which waits for the response. To get the actual response (update attribute) you need to change your code:

result = sendFile(tg,123,"/some/real/path.png","/some")
result.wait()
print(result.update)  
# or
# print(result.error_info)

First of all thanks for this 🤝

But still this doesn't solve my issue. If this is just a warning then what is the real problem or how do find it ?

The complete output :

This is all the output I am getting. And me not being able to handle the exception rather than just getting a printed output is not helping either.

So what steps would you suggest to debug further ? And is there any better way to send file ?

alexander-akhmetov commented 3 years ago

In general, I'd suggest to print result.error_info first, it should contain an error message from tdlib. You can also increase verbosity of the tdlib library to see more logs:

tg = Telegram(
    ...,
    tdlib_verbosity=7,
)

sendMessageAlbum is a method, and sendMessage is another method, which one do you want to use? Also, don't specify @type field in the param dictionary if you use Telegram.call_method. It automatically puts the method name to as a value of the @type key.

If you want just to send a file, you can use sendMessage:

file_path = './file.txt'

params = {
    'chat_id': chat_id,
    'input_message_content': {
        '@type': 'inputMessageDocument',
        'document': {'@type': 'inputFileLocal', 'path': file_path},
    },
}

result = tg.call_method('sendMessage', params)
result.wait()
print('Error: %s' % result.error_info)
print('tdlib response: %s' % result.update)

If you want to send a picture, use sendMessageAlbum:


file_path = './file.png'

params = {
    'chat_id': chat_id,
    'input_message_contents': [
        {
            '@type': 'inputMessagePhoto',
            'photo': {'@type': 'inputFileLocal', 'path': file_path},
            'caption': {
                '@type': 'formattedText',
                'text': 'hello',
            },
        }
    ],
}

result = tg.call_method('sendMessageAlbum', params)
result.wait()
print('Error: %s' % result.error_info)
print('tdlib response: %s' % result.update)
rohittp0 commented 3 years ago

In general, I'd suggest to print result.error_info first, it should contain an error message from tdlib. You can also increase verbosity of the tdlib library to see more logs

I will surely try this.

If you want to send a picture, use sendMessageAlbum

I want to send images and videos but don't want telegram to compress them. So are there any options I can set or should I just use send message ?

alexander-akhmetov commented 3 years ago

If you want to send a picture, use sendMessageAlbum

I want to send images and videos but don't want telegram to compress them. So are there any options I can set or should I just use send message ?

I think, the example with sendMessage is what you need :) You can also have a look at sendMessage and inputMessageDocument, but the code in the example should already work and send files.

rohittp0 commented 3 years ago

@alexander-akhmetov With your help, I finally solved the problem

def sendFile(tg,chat_id,file_path,parent_folder="/") :
        param= {
            'chat_id': chat_id,
            'input_message_content': {
                '@type':'inputMessageDocument',
                'document': {
                    '@type':'inputFileLocal',
                    'path': file_path
                },
                'caption' : {
                    '@type': 'formattedText', 
                    'text': str(path.relpath(file_path,parent_folder))
                }
            },
            '@extra': {
                'path': file_path
            }
        }
        return tg.call_method("sendMessage",param)

This is the working code. The problem was I used :


'caption' : {
     'text': {
         '@type': 'formattedText', 
         'text': str(path.relpath(file_path,parent_folder))
      }
}