Split and rewrite message treatment from consumers

This commit is contained in:
nemunaire 2015-09-03 01:26:13 +02:00
parent a4fd04c310
commit 4af108265b
2 changed files with 170 additions and 150 deletions

View File

@ -29,176 +29,62 @@ class MessageConsumer:
def __init__(self, srv, msg):
self.srv = srv
self.orig = msg
self.msgs = [ ]
self.responses = None
def first_treat(self, msg):
"""Qualify a new message/response
Argument:
msg -- The Message or Response to qualify
"""
# Define the source server if not already done
if not hasattr(msg, "server") or msg.server is None:
msg.server = self.srv.id
if hasattr(msg, "frm_owner"):
msg.frm_owner = (not hasattr(self.srv, "owner") or self.srv.owner == msg.frm)
return msg
def pre_treat(self, hm):
"""Modify input Messages
Arguments:
hm -- Hooks manager
"""
new_msg = list()
new_msg += self.msgs
self.msgs = list()
while len(new_msg) > 0:
msg = new_msg.pop(0)
for h in hm.get_hooks("pre", type(msg).__name__):
if h.match(msg, server=self.srv):
res = h.run(msg)
if isinstance(res, list):
for i in range(len(res)):
if res[i] == msg:
res.pop(i)
break
new_msg += res
elif res is not None and res != msg:
new_msg.append(res)
msg = None
break
elif res is None or res is False:
msg = None
break
if msg is not None:
self.msgs.append(msg)
def in_treat(self, hm):
"""Treat Messages and store responses
Arguments:
hm -- Hooks manager
"""
self.responses = list()
for msg in self.msgs:
for h in hm.get_hooks("in", type(msg).__name__):
if h.match(msg, server=self.srv):
res = h.run(msg)
if isinstance(res, list):
self.responses += res
elif res is not None:
self.responses.append(res)
def post_treat(self, hm):
"""Modify output Messages
Arguments:
hm -- Hooks manager
"""
new_msg = list()
new_msg += self.responses
self.responses = list()
while len(new_msg) > 0:
ff = new_msg.pop(0)
if isinstance(ff, str):
self.responses.append(ff)
continue
msg = self.first_treat(ff)
for h in hm.get_hooks("post"):
if h.match(msg, server=self.srv):
res = h.run(msg)
if isinstance(res, list):
for i in range(len(res)):
if isinstance(res[i], str):
self.responses.append(res.pop(i))
break
msg = None
new_msg += res
break
elif res is not None and res != msg:
new_msg.append(res)
msg = None
break
elif res is None or res is False:
msg = None
break
else:
msg = res
if msg is not None:
self.responses.append(msg)
def run(self, context):
"""Create, parse and treat the message"""
from nemubot.bot import Bot
assert isinstance(context, Bot)
msgs = []
# Parse the message
try:
for msg in self.srv.parse(self.orig):
self.msgs.append(msg)
msgs.append(msg)
except:
logger.exception("Error occurred during the processing of the %s: "
"%s", type(self.msgs[0]).__name__, self.msgs[0])
if len(self.msgs) <= 0:
if len(msgs) <= 0:
return
try:
for msg in self.msgs:
self.first_treat(msg)
# Qualify the message
if not hasattr(msg, "server") or msg.server is None:
msg.server = self.srv.id
if hasattr(msg, "frm_owner"):
msg.frm_owner = (not hasattr(self.srv, "owner") or self.srv.owner == msg.frm)
# Run pre-treatment: from Message to [ Message ]
self.pre_treat(context.hooks)
# Treat the message
from nemubot.treatment import MessageTreater
mt = MessageTreater(context.hooks) # Should be in context, this is static
for msg in msgs:
for res in mt.treat_msg(msg):
# Identify the destination
to_server = None
if isinstance(res, str):
to_server = self.srv
elif res.server is None:
to_server = self.srv
res.server = self.srv.id
elif isinstance(res.server, str) and res.server in context.servers:
to_server = context.servers[res.server]
# Run in-treatment: from Message to [ Response ]
if len(self.msgs) > 0:
self.in_treat(context.hooks)
if to_server is None:
logger.error("The server defined in this response doesn't "
"exist: %s", res.server)
continue
# Run post-treatment: from Response to [ Response ]
if self.responses is not None and len(self.responses) > 0:
self.post_treat(context.hooks)
except BaseException as e:
logger.exception("Error occurred during the processing of the %s: "
"%s", type(self.msgs[0]).__name__, self.msgs[0])
from nemubot.message import Text
self.responses.append(Text("Sorry, an error occured (%s). Feel free to open a new issue at https://github.com/nemunaire/nemubot/issues/new" % type(e).__name__,
server=self.srv.id, to=self.msgs[0].to_response))
for res in self.responses:
to_server = None
if isinstance(res, str):
to_server = self.srv
elif res.server is None:
to_server = self.srv
res.server = self.srv.id
elif isinstance(res.server, str) and res.server in context.servers:
to_server = context.servers[res.server]
if to_server is None:
logger.error("The server defined in this response doesn't "
"exist: %s", res.server)
continue
# Sent the message only if treat_post authorize it
to_server.send_response(res)
# Sent the message only if treat_post authorize it
to_server.send_response(res)
class EventConsumer:
"""Store a event before treating"""
def __init__(self, evt, timeout=20):
self.evt = evt
self.timeout = timeout
@ -222,12 +108,15 @@ class EventConsumer:
class Consumer(threading.Thread):
"""Dequeue and exec requested action"""
def __init__(self, context):
self.context = context
self.stop = False
threading.Thread.__init__(self)
def run(self):
try:
while not self.stop:

