GNU/Weeb Mailing List <[email protected]>
 help / color / mirror / Atom feed
From: Muhammad Rizki <[email protected]>
To: Ammar Faizi <[email protected]>
Cc: Muhammad Rizki <[email protected]>,
	Alviro Iskandar Setiawan <[email protected]>,
	GNU/Weeb Mailing List <[email protected]>
Subject: [PATCH v1 16/26] discord: Add mail listener
Date: Sat,  1 Oct 2022 20:03:44 +0700	[thread overview]
Message-ID: <[email protected]> (raw)
In-Reply-To: <[email protected]>

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 <[email protected]>
---
 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 <[email protected]>
+#
+
+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 <[email protected]>
+# Copyright (C) 2022  Ammar Faizi <[email protected]>
+#
+
+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


  parent reply	other threads:[~2022-10-01 13:04 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 01/26] discord: Add get_atom_urls() to get the list of atom URLs Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 02/26] Fix the storage management after the refactor was happened Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 03/26] discord: Add get_broadcast_chats() to get the list of broadcast chats Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 04/26] discord: Add get_email_id() in getter directory Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 05/26] discord: Add get_reply_id() " Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 06/26] discord: Inherit Getter() class to the DBMethods() class Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 07/26] discord: Add delete_atom() in deletion directory Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 08/26] discord: Add delete_broadcast() " Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 09/26] discord: Inherit the Deletion() class to the DBMethods() class Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 10/26] discord: Inherit the DBMethods() class to the DB() class Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 11/26] discord: Use the created " Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 12/26] telegram: Rename some utility functions Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 13/26] discord: Add a FullMessageBtn() class in models Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 14/26] discord: Add filters.wait_on_limit() decorator Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 15/26] discord: Add send lore email message functions Muhammad Rizki
2022-10-01 13:03 ` Muhammad Rizki [this message]
2022-10-01 13:03 ` [PATCH v1 17/26] discord: Implement the mail Listener() class Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 18/26] discord: Add @filters.lore_admin() decorator Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 19/26] discord: Add a list of atom URL slash command Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 20/26] discord: Add an add atom " Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 21/26] discord: Add a delete " Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 22/26] discord: Add channel_link() in the atom/utils.py Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 23/26] discord: Add a list broadcast slash command Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 24/26] discord: Add an add " Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 25/26] discord: Add a delete " Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 26/26] discord: Change the on_ready message Muhammad Rizki
2022-10-03 12:48 ` [PATCH v1 00/26] The complete version of the Discord bot Ammar Faizi
2022-10-03 13:04   ` Muhammad Rizki
2022-10-03 13:13     ` Ammar Faizi
2022-10-03 13:12   ` Muhammad Rizki
2022-10-03 13:13     ` Ammar Faizi
2022-10-03 23:12   ` Alviro Iskandar Setiawan
2022-10-03 23:14     ` Ammar Faizi
2022-10-03 23:18     ` Muhammad Rizki
2022-10-03 23:22       ` Alviro Iskandar Setiawan
2022-10-03 23:31         ` Ammar Faizi
2022-10-03 23:33         ` Muhammad Rizki
2022-10-03 23:36           ` Ammar Faizi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    [email protected] \
    [email protected] \
    [email protected] \
    [email protected] \
    [email protected] \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox