From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on gnuweeb.org X-Spam-Level: X-Spam-Status: No, score=-0.8 required=5.0 tests=ALL_TRUSTED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,NO_DNS_FOR_FROM,URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.6 Received: from localhost.localdomain (unknown [101.128.125.177]) by gnuweeb.org (Postfix) with ESMTPSA id 78FA7804FD; Sat, 1 Oct 2022 13:04:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gnuweeb.org; s=default; t=1664629495; bh=0uT7f/r2xrHVv/hlkRnk77jRsI+pF3DRGG9blhdBaGg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uDGsOZkQ8AYGZ/6Mq8DqhWgj0+ZTR4SR3r3vEyb7TjH7V9/9O7aX+zHz6aDl+oFup NUSp04KTuazNfsSc9LvVVHwMtaWRTSzsR67fmqW2oXkRXhfhTeIqMKcepBatZI0/0I b/ldztT+uVjzX2yaIfUDJLeXn7XJHjO4yQLZ4NET0MU47gytmeO2hwY9dzEJCYf8+9 Ags5GJGfD2lJGFt2Trn8yx21YHgemfb6U12c1AEBU3oVx0C/t4O9wLNLeG0QTFf5/1 qGw/IpKLyd10SMqU7im3+jL1b+67GL++MWNWZd7caf27RVAGcSKvKbLDRAiu87DxiR RLaru4Hl3jPXA== From: Muhammad Rizki To: Ammar Faizi Cc: Muhammad Rizki , Alviro Iskandar Setiawan , GNU/Weeb Mailing List Subject: [PATCH v1 16/26] discord: Add mail listener Date: Sat, 1 Oct 2022 20:03:44 +0700 Message-Id: <20221001130355.784-17-kiizuha@gnuweeb.org> X-Mailer: git-send-email 2.34.1.windows.1 In-Reply-To: <20221001130355.784-1-kiizuha@gnuweeb.org> References: <20221001130355.784-1-kiizuha@gnuweeb.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: Add the mail listener to receive new lore kernel email messages, then send them to the Discord channel. If there is no new email message, the listener will ignore it. Signed-off-by: Muhammad Rizki --- daemon/dscord/mailer/__init__.py | 7 ++ daemon/dscord/mailer/listener.py | 154 +++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 daemon/dscord/mailer/__init__.py create mode 100644 daemon/dscord/mailer/listener.py diff --git a/daemon/dscord/mailer/__init__.py b/daemon/dscord/mailer/__init__.py new file mode 100644 index 0000000..5d7e8d8 --- /dev/null +++ b/daemon/dscord/mailer/__init__.py @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2022 Muhammad Rizki +# + +from .listener import Listener +from .listener import Mutexes diff --git a/daemon/dscord/mailer/listener.py b/daemon/dscord/mailer/listener.py new file mode 100644 index 0000000..a1c71ed --- /dev/null +++ b/daemon/dscord/mailer/listener.py @@ -0,0 +1,154 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2022 Muhammad Rizki +# Copyright (C) 2022 Ammar Faizi +# + +import asyncio +import traceback +import shutil +import re +from apscheduler.schedulers.asyncio import AsyncIOScheduler +from discord import File +from discord import Message + +from dscord.gnuweeb import GWClient +from atom.scraper import Scraper +from atom import utils + + +class Mutexes: + def __init__(self): + self.lock = asyncio.Lock() + + +class Listener: + def __init__( + self, + client: "GWClient", + sched: "AsyncIOScheduler", + scraper: "Scraper", + mutexes: "Mutexes" + ): + self.client = client + self.sched = sched + self.scraper = scraper + self.mutexes = mutexes + self.db = client.db + self.isRunnerFixed = False + self.runner = None + + + def run(self): + # + # Execute __run() once to avoid high latency at + # initilization. + # + print("Initialize listener...\n") + self.sched.start() + self.runner = self.sched.add_job(func=self.__run) + + + async def __run(self): + print("[__run]: Running...") + for url in self.db.get_atom_urls(): + try: + await self.__handle_atom_url(url) + except: + print(traceback.format_exc()) + + if not self.isRunnerFixed: + self.isRunnerFixed = True + self.runner = self.sched.add_job( + func=self.__run, + trigger="interval", + seconds=30, + misfire_grace_time=None, + max_instances=1 + ) + + + async def __handle_atom_url(self, url): + urls = await self.scraper.get_new_threads_urls(url) + for url in urls: + mail = await self.scraper.get_email_from_url(url) + await self.__handle_mail(url, mail) + + + async def __handle_mail(self, url, mail): + chats = self.db.get_broadcast_chats() + for chat in chats: + async with self.mutexes.lock: + should_wait = \ + await self.__send_to_discord(url, mail, + chat[1], chat[2]) + + if should_wait: + await asyncio.sleep(1) + + + # @__must_hold(self.mutexes.lock) + async def __send_to_discord(self, url, mail, dc_guild_id, dc_chat_id): + email_msg_id = utils.get_email_msg_id(mail) + if not email_msg_id: + # + # It doesn't have a Message-Id. + # A malformed email. Skip! + # + return False + + email_id = self.__get_email_id_sent( + email_msg_id=email_msg_id, + dc_chat_id=dc_chat_id + ) + if not email_id: + # + # Email has already been sent to Discord. + # Skip! + # + return False + + text, files, is_patch = utils.create_template(mail, "discord") + reply_to = self.get_discord_reply(mail, dc_chat_id) + url = str(re.sub(r"/raw$", "", url)) + + if is_patch: + m: Message = await self.client.send_patch_email( + mail, dc_guild_id, dc_chat_id, text, reply_to, url + ) + else: + text = "#ml\n" + text + m: Message = await self.client.send_text_email( + dc_guild_id, dc_chat_id, text, reply_to, url + ) + + self.db.save_discord_mail(email_id, m.channel.id, m.id) + for d, f in files: + await m.reply(f"{d}/{f}", file=File(f)) + await asyncio.sleep(1) + + if files: + shutil.rmtree(str(files[0][0])) + + return True + + + def __get_email_id_sent(self, email_msg_id, dc_chat_id): + email_id = self.db.save_email(email_msg_id) + if email_id: + return email_id + + email_id = self.db.get_email_id(email_msg_id, dc_chat_id) + return email_id + + + def get_discord_reply(self, mail, dc_chat_id): + reply_to = mail.get("in-reply-to") + if not reply_to: + return None + + reply_to = utils.extract_email_msg_id(reply_to) + if not reply_to: + return None + + return self.db.get_reply_id(reply_to, dc_chat_id) -- Muhammad Rizki