131
nemubot/treatment.py Normal file
View File

@ -0,0 +1,131 @@
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2015 Mercier Pierre-Olivier
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
logger = logging.getLogger("nemubot.treatment")
class MessageTreater:
"""Treat a message"""
def __init__(self, hm):
self.hm = hm # Pointer to the HookManager
def treat_msg(self, msg):
"""Treat a given message
Arguments:
msg -- the message to treat
"""
try:
# Run pre-treatment: from Message to [ Message ]
msg_gen = self._pre_treat(msg)
m = next(msg_gen, None)
# Run in-treatment: from Message to [ Response ]
while m is not None:
for response in self._in_treat(m):
# Run post-treatment: from Response to [ Response ]
yield from self._post_treat(response)
m = next(msg_gen, None)
except BaseException as e:
logger.exception("Error occurred during the processing of the %s: "
"%s", type(msg).__name__, msg)
from nemubot.message import Text
yield from self._post_treat(Text("Sorry, an error occured (%s). Feel free to open a new issue at https://github.com/nemunaire/nemubot/issues/new" % type(e).__name__,
to=msg.to_response))
def _pre_treat(self, msg):
"""Modify input Messages
Arguments:
msg -- message to treat
"""
for h in self.hm.get_hooks("pre", type(msg).__name__):
if h.match(msg):
res = h.run(msg)
if isinstance(res, list):
for i in range(len(res)):
# Avoid infinite loop
if res[i] != msg:
yield from self._pre_treat(res[i])
elif res is not None and res != msg:
yield from self._pre_treat(res)
elif res is None or res is False:
break
else:
yield msg
def _in_treat(self, msg):
"""Treats Messages and returns Responses
Arguments:
msg -- message to treat
"""
for h in self.hm.get_hooks("in", type(msg).__name__):
if h.match(msg):
res = h.run(msg)
if isinstance(res, list):
for r in res:
yield r
elif res is not None:
if not hasattr(res, "server") or res.server is None:
res.server = msg.server
yield res
def _post_treat(self, msg):
"""Modify output Messages
Arguments:
msg -- response to treat
"""
for h in self.hm.get_hooks("post"):
if h.match(msg):
res = h.run(msg)
if isinstance(res, list):
for i in range(len(res)):
# Avoid infinite loop
if res[i] != msg:
yield from self._post_treat(res[i])
elif res is not None and res != msg:
yield from self._post_treat(res)
elif res is None or res is False:
break
else:
yield msg