1) Add e-mail tunnel support 2) Modify all __new__ to get_instance() 3) init docker build scripts
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
import asyncio
|
||||
import aiosmtplib
|
||||
import aioimaplib
|
||||
import email
|
||||
from email.header import decode_header
|
||||
import mailparser
|
||||
import logging
|
||||
import time
|
||||
import datetime
|
||||
from .tunnel import AgentTunnel
|
||||
from .agent_message import AgentMsg
|
||||
|
||||
from email.message import EmailMessage
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class EmailTunnel(AgentTunnel):
|
||||
@classmethod
|
||||
def register_to_loader(cls):
|
||||
async def load_email_tunnel(config:dict) -> AgentTunnel:
|
||||
result_tunnel = EmailTunnel()
|
||||
if await result_tunnel.load_from_config(config):
|
||||
return result_tunnel
|
||||
else:
|
||||
return None
|
||||
|
||||
AgentTunnel.register_loader("EmailTunnel",load_email_tunnel)
|
||||
|
||||
async def load_from_config(self,config:dict)->bool:
|
||||
self.target_id = config["target"]
|
||||
self.tunnel_id = config["tunnel_id"]
|
||||
|
||||
self.type = "TelegramTunnel"
|
||||
self.email = config["email"]
|
||||
self.imap_server = config["imap"]
|
||||
s = self.imap_server.split(":")
|
||||
if len(s) == 2:
|
||||
self.imap_server = s[0]
|
||||
self.imap_port = int(s[1])
|
||||
|
||||
self.smtp_server = config["smtp"]
|
||||
s = self.smtp_server.split(":")
|
||||
if len(s) == 2:
|
||||
self.smtp_server = s[0]
|
||||
self.smtp_port = int(s[1])
|
||||
|
||||
self.login_user = config["user"]
|
||||
self.login_password = config["password"]
|
||||
self.folder = config["folder"]
|
||||
self.check_interval = config["interval"]
|
||||
|
||||
return True
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.is_start = False
|
||||
self.read_email = {}
|
||||
|
||||
async def on_new_email(self,mail:mailparser.MailParser) -> None:
|
||||
remote_email_addr = mail.from_[0][1]
|
||||
remote_user_name = remote_email_addr.split("@")[0]
|
||||
agent_msg = self.conver_mail_to_agent_msg(mail)
|
||||
agent_msg.sender = remote_user_name
|
||||
agent_msg.target = self.target_id
|
||||
self.ai_bus.register_message_handler(remote_user_name, self._process_message)
|
||||
|
||||
resp_msg = await self.ai_bus.send_message(agent_msg)
|
||||
if resp_msg is None:
|
||||
await self.reply_email(remote_email_addr,"Sorry, I can't understand your message","")
|
||||
else:
|
||||
if resp_msg.body_mime is None:
|
||||
await self.reply_email(remote_email_addr,"result",resp_msg.body)
|
||||
|
||||
async def reply_email(self,target_email:str,title:str,msg:str) -> None:
|
||||
email_msg = EmailMessage()
|
||||
email_msg['Subject'] = f"Reply: {title}"
|
||||
email_msg['From'] = self.email
|
||||
email_msg['To'] = target_email
|
||||
email_msg.set_content(msg)
|
||||
|
||||
await aiosmtplib.send(
|
||||
email_msg,
|
||||
hostname = self.smtp_server,
|
||||
port=self.smtp_port,
|
||||
username=self.login_user,
|
||||
password=self.login_password,
|
||||
)
|
||||
|
||||
|
||||
|
||||
def conver_mail_to_agent_msg(self,mail:mailparser.MailParser) -> AgentMsg:
|
||||
msg = AgentMsg()
|
||||
msg.set("",self.target_id,mail.text_plain[0])
|
||||
msg.topic = "email"
|
||||
return msg
|
||||
|
||||
async def check_email(self) -> None:
|
||||
self.last_check_num = 0
|
||||
self.last_check_time = datetime.datetime.now()
|
||||
while True:
|
||||
if self.is_start == False:
|
||||
return
|
||||
|
||||
await asyncio.sleep(self.check_interval)
|
||||
imap_client = aioimaplib.IMAP4_SSL(host=self.imap_server,port=self.imap_port)
|
||||
await imap_client.wait_hello_from_server()
|
||||
await imap_client.login(self.login_user, self.login_password)
|
||||
|
||||
date_since = self.last_check_time.strftime("%d-%b-%Y")
|
||||
|
||||
await imap_client.select(self.folder)
|
||||
status, messages = await imap_client.search('UNSEEN',charset='US-ASCII')
|
||||
self.last_check_time = datetime.datetime.now()
|
||||
if status == "OK":
|
||||
message_numbers = messages[0].split()
|
||||
for num in message_numbers:
|
||||
num = int(num)
|
||||
if self.read_email.get(num) is not None:
|
||||
continue
|
||||
|
||||
status, email_data = await imap_client.fetch(str(num), "(RFC822)")
|
||||
if status == "OK":
|
||||
#r = email.message_from_bytes(email_data[1])
|
||||
mail = mailparser.parse_from_bytes(email_data[1])
|
||||
self.read_email[num] = mail
|
||||
await self.on_new_email(mail)
|
||||
|
||||
await imap_client.logout()
|
||||
|
||||
async def start(self) -> bool:
|
||||
if self.is_start:
|
||||
logger.warning(f"tunnel {self.tunnel_id} is already started")
|
||||
return False
|
||||
self.is_start = True
|
||||
|
||||
asyncio.create_task(self.check_email())
|
||||
return True
|
||||
|
||||
async def close(self) -> None:
|
||||
self.is_start = False
|
||||
|
||||
async def _process_message(self, msg: AgentMsg) -> None:
|
||||
logger.warn(f"process message {msg.msg_id} from {msg.sender} to {msg.target}")
|
||||
Reference in New Issue
Block a user