Files
messageLogger/src/tg.py
T
lyuksovannyyandClaude Opus 5.5 9b2f26a845
Publish plugin / publish (push) Successful in 4s
Message Logger: show logged edits and deletions from telegram-panel [no bump]
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>
2026-10-08 23:55:23 +02:00

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)