PEP8 clean
This commit is contained in:
parent
95deafe7af
commit
e17996d858
9
bot.py
9
bot.py
@ -36,11 +36,13 @@ from networkbot import NetworkBot
|
||||
|
||||
logger = logging.getLogger("nemubot.bot")
|
||||
|
||||
|
||||
class Bot(threading.Thread):
|
||||
|
||||
"""Class containing the bot context and ensuring key goals"""
|
||||
|
||||
def __init__(self, ip="127.0.0.1", modules_paths=list(), data_path="./datas/"):
|
||||
def __init__(self, ip="127.0.0.1", modules_paths=list(),
|
||||
data_path="./datas/"):
|
||||
"""Initialize the bot context
|
||||
|
||||
Keyword arguments:
|
||||
@ -71,6 +73,7 @@ class Bot(threading.Thread):
|
||||
|
||||
# Own hooks
|
||||
self.hooks = HooksManager()
|
||||
|
||||
def in_ping(msg):
|
||||
if re.match("^ *(m[' ]?entends?[ -]+tu|h?ear me|do you copy|ping)", msg.message, re.I) is not None:
|
||||
return msg.respond("pong")
|
||||
@ -477,9 +480,9 @@ def reload():
|
||||
prompt.reload()
|
||||
|
||||
import server
|
||||
rl,wl,xl = server._rlist,server._wlist,server._xlist
|
||||
rl, wl, xl = server._rlist, server._wlist, server._xlist
|
||||
imp.reload(server)
|
||||
server._rlist,server._wlist,server._xlist = rl,wl,xl
|
||||
server._rlist, server._wlist, server._xlist = rl, wl, xl
|
||||
|
||||
server.reload()
|
||||
|
||||
|
67
channel.py
67
channel.py
@ -18,8 +18,19 @@
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
class Channel:
|
||||
|
||||
"""A chat room"""
|
||||
|
||||
def __init__(self, name, password=None):
|
||||
"""Initialize the channel
|
||||
|
||||
Arguments:
|
||||
name -- the channel name
|
||||
password -- the optional password use to join it
|
||||
"""
|
||||
|
||||
self.name = name
|
||||
self.password = password
|
||||
self.people = dict()
|
||||
@ -27,6 +38,13 @@ class Channel:
|
||||
self.logger = logging.getLogger("nemubot.channel." + name)
|
||||
|
||||
def treat(self, cmd, msg):
|
||||
"""Treat a incoming IRC command
|
||||
|
||||
Arguments:
|
||||
cmd -- the command
|
||||
msg -- the whole message
|
||||
"""
|
||||
|
||||
if cmd == "353":
|
||||
self.parse353(msg)
|
||||
elif cmd == "332":
|
||||
@ -42,18 +60,35 @@ class Channel:
|
||||
elif cmd == "TOPIC":
|
||||
self.topic = self.text
|
||||
|
||||
def join(self, nick, level = 0):
|
||||
"""Someone join the channel"""
|
||||
def join(self, nick, level=0):
|
||||
"""Someone join the channel
|
||||
|
||||
Argument:
|
||||
nick -- nickname of the user joining the channel
|
||||
level -- authorization level of the user
|
||||
"""
|
||||
|
||||
self.logger.debug("%s join", nick)
|
||||
self.people[nick] = level
|
||||
|
||||
def chtopic(self, newtopic):
|
||||
"""Send command to change the topic"""
|
||||
"""Send command to change the topic
|
||||
|
||||
Arguments:
|
||||
newtopic -- the new topic of the channel
|
||||
"""
|
||||
|
||||
self.srv.send_msg(self.name, newtopic, "TOPIC")
|
||||
self.topic = newtopic
|
||||
|
||||
def nick(self, oldnick, newnick):
|
||||
"""Someone change his nick"""
|
||||
"""Someone change his nick
|
||||
|
||||
Arguments:
|
||||
oldnick -- the previous nick of the user
|
||||
newnick -- the new nick of the user
|
||||
"""
|
||||
|
||||
if oldnick in self.people:
|
||||
self.logger.debug("%s switch nick to %s on", oldnick, newnick)
|
||||
lvl = self.people[oldnick]
|
||||
@ -61,12 +96,22 @@ class Channel:
|
||||
self.people[newnick] = lvl
|
||||
|
||||
def part(self, nick):
|
||||
"""Someone leave the channel"""
|
||||
"""Someone leave the channel
|
||||
|
||||
Argument:
|
||||
nick -- name of the user that leave
|
||||
"""
|
||||
|
||||
if nick in self.people:
|
||||
self.logger.debug("%s has left", nick)
|
||||
del self.people[nick]
|
||||
|
||||
def mode(self, msg):
|
||||
"""Channel or user mode change
|
||||
|
||||
Argument:
|
||||
msg -- the whole message
|
||||
"""
|
||||
if msg.text[0] == "-k":
|
||||
self.password = ""
|
||||
elif msg.text[0] == "+k":
|
||||
@ -88,9 +133,21 @@ class Channel:
|
||||
self.people[msg.nick] &= ~1
|
||||
|
||||
def parse332(self, msg):
|
||||
"""Parse RPL_TOPIC message
|
||||
|
||||
Argument:
|
||||
msg -- the whole message
|
||||
"""
|
||||
|
||||
self.topic = msg.text
|
||||
|
||||
def parse353(self, msg):
|
||||
"""Parse RPL_ENDOFWHO message
|
||||
|
||||
Argument:
|
||||
msg -- the whole message
|
||||
"""
|
||||
|
||||
for p in msg.text:
|
||||
p = p.decode()
|
||||
if p[0] == "@":
|
||||
|
12
consumer.py
12
consumer.py
@ -23,6 +23,7 @@ import threading
|
||||
|
||||
logger = logging.getLogger("nemubot.consumer")
|
||||
|
||||
|
||||
class MessageConsumer:
|
||||
|
||||
"""Store a message before treating"""
|
||||
@ -77,7 +78,7 @@ class MessageConsumer:
|
||||
new_msg.append(res)
|
||||
msg = None
|
||||
break
|
||||
elif res is None or res == False:
|
||||
elif res is None or res is False:
|
||||
msg = None
|
||||
break
|
||||
if msg is not None:
|
||||
@ -134,7 +135,7 @@ class MessageConsumer:
|
||||
new_msg.append(res)
|
||||
msg = None
|
||||
break
|
||||
elif res is None or res == False:
|
||||
elif res is None or res is False:
|
||||
msg = None
|
||||
break
|
||||
else:
|
||||
@ -160,7 +161,8 @@ class MessageConsumer:
|
||||
if self.responses is not None and len(self.responses) > 0:
|
||||
self.post_treat(context.hooks)
|
||||
except:
|
||||
logger.exception("Error occurred during the processing of the %s: %s", type(self.msgs[0]).__name__, self.msgs[0])
|
||||
logger.exception("Error occurred during the processing of the %s: "
|
||||
"%s", type(self.msgs[0]).__name__, self.msgs[0])
|
||||
|
||||
for res in self.responses:
|
||||
to_server = None
|
||||
@ -180,6 +182,7 @@ class MessageConsumer:
|
||||
# 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):
|
||||
@ -198,7 +201,8 @@ class EventConsumer:
|
||||
context.add_event(self.evt, eid=self.evt.id)
|
||||
|
||||
# Or remove reference of this event
|
||||
elif hasattr(self.evt, "module_src") and self.evt.module_src is not None:
|
||||
elif (hasattr(self.evt, "module_src") and
|
||||
self.evt.module_src is not None):
|
||||
self.evt.module_src.REGISTERED_EVENTS.remove(self.evt.id)
|
||||
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
from message import TextMessage, DirectAsk
|
||||
|
||||
|
||||
class IRCException(Exception):
|
||||
|
||||
def __init__(self, message, personnal=True):
|
||||
@ -27,6 +28,8 @@ class IRCException(Exception):
|
||||
|
||||
def fill_response(self, msg):
|
||||
if self.personnal:
|
||||
return DirectAsk(msg.frm, self.message, server=msg.server, to=msg.to_response)
|
||||
return DirectAsk(msg.frm, self.message,
|
||||
server=msg.server, to=msg.to_response)
|
||||
else:
|
||||
return TextMessage(self.message, server=msg.server, to=msg.to_response)
|
||||
return TextMessage(self.message,
|
||||
server=msg.server, to=msg.to_response)
|
||||
|
@ -20,6 +20,7 @@ import imp
|
||||
|
||||
from exception import IRCException
|
||||
|
||||
|
||||
def call_game(call, *args, **kargs):
|
||||
"""TODO"""
|
||||
l = list()
|
||||
@ -70,6 +71,7 @@ from hooks.messagehook import MessageHook
|
||||
|
||||
last_registered = []
|
||||
|
||||
|
||||
def hook(store, *args, **kargs):
|
||||
"""Function used as a decorator for module loading"""
|
||||
def sec(call):
|
||||
|
@ -16,6 +16,7 @@
|
||||
# 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/>.
|
||||
|
||||
|
||||
class HooksManager:
|
||||
|
||||
"""Class to manage hooks"""
|
||||
|
@ -22,6 +22,7 @@ from exception import IRCException
|
||||
import hooks
|
||||
import message
|
||||
|
||||
|
||||
class MessageHook(hooks.AbstractHook):
|
||||
|
||||
"""Class storing hook information, specialized for a generic Message"""
|
||||
@ -52,9 +53,9 @@ class MessageHook(hooks.AbstractHook):
|
||||
|
||||
def is_matching(self, strcmp, receivers=list(), server=None):
|
||||
"""Test if the current hook correspond to the message"""
|
||||
if (server is None or self.server is None or self.server == server
|
||||
) and ((self.name is None or strcmp == self.name) and (
|
||||
self.regexp is None or re.match(self.regexp, strcmp))):
|
||||
if ((server is None or self.server is None or self.server == server)
|
||||
and ((self.name is None or strcmp == self.name) and (
|
||||
self.regexp is None or re.match(self.regexp, strcmp)))):
|
||||
|
||||
if receivers and self.channels:
|
||||
for receiver in receivers:
|
||||
|
@ -19,6 +19,7 @@
|
||||
from datetime import datetime, timezone
|
||||
import imp
|
||||
|
||||
|
||||
class AbstractMessage:
|
||||
|
||||
"""This class represents an abstract message"""
|
||||
@ -37,7 +38,9 @@ class AbstractMessage:
|
||||
self.server = server
|
||||
self.date = datetime.now(timezone.utc) if date is None else date
|
||||
self.to = to if to is not None else list()
|
||||
self._to_response = to_response if to_response is None or isinstance(to_response, list) else [ to_response ]
|
||||
self._to_response = (to_response if (to_response is None or
|
||||
isinstance(to_response, list))
|
||||
else [ to_response ])
|
||||
self.frm = frm # None allowed when it designate this bot
|
||||
|
||||
self.frm_owner = False # Filled later, in consumer
|
||||
@ -129,7 +132,6 @@ class DirectAsk(TextMessage):
|
||||
|
||||
self.designated = designated
|
||||
|
||||
|
||||
def respond(self, message):
|
||||
return DirectAsk(self.frm,
|
||||
message,
|
||||
|
@ -19,6 +19,7 @@
|
||||
from message import TextMessage
|
||||
from message.visitor import AbstractVisitor
|
||||
|
||||
|
||||
class IRC(AbstractVisitor):
|
||||
|
||||
def __init__(self):
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
import imp
|
||||
|
||||
|
||||
def reload():
|
||||
import message.printer.IRC
|
||||
imp.reload(message.printer.IRC)
|
||||
|
@ -16,6 +16,7 @@
|
||||
# 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/>.
|
||||
|
||||
|
||||
class AbstractVisitor:
|
||||
|
||||
def visit(self, obj):
|
||||
|
10
nemubot.py
10
nemubot.py
@ -31,7 +31,8 @@ if __name__ == "__main__":
|
||||
# Setup loggin interface
|
||||
logger = logging.getLogger("nemubot")
|
||||
|
||||
formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(message)s')
|
||||
formatter = logging.Formatter(
|
||||
'%(asctime)s %(name)s %(levelname)s %(message)s')
|
||||
|
||||
ch = logging.StreamHandler()
|
||||
ch.setFormatter(formatter)
|
||||
@ -52,7 +53,7 @@ if __name__ == "__main__":
|
||||
# Register the hook for futur import
|
||||
sys.meta_path.append(importer.ModuleFinder(context, prmpt))
|
||||
|
||||
#Add modules dir path
|
||||
# Add modules dir path
|
||||
if os.path.isdir("./modules/"):
|
||||
context.add_modules_path(
|
||||
os.path.realpath(os.path.abspath("./modules/")))
|
||||
@ -82,8 +83,9 @@ if __name__ == "__main__":
|
||||
bot.__version__)
|
||||
context.start()
|
||||
except:
|
||||
logger.exception("\033[1;31mUnable to reload the prompt due to errors.\033[0"
|
||||
"m Fix them before trying to reload the prompt.")
|
||||
logger.exception("\033[1;31mUnable to reload the prompt due to "
|
||||
"errors.\033[0m Fix them before trying to reload "
|
||||
"the prompt.")
|
||||
|
||||
context.quit()
|
||||
print("\nWaiting for other threads shuts down...")
|
||||
|
@ -25,7 +25,9 @@ import traceback
|
||||
|
||||
from . import builtins
|
||||
|
||||
|
||||
class Prompt:
|
||||
|
||||
def __init__(self, hc=dict(), hl=dict()):
|
||||
self.selectedServer = None
|
||||
|
||||
@ -56,8 +58,8 @@ class Prompt:
|
||||
return ret
|
||||
except:
|
||||
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||
sys.stderr.write (traceback.format_exception_only(
|
||||
exc_type, exc_value)[0])
|
||||
sys.stderr.write(traceback.format_exception_only(exc_type,
|
||||
exc_value)[0])
|
||||
return ret
|
||||
|
||||
def exec_cmd(self, toks, context):
|
||||
@ -65,7 +67,7 @@ class Prompt:
|
||||
if toks[0] in builtins.CAPS:
|
||||
return builtins.CAPS[toks[0]](toks, context, self)
|
||||
elif toks[0] in self.HOOKS_CAPS:
|
||||
(f,d) = self.HOOKS_CAPS[toks[0]]
|
||||
f, d = self.HOOKS_CAPS[toks[0]]
|
||||
return f(d, toks, context, self)
|
||||
else:
|
||||
print("Unknown command: `%s'" % toks[0])
|
||||
@ -90,7 +92,8 @@ class Prompt:
|
||||
ret = self.exec_cmd(toks, context)
|
||||
except:
|
||||
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||
traceback.print_exception(exc_type, exc_value, exc_traceback)
|
||||
traceback.print_exception(exc_type, exc_value,
|
||||
exc_traceback)
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
except EOFError:
|
||||
@ -102,6 +105,7 @@ class Prompt:
|
||||
def hotswap(prompt):
|
||||
return Prompt(prompt.HOOKS_CAPS, prompt.HOOKS_LIST)
|
||||
|
||||
|
||||
def reload():
|
||||
import prompt.builtins
|
||||
imp.reload(prompt.builtins)
|
||||
|
@ -25,6 +25,13 @@ logger = logging.getLogger("nemubot.prompt.builtins")
|
||||
from server.IRC import IRC as IRCServer
|
||||
import xmlparser
|
||||
|
||||
|
||||
def get_boolean(d, k):
|
||||
return (k in d and
|
||||
mod["autoload"].lower() != "false" and
|
||||
mod["autoload"].lower() != "off")
|
||||
|
||||
|
||||
def end(toks, context, prompt):
|
||||
"""Quit the prompt for reload or exit"""
|
||||
if toks[0] == "refresh":
|
||||
@ -52,7 +59,7 @@ def liste(toks, context, prompt):
|
||||
if len(context.modules) == 0:
|
||||
print (" > No module loaded")
|
||||
elif l in prompt.HOOKS_LIST:
|
||||
(f,d) = prompt.HOOKS_LIST[l]
|
||||
f, d = prompt.HOOKS_LIST[l]
|
||||
f(d, context, prompt)
|
||||
else:
|
||||
print (" Unknown list `%s'" % l)
|
||||
@ -65,8 +72,7 @@ def load_file(filename, context):
|
||||
config = xmlparser.parse_file(filename)
|
||||
|
||||
# This is a true nemubot configuration file, load it!
|
||||
if (config.getName() == "botconfig"
|
||||
or config.getName() == "nemubotconfig"):
|
||||
if config.getName() == "nemubotconfig":
|
||||
# Preset each server in this file
|
||||
for server in config.getNodes("server"):
|
||||
opts = {
|
||||
@ -78,7 +84,8 @@ def load_file(filename, context):
|
||||
}
|
||||
|
||||
# Optional keyword arguments
|
||||
for optional_opt in [ "port", "username", "realname", "password", "encoding", "caps" ]:
|
||||
for optional_opt in [ "port", "username", "realname",
|
||||
"password", "encoding", "caps" ]:
|
||||
if server.hasAttribute(optional_opt):
|
||||
opts[optional_opt] = server[optional_opt]
|
||||
elif optional_opt in config:
|
||||
@ -94,11 +101,14 @@ def load_file(filename, context):
|
||||
if server.hasNode("channel"):
|
||||
opts["channels"] = list()
|
||||
for chn in server.getNodes("channel"):
|
||||
opts["channels"].append((chn["name"], chn["password"]) if chn["password"] is not None else chn["name"])
|
||||
opts["channels"].append((chn["name"], chn["password"])
|
||||
if chn["password"] is not None
|
||||
else chn["name"])
|
||||
|
||||
# Server/client capabilities
|
||||
if "caps" in server or "caps" in config:
|
||||
capsl = (server["caps"] if server.hasAttribute("caps") else config["caps"]).lower()
|
||||
capsl = (server["caps"] if server.hasAttribute("caps")
|
||||
else config["caps"]).lower()
|
||||
if capsl == "no" or capsl == "off" or capsl == "false":
|
||||
opts["caps"] = None
|
||||
else:
|
||||
@ -110,14 +120,14 @@ def load_file(filename, context):
|
||||
if "protocol" not in server or server["protocol"] == "irc":
|
||||
srvcls = IRCServer
|
||||
else:
|
||||
raise Exception("Unhandled protocol '%s'" % server["protocol"])
|
||||
raise Exception("Unhandled protocol '%s'" %
|
||||
server["protocol"])
|
||||
|
||||
# Initialize the server
|
||||
srv = srvcls(**opts)
|
||||
|
||||
# Add the server in the context
|
||||
if context.add_server(srv,
|
||||
"autoconnect" in server and server["autoconnect"].lower() != "false"):
|
||||
if context.add_server(srv, get_boolean(server, "autoconnect")):
|
||||
print("Server '%s' successfully added." % srv.id)
|
||||
else:
|
||||
print("Can't add server '%s'." % srv.id)
|
||||
@ -125,7 +135,7 @@ def load_file(filename, context):
|
||||
# Load module and their configuration
|
||||
for mod in config.getNodes("module"):
|
||||
context.modules_configuration[mod["name"]] = mod
|
||||
if not mod.hasAttribute("autoload") or (mod["autoload"].lower() != "false" and mod["autoload"].lower() != "off"):
|
||||
if get_boolean(mod, "autoload"):
|
||||
__import__(mod["name"])
|
||||
|
||||
# Load files asked by the configuration file
|
||||
@ -155,8 +165,8 @@ def load(toks, context, prompt):
|
||||
|
||||
def select(toks, context, prompt):
|
||||
"""Select the current server"""
|
||||
if (len(toks) == 2 and toks[1] != "None"
|
||||
and toks[1] != "nemubot" and toks[1] != "none"):
|
||||
if (len(toks) == 2 and toks[1] != "None" and
|
||||
toks[1] != "nemubot" and toks[1] != "none"):
|
||||
if toks[1] in context.servers:
|
||||
prompt.selectedServer = context.servers[toks[1]]
|
||||
else:
|
||||
@ -197,15 +207,15 @@ def debug(toks, context, prompt):
|
||||
print ("Not enough arguments. `debug' takes a module name.")
|
||||
|
||||
|
||||
#Register build-ins
|
||||
# Register build-ins
|
||||
CAPS = {
|
||||
'quit': end, #Disconnect all server and quit
|
||||
'exit': end, #Alias for quit
|
||||
'reset': end, #Reload the prompt
|
||||
'refresh': end, #Reload the prompt but save modules
|
||||
'load': load, #Load a servers or module configuration file
|
||||
'unload': unload, #Unload a module and remove it from the list
|
||||
'select': select, #Select a server
|
||||
'list': liste, #Show lists
|
||||
'debug': debug, #Pass a module in debug mode
|
||||
'quit': end, # Disconnect all server and quit
|
||||
'exit': end, # Alias for quit
|
||||
'reset': end, # Reload the prompt
|
||||
'refresh': end, # Reload the prompt but save modules
|
||||
'load': load, # Load a servers or module configuration file
|
||||
'unload': unload, # Unload a module and remove it from the list
|
||||
'select': select, # Select a server
|
||||
'list': liste, # Show lists
|
||||
'debug': debug, # Pass a module in debug mode
|
||||
}
|
||||
|
@ -28,8 +28,11 @@ from message.printer.IRC import IRC as IRCPrinter
|
||||
from server.socket import SocketServer
|
||||
import tools
|
||||
|
||||
|
||||
class IRC(SocketServer):
|
||||
|
||||
"""Concrete implementation of a connexion to an IRC server"""
|
||||
|
||||
def __init__(self, owner, nick="nemubot", host="localhost", port=6667,
|
||||
ssl=False, username=None, password=None, realname="Nemubot",
|
||||
encoding="utf-8", caps=None, channels=list(),
|
||||
@ -155,7 +158,8 @@ class IRC(SocketServer):
|
||||
|
||||
# Respond to JOIN
|
||||
def _on_join(msg):
|
||||
if len(msg.params) == 0: return
|
||||
if len(msg.params) == 0:
|
||||
return
|
||||
|
||||
for chname in msg.decode(msg.params[0]).split(","):
|
||||
# Register the channel
|
||||
@ -164,7 +168,8 @@ class IRC(SocketServer):
|
||||
self.hookscmd["JOIN"] = _on_join
|
||||
# Respond to PART
|
||||
def _on_part(msg):
|
||||
if len(msg.params) != 1 and len(msg.params) != 2: return
|
||||
if len(msg.params) != 1 and len(msg.params) != 2:
|
||||
return
|
||||
|
||||
for chname in msg.params[0].split(b","):
|
||||
if chname in self.channels:
|
||||
@ -175,7 +180,8 @@ class IRC(SocketServer):
|
||||
self.hookscmd["PART"] = _on_part
|
||||
# Respond to 331/RPL_NOTOPIC,332/RPL_TOPIC,TOPIC
|
||||
def _on_topic(msg):
|
||||
if len(msg.params) != 1 and len(msg.params) != 2: return
|
||||
if len(msg.params) != 1 and len(msg.params) != 2:
|
||||
return
|
||||
if msg.params[0] in self.channels:
|
||||
if len(msg.params) == 1 or len(msg.params[1]) == 0:
|
||||
self.channels[msg.params[0]].topic = None
|
||||
@ -186,8 +192,10 @@ class IRC(SocketServer):
|
||||
self.hookscmd["TOPIC"] = _on_topic
|
||||
# Respond to 353/RPL_NAMREPLY
|
||||
def _on_353(msg):
|
||||
if len(msg.params) == 3: msg.params.pop(0) # 353: like RFC 1459
|
||||
if len(msg.params) != 2: return
|
||||
if len(msg.params) == 3:
|
||||
msg.params.pop(0) # 353: like RFC 1459
|
||||
if len(msg.params) != 2:
|
||||
return
|
||||
if msg.params[0] in self.channels:
|
||||
for nk in msg.decode(msg.params[1]).split(" "):
|
||||
res = re.match("^(?P<level>[^a-zA-Z[\]\\`_^{|}])(?P<nickname>[a-zA-Z[\]\\`_^{|}][a-zA-Z0-9[\]\\`_^{|}-]*)$")
|
||||
@ -196,7 +204,8 @@ class IRC(SocketServer):
|
||||
|
||||
# Respond to INVITE
|
||||
def _on_invite(msg):
|
||||
if len(msg.params) != 2: return
|
||||
if len(msg.params) != 2:
|
||||
return
|
||||
self.write("JOIN " + msg.decode(msg.params[1]))
|
||||
self.hookscmd["INVITE"] = _on_invite
|
||||
|
||||
@ -209,7 +218,8 @@ class IRC(SocketServer):
|
||||
|
||||
# Handle CTCP requests
|
||||
def _on_ctcp(msg):
|
||||
if len(msg.params) != 2 or not msg.is_ctcp: return
|
||||
if len(msg.params) != 2 or not msg.is_ctcp:
|
||||
return
|
||||
cmds = msg.decode(msg.params[1][1:len(msg.params[1])-1]).split(' ')
|
||||
if cmds[0] in self.ctcp_capabilities:
|
||||
res = self.ctcp_capabilities[cmds[0]](msg, cmds)
|
||||
@ -353,9 +363,10 @@ class IRCMessage:
|
||||
client -- export as a client-side string if true
|
||||
"""
|
||||
|
||||
res = ";".join(["@%s=%s" % (k,v if not isinstance(v, datetime) else v.strftime("%Y-%m-%dT%H:%M:%S.%fZ")) for k, v in self.tags.items()])
|
||||
res = ";".join(["@%s=%s" % (k, v if not isinstance(v, datetime) else v.strftime("%Y-%m-%dT%H:%M:%S.%fZ")) for k, v in self.tags.items()])
|
||||
|
||||
if not client: res += " :%s!%s@%s" % (self.nick, self.user, self.host)
|
||||
if not client:
|
||||
res += " :%s!%s@%s" % (self.nick, self.user, self.host)
|
||||
|
||||
res += " " + self.cmd
|
||||
|
||||
|
@ -27,6 +27,7 @@ _rlist = []
|
||||
_wlist = []
|
||||
_xlist = []
|
||||
|
||||
|
||||
# Extends from IOBase in order to be compatible with select function
|
||||
class AbstractServer(io.IOBase):
|
||||
|
||||
@ -62,7 +63,8 @@ class AbstractServer(io.IOBase):
|
||||
|
||||
|
||||
def open(self):
|
||||
"""Generic open function that register the server un _rlist in case of successful _open"""
|
||||
"""Generic open function that register the server un _rlist in case
|
||||
of successful _open"""
|
||||
self.logger.info("Opening connection to %s", self.id)
|
||||
if not hasattr(self, "_open") or self._open():
|
||||
_rlist.append(self)
|
||||
@ -70,7 +72,8 @@ class AbstractServer(io.IOBase):
|
||||
|
||||
|
||||
def close(self):
|
||||
"""Generic close function that register the server un _{r,w,x}list in case of successful _close"""
|
||||
"""Generic close function that register the server un _{r,w,x}list in
|
||||
case of successful _close"""
|
||||
self.logger.info("Closing connection to %s", self.id)
|
||||
if not hasattr(self, "_close") or self._close():
|
||||
if self in _rlist:
|
||||
|
@ -21,8 +21,11 @@ import socket
|
||||
|
||||
from server import AbstractServer
|
||||
|
||||
|
||||
class SocketServer(AbstractServer):
|
||||
|
||||
"""Concrete implementation of a socket connexion (can be wrapped with TLS)"""
|
||||
|
||||
def __init__(self, host, port, ssl=False):
|
||||
AbstractServer.__init__(self)
|
||||
self.host = host
|
||||
@ -55,12 +58,13 @@ class SocketServer(AbstractServer):
|
||||
self.socket = ctx.wrap_socket(self.socket)
|
||||
|
||||
try:
|
||||
self.socket.connect((self.host, self.port)) #Connect to server
|
||||
self.socket.connect((self.host, self.port)) # Connect to server
|
||||
self.logger.info("Connected to %s:%d", self.host, self.port)
|
||||
except socket.error as e:
|
||||
self.socket = None
|
||||
self.logger.critical("Unable to connect to %s:%d: %s",
|
||||
self.host, self.port, os.strerror(e.errno))
|
||||
self.host, self.port,
|
||||
os.strerror(e.errno))
|
||||
return False
|
||||
|
||||
return True
|
||||
@ -81,7 +85,8 @@ class SocketServer(AbstractServer):
|
||||
# Write
|
||||
|
||||
def _write(self, cnt):
|
||||
if not self.connected: return
|
||||
if not self.connected:
|
||||
return
|
||||
|
||||
self.socket.send(cnt)
|
||||
|
||||
@ -96,7 +101,8 @@ class SocketServer(AbstractServer):
|
||||
# Read
|
||||
|
||||
def read(self):
|
||||
if not self.connected: return
|
||||
if not self.connected:
|
||||
return
|
||||
|
||||
raw = self.socket.recv(1024)
|
||||
temp = (self.readbuffer + raw).split(b'\r\n')
|
||||
|
@ -18,14 +18,16 @@
|
||||
|
||||
import imp
|
||||
|
||||
|
||||
def intToIP(n):
|
||||
ip = ""
|
||||
for i in range(0,4):
|
||||
for i in range(0, 4):
|
||||
mod = n % 256
|
||||
ip = "%d.%s" % (mod, ip)
|
||||
n = (n - mod) / 256
|
||||
return ip[:len(ip) - 1]
|
||||
|
||||
|
||||
def ipToInt(ip):
|
||||
sum = 0
|
||||
for b in ip.split("."):
|
||||
|
@ -19,6 +19,7 @@
|
||||
from datetime import datetime, timezone
|
||||
import time
|
||||
|
||||
|
||||
def countdown(delta, resolution=5):
|
||||
sec = delta.seconds
|
||||
hours, remainder = divmod(sec, 3600)
|
||||
@ -31,7 +32,7 @@ def countdown(delta, resolution=5):
|
||||
|
||||
if resolution > 0 and (force or an > 0):
|
||||
force = True
|
||||
sentence += " %i an"%(an)
|
||||
sentence += " %i an" % an
|
||||
|
||||
if an > 1:
|
||||
sentence += "s"
|
||||
@ -42,7 +43,7 @@ def countdown(delta, resolution=5):
|
||||
|
||||
if resolution > 1 and (force or days > 0):
|
||||
force = True
|
||||
sentence += " %i jour"%(days)
|
||||
sentence += " %i jour" % days
|
||||
|
||||
if days > 1:
|
||||
sentence += "s"
|
||||
@ -53,7 +54,7 @@ def countdown(delta, resolution=5):
|
||||
|
||||
if resolution > 2 and (force or hours > 0):
|
||||
force = True
|
||||
sentence += " %i heure"%(hours)
|
||||
sentence += " %i heure" % hours
|
||||
if hours > 1:
|
||||
sentence += "s"
|
||||
if resolution > 4:
|
||||
@ -63,7 +64,7 @@ def countdown(delta, resolution=5):
|
||||
|
||||
if resolution > 3 and (force or minutes > 0):
|
||||
force = True
|
||||
sentence += " %i minute"%(minutes)
|
||||
sentence += " %i minute" % minutes
|
||||
if minutes > 1:
|
||||
sentence += "s"
|
||||
if resolution > 4:
|
||||
@ -71,20 +72,21 @@ def countdown(delta, resolution=5):
|
||||
|
||||
if resolution > 4 and (force or seconds > 0):
|
||||
force = True
|
||||
sentence += " %i seconde"%(seconds)
|
||||
sentence += " %i seconde" % seconds
|
||||
if seconds > 1:
|
||||
sentence += "s"
|
||||
return sentence[1:]
|
||||
|
||||
|
||||
def countdown_format(date, msg_before, msg_after, tz=None):
|
||||
"""Replace in a text %s by a sentence incidated the remaining time before/after an event"""
|
||||
if tz != None:
|
||||
"""Replace in a text %s by a sentence incidated the remaining time
|
||||
before/after an event"""
|
||||
if tz is not None:
|
||||
oldtz = os.environ['TZ']
|
||||
os.environ['TZ'] = tz
|
||||
time.tzset()
|
||||
|
||||
#Calculate time before the date
|
||||
# Calculate time before the date
|
||||
try:
|
||||
if datetime.now(timezone.utc) > date:
|
||||
sentence_c = msg_after
|
||||
@ -100,8 +102,7 @@ def countdown_format(date, msg_before, msg_after, tz=None):
|
||||
sentence_c = msg_before
|
||||
delta = date - datetime.now()
|
||||
|
||||
|
||||
if tz != None:
|
||||
if tz is not None:
|
||||
os.environ['TZ'] = oldtz
|
||||
|
||||
return sentence_c % countdown(delta)
|
||||
|
@ -29,24 +29,37 @@ xtrdt = re.compile(r'''^.*? (?P<day>[0-9]{1,4}) .+?
|
||||
(?:[^0-9]*[m\":][^0-9]*(?P<second>[0-9]{1,2}))?)?)?.*?
|
||||
$''', re.X)
|
||||
|
||||
|
||||
def extractDate(msg):
|
||||
"""Parse a message to extract a time and date"""
|
||||
result = xtrdt.match(msg.lower())
|
||||
if result is not None:
|
||||
day = result.group("day")
|
||||
month = result.group("month")
|
||||
if month == "janvier" or month == "january" or month == "januar": month = 1
|
||||
elif month == "fevrier" or month == "février" or month == "february": month = 2
|
||||
elif month == "mars" or month == "march": month = 3
|
||||
elif month == "avril" or month == "april": month = 4
|
||||
elif month == "mai" or month == "may" or month == "maï": month = 5
|
||||
elif month == "juin" or month == "juni" or month == "junni": month = 6
|
||||
elif month == "juillet" or month == "jully" or month == "july": month = 7
|
||||
elif month == "aout" or month == "août" or month == "august": month = 8
|
||||
elif month == "september" or month == "septembre": month = 9
|
||||
elif month == "october" or month == "october" or month == "oktober": month = 10
|
||||
elif month == "november" or month == "novembre": month = 11
|
||||
elif month == "december" or month == "decembre" or month == "décembre": month = 12
|
||||
if month == "janvier" or month == "january" or month == "januar":
|
||||
month = 1
|
||||
elif month == "fevrier" or month == "février" or month == "february":
|
||||
month = 2
|
||||
elif month == "mars" or month == "march":
|
||||
month = 3
|
||||
elif month == "avril" or month == "april":
|
||||
month = 4
|
||||
elif month == "mai" or month == "may" or month == "maï":
|
||||
month = 5
|
||||
elif month == "juin" or month == "juni" or month == "junni":
|
||||
month = 6
|
||||
elif month == "juillet" or month == "jully" or month == "july":
|
||||
month = 7
|
||||
elif month == "aout" or month == "août" or month == "august":
|
||||
month = 8
|
||||
elif month == "september" or month == "septembre":
|
||||
month = 9
|
||||
elif month == "october" or month == "october" or month == "oktober":
|
||||
month = 10
|
||||
elif month == "november" or month == "novembre":
|
||||
month = 11
|
||||
elif month == "december" or month == "decembre" or month == "décembre":
|
||||
month = 12
|
||||
|
||||
year = result.group("year")
|
||||
|
||||
@ -57,9 +70,12 @@ def extractDate(msg):
|
||||
minute = result.group("minute")
|
||||
second = result.group("second")
|
||||
|
||||
if year is None: year = date.today().year
|
||||
if hour is None: hour = 0
|
||||
if minute is None: minute = 0
|
||||
if year is None:
|
||||
year = date.today().year
|
||||
if hour is None:
|
||||
hour = 0
|
||||
if minute is None:
|
||||
minute = 0
|
||||
if second is None:
|
||||
second = 1
|
||||
else:
|
||||
@ -68,6 +84,7 @@ def extractDate(msg):
|
||||
minute = int(minute) + 1
|
||||
second = 0
|
||||
|
||||
return datetime(int(year), int(month), int(day), int(hour), int(minute), int(second))
|
||||
return datetime(int(year), int(month), int(day),
|
||||
int(hour), int(minute), int(second))
|
||||
else:
|
||||
return None
|
||||
|
33
tools/web.py
33
tools/web.py
@ -28,31 +28,39 @@ from urllib.request import urlopen
|
||||
from exception import IRCException
|
||||
import xmlparser
|
||||
|
||||
|
||||
def isURL(url):
|
||||
"""Return True if the URL can be parsed"""
|
||||
o = urlparse(url)
|
||||
return o.scheme == "" and o.netloc == "" and o.path == ""
|
||||
|
||||
|
||||
def getScheme(url):
|
||||
"""Return the protocol of a given URL"""
|
||||
o = urlparse(url)
|
||||
return o.scheme
|
||||
|
||||
|
||||
def getHost(url):
|
||||
"""Return the domain of a given URL"""
|
||||
return urlparse(url).netloc
|
||||
|
||||
|
||||
def getPort(url):
|
||||
"""Return the port of a given URL"""
|
||||
return urlparse(url).port
|
||||
|
||||
|
||||
def getPath(url):
|
||||
"""Return the page request of a given URL"""
|
||||
return urlparse(url).path
|
||||
|
||||
|
||||
def getUser(url):
|
||||
"""Return the page request of a given URL"""
|
||||
return urlparse(url).username
|
||||
|
||||
|
||||
def getPassword(url):
|
||||
"""Return the page request of a given URL"""
|
||||
return urlparse(url).password
|
||||
@ -67,16 +75,19 @@ def getURLContent(url, timeout=15):
|
||||
o = urlparse("http://" + url)
|
||||
|
||||
if o.scheme == "http":
|
||||
conn = http.client.HTTPConnection(o.netloc, port=o.port, timeout=timeout)
|
||||
conn = http.client.HTTPConnection(o.netloc, port=o.port,
|
||||
timeout=timeout)
|
||||
elif o.scheme == "https":
|
||||
conn = http.client.HTTPSConnection(o.netloc, port=o.port, timeout=timeout)
|
||||
conn = http.client.HTTPSConnection(o.netloc, port=o.port,
|
||||
timeout=timeout)
|
||||
elif o.scheme is None or o.scheme == "":
|
||||
conn = http.client.HTTPConnection(o.netloc, port=80, timeout=timeout)
|
||||
else:
|
||||
return None
|
||||
try:
|
||||
if o.query != '':
|
||||
conn.request("GET", o.path + "?" + o.query, None, {"User-agent": "Nemubot v3"})
|
||||
conn.request("GET", o.path + "?" + o.query,
|
||||
None, {"User-agent": "Nemubot v3"})
|
||||
else:
|
||||
conn.request("GET", o.path, None, {"User-agent": "Nemubot v3"})
|
||||
except socket.timeout:
|
||||
@ -115,10 +126,14 @@ def getURLContent(url, timeout=15):
|
||||
|
||||
if res.status == http.client.OK or res.status == http.client.SEE_OTHER:
|
||||
return data.decode(charset)
|
||||
elif (res.status == http.client.FOUND or res.status == http.client.MOVED_PERMANENTLY) and res.getheader("Location") != url:
|
||||
elif ((res.status == http.client.FOUND or
|
||||
res.status == http.client.MOVED_PERMANENTLY) and
|
||||
res.getheader("Location") != url):
|
||||
return getURLContent(res.getheader("Location"), timeout)
|
||||
else:
|
||||
raise IRCException("A HTTP error occurs: %d - %s" % (res.status, http.client.responses[res.status]))
|
||||
raise IRCException("A HTTP error occurs: %d - %s" %
|
||||
(res.status, http.client.responses[res.status]))
|
||||
|
||||
|
||||
def getXML(url, timeout=15):
|
||||
"""Get content page and return XML parsed content"""
|
||||
@ -128,6 +143,7 @@ def getXML(url, timeout=15):
|
||||
else:
|
||||
return xmlparser.parse_string(cnt.encode())
|
||||
|
||||
|
||||
def getJSON(url, timeout=15):
|
||||
"""Get content page and return JSON content"""
|
||||
cnt = getURLContent(url, timeout)
|
||||
@ -136,6 +152,7 @@ def getJSON(url, timeout=15):
|
||||
else:
|
||||
return json.loads(cnt.decode())
|
||||
|
||||
|
||||
# Other utils
|
||||
|
||||
def htmlentitydecode(s):
|
||||
@ -143,7 +160,11 @@ def htmlentitydecode(s):
|
||||
return re.sub('&(%s);' % '|'.join(name2codepoint),
|
||||
lambda m: chr(name2codepoint[m.group(1)]), s)
|
||||
|
||||
|
||||
def striphtml(data):
|
||||
"""Remove HTML tags from text"""
|
||||
p = re.compile(r'<.*?>')
|
||||
return htmlentitydecode(p.sub('', data).replace("(", "/(").replace(")", ")/").replace(""", "\""))
|
||||
return htmlentitydecode(p.sub('', data)
|
||||
.replace("(", "/(")
|
||||
.replace(")", ")/")
|
||||
.replace(""", "\""))
|
||||
|
@ -25,6 +25,7 @@ from . import node as module_state
|
||||
|
||||
logger = logging.getLogger("nemubot.xmlparser")
|
||||
|
||||
|
||||
class ModuleStatesFile(xml.sax.ContentHandler):
|
||||
def startDocument(self):
|
||||
self.root = None
|
||||
@ -50,6 +51,7 @@ class ModuleStatesFile(xml.sax.ContentHandler):
|
||||
else:
|
||||
self.root = child
|
||||
|
||||
|
||||
def parse_file(filename):
|
||||
parser = xml.sax.make_parser()
|
||||
mod = ModuleStatesFile()
|
||||
@ -67,6 +69,7 @@ def parse_file(filename):
|
||||
else:
|
||||
return mod.root
|
||||
|
||||
|
||||
def parse_string(string):
|
||||
mod = ModuleStatesFile()
|
||||
try:
|
||||
|
@ -9,6 +9,7 @@ import traceback
|
||||
|
||||
logger = logging.getLogger("nemubot.xmlparser.node")
|
||||
|
||||
|
||||
class ModuleState:
|
||||
"""Tiny tree representation of an XML file"""
|
||||
|
||||
@ -30,7 +31,8 @@ class ModuleState:
|
||||
out = list()
|
||||
for k in self.attributes:
|
||||
out.append("%s : %s" % (k, self.attributes[k]))
|
||||
ret += "%s%s { %s } = '%s'\n" % (' ' * level, self.name, ' ; '.join(out), self.content)
|
||||
ret += "%s%s { %s } = '%s'\n" % (' ' * level, self.name,
|
||||
' ; '.join(out), self.content)
|
||||
for c in self.childs:
|
||||
ret += c.display(level + 2)
|
||||
return ret
|
||||
@ -71,7 +73,8 @@ class ModuleState:
|
||||
while True:
|
||||
try:
|
||||
return datetime.fromtimestamp(time.mktime(
|
||||
time.strptime(source[:19], "%Y-%m-%d %H:%M:%S")), timezone.utc)
|
||||
time.strptime(source[:19], "%Y-%m-%d %H:%M:%S")),
|
||||
timezone.utc)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
@ -100,12 +103,14 @@ class ModuleState:
|
||||
def tmpIndex(self, fieldname="name", tagname=None):
|
||||
index = dict()
|
||||
for child in self.childs:
|
||||
if (tagname is None or tagname == child.name) and child.hasAttribute(fieldname):
|
||||
if ((tagname is None or tagname == child.name) and
|
||||
child.hasAttribute(fieldname)):
|
||||
index[child[fieldname]] = child
|
||||
return index
|
||||
|
||||
def setIndex(self, fieldname="name", tagname=None):
|
||||
"""Defines an hash table to accelerate childs search. You have just to define a common attribute"""
|
||||
"""Defines an hash table to accelerate childs search.
|
||||
You have just to define a common attribute"""
|
||||
self.index = self.tmpIndex(fieldname, tagname)
|
||||
self.index_fieldname = fieldname
|
||||
self.index_tagname = tagname
|
||||
@ -123,10 +128,12 @@ class ModuleState:
|
||||
|
||||
def setAttribute(self, name, value):
|
||||
"""DOM like method"""
|
||||
if isinstance(value, datetime) or isinstance(value, str) or isinstance(value, int) or isinstance(value, float):
|
||||
if (isinstance(value, datetime) or isinstance(value, str) or
|
||||
isinstance(value, int) or isinstance(value, float)):
|
||||
self.attributes[name] = value
|
||||
else:
|
||||
raise TypeError("attributes must be primary type or datetime (here %s)" % type(value))
|
||||
raise TypeError("attributes must be primary type "
|
||||
"or datetime (here %s)" % type(value))
|
||||
|
||||
def getContent(self):
|
||||
return self.content
|
||||
@ -181,7 +188,8 @@ class ModuleState:
|
||||
for att in self.attributes.keys():
|
||||
if att[0] != "_": # Don't save attribute starting by _
|
||||
if isinstance(self.attributes[att], datetime):
|
||||
attribs[att] = str(time.mktime(self.attributes[att].timetuple()))
|
||||
attribs[att] = str(time.mktime(
|
||||
self.attributes[att].timetuple()))
|
||||
else:
|
||||
attribs[att] = str(self.attributes[att])
|
||||
attrs = xml.sax.xmlreader.AttributesImpl(attribs)
|
||||
@ -194,11 +202,12 @@ class ModuleState:
|
||||
|
||||
gen.endElement(self.name)
|
||||
except:
|
||||
logger.exception("Error occured when saving the following XML node: %s with %s", self.name, attrs)
|
||||
logger.exception("Error occured when saving the following "
|
||||
"XML node: %s with %s", self.name, attrs)
|
||||
|
||||
def save(self, filename):
|
||||
"""Save the current node as root node in a XML file"""
|
||||
with open(filename,"w") as f:
|
||||
with open(filename, "w") as f:
|
||||
gen = xml.sax.saxutils.XMLGenerator(f, "utf-8")
|
||||
gen.startDocument()
|
||||
self.save_node(gen)
|
||||
|
Loading…
Reference in New Issue
Block a user