2016-09-04 12:07:18 +03:00
|
|
|
# This file is based on TLSharp
|
|
|
|
# https://github.com/sochix/TLSharp/blob/master/TLSharp.Core/TelegramClient.cs
|
2016-09-04 13:42:11 +03:00
|
|
|
import platform
|
2016-09-04 12:07:18 +03:00
|
|
|
|
2016-09-04 13:42:11 +03:00
|
|
|
import utils
|
|
|
|
import network.authenticator
|
|
|
|
from network import MtProtoSender, TcpTransport
|
2016-09-05 19:35:12 +03:00
|
|
|
from errors import *
|
2016-09-04 12:07:18 +03:00
|
|
|
|
2016-09-04 13:42:11 +03:00
|
|
|
from tl import Session
|
2016-09-06 19:54:49 +03:00
|
|
|
from tl.types import InputPeerUser, InputPeerEmpty
|
2016-09-04 13:42:11 +03:00
|
|
|
from tl.functions import InvokeWithLayerRequest, InitConnectionRequest
|
|
|
|
from tl.functions.help import GetConfigRequest
|
|
|
|
from tl.functions.auth import CheckPhoneRequest, SendCodeRequest, SignInRequest
|
2016-09-06 19:54:49 +03:00
|
|
|
from tl.functions.messages import GetDialogsRequest, SendMessageRequest
|
2016-09-04 12:07:18 +03:00
|
|
|
|
|
|
|
|
2016-09-04 13:42:11 +03:00
|
|
|
class TelegramClient:
|
2016-09-04 12:07:18 +03:00
|
|
|
def __init__(self, session_user_id, layer, api_id=None, api_hash=None):
|
|
|
|
if api_id is None or api_hash is None:
|
2016-09-04 13:42:11 +03:00
|
|
|
raise PermissionError('Your API ID or Hash are invalid. Please read "Requirements" on README.md')
|
2016-09-04 12:07:18 +03:00
|
|
|
|
|
|
|
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)
|
2016-09-04 13:42:11 +03:00
|
|
|
|
|
|
|
# These will be set later
|
2016-09-04 12:07:18 +03:00
|
|
|
self.dc_options = None
|
2016-09-04 13:42:11 +03:00
|
|
|
self.sender = None
|
2016-09-06 19:54:49 +03:00
|
|
|
self.phone_code_hash = None
|
2016-09-04 12:07:18 +03:00
|
|
|
|
|
|
|
def connect(self, reconnect=False):
|
2016-09-04 13:42:11 +03:00
|
|
|
if not self.session.auth_key or reconnect:
|
|
|
|
self.session.auth_key, self.session.time_offset = network.authenticator.do_authentication(self.transport)
|
2016-09-06 19:54:49 +03:00
|
|
|
self.session.save()
|
2016-09-04 12:07:18 +03:00
|
|
|
|
|
|
|
self.sender = MtProtoSender(self.transport, self.session)
|
2016-09-06 19:54:49 +03:00
|
|
|
self.sender.add_update_handler(self.on_update)
|
|
|
|
|
|
|
|
# Always init connection by using the latest layer, not only when not reconnecting (as in original TLSharp's)
|
|
|
|
# Otherwise, the server thinks that were using the oldest layer!
|
|
|
|
# (Note that this is mainly untested, but it seems like it since some errors point in that direction)
|
|
|
|
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()))
|
2016-09-04 12:07:18 +03:00
|
|
|
|
2016-09-06 19:54:49 +03:00
|
|
|
self.sender.send(request)
|
|
|
|
self.sender.receive(request)
|
2016-09-04 12:07:18 +03:00
|
|
|
|
2016-09-06 19:54:49 +03:00
|
|
|
# Result is a Config TLObject
|
|
|
|
self.dc_options = request.result.dc_options
|
2016-09-04 12:07:18 +03:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2016-09-06 19:54:49 +03:00
|
|
|
self.transport.close()
|
2016-09-04 12:07:18 +03:00
|
|
|
self.transport = TcpTransport(dc.ip_address, dc.port)
|
|
|
|
self.session.server_address = dc.ip_address
|
|
|
|
self.session.port = dc.port
|
2016-09-06 19:54:49 +03:00
|
|
|
self.session.save()
|
2016-09-04 12:07:18 +03:00
|
|
|
|
|
|
|
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!'
|
|
|
|
|
2016-09-04 13:42:11 +03:00
|
|
|
request = CheckPhoneRequest(phone_number)
|
2016-09-04 12:07:18 +03:00
|
|
|
self.sender.send(request)
|
|
|
|
self.sender.receive(request)
|
|
|
|
|
|
|
|
# Result is an Auth.CheckedPhone
|
|
|
|
return request.result.phone_registered
|
|
|
|
|
2016-09-04 13:42:11 +03:00
|
|
|
def send_code_request(self, phone_number):
|
|
|
|
request = SendCodeRequest(phone_number, self.api_id, self.api_hash)
|
2016-09-04 12:07:18 +03:00
|
|
|
completed = False
|
|
|
|
while not completed:
|
|
|
|
try:
|
|
|
|
self.sender.send(request)
|
|
|
|
self.sender.receive(request)
|
|
|
|
completed = True
|
2016-09-06 19:54:49 +03:00
|
|
|
if request.result:
|
|
|
|
self.phone_code_hash = request.result.phone_code_hash
|
|
|
|
|
2016-09-05 19:35:12 +03:00
|
|
|
except InvalidDCError as error:
|
|
|
|
self.reconnect_to_dc(error.new_dc)
|
|
|
|
|
2016-09-06 19:54:49 +03:00
|
|
|
def make_auth(self, phone_number, code):
|
|
|
|
if not self.phone_code_hash:
|
|
|
|
raise ValueError('Please make sure you have called send_code_request first!')
|
2016-09-04 12:07:18 +03:00
|
|
|
|
2016-09-06 19:54:49 +03:00
|
|
|
request = SignInRequest(phone_number, self.phone_code_hash, code)
|
2016-09-04 12:07:18 +03:00
|
|
|
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
|
|
|
|
|
2016-09-06 19:54:49 +03:00
|
|
|
def get_dialogs(self):
|
|
|
|
request = GetDialogsRequest(offset_date=0,
|
|
|
|
offset_id=0,
|
|
|
|
offset_peer=InputPeerEmpty(),
|
|
|
|
limit=20)
|
|
|
|
|
|
|
|
self.sender.send(request)
|
|
|
|
self.sender.receive(request)
|
|
|
|
|
|
|
|
print(request.result)
|
|
|
|
|
2016-09-04 12:07:18 +03:00
|
|
|
def send_message(self, user, message):
|
|
|
|
peer = InputPeerUser(user.id, user.access_hash)
|
2016-09-04 13:42:11 +03:00
|
|
|
request = SendMessageRequest(peer, message, utils.generate_random_long())
|
2016-09-04 12:07:18 +03:00
|
|
|
|
|
|
|
self.sender.send(request)
|
2016-09-06 19:54:49 +03:00
|
|
|
self.sender.receive(request)
|
|
|
|
|
|
|
|
def on_update(self, tlobject):
|
|
|
|
"""This method is fired when there are updates from Telegram.
|
|
|
|
Add your own implementation below, or simply override it!"""
|
|
|
|
print('We have an update: {}'.format(str(tlobject)))
|