mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-02-03 13:14:31 +03:00
Use RLocks properly on MtProtoSender (only needed on net IO)
This commit is contained in:
parent
16a5ab3070
commit
25bbb20b0c
|
@ -28,8 +28,10 @@ class MtProtoSender:
|
||||||
self._need_confirmation = [] # Message IDs that need confirmation
|
self._need_confirmation = [] # Message IDs that need confirmation
|
||||||
self._pending_receive = [] # Requests sent waiting to be received
|
self._pending_receive = [] # Requests sent waiting to be received
|
||||||
|
|
||||||
# Store an RLock instance to make this class safely multi-threaded
|
# Sending and receiving are independent, but two threads cannot
|
||||||
self._lock = RLock()
|
# send or receive at the same time no matter what.
|
||||||
|
self._send_lock = RLock()
|
||||||
|
self._recv_lock = RLock()
|
||||||
|
|
||||||
# Used when logging out, the only request that seems to use 'ack'
|
# Used when logging out, the only request that seems to use 'ack'
|
||||||
# TODO There might be a better way to handle msgs_ack requests
|
# TODO There might be a better way to handle msgs_ack requests
|
||||||
|
@ -52,10 +54,6 @@ class MtProtoSender:
|
||||||
"""Sends the specified MTProtoRequest, previously sending any message
|
"""Sends the specified MTProtoRequest, previously sending any message
|
||||||
which needed confirmation."""
|
which needed confirmation."""
|
||||||
|
|
||||||
# Now only us can be using this method
|
|
||||||
with self._lock:
|
|
||||||
self._logger.debug('send() acquired the lock')
|
|
||||||
|
|
||||||
# If any message needs confirmation send an AckRequest first
|
# If any message needs confirmation send an AckRequest first
|
||||||
self._send_acknowledges()
|
self._send_acknowledges()
|
||||||
|
|
||||||
|
@ -68,8 +66,6 @@ class MtProtoSender:
|
||||||
# And update the saved session
|
# And update the saved session
|
||||||
self.session.save()
|
self.session.save()
|
||||||
|
|
||||||
self._logger.debug('send() released the lock')
|
|
||||||
|
|
||||||
def _send_acknowledges(self):
|
def _send_acknowledges(self):
|
||||||
"""Sends a messages acknowledge for all those who _need_confirmation"""
|
"""Sends a messages acknowledge for all those who _need_confirmation"""
|
||||||
if self._need_confirmation:
|
if self._need_confirmation:
|
||||||
|
@ -90,16 +86,13 @@ class MtProtoSender:
|
||||||
Any unhandled object (likely updates) will be passed to
|
Any unhandled object (likely updates) will be passed to
|
||||||
update_state.process(TLObject).
|
update_state.process(TLObject).
|
||||||
"""
|
"""
|
||||||
# TODO Don't ignore updates
|
with self._recv_lock:
|
||||||
self._logger.debug('Receiving a message...')
|
|
||||||
body = self.connection.recv()
|
body = self.connection.recv()
|
||||||
message, remote_msg_id, remote_seq = self._decode_msg(body)
|
|
||||||
|
|
||||||
|
message, remote_msg_id, remote_seq = self._decode_msg(body)
|
||||||
with BinaryReader(message) as reader:
|
with BinaryReader(message) as reader:
|
||||||
self._process_msg(remote_msg_id, remote_seq, reader, update_state)
|
self._process_msg(remote_msg_id, remote_seq, reader, update_state)
|
||||||
|
|
||||||
self._logger.debug('Received message.')
|
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
# region Low level processing
|
# region Low level processing
|
||||||
|
@ -107,8 +100,6 @@ class MtProtoSender:
|
||||||
def _send_packet(self, packet, request):
|
def _send_packet(self, packet, request):
|
||||||
"""Sends the given packet bytes with the additional
|
"""Sends the given packet bytes with the additional
|
||||||
information of the original request.
|
information of the original request.
|
||||||
|
|
||||||
This does NOT lock the threads!
|
|
||||||
"""
|
"""
|
||||||
request.request_msg_id = self.session.get_new_msg_id()
|
request.request_msg_id = self.session.get_new_msg_id()
|
||||||
|
|
||||||
|
@ -134,6 +125,7 @@ class MtProtoSender:
|
||||||
self.session.auth_key.key_id, signed=False)
|
self.session.auth_key.key_id, signed=False)
|
||||||
cipher_writer.write(msg_key)
|
cipher_writer.write(msg_key)
|
||||||
cipher_writer.write(cipher_text)
|
cipher_writer.write(cipher_text)
|
||||||
|
with self._send_lock:
|
||||||
self.connection.send(cipher_writer.get_bytes())
|
self.connection.send(cipher_writer.get_bytes())
|
||||||
|
|
||||||
def _decode_msg(self, body):
|
def _decode_msg(self, body):
|
||||||
|
|
|
@ -2,7 +2,7 @@ import os
|
||||||
import threading
|
import threading
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from mimetypes import guess_type
|
from mimetypes import guess_type
|
||||||
from threading import RLock, Thread
|
from threading import Thread
|
||||||
|
|
||||||
from . import TelegramBareClient
|
from . import TelegramBareClient
|
||||||
from . import helpers as utils
|
from . import helpers as utils
|
||||||
|
@ -50,9 +50,6 @@ class TelegramClient(TelegramBareClient):
|
||||||
As opposed to the TelegramBareClient, this one features downloading
|
As opposed to the TelegramBareClient, this one features downloading
|
||||||
media from different data centers, starting a second thread to
|
media from different data centers, starting a second thread to
|
||||||
handle updates, and some very common functionality.
|
handle updates, and some very common functionality.
|
||||||
|
|
||||||
This should be used when the (slight) overhead of having locks,
|
|
||||||
threads, and possibly multiple connections is not an issue.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# region Initialization
|
# region Initialization
|
||||||
|
@ -118,9 +115,6 @@ class TelegramClient(TelegramBareClient):
|
||||||
timeout=timeout
|
timeout=timeout
|
||||||
)
|
)
|
||||||
|
|
||||||
# Safety across multiple threads (for the updates thread)
|
|
||||||
self._lock = RLock()
|
|
||||||
|
|
||||||
# Used on connection - the user may modify these and reconnect
|
# Used on connection - the user may modify these and reconnect
|
||||||
kwargs['app_version'] = kwargs.get('app_version', self.__version__)
|
kwargs['app_version'] = kwargs.get('app_version', self.__version__)
|
||||||
for name, value in kwargs.items():
|
for name, value in kwargs.items():
|
||||||
|
@ -239,8 +233,6 @@ class TelegramClient(TelegramBareClient):
|
||||||
raise AssertionError('Cannot invoke requests from the ReadThread')
|
raise AssertionError('Cannot invoke requests from the ReadThread')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._lock.acquire()
|
|
||||||
|
|
||||||
# Users may call this method from within some update handler.
|
# Users may call this method from within some update handler.
|
||||||
# If this is the case, then the thread invoking the request
|
# If this is the case, then the thread invoking the request
|
||||||
# will be the one which should be reading (but is invoking the
|
# will be the one which should be reading (but is invoking the
|
||||||
|
@ -259,9 +251,6 @@ class TelegramClient(TelegramBareClient):
|
||||||
self.reconnect(new_dc=e.new_dc)
|
self.reconnect(new_dc=e.new_dc)
|
||||||
return self.invoke(request)
|
return self.invoke(request)
|
||||||
|
|
||||||
finally:
|
|
||||||
self._lock.release()
|
|
||||||
|
|
||||||
# Let people use client(SomeRequest()) instead client.invoke(...)
|
# Let people use client(SomeRequest()) instead client.invoke(...)
|
||||||
__call__ = invoke
|
__call__ = invoke
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user