mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-08-07 05:30:20 +03:00
Add full_sync module
This commit is contained in:
parent
c2966297f1
commit
1189788c2c
|
@ -2,7 +2,7 @@ import logging
|
|||
from .client.telegramclient import TelegramClient
|
||||
from .network import connection
|
||||
from .tl import types, functions, custom
|
||||
from . import version, events, utils, errors
|
||||
from . import version, events, utils, errors, full_sync
|
||||
|
||||
|
||||
__version__ = version.__version__
|
||||
|
|
141
telethon/full_sync.py
Normal file
141
telethon/full_sync.py
Normal file
|
@ -0,0 +1,141 @@
|
|||
"""
|
||||
This magical module will rewrite all public methods in the public interface of
|
||||
the library so they can delegate the call to an asyncio event loop in another
|
||||
thread and wait for the result. This rewrite may not be desirable if the end
|
||||
user always uses the methods they way they should be ran, but it's incredibly
|
||||
useful for quick scripts and legacy code.
|
||||
"""
|
||||
import asyncio
|
||||
import functools
|
||||
import inspect
|
||||
import threading
|
||||
from concurrent import futures
|
||||
|
||||
from async_generator import isasyncgenfunction
|
||||
|
||||
from .client.telegramclient import TelegramClient
|
||||
from .tl.custom import (
|
||||
Draft, Dialog, MessageButton, Forward, Message, InlineResult, Conversation
|
||||
)
|
||||
from .tl.custom.chatgetter import ChatGetter
|
||||
from .tl.custom.sendergetter import SenderGetter
|
||||
|
||||
|
||||
async def _proxy_future(af, cf):
|
||||
try:
|
||||
res = await af
|
||||
cf.set_result(res)
|
||||
except Exception as e:
|
||||
cf.set_exception(e)
|
||||
|
||||
|
||||
def _sync_result(loop, x):
|
||||
f = futures.Future()
|
||||
loop.call_soon_threadsafe(asyncio.ensure_future, _proxy_future(x, f))
|
||||
return f.result()
|
||||
|
||||
|
||||
def _syncify_coro(t, method_name, loop, thread_name):
|
||||
method = getattr(t, method_name)
|
||||
|
||||
@functools.wraps(method)
|
||||
def syncified(*args, **kwargs):
|
||||
coro = method(*args, **kwargs)
|
||||
return (
|
||||
coro if threading.current_thread().name == thread_name
|
||||
else _sync_result(loop, coro)
|
||||
)
|
||||
|
||||
setattr(t, method_name, syncified)
|
||||
|
||||
|
||||
class _SyncGen:
|
||||
def __init__(self, loop, gen):
|
||||
self.loop = loop
|
||||
self.gen = gen
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
try:
|
||||
return _sync_result(self.loop, self.gen.__anext__())
|
||||
except StopAsyncIteration:
|
||||
raise StopIteration from None
|
||||
|
||||
|
||||
def _syncify_gen(t, method_name, loop, thread_name):
|
||||
method = getattr(t, method_name)
|
||||
|
||||
@functools.wraps(method)
|
||||
def syncified(*args, **kwargs):
|
||||
coro = method(*args, **kwargs)
|
||||
return (
|
||||
coro if threading.current_thread().name == thread_name
|
||||
else _SyncGen(loop, coro)
|
||||
)
|
||||
|
||||
setattr(t, method_name, syncified)
|
||||
|
||||
|
||||
def _syncify(*types, loop, thread_name):
|
||||
for t in types:
|
||||
for method_name in dir(t):
|
||||
if not method_name.startswith('_') or method_name == '__call__':
|
||||
if inspect.iscoroutinefunction(getattr(t, method_name)):
|
||||
_syncify_coro(t, method_name, loop, thread_name)
|
||||
elif isasyncgenfunction(getattr(t, method_name)):
|
||||
_syncify_gen(t, method_name, loop, thread_name)
|
||||
|
||||
|
||||
def enable(loop=None, thread_name="__telethon_async_thread__"):
|
||||
if not loop:
|
||||
loop = asyncio.get_event_loop()
|
||||
old_init = TelegramClient.__init__
|
||||
|
||||
@functools.wraps(old_init)
|
||||
def new_init(*args, **kwargs):
|
||||
kwargs['loop'] = loop
|
||||
return old_init(*args, **kwargs)
|
||||
|
||||
TelegramClient.__init__ = new_init
|
||||
|
||||
_syncify(TelegramClient, Draft, Dialog, MessageButton, ChatGetter,
|
||||
SenderGetter, Forward, Message, InlineResult, Conversation,
|
||||
loop=loop, thread_name=thread_name)
|
||||
_syncify_coro(TelegramClient, "start", loop, thread_name)
|
||||
|
||||
old_add_event_handler = TelegramClient.add_event_handler
|
||||
old_remove_event_handler = TelegramClient.remove_event_handler
|
||||
proxied_event_handlers = {}
|
||||
|
||||
@functools.wraps(old_add_event_handler)
|
||||
def add_proxied_event_handler(self, callback, event_type=None):
|
||||
async def _proxy(event):
|
||||
h_t = threading.Thread(target=callback, args=(event,))
|
||||
h_t.start()
|
||||
|
||||
proxied_event_handlers[callback] = _proxy
|
||||
|
||||
return old_add_event_handler(self, _proxy, event_type)
|
||||
|
||||
@functools.wraps(old_remove_event_handler)
|
||||
def remove_proxied_event_handler(self, callback, event_type=None):
|
||||
return old_remove_event_handler(
|
||||
self, proxied_event_handlers.get(callback, callback), event_type)
|
||||
|
||||
TelegramClient.add_event_handler = add_proxied_event_handler
|
||||
TelegramClient.remove_event_handler = remove_proxied_event_handler
|
||||
|
||||
def run_until_disconnected(self):
|
||||
return _sync_result(loop, self._run_until_disconnected())
|
||||
|
||||
TelegramClient.run_until_disconnected = run_until_disconnected
|
||||
|
||||
def start():
|
||||
asyncio.set_event_loop(loop)
|
||||
loop.run_forever()
|
||||
|
||||
asyncthread = threading.Thread(target=start, name=thread_name)
|
||||
asyncthread.start()
|
||||
return asyncthread
|
Loading…
Reference in New Issue
Block a user