3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-11-30 14:49:28 +01:00

It's almost June! Updates:

- Move config handling into separate module
- Implement identify and status commands, currently only supporting the admin account defined in the config. Closes #1.
- Move proto.add_cmd to utils.py, rename _msg() to msg()
- Allow sending the command name as an optional argument in add_cmd
- Add catch-all exception handling in plugins to prevent them from crashing the program!
This commit is contained in:
James Lu 2015-05-31 12:20:09 -07:00
parent 0e53a0fee4
commit d9db7e1b9e
6 changed files with 79 additions and 31 deletions

5
conf.py Normal file
View File

@ -0,0 +1,5 @@
import yaml
with open("config.yml", 'r') as f:
global conf
conf = yaml.load(f)

16
main.py
View File

@ -1,20 +1,17 @@
#!/usr/bin/python3 #!/usr/bin/python3
import yaml
import imp import imp
import os import os
import socket import socket
import time import time
import sys import sys
from conf import conf
import proto import proto
print('PyLink starting...')
with open("config.yml", 'r') as f: if conf['login']['password'] == 'changeme':
conf = yaml.load(f) print("You have not set the login details correctly! Exiting...")
sys.exit(2)
# if conf['login']['password'] == 'changeme':
# print("You have not set the login details correctly! Exiting...")
class Irc(): class Irc():
def __init__(self): def __init__(self):
@ -74,5 +71,6 @@ class Irc():
self.loaded.append(imp.load_source(plugin, moduleinfo[1])) self.loaded.append(imp.load_source(plugin, moduleinfo[1]))
print("loaded plugins: %s" % self.loaded) print("loaded plugins: %s" % self.loaded)
if __name__ == '__main__':
irc_obj = Irc() print('PyLink starting...')
irc_obj = Irc()

View File

@ -3,22 +3,54 @@ import sys, os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import proto import proto
import utils import utils
from conf import conf
@proto.add_cmd @utils.add_cmd
def tell(irc, source, args): def tell(irc, source, args):
try: try:
target, text = args[0], ' '.join(args[1:]) target, text = args[0], ' '.join(args[1:])
except IndexError: except IndexError:
utils._msg(irc, source, 'Error: not enough arguments.', notice=False) utils.msg(irc, source, 'Error: not enough arguments.')
return return
targetuid = proto._nicktoUid(irc, target) targetuid = proto._nicktoUid(irc, target)
if targetuid is None: if targetuid is None:
utils._msg(irc, source, 'Error: unknown user %r' % target, notice=False) utils.msg(irc, source, 'Error: unknown user %r' % target)
return return
utils._msg(irc, target, text) if not text:
utils.msg(irc, source, "Error: can't send an empty message!")
return
utils.msg(irc, target, text, notice=True)
@proto.add_cmd @utils.add_cmd
def debug(irc, source, args): def debug(irc, source, args):
utils._msg(irc, source, 'Debug info printed to console.') utils.msg(irc, source, 'Debug info printed to console.')
print(irc.users) print(irc.users)
print(irc.servers) print(irc.servers)
@utils.add_cmd
def status(irc, source, args):
identified = irc.users[source].identified
if identified:
utils.msg(irc, source, 'You are identified as %s.' % identified)
else:
utils.msg(irc, source, 'You are not identified as anyone.')
@utils.add_cmd
def identify(irc, source, args):
try:
username, password = args[0], args[1]
except IndexError:
utils.msg(irc, source, 'Error: not enough arguments.')
return
if username.lower() == conf['login']['user'].lower() and password == conf['login']['password']:
realuser = conf['login']['user']
irc.users[source].identified = realuser
utils.msg(irc, source, 'Successfully logged in as %s.' % realuser)
else:
utils.msg(irc, source, 'Incorrect credentials.')
def listcommands(irc, source, args):
cmds = list(utils.bot_commands.keys())
cmds.sort()
utils.msg(irc, source, 'Available commands include: %s' % ', '.join(cmds))
utils.add_cmd(listcommands, 'list')

View File

@ -1,7 +1,7 @@
import sys, os import sys, os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import proto import utils
@proto.add_cmd @utils.add_cmd
def hello(irc, source, args): def hello(irc, source, args):
proto._sendFromUser(irc, 'PRIVMSG %s :hello!' % source) utils.msg(irc, source, 'hello!')

View File

