Telethon/tl/telegram_client.py
Lonami 251c1830a5 Added custom errors, fixes to code generator
The code generator now handles okay the flags using True type
Also, double checking for the flag is now avoided in cases where the
flag was a Vector type
2016-09-05 18:35:12 +02:00

121 lines
4.3 KiB
Python

# This file is based on TLSharp
# https://github.com/sochix/TLSharp/blob/master/TLSharp.Core/TelegramClient.cs
import re
import platform
import utils
import network.authenticator
from network import MtProtoSender, TcpTransport
from errors import *
from tl import Session
from tl.types import InputPeerUser
from tl.functions import InvokeWithLayerRequest, InitConnectionRequest
from tl.functions.help import GetConfigRequest
from tl.functions.auth import CheckPhoneRequest, SendCodeRequest, SignInRequest
from tl.functions.messages import SendMessageRequest
class TelegramClient:
def __init__(self, session_user_id, layer, api_id=None, api_hash=None):
if api_id is None or api_hash is None:
raise PermissionError('Your API ID or Hash are invalid. Please read "Requirements" on README.md')
self.api_id = api_id
self.api_hash = api_hash
self.layer = layer
self.session = Session.try_load_or_create_new(session_user_id)
self.transport = TcpTransport(self.session.server_address, self.session.port)
# These will be set later
self.dc_options = None
self.sender = None
# TODO Should this be async?
def connect(self, reconnect=False):
if not self.session.auth_key or reconnect:
self.session.auth_key, self.session.time_offset = network.authenticator.do_authentication(self.transport)
self.sender = MtProtoSender(self.transport, self.session)
if not reconnect:
request = InvokeWithLayerRequest(layer=self.layer,
query=InitConnectionRequest(api_id=self.api_id,
device_model=platform.node(),
system_version=platform.system(),
app_version='0.1',
lang_code='en',
query=GetConfigRequest()))
self.sender.send(request)
self.sender.receive(request)
# Result is a Config TLObject
self.dc_options = request.result.dc_options
return True
def reconnect_to_dc(self, dc_id):
if self.dc_options is None or not self.dc_options:
raise ConnectionError("Can't reconnect. Stabilise an initial connection first.")
# dc is a DcOption TLObject
dc = next(dc for dc in self.dc_options if dc.id == dc_id)
self.transport = TcpTransport(dc.ip_address, dc.port)
self.session.server_address = dc.ip_address
self.session.port = dc.port
self.connect(reconnect=True)
def is_user_authorized(self):
return self.session.user is not None
def is_phone_registered(self, phone_number):
assert self.sender is not None, 'Not connected!'
request = CheckPhoneRequest(phone_number)
self.sender.send(request)
self.sender.receive(request)
# Result is an Auth.CheckedPhone
return request.result.phone_registered
def send_code_request(self, phone_number):
"""May return None if an error occured!"""
request = SendCodeRequest(phone_number, self.api_id, self.api_hash)
completed = False
while not completed:
try:
self.sender.send(request)
self.sender.receive(request)
completed = True
except InvalidDCError as error:
self.reconnect_to_dc(error.new_dc)
if request.result is None:
return None
else:
return request.result.phone_code_hash
def make_auth(self, phone_number, phone_code_hash, code):
request = SignInRequest(phone_number, phone_code_hash, code)
self.sender.send(request)
self.sender.receive(request)
# Result is an Auth.Authorization TLObject
self.session.user = request.result.user
self.session.save()
return self.session.user
def send_message(self, user, message):
peer = InputPeerUser(user.id, user.access_hash)
request = SendMessageRequest(peer, message, utils.generate_random_long())
self.sender.send(request)
self.sender.send(request)