generated from exteraGramPlugins/pluginBase
Publish plugin / publish (push) Successful in 4s
Keeps deleted messages (75% opacity, red icon-pack trash icon), restores logged messages deleted while away, reports deletions, and shows edit history as a mock chat (Edit history in the message menu, Open topic). Message links and history open as any signed-in account with access. Per-master API tokens; chat state synced per checked range with an hour's validity, cached in SQLite with a configurable lifetime. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
129 lines
3.9 KiB
Python
129 lines
3.9 KiB
Python
"""Telegram requests through the client's own session.
|
|
|
|
Sent with ConnectionsManager.sendRequest and a Java RequestDelegate proxy,
|
|
kept strongly referenced until it fires: on 12.10.6 the SDK's send_request
|
|
never invoked the callback for these requests.
|
|
"""
|
|
|
|
import threading
|
|
|
|
import diag
|
|
from jutil import java_list
|
|
|
|
_pending = set()
|
|
_lock = threading.Lock()
|
|
|
|
|
|
_Delegate = None
|
|
|
|
|
|
def _delegate_class():
|
|
"""A Java RequestDelegate calling a Python function (created once)."""
|
|
global _Delegate
|
|
if _Delegate is None:
|
|
from java import dynamic_proxy
|
|
from org.telegram.tgnet import RequestDelegate
|
|
|
|
class Delegate(dynamic_proxy(RequestDelegate)):
|
|
def __init__(self, fn):
|
|
super().__init__()
|
|
self.fn = fn
|
|
|
|
def run(self, response, error):
|
|
self.fn(response, error)
|
|
|
|
_Delegate = Delegate
|
|
return _Delegate
|
|
|
|
|
|
def _send(account, request, callback):
|
|
from org.telegram.tgnet import ConnectionsManager
|
|
|
|
box = []
|
|
|
|
def done(response, error):
|
|
with _lock:
|
|
for proxy in box:
|
|
_pending.discard(proxy)
|
|
try:
|
|
callback(response, error)
|
|
except Exception as exc:
|
|
diag.error("tg callback", exc)
|
|
|
|
delegate = _delegate_class()(done)
|
|
box.append(delegate)
|
|
with _lock:
|
|
_pending.add(delegate)
|
|
ConnectionsManager.getInstance(account).sendRequest(request, delegate)
|
|
|
|
|
|
def _message_ids(ids):
|
|
"""getMessages ids: ArrayList<Integer>. `jint` forces Integer boxing;
|
|
a plain Python int (even from Integer.valueOf) is boxed as Long, which
|
|
fails serialization on the network thread without any callback."""
|
|
from java import jint
|
|
from java.util import ArrayList
|
|
|
|
items = ArrayList()
|
|
for i in ids:
|
|
items.add(jint(int(i)))
|
|
return items
|
|
|
|
|
|
def channel_chat(account, channel_id):
|
|
"""The cached TLRPC.Chat of a channel, loading it from storage if needed."""
|
|
from org.telegram.messenger import MessagesController, MessagesStorage
|
|
|
|
controller = MessagesController.getInstance(account)
|
|
chat = controller.getChat(int(channel_id))
|
|
if chat is None:
|
|
try:
|
|
chat = MessagesStorage.getInstance(account).getChatSync(int(channel_id))
|
|
if chat is not None:
|
|
controller.putChat(chat, True)
|
|
except Exception as exc:
|
|
diag.error("tg.channel_chat", exc)
|
|
return chat
|
|
|
|
|
|
def get_messages(account, dialog_id, ids, callback):
|
|
"""Fetches `ids` of a dialog (a channel when `dialog_id` is one).
|
|
|
|
`callback(messages, error_text)`: messages by id (TL_messageEmpty for
|
|
deleted ones), or None and an error.
|
|
"""
|
|
from org.telegram.messenger import ChatObject, MessagesController
|
|
from org.telegram.tgnet import TLRPC
|
|
|
|
controller = MessagesController.getInstance(account)
|
|
dialog_id = int(dialog_id)
|
|
chat = channel_chat(account, -dialog_id) if dialog_id < 0 else None
|
|
if chat is not None and ChatObject.isChannel(chat):
|
|
request = TLRPC.TL_channels_getMessages()
|
|
request.channel = controller.getInputChannel(chat)
|
|
if request.channel is None or getattr(request.channel, "access_hash", 0) == 0:
|
|
callback(None, "not a member of that chat")
|
|
return
|
|
elif dialog_id < 0 and chat is None:
|
|
callback(None, "chat not found (not a member?)")
|
|
return
|
|
else:
|
|
request = TLRPC.TL_messages_getMessages()
|
|
request.id = _message_ids(ids)
|
|
|
|
def done(response, error):
|
|
if error is not None or response is None:
|
|
callback(None, getattr(error, "text", None) or "request failed")
|
|
return
|
|
try:
|
|
controller.putUsers(response.users, False)
|
|
controller.putChats(response.chats, False)
|
|
except Exception:
|
|
pass
|
|
found = {}
|
|
for message in java_list(response.messages):
|
|
found[int(message.id)] = message
|
|
callback(found, None)
|
|
|
|
_send(account, request, done)
|