@ -3,10 +3,7 @@ import time
import sys import sys
from utils import * from utils import *
from copy import copy from copy import copy
import traceback
global bot_commands
# This should be a mapping of command names to functions
bot_commands = {}
class IrcUser(): class IrcUser():
def __init__(self, nick, ts, uid, ident='null', host='null', def __init__(self, nick, ts, uid, ident='null', host='null',
@ -21,6 +18,8 @@ class IrcUser():
self.ip = ip self.ip = ip
self.realname = realname self.realname = realname
self.identified = False
def __repr__(self): def __repr__(self):
return repr(self.__dict__) return repr(self.__dict__)
@ -48,12 +47,12 @@ def _nicktoUid(irc, nick):
if v.nick == nick: if v.nick == nick:
return k return k
def introduceUser(irc, nick, user, host): def spawnClient(irc, nick, user, host, *args):
uid = next_uid(irc.sid) uid = next_uid(irc.sid)
_sendFromServer(irc, "UID {uid} {ts} {nick} {host} {host} {user} 0.0.0.0 {ts} +o +" _sendFromServer(irc, "UID {uid} {ts} {nick} {host} {host} {user} 0.0.0.0 {ts} +o +"
" :PyLink Client".format(ts=int(time.time()), host=host, " :PyLink Client".format(ts=int(time.time()), host=host,
nick=nick, user=user, uid=uid)) nick=nick, user=user, uid=uid))
irc.users[uid] = IrcUser(nick, ts, uid, ident, host, realname, realhost, ip) irc.users[uid] = IrcUser(nick, ts, uid, ident, host, *args)
irc.servers[irc.sid].users.append(uid) irc.servers[irc.sid].users.append(uid)
def connect(irc): def connect(irc):
@ -96,15 +95,22 @@ def handle_privmsg(irc, source, command, args):
prefix = irc.conf['bot']['prefix'] prefix = irc.conf['bot']['prefix']
if args[0] == irc.pseudoclient.uid: if args[0] == irc.pseudoclient.uid:
cmd_args = args[1].split(' ') cmd_args = args[1].split(' ')
cmd = cmd_args[0] cmd = cmd_args[0].lower()
try: try:
cmd_args = cmd_args[1:] cmd_args = cmd_args[1:]
except IndexError: except IndexError:
cmd_args = [] cmd_args = []
try: try:
bot_commands[cmd](irc, source, cmd_args) func = bot_commands[cmd]
except KeyError: except KeyError:
_sendFromUser(irc, 'PRIVMSG %s :unknown command %r' % (source, cmd)) msg(irc, source, 'Unknown command %r.' % cmd)
return
try:
func(irc, source, cmd_args)
except Exception as e:
traceback.print_exc()
msg(irc, source, 'Uncaught exception in command %r: %s: %s' % (cmd, type(e).__name__, str(e)))
return
def handle_error(irc, numeric, command, args): def handle_error(irc, numeric, command, args):
print('Received an ERROR, killing!') print('Received an ERROR, killing!')
@ -214,6 +220,3 @@ def handle_events(irc, data):
func(irc, numeric, command, args) func(irc, numeric, command, args)
except KeyError: # unhandled event except KeyError: # unhandled event
pass pass
def add_cmd(func):
bot_commands[func.__name__.lower()] = func

View File

@ -1,6 +1,10 @@
import string import string
import proto import proto
global bot_commands
# This should be a mapping of command names to functions
bot_commands = {}
# From http://www.inspircd.org/wiki/Modules/spanningtree/UUIDs.html # From http://www.inspircd.org/wiki/Modules/spanningtree/UUIDs.html
chars = string.digits + string.ascii_uppercase chars = string.digits + string.ascii_uppercase
iters = [iter(chars) for _ in range(6)] iters = [iter(chars) for _ in range(6)]
@ -13,6 +17,12 @@ def next_uid(sid, level=-1):
except StopIteration: except StopIteration:
return UID(level-1) return UID(level-1)
def _msg(irc, target, text, notice=True): def msg(irc, target, text, notice=False):
command = 'NOTICE' if notice else 'PRIVMSG' command = 'NOTICE' if notice else 'PRIVMSG'
proto._sendFromUser(irc, '%s %s :%s' % (command, target, text)) proto._sendFromUser(irc, '%s %s :%s' % (command, target, text))
def add_cmd(func, name=None):
if name is None:
name = func.__name__
name = name.lower()
bot_commands[name] = func