Add eval/exec to RPC
This commit is contained in:
parent
c2e2199b02
commit
5a511944bd
|
@ -8,3 +8,4 @@ build
|
||||||
pyircbot.egg-info
|
pyircbot.egg-info
|
||||||
dev
|
dev
|
||||||
docs/builder/build.sh
|
docs/builder/build.sh
|
||||||
|
examples/config.test.json
|
||||||
|
|
|
@ -47,7 +47,7 @@ We can retrieve an arbitrary property from a module:
|
||||||
[True, {'apikey': 'deadbeefcafe', 'defaultUnit': 'f'}]
|
[True, {'apikey': 'deadbeefcafe', 'defaultUnit': 'f'}]
|
||||||
>>>
|
>>>
|
||||||
|
|
||||||
Or run a method in a module, passing args:
|
Run a method in a module, passing args:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -55,6 +55,71 @@ Or run a method in a module, passing args:
|
||||||
[True, {'definition': "Loyal, unlike its predecessor", 'word': 'rhobot2', 'by': 'xMopxShell'}]
|
[True, {'definition': "Loyal, unlike its predecessor", 'word': 'rhobot2', 'by': 'xMopxShell'}]
|
||||||
>>>
|
>>>
|
||||||
|
|
||||||
|
Or simply pass a string to eval() or exec() to do anything. In this case,
|
||||||
|
retrieving a full stack trace of the bot, which is useful during module
|
||||||
|
development:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> print( rpc.eval("self.bot.irc.trace()")[1] )
|
||||||
|
|
||||||
|
*** STACKTRACE - START ***
|
||||||
|
|
||||||
|
# ThreadID: 140289192748800
|
||||||
|
File: "/usr/lib/python3.4/threading.py", line 888, in _bootstrap
|
||||||
|
self._bootstrap_inner()
|
||||||
|
File: "/usr/lib/python3.4/threading.py", line 920, in _bootstrap_inner
|
||||||
|
self.run()
|
||||||
|
File: "/usr/lib/python3.4/threading.py", line 1184, in run
|
||||||
|
self.finished.wait(self.interval)
|
||||||
|
File: "/usr/lib/python3.4/threading.py", line 552, in wait
|
||||||
|
signaled = self._cond.wait(timeout)
|
||||||
|
File: "/usr/lib/python3.4/threading.py", line 293, in wait
|
||||||
|
gotit = waiter.acquire(True, timeout)
|
||||||
|
|
||||||
|
# ThreadID: 140289297204992
|
||||||
|
File: "/usr/lib/python3.4/threading.py", line 888, in _bootstrap
|
||||||
|
self._bootstrap_inner()
|
||||||
|
File: "/usr/lib/python3.4/threading.py", line 920, in _bootstrap_inner
|
||||||
|
self.run()
|
||||||
|
File: "/usr/local/lib/python3.4/dist-packages/pyircbot-4.0.0_r02-py3.4.egg/pyircbot/rpc.py", line 51, in run
|
||||||
|
self.server.serve()
|
||||||
|
File: "/usr/local/lib/python3.4/dist-packages/pyircbot-4.0.0_r02-py3.4.egg/pyircbot/jsonrpc.py", line 1110, in serve
|
||||||
|
self.__transport.serve( self.handle, n )
|
||||||
|
File: "/usr/local/lib/python3.4/dist-packages/pyircbot-4.0.0_r02-py3.4.egg/pyircbot/jsonrpc.py", line 851, in serve
|
||||||
|
result = handler(data)
|
||||||
|
File: "/usr/local/lib/python3.4/dist-packages/pyircbot-4.0.0_r02-py3.4.egg/pyircbot/jsonrpc.py", line 1086, in handle
|
||||||
|
result = self.funcs[method]( *params )
|
||||||
|
File: "/usr/local/lib/python3.4/dist-packages/pyircbot-4.0.0_r02-py3.4.egg/pyircbot/rpc.py", line 167, in eval
|
||||||
|
return (True, eval(code))
|
||||||
|
File: "<string>", line 1, in <module>
|
||||||
|
File: "/usr/local/lib/python3.4/dist-packages/pyircbot-4.0.0_r02-py3.4.egg/pyircbot/irccore.py", line 288, in trace
|
||||||
|
for filename, lineno, name, line in traceback.extract_stack(stack):
|
||||||
|
|
||||||
|
# ThreadID: 140289333405504
|
||||||
|
File: "/usr/local/bin/pyircbot", line 5, in <module>
|
||||||
|
pkg_resources.run_script('pyircbot==4.0.0-r02', 'pyircbot')
|
||||||
|
File: "/usr/lib/python3/dist-packages/pkg_resources.py", line 528, in run_script
|
||||||
|
self.require(requires)[0].run_script(script_name, ns)
|
||||||
|
File: "/usr/lib/python3/dist-packages/pkg_resources.py", line 1394, in run_script
|
||||||
|
execfile(script_filename, namespace, namespace)
|
||||||
|
File: "/usr/lib/python3/dist-packages/pkg_resources.py", line 55, in execfile
|
||||||
|
exec(compile(open(fn).read(), fn, 'exec'), globs, locs)
|
||||||
|
File: "/usr/local/lib/python3.4/dist-packages/pyircbot-4.0.0_r02-py3.4.egg/EGG-INFO/scripts/pyircbot", line 32, in <module>
|
||||||
|
bot.loop()
|
||||||
|
File: "/usr/local/lib/python3.4/dist-packages/pyircbot-4.0.0_r02-py3.4.egg/pyircbot/pyircbot.py", line 68, in loop
|
||||||
|
self.irc.loop()
|
||||||
|
File: "/usr/local/lib/python3.4/dist-packages/pyircbot-4.0.0_r02-py3.4.egg/pyircbot/irccore.py", line 56, in loop
|
||||||
|
asyncore.loop(map=self.asynmap)
|
||||||
|
File: "/usr/lib/python3.4/asyncore.py", line 208, in loop
|
||||||
|
poll_fun(timeout, map)
|
||||||
|
File: "/usr/lib/python3.4/asyncore.py", line 145, in poll
|
||||||
|
r, w, e = select.select(r, w, e, timeout)
|
||||||
|
|
||||||
|
*** STACKTRACE - END ***
|
||||||
|
|
||||||
|
>>>
|
||||||
|
|
||||||
Careful, you can probably crash the bot by tweaking the wrong things. Only
|
Careful, you can probably crash the bot by tweaking the wrong things. Only
|
||||||
basic types can be passed over the RPC connection. Trying to access anything
|
basic types can be passed over the RPC connection. Trying to access anything
|
||||||
extra results in an error:
|
extra results in an error:
|
||||||
|
|
|
@ -11,364 +11,377 @@ import asynchat
|
||||||
import asyncore
|
import asyncore
|
||||||
import logging
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
|
import sys
|
||||||
from socket import SHUT_RDWR
|
from socket import SHUT_RDWR
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
except:
|
except:
|
||||||
from io import BytesIO as StringIO
|
from io import BytesIO as StringIO
|
||||||
|
|
||||||
class IRCCore(asynchat.async_chat):
|
class IRCCore(asynchat.async_chat):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
asynchat.async_chat.__init__(self)
|
asynchat.async_chat.__init__(self)
|
||||||
|
|
||||||
self.connected=False
|
self.connected=False
|
||||||
"""If we're connected or not"""
|
"""If we're connected or not"""
|
||||||
|
|
||||||
self.log = logging.getLogger('IRCCore')
|
self.log = logging.getLogger('IRCCore')
|
||||||
"""Reference to logger object"""
|
"""Reference to logger object"""
|
||||||
|
|
||||||
self.buffer = StringIO()
|
self.buffer = StringIO()
|
||||||
"""cStringIO used as a buffer"""
|
"""cStringIO used as a buffer"""
|
||||||
|
|
||||||
self.alive = True
|
self.alive = True
|
||||||
"""True if we should try to stay connected"""
|
"""True if we should try to stay connected"""
|
||||||
|
|
||||||
self.server = None
|
self.server = None
|
||||||
"""Server address"""
|
"""Server address"""
|
||||||
self.port = 0
|
self.port = 0
|
||||||
"""Server port"""
|
"""Server port"""
|
||||||
self.ipv6 = False
|
self.ipv6 = False
|
||||||
"""Use IPv6?"""
|
"""Use IPv6?"""
|
||||||
|
|
||||||
# IRC Messages are terminated with \r\n
|
# IRC Messages are terminated with \r\n
|
||||||
self.set_terminator(b"\r\n")
|
self.set_terminator(b"\r\n")
|
||||||
|
|
||||||
# Set up hooks for modules
|
# Set up hooks for modules
|
||||||
self.initHooks()
|
self.initHooks()
|
||||||
|
|
||||||
# Map for asynchat
|
# Map for asynchat
|
||||||
self.asynmap = {}
|
self.asynmap = {}
|
||||||
|
|
||||||
def loop(self):
|
def loop(self):
|
||||||
asyncore.loop(map=self.asynmap)
|
asyncore.loop(map=self.asynmap)
|
||||||
|
|
||||||
def kill(self):
|
def kill(self):
|
||||||
"""TODO close the socket"""
|
"""TODO close the socket"""
|
||||||
self.act_QUIT("Help! Another thread is killing me :(")
|
self.act_QUIT("Help! Another thread is killing me :(")
|
||||||
|
|
||||||
" Net related code here on down "
|
" Net related code here on down "
|
||||||
|
|
||||||
def getBuf(self):
|
def getBuf(self):
|
||||||
"""Return the network buffer and clear it"""
|
"""Return the network buffer and clear it"""
|
||||||
self.buffer.seek(0)
|
self.buffer.seek(0)
|
||||||
data = self.buffer.read()
|
data = self.buffer.read()
|
||||||
self.buffer = StringIO()
|
self.buffer = StringIO()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def collect_incoming_data(self, data):
|
def collect_incoming_data(self, data):
|
||||||
"""Recieve data from the IRC server, append it to the buffer
|
"""Recieve data from the IRC server, append it to the buffer
|
||||||
|
|
||||||
:param data: the data that was recieved
|
:param data: the data that was recieved
|
||||||
:type data: str"""
|
:type data: str"""
|
||||||
#self.log.debug("<< %(message)s", {"message":repr(data)})
|
#self.log.debug("<< %(message)s", {"message":repr(data)})
|
||||||
self.buffer.write(data)
|
self.buffer.write(data)
|
||||||
|
|
||||||
def found_terminator(self):
|
def found_terminator(self):
|
||||||
"""A complete command was pushed through, so clear the buffer and process it."""
|
"""A complete command was pushed through, so clear the buffer and process it."""
|
||||||
line = None
|
line = None
|
||||||
buf = self.getBuf()
|
buf = self.getBuf()
|
||||||
try:
|
try:
|
||||||
line = buf.decode("UTF-8")
|
line = buf.decode("UTF-8")
|
||||||
except UnicodeDecodeError as ude:
|
except UnicodeDecodeError as ude:
|
||||||
self.log.error("found_terminator(): could not decode input as UTF-8")
|
self.log.error("found_terminator(): could not decode input as UTF-8")
|
||||||
self.log.error("found_terminator(): data: %s" % line)
|
self.log.error("found_terminator(): data: %s" % line)
|
||||||
self.log.error("found_terminator(): repr(data): %s" % repr(line))
|
self.log.error("found_terminator(): repr(data): %s" % repr(line))
|
||||||
self.log.error("found_terminator(): error: %s" % str(ude))
|
self.log.error("found_terminator(): error: %s" % str(ude))
|
||||||
return
|
return
|
||||||
self.process_data(line)
|
self.process_data(line)
|
||||||
|
|
||||||
def handle_close(self):
|
def handle_close(self):
|
||||||
"""Called when the socket is disconnected. Triggers the _DISCONNECT hook"""
|
"""Called when the socket is disconnected. Triggers the _DISCONNECT hook"""
|
||||||
self.log.debug("handle_close")
|
self.log.debug("handle_close")
|
||||||
self.connected=False
|
self.connected=False
|
||||||
self.close()
|
self.close()
|
||||||
self.fire_hook("_DISCONNECT")
|
self.fire_hook("_DISCONNECT")
|
||||||
|
|
||||||
def handle_error(self, *args, **kwargs):
|
def handle_error(self, *args, **kwargs):
|
||||||
"""Called on fatal network errors."""
|
"""Called on fatal network errors."""
|
||||||
self.log.error("Connection failed (handle_error)")
|
self.log.error("Connection failed (handle_error)")
|
||||||
self.log.error(str(args))
|
self.log.error(str(args))
|
||||||
self.log.error(str(kwargs))
|
self.log.error(str(kwargs))
|
||||||
self.log(IRCCore.trace());
|
self.log(IRCCore.trace());
|
||||||
|
|
||||||
def _connect(self):
|
def _connect(self):
|
||||||
"""Connect to IRC"""
|
"""Connect to IRC"""
|
||||||
self.log.debug("Connecting to %(server)s:%(port)i", {"server":self.server, "port":self.port})
|
self.log.debug("Connecting to %(server)s:%(port)i", {"server":self.server, "port":self.port})
|
||||||
socket_type = socket.AF_INET
|
socket_type = socket.AF_INET
|
||||||
if self.ipv6:
|
if self.ipv6:
|
||||||
self.log.info("IPv6 is enabled.")
|
self.log.info("IPv6 is enabled.")
|
||||||
socket_type = socket.AF_INET6
|
socket_type = socket.AF_INET6
|
||||||
socketInfo = socket.getaddrinfo(self.server, self.port, socket_type)
|
socketInfo = socket.getaddrinfo(self.server, self.port, socket_type)
|
||||||
self.create_socket(socket_type, socket.SOCK_STREAM)
|
self.create_socket(socket_type, socket.SOCK_STREAM)
|
||||||
|
|
||||||
self.connect(socketInfo[0][4])
|
self.connect(socketInfo[0][4])
|
||||||
self.asynmap[self._fileno] = self # http://willpython.blogspot.com/2010/08/multiple-event-loops-with-asyncore-and.html
|
self.asynmap[self._fileno] = self # http://willpython.blogspot.com/2010/08/multiple-event-loops-with-asyncore-and.html
|
||||||
|
|
||||||
def handle_connect(self):
|
def handle_connect(self):
|
||||||
"""When asynchat indicates our socket is connected, fire the _CONNECT hook"""
|
"""When asynchat indicates our socket is connected, fire the _CONNECT hook"""
|
||||||
self.connected=True
|
self.connected=True
|
||||||
self.log.debug("handle_connect: connected")
|
self.log.debug("handle_connect: connected")
|
||||||
self.fire_hook("_CONNECT")
|
self.fire_hook("_CONNECT")
|
||||||
self.log.debug("handle_connect: complete")
|
self.log.debug("handle_connect: complete")
|
||||||
|
|
||||||
def sendRaw(self, text):
|
def sendRaw(self, text):
|
||||||
"""Send a raw string to the IRC server
|
"""Send a raw string to the IRC server
|
||||||
|
|
||||||
:param text: the string to send
|
:param text: the string to send
|
||||||
:type text: str"""
|
:type text: str"""
|
||||||
if self.connected:
|
if self.connected:
|
||||||
#self.log.debug(">> "+text)
|
#self.log.debug(">> "+text)
|
||||||
self.send( (text+"\r\n").encode("UTF-8").decode().encode("UTF-8"))
|
self.send( (text+"\r\n").encode("UTF-8").decode().encode("UTF-8"))
|
||||||
else:
|
else:
|
||||||
self.log.warning("Send attempted while disconnected. >> "+text)
|
self.log.warning("Send attempted while disconnected. >> "+text)
|
||||||
|
|
||||||
def process_data(self, data):
|
def process_data(self, data):
|
||||||
"""Process one line of tet irc sent us
|
"""Process one line of tet irc sent us
|
||||||
|
|
||||||
:param data: the data to process
|
:param data: the data to process
|
||||||
:type data: str"""
|
:type data: str"""
|
||||||
if data.strip() == "":
|
if data.strip() == "":
|
||||||
return
|
return
|
||||||
|
|
||||||
prefix = None
|
prefix = None
|
||||||
command = None
|
command = None
|
||||||
args=[]
|
args=[]
|
||||||
trailing=None
|
trailing=None
|
||||||
|
|
||||||
if data[0]==":":
|
if data[0]==":":
|
||||||
prefix=data.split(" ")[0][1:]
|
prefix=data.split(" ")[0][1:]
|
||||||
data=data[data.find(" ")+1:]
|
data=data[data.find(" ")+1:]
|
||||||
command = data.split(" ")[0]
|
command = data.split(" ")[0]
|
||||||
data=data[data.find(" ")+1:]
|
data=data[data.find(" ")+1:]
|
||||||
if(data[0]==":"):
|
if(data[0]==":"):
|
||||||
# no args
|
# no args
|
||||||
trailing = data[1:].strip()
|
trailing = data[1:].strip()
|
||||||
else:
|
else:
|
||||||
trailing = data[data.find(" :")+2:].strip()
|
trailing = data[data.find(" :")+2:].strip()
|
||||||
data = data[:data.find(" :")]
|
data = data[:data.find(" :")]
|
||||||
args = data.split(" ")
|
args = data.split(" ")
|
||||||
for index,arg in enumerate(args):
|
for index,arg in enumerate(args):
|
||||||
args[index]=arg.strip()
|
args[index]=arg.strip()
|
||||||
if not command in self.hookcalls:
|
if not command in self.hookcalls:
|
||||||
self.log.warning("Unknown command: cmd='%s' prefix='%s' args='%s' trailing='%s'" % (command, prefix, args, trailing))
|
self.log.warning("Unknown command: cmd='%s' prefix='%s' args='%s' trailing='%s'" % (command, prefix, args, trailing))
|
||||||
else:
|
else:
|
||||||
self.fire_hook(command, args=args, prefix=prefix, trailing=trailing)
|
self.fire_hook(command, args=args, prefix=prefix, trailing=trailing)
|
||||||
|
|
||||||
|
|
||||||
" Module related code "
|
" Module related code "
|
||||||
def initHooks(self):
|
def initHooks(self):
|
||||||
"""Defines hooks that modules can listen for events of"""
|
"""Defines hooks that modules can listen for events of"""
|
||||||
self.hooks = [
|
self.hooks = [
|
||||||
'_CONNECT', # Called when the bot connects to IRC on the socket level
|
'_CONNECT', # Called when the bot connects to IRC on the socket level
|
||||||
'_DISCONNECT', # Called when the irc socket is forcibly closed
|
'_DISCONNECT', # Called when the irc socket is forcibly closed
|
||||||
'NOTICE', # :irc.129irc.com NOTICE AUTH :*** Looking up your hostname...
|
'NOTICE', # :irc.129irc.com NOTICE AUTH :*** Looking up your hostname...
|
||||||
'MODE', # :CloneABCD MODE CloneABCD :+iwx
|
'MODE', # :CloneABCD MODE CloneABCD :+iwx
|
||||||
'PING', # PING :irc.129irc.com
|
'PING', # PING :irc.129irc.com
|
||||||
'JOIN', # :CloneA!dave@hidden-B4F6B1AA.rit.edu JOIN :#clonea
|
'JOIN', # :CloneA!dave@hidden-B4F6B1AA.rit.edu JOIN :#clonea
|
||||||
'QUIT', # :HCSMPBot!~HCSMPBot@108.170.48.18 QUIT :Quit: Disconnecting!
|
'QUIT', # :HCSMPBot!~HCSMPBot@108.170.48.18 QUIT :Quit: Disconnecting!
|
||||||
'NICK', # :foxiAway!foxi@irc.hcsmp.com NICK :foxi
|
'NICK', # :foxiAway!foxi@irc.hcsmp.com NICK :foxi
|
||||||
'PART', # :CloneA!dave@hidden-B4F6B1AA.rit.edu PART #clonea
|
'PART', # :CloneA!dave@hidden-B4F6B1AA.rit.edu PART #clonea
|
||||||
'PRIVMSG', # :CloneA!dave@hidden-B4F6B1AA.rit.edu PRIVMSG #clonea :aaa
|
'PRIVMSG', # :CloneA!dave@hidden-B4F6B1AA.rit.edu PRIVMSG #clonea :aaa
|
||||||
'KICK', # :xMopxShell!~rduser@host KICK #xMopx2 xBotxShellTest :xBotxShellTest
|
'KICK', # :xMopxShell!~rduser@host KICK #xMopx2 xBotxShellTest :xBotxShellTest
|
||||||
'INVITE', # :gmx!~gmxgeek@irc.hcsmp.com INVITE Tyrone :#hcsmp'
|
'INVITE', # :gmx!~gmxgeek@irc.hcsmp.com INVITE Tyrone :#hcsmp'
|
||||||
'001', # :irc.129irc.com 001 CloneABCD :Welcome to the 129irc IRC Network CloneABCD!CloneABCD@djptwc-laptop1.rit.edu
|
'001', # :irc.129irc.com 001 CloneABCD :Welcome to the 129irc IRC Network CloneABCD!CloneABCD@djptwc-laptop1.rit.edu
|
||||||
'002', # :irc.129irc.com 002 CloneABCD :Your host is irc.129irc.com, running version Unreal3.2.8.1
|
'002', # :irc.129irc.com 002 CloneABCD :Your host is irc.129irc.com, running version Unreal3.2.8.1
|
||||||
'003', # :irc.129irc.com 003 CloneABCD :This server was created Mon Jul 19 2010 at 03:12:01 EDT
|
'003', # :irc.129irc.com 003 CloneABCD :This server was created Mon Jul 19 2010 at 03:12:01 EDT
|
||||||
'004', # :irc.129irc.com 004 CloneABCD irc.129irc.com Unreal3.2.8.1 iowghraAsORTVSxNCWqBzvdHtGp lvhopsmntikrRcaqOALQbSeIKVfMCuzNTGj
|
'004', # :irc.129irc.com 004 CloneABCD irc.129irc.com Unreal3.2.8.1 iowghraAsORTVSxNCWqBzvdHtGp lvhopsmntikrRcaqOALQbSeIKVfMCuzNTGj
|
||||||
'005', # :irc.129irc.com 005 CloneABCD CMDS=KNOCK,MAP,DCCALLOW,USERIP UHNAMES NAMESX SAFELIST HCN MAXCHANNELS=10 CHANLIMIT=#:10 MAXLIST=b:60,e:60,I:60 NICKLEN=30 CHANNELLEN=32 TOPICLEN=307 KICKLEN=307 AWAYLEN=307 :are supported by this server
|
'005', # :irc.129irc.com 005 CloneABCD CMDS=KNOCK,MAP,DCCALLOW,USERIP UHNAMES NAMESX SAFELIST HCN MAXCHANNELS=10 CHANLIMIT=#:10 MAXLIST=b:60,e:60,I:60 NICKLEN=30 CHANNELLEN=32 TOPICLEN=307 KICKLEN=307 AWAYLEN=307 :are supported by this server
|
||||||
'250', # :chaos.esper.net 250 xBotxShellTest :Highest connection count: 1633 (1632 clients) (186588 connections received)
|
'250', # :chaos.esper.net 250 xBotxShellTest :Highest connection count: 1633 (1632 clients) (186588 connections received)
|
||||||
'251', # :irc.129irc.com 251 CloneABCD :There are 1 users and 48 invisible on 2 servers
|
'251', # :irc.129irc.com 251 CloneABCD :There are 1 users and 48 invisible on 2 servers
|
||||||
'252', # :irc.129irc.com 252 CloneABCD 9 :operator(s) online
|
'252', # :irc.129irc.com 252 CloneABCD 9 :operator(s) online
|
||||||
'254', # :irc.129irc.com 254 CloneABCD 6 :channels formed
|
'254', # :irc.129irc.com 254 CloneABCD 6 :channels formed
|
||||||
'255', # :irc.129irc.com 255 CloneABCD :I have 42 clients and 1 servers
|
'255', # :irc.129irc.com 255 CloneABCD :I have 42 clients and 1 servers
|
||||||
'265', # :irc.129irc.com 265 CloneABCD :Current Local Users: 42 Max: 47
|
'265', # :irc.129irc.com 265 CloneABCD :Current Local Users: 42 Max: 47
|
||||||
'266', # :irc.129irc.com 266 CloneABCD :Current Global Users: 49 Max: 53
|
'266', # :irc.129irc.com 266 CloneABCD :Current Global Users: 49 Max: 53
|
||||||
'332', # :chaos.esper.net 332 xBotxShellTest #xMopx2 :/ #XMOPX2 / https://code.google.com/p/pyircbot/ (Channel Topic)
|
'332', # :chaos.esper.net 332 xBotxShellTest #xMopx2 :/ #XMOPX2 / https://code.google.com/p/pyircbot/ (Channel Topic)
|
||||||
'333', # :chaos.esper.net 333 xBotxShellTest #xMopx2 xMopxShell!~rduser@108.170.60.242 1344370109
|
'333', # :chaos.esper.net 333 xBotxShellTest #xMopx2 xMopxShell!~rduser@108.170.60.242 1344370109
|
||||||
'353', # :irc.129irc.com 353 CloneABCD = #clonea :CloneABCD CloneABC
|
'353', # :irc.129irc.com 353 CloneABCD = #clonea :CloneABCD CloneABC
|
||||||
'366', # :irc.129irc.com 366 CloneABCD #clonea :End of /NAMES list.
|
'366', # :irc.129irc.com 366 CloneABCD #clonea :End of /NAMES list.
|
||||||
'372', # :chaos.esper.net 372 xBotxShell :motd text here
|
'372', # :chaos.esper.net 372 xBotxShell :motd text here
|
||||||
'375', # :chaos.esper.net 375 xBotxShellTest :- chaos.esper.net Message of the Day -
|
'375', # :chaos.esper.net 375 xBotxShellTest :- chaos.esper.net Message of the Day -
|
||||||
'376', # :chaos.esper.net 376 xBotxShell :End of /MOTD command.
|
'376', # :chaos.esper.net 376 xBotxShell :End of /MOTD command.
|
||||||
'422', # :irc.129irc.com 422 CloneABCD :MOTD File is missing
|
'422', # :irc.129irc.com 422 CloneABCD :MOTD File is missing
|
||||||
'433', # :nova.esper.net 433 * pyircbot3 :Nickname is already in use.
|
'433', # :nova.esper.net 433 * pyircbot3 :Nickname is already in use.
|
||||||
]
|
]
|
||||||
" mapping of hooks to methods "
|
" mapping of hooks to methods "
|
||||||
self.hookcalls = {}
|
self.hookcalls = {}
|
||||||
for command in self.hooks:
|
for command in self.hooks:
|
||||||
self.hookcalls[command]=[]
|
self.hookcalls[command]=[]
|
||||||
|
|
||||||
def fire_hook(self, command, args=None, prefix=None, trailing=None):
|
def fire_hook(self, command, args=None, prefix=None, trailing=None):
|
||||||
"""Run any listeners for a specific hook
|
"""Run any listeners for a specific hook
|
||||||
|
|
||||||
:param command: the hook to fire
|
:param command: the hook to fire
|
||||||
:type command: str
|
:type command: str
|
||||||
:param args: the list of arguments, if any, the command was passed
|
:param args: the list of arguments, if any, the command was passed
|
||||||
:type args: list
|
:type args: list
|
||||||
:param prefix: prefix of the sender of this command
|
:param prefix: prefix of the sender of this command
|
||||||
:type prefix: str
|
:type prefix: str
|
||||||
:param trailing: data payload of the command
|
:param trailing: data payload of the command
|
||||||
:type trailing: str"""
|
:type trailing: str"""
|
||||||
|
|
||||||
for hook in self.hookcalls[command]:
|
for hook in self.hookcalls[command]:
|
||||||
try:
|
try:
|
||||||
hook(args, prefix, trailing)
|
hook(args, prefix, trailing)
|
||||||
except:
|
except:
|
||||||
self.log.warning("Error processing hook: \n%s"% self.trace())
|
self.log.warning("Error processing hook: \n%s"% self.trace())
|
||||||
|
|
||||||
def addHook(self, command, method):
|
def addHook(self, command, method):
|
||||||
"""**Internal.** Enable (connect) a single hook of a module
|
"""**Internal.** Enable (connect) a single hook of a module
|
||||||
|
|
||||||
:param command: command this hook will trigger on
|
:param command: command this hook will trigger on
|
||||||
:type command: str
|
:type command: str
|
||||||
:param method: callable method object to hook in
|
:param method: callable method object to hook in
|
||||||
:type method: object"""
|
:type method: object"""
|
||||||
" add a single hook "
|
" add a single hook "
|
||||||
if command in self.hooks:
|
if command in self.hooks:
|
||||||
self.hookcalls[command].append(method)
|
self.hookcalls[command].append(method)
|
||||||
else:
|
else:
|
||||||
self.log.warning("Invalid hook - %s" % command)
|
self.log.warning("Invalid hook - %s" % command)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def removeHook(self, command, method):
|
def removeHook(self, command, method):
|
||||||
"""**Internal.** Disable (disconnect) a single hook of a module
|
"""**Internal.** Disable (disconnect) a single hook of a module
|
||||||
|
|
||||||
:param command: command this hook triggers on
|
:param command: command this hook triggers on
|
||||||
:type command: str
|
:type command: str
|
||||||
:param method: callable method that should be removed
|
:param method: callable method that should be removed
|
||||||
:type method: object"""
|
:type method: object"""
|
||||||
" remove a single hook "
|
" remove a single hook "
|
||||||
if command in self.hooks:
|
if command in self.hooks:
|
||||||
for hookedMethod in self.hookcalls[command]:
|
for hookedMethod in self.hookcalls[command]:
|
||||||
if hookedMethod == method:
|
if hookedMethod == method:
|
||||||
self.hookcalls[command].remove(hookedMethod)
|
self.hookcalls[command].remove(hookedMethod)
|
||||||
else:
|
else:
|
||||||
self.log.warning("Invalid hook - %s" % command)
|
self.log.warning("Invalid hook - %s" % command)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
" Utility methods "
|
" Utility methods "
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def decodePrefix(prefix):
|
def decodePrefix(prefix):
|
||||||
"""Given a prefix like nick!username@hostname, return an object with these properties
|
"""Given a prefix like nick!username@hostname, return an object with these properties
|
||||||
|
|
||||||
:param prefix: the prefix to disassemble
|
:param prefix: the prefix to disassemble
|
||||||
:type prefix: str
|
:type prefix: str
|
||||||
:returns: object -- an UserPrefix object with the properties `nick`, `username`, `hostname` or a ServerPrefix object with the property `hostname`"""
|
:returns: object -- an UserPrefix object with the properties `nick`, `username`, `hostname` or a ServerPrefix object with the property `hostname`"""
|
||||||
if "!" in prefix:
|
if "!" in prefix:
|
||||||
ob = type('UserPrefix', (object,), {})
|
ob = type('UserPrefix', (object,), {})
|
||||||
ob.nick, prefix = prefix.split("!")
|
ob.nick, prefix = prefix.split("!")
|
||||||
ob.username, ob.hostname = prefix.split("@")
|
ob.username, ob.hostname = prefix.split("@")
|
||||||
return ob
|
return ob
|
||||||
else:
|
else:
|
||||||
ob = type('ServerPrefix', (object,), {})
|
ob = type('ServerPrefix', (object,), {})
|
||||||
ob.hostname = prefix
|
ob.hostname = prefix
|
||||||
return ob
|
return ob
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def trace():
|
def trace():
|
||||||
"""Return the stack trace of the bot as a string"""
|
"""Return the stack trace of the bot as a string"""
|
||||||
return traceback.format_exc()
|
result = ""
|
||||||
|
result += "\n*** STACKTRACE - START ***\n"
|
||||||
" Data Methods "
|
code = []
|
||||||
def get_nick(self):
|
for threadId, stack in sys._current_frames().items():
|
||||||
"""Get the bot's current nick
|
code.append("\n# ThreadID: %s" % threadId)
|
||||||
|
for filename, lineno, name, line in traceback.extract_stack(stack):
|
||||||
:returns: str - the bot's current nickname"""
|
code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
|
||||||
return self.nick
|
if line:
|
||||||
|
code.append(" %s" % (line.strip()))
|
||||||
" Action Methods "
|
for line in code:
|
||||||
def act_PONG(self, data):
|
result += line + "\n"
|
||||||
"""Use the `/pong` command - respond to server pings
|
result += "\n*** STACKTRACE - END ***\n"
|
||||||
|
return result
|
||||||
:param data: the string or number the server sent with it's ping
|
|
||||||
:type data: str"""
|
" Data Methods "
|
||||||
self.sendRaw("PONG :%s" % data)
|
def get_nick(self):
|
||||||
|
"""Get the bot's current nick
|
||||||
def act_USER(self, username, hostname, realname):
|
|
||||||
"""Use the USER protocol command. Used during connection
|
:returns: str - the bot's current nickname"""
|
||||||
|
return self.nick
|
||||||
:param username: the bot's username
|
|
||||||
:type username: str
|
" Action Methods "
|
||||||
:param hostname: the bot's hostname
|
def act_PONG(self, data):
|
||||||
:type hostname: str
|
"""Use the `/pong` command - respond to server pings
|
||||||
:param realname: the bot's realname
|
|
||||||
:type realname: str"""
|
:param data: the string or number the server sent with it's ping
|
||||||
self.sendRaw("USER %s %s %s :%s" % (username, hostname, self.server, realname))
|
:type data: str"""
|
||||||
|
self.sendRaw("PONG :%s" % data)
|
||||||
def act_NICK(self, newNick):
|
|
||||||
"""Use the `/nick` command
|
def act_USER(self, username, hostname, realname):
|
||||||
|
"""Use the USER protocol command. Used during connection
|
||||||
:param newNick: new nick for the bot
|
|
||||||
:type newNick: str"""
|
:param username: the bot's username
|
||||||
self.nick = newNick
|
:type username: str
|
||||||
self.sendRaw("NICK %s" % newNick)
|
:param hostname: the bot's hostname
|
||||||
|
:type hostname: str
|
||||||
def act_JOIN(self, channel):
|
:param realname: the bot's realname
|
||||||
"""Use the `/join` command
|
:type realname: str"""
|
||||||
|
self.sendRaw("USER %s %s %s :%s" % (username, hostname, self.server, realname))
|
||||||
:param channel: the channel to attempt to join
|
|
||||||
:type channel: str"""
|
def act_NICK(self, newNick):
|
||||||
self.sendRaw("JOIN %s"%channel)
|
"""Use the `/nick` command
|
||||||
|
|
||||||
def act_PRIVMSG(self, towho, message):
|
:param newNick: new nick for the bot
|
||||||
"""Use the `/msg` command
|
:type newNick: str"""
|
||||||
|
self.nick = newNick
|
||||||
:param towho: the target #channel or user's name
|
self.sendRaw("NICK %s" % newNick)
|
||||||
:type towho: str
|
|
||||||
:param message: the message to send
|
def act_JOIN(self, channel):
|
||||||
:type message: str"""
|
"""Use the `/join` command
|
||||||
self.sendRaw("PRIVMSG %s :%s"%(towho,message))
|
|
||||||
|
:param channel: the channel to attempt to join
|
||||||
def act_MODE(self, channel, mode, extra=None):
|
:type channel: str"""
|
||||||
"""Use the `/mode` command
|
self.sendRaw("JOIN %s"%channel)
|
||||||
|
|
||||||
:param channel: the channel this mode is for
|
def act_PRIVMSG(self, towho, message):
|
||||||
:type channel: str
|
"""Use the `/msg` command
|
||||||
:param mode: the mode string. Example: +b
|
|
||||||
:type mode: str
|
:param towho: the target #channel or user's name
|
||||||
:param extra: additional argument if the mode needs it. Example: user@*!*
|
:type towho: str
|
||||||
:type extra: str"""
|
:param message: the message to send
|
||||||
if extra != None:
|
:type message: str"""
|
||||||
self.sendRaw("MODE %s %s %s" % (channel,mode,extra))
|
self.sendRaw("PRIVMSG %s :%s"%(towho,message))
|
||||||
else:
|
|
||||||
self.sendRaw("MODE %s %s" % (channel,mode))
|
def act_MODE(self, channel, mode, extra=None):
|
||||||
|
"""Use the `/mode` command
|
||||||
def act_ACTION(self, channel, action):
|
|
||||||
"""Use the `/me <action>` command
|
:param channel: the channel this mode is for
|
||||||
|
:type channel: str
|
||||||
:param channel: the channel name or target's name the message is sent to
|
:param mode: the mode string. Example: +b
|
||||||
:type channel: str
|
:type mode: str
|
||||||
:param action: the text to send
|
:param extra: additional argument if the mode needs it. Example: user@*!*
|
||||||
:type action: str"""
|
:type extra: str"""
|
||||||
self.sendRaw("PRIVMSG %s :\x01ACTION %s"%(channel,action))
|
if extra != None:
|
||||||
|
self.sendRaw("MODE %s %s %s" % (channel,mode,extra))
|
||||||
def act_KICK(self, channel, who, comment=""):
|
else:
|
||||||
"""Use the `/kick <user> <message>` command
|
self.sendRaw("MODE %s %s" % (channel,mode))
|
||||||
|
|
||||||
:param channel: the channel from which the user will be kicked
|
def act_ACTION(self, channel, action):
|
||||||
:type channel: str
|
"""Use the `/me <action>` command
|
||||||
:param who: the nickname of the user to kick
|
|
||||||
:type action: str
|
:param channel: the channel name or target's name the message is sent to
|
||||||
:param comment: the kick message
|
:type channel: str
|
||||||
:type comment: str"""
|
:param action: the text to send
|
||||||
self.sendRaw("KICK %s %s :%s" % (channel, who, comment))
|
:type action: str"""
|
||||||
|
self.sendRaw("PRIVMSG %s :\x01ACTION %s"%(channel,action))
|
||||||
def act_QUIT(self, message):
|
|
||||||
"""Use the `/quit` command
|
def act_KICK(self, channel, who, comment=""):
|
||||||
|
"""Use the `/kick <user> <message>` command
|
||||||
:param message: quit message
|
|
||||||
:type message: str"""
|
:param channel: the channel from which the user will be kicked
|
||||||
self.sendRaw("QUIT :%s" % message)
|
:type channel: str
|
||||||
|
:param who: the nickname of the user to kick
|
||||||
|
:type action: str
|
||||||
|
:param comment: the kick message
|
||||||
|
:type comment: str"""
|
||||||
|
self.sendRaw("KICK %s %s :%s" % (channel, who, comment))
|
||||||
|
|
||||||
|
def act_QUIT(self, message):
|
||||||
|
"""Use the `/quit` command
|
||||||
|
|
||||||
|
:param message: quit message
|
||||||
|
:type message: str"""
|
||||||
|
self.sendRaw("QUIT :%s" % message)
|
||||||
|
|
||||||
|
|
324
pyircbot/rpc.py
324
pyircbot/rpc.py
|
@ -12,157 +12,173 @@ from pyircbot import jsonrpc
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
class BotRPC(Thread):
|
class BotRPC(Thread):
|
||||||
""":param main: A reference to the PyIRCBot instance this instance will control
|
""":param main: A reference to the PyIRCBot instance this instance will control
|
||||||
:type main: PyIRCBot
|
:type main: PyIRCBot
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, main):
|
def __init__(self, main):
|
||||||
Thread.__init__(self, daemon=True)
|
Thread.__init__(self, daemon=True)
|
||||||
self.bot = main
|
self.bot = main
|
||||||
self.log = logging.getLogger('RPC')
|
self.log = logging.getLogger('RPC')
|
||||||
self.server = jsonrpc.Server(
|
self.server = jsonrpc.Server(
|
||||||
jsonrpc.JsonRpc20(),
|
jsonrpc.JsonRpc20(),
|
||||||
jsonrpc.TransportTcpIp(
|
jsonrpc.TransportTcpIp(
|
||||||
addr=(
|
addr=(
|
||||||
self.bot.botconfig["bot"]["rpcbind"],
|
self.bot.botconfig["bot"]["rpcbind"],
|
||||||
self.bot.botconfig["bot"]["rpcport"]
|
self.bot.botconfig["bot"]["rpcport"]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.server.register_function( self.importModule )
|
self.server.register_function( self.importModule )
|
||||||
self.server.register_function( self.deportModule )
|
self.server.register_function( self.deportModule )
|
||||||
self.server.register_function( self.loadModule )
|
self.server.register_function( self.loadModule )
|
||||||
self.server.register_function( self.unloadModule )
|
self.server.register_function( self.unloadModule )
|
||||||
self.server.register_function( self.reloadModule )
|
self.server.register_function( self.reloadModule )
|
||||||
self.server.register_function( self.redoModule )
|
self.server.register_function( self.redoModule )
|
||||||
self.server.register_function( self.getLoadedModules )
|
self.server.register_function( self.getLoadedModules )
|
||||||
self.server.register_function( self.pluginCommand )
|
self.server.register_function( self.pluginCommand )
|
||||||
self.server.register_function( self.setPluginVar )
|
self.server.register_function( self.setPluginVar )
|
||||||
self.server.register_function( self.getPluginVar )
|
self.server.register_function( self.getPluginVar )
|
||||||
self.server.register_function( self.quit )
|
self.server.register_function( self.quit )
|
||||||
|
self.server.register_function( self.eval )
|
||||||
self.start()
|
self.server.register_function( self.exec )
|
||||||
|
|
||||||
def run(self):
|
self.start()
|
||||||
"""Internal, starts the RPC server"""
|
|
||||||
self.server.serve()
|
def run(self):
|
||||||
|
"""Internal, starts the RPC server"""
|
||||||
def importModule(self, moduleName):
|
self.server.serve()
|
||||||
"""Import a module
|
|
||||||
|
def importModule(self, moduleName):
|
||||||
:param moduleName: Name of the module to import
|
"""Import a module
|
||||||
:type moduleName: str"""
|
|
||||||
self.log.info("RPC: calling importModule(%s)"%moduleName)
|
:param moduleName: Name of the module to import
|
||||||
return self.bot.importmodule(moduleName)
|
:type moduleName: str"""
|
||||||
|
self.log.info("RPC: calling importModule(%s)"%moduleName)
|
||||||
def deportModule(self, moduleName):
|
return self.bot.importmodule(moduleName)
|
||||||
"""Remove a module's code from memory. If the module is loaded it will be unloaded silently.
|
|
||||||
|
def deportModule(self, moduleName):
|
||||||
:param moduleName: Name of the module to import
|
"""Remove a module's code from memory. If the module is loaded it will be unloaded silently.
|
||||||
:type moduleName: str"""
|
|
||||||
self.log.info("RPC: calling deportModule(%s)"%moduleName)
|
:param moduleName: Name of the module to import
|
||||||
self.bot.deportmodule(moduleName)
|
:type moduleName: str"""
|
||||||
|
self.log.info("RPC: calling deportModule(%s)"%moduleName)
|
||||||
def loadModule(self, moduleName):
|
self.bot.deportmodule(moduleName)
|
||||||
"""Activate a module.
|
|
||||||
|
def loadModule(self, moduleName):
|
||||||
:param moduleName: Name of the module to activate
|
"""Activate a module.
|
||||||
:type moduleName: str"""
|
|
||||||
self.log.info("RPC: calling loadModule(%s)"%moduleName)
|
:param moduleName: Name of the module to activate
|
||||||
return self.bot.loadmodule(moduleName)
|
:type moduleName: str"""
|
||||||
|
self.log.info("RPC: calling loadModule(%s)"%moduleName)
|
||||||
def unloadModule(self, moduleName):
|
return self.bot.loadmodule(moduleName)
|
||||||
"""Deactivate a module.
|
|
||||||
|
def unloadModule(self, moduleName):
|
||||||
:param moduleName: Name of the module to deactivate
|
"""Deactivate a module.
|
||||||
:type moduleName: str"""
|
|
||||||
self.log.info("RPC: calling unloadModule(%s)"%moduleName)
|
:param moduleName: Name of the module to deactivate
|
||||||
self.bot.unloadmodule(moduleName)
|
:type moduleName: str"""
|
||||||
|
self.log.info("RPC: calling unloadModule(%s)"%moduleName)
|
||||||
def reloadModule(self, moduleName):
|
self.bot.unloadmodule(moduleName)
|
||||||
"""Deactivate and activate a module.
|
|
||||||
|
def reloadModule(self, moduleName):
|
||||||
:param moduleName: Name of the target module
|
"""Deactivate and activate a module.
|
||||||
:type moduleName: str"""
|
|
||||||
self.log.info("RPC: calling reloadModule(%s)"%moduleName)
|
:param moduleName: Name of the target module
|
||||||
self.bot.unloadmodule(moduleName)
|
:type moduleName: str"""
|
||||||
return self.bot.loadmodule(moduleName)
|
self.log.info("RPC: calling reloadModule(%s)"%moduleName)
|
||||||
|
self.bot.unloadmodule(moduleName)
|
||||||
def redoModule(self, moduleName):
|
return self.bot.loadmodule(moduleName)
|
||||||
"""Reload a running module from disk
|
|
||||||
|
def redoModule(self, moduleName):
|
||||||
:param moduleName: Name of the target module
|
"""Reload a running module from disk
|
||||||
:type moduleName: str"""
|
|
||||||
self.log.info("RPC: calling redoModule(%s)"%moduleName)
|
:param moduleName: Name of the target module
|
||||||
return self.bot.redomodule(moduleName)
|
:type moduleName: str"""
|
||||||
|
self.log.info("RPC: calling redoModule(%s)"%moduleName)
|
||||||
def getLoadedModules(self):
|
return self.bot.redomodule(moduleName)
|
||||||
"""Return a list of active modules
|
|
||||||
|
def getLoadedModules(self):
|
||||||
:returns: list -- ['ModuleName1', 'ModuleName2']"""
|
"""Return a list of active modules
|
||||||
self.log.info("RPC: calling getLoadedModules()")
|
|
||||||
return list(self.bot.moduleInstances.keys())
|
:returns: list -- ['ModuleName1', 'ModuleName2']"""
|
||||||
|
self.log.info("RPC: calling getLoadedModules()")
|
||||||
def pluginCommand(self, moduleName, methodName, argList):
|
return list(self.bot.moduleInstances.keys())
|
||||||
"""Run a method of an active module
|
|
||||||
|
def pluginCommand(self, moduleName, methodName, argList):
|
||||||
:param moduleName: Name of the target module
|
"""Run a method of an active module
|
||||||
:type moduleName: str
|
|
||||||
:param methodName: Name of the target method
|
:param moduleName: Name of the target module
|
||||||
:type methodName: str
|
:type moduleName: str
|
||||||
:param argList: List of positional arguments to call the method with
|
:param methodName: Name of the target method
|
||||||
:type argList: list
|
:type methodName: str
|
||||||
:returns: mixed -- Any basic type the target method may return"""
|
:param argList: List of positional arguments to call the method with
|
||||||
plugin = self.bot.getmodulebyname(moduleName)
|
:type argList: list
|
||||||
if not plugin:
|
:returns: mixed -- Any basic type the target method may return"""
|
||||||
return (False, "Plugin not found")
|
plugin = self.bot.getmodulebyname(moduleName)
|
||||||
method = getattr(plugin, methodName)
|
if not plugin:
|
||||||
if not method:
|
return (False, "Plugin not found")
|
||||||
return (False, "Method not found")
|
method = getattr(plugin, methodName)
|
||||||
self.log.info("RPC: calling %s.%s(%s)" % (moduleName, methodName, argList))
|
if not method:
|
||||||
return (True, method(*argList))
|
return (False, "Method not found")
|
||||||
|
self.log.info("RPC: calling %s.%s(%s)" % (moduleName, methodName, argList))
|
||||||
def getPluginVar(self, moduleName, moduleVarName):
|
return (True, method(*argList))
|
||||||
"""Extract a property from an active module and return it
|
|
||||||
|
def getPluginVar(self, moduleName, moduleVarName):
|
||||||
:param moduleName: Name of the target module
|
"""Extract a property from an active module and return it
|
||||||
:type moduleName: str
|
|
||||||
:param moduleVarName: Name of the target property
|
:param moduleName: Name of the target module
|
||||||
:type moduleVarName: str
|
:type moduleName: str
|
||||||
:returns: mixed -- Any basic type extracted from an active module"""
|
:param moduleVarName: Name of the target property
|
||||||
plugin = self.bot.getmodulebyname(moduleName)
|
:type moduleVarName: str
|
||||||
if moduleName == "_core":
|
:returns: mixed -- Any basic type extracted from an active module"""
|
||||||
plugin = self.bot
|
plugin = self.bot.getmodulebyname(moduleName)
|
||||||
if not plugin:
|
if moduleName == "_core":
|
||||||
return (False, "Plugin not found")
|
plugin = self.bot
|
||||||
self.log.info("RPC: getting %s.%s" % (moduleName, moduleVarName))
|
if not plugin:
|
||||||
return (True, getattr(plugin, moduleVarName))
|
return (False, "Plugin not found")
|
||||||
|
self.log.info("RPC: getting %s.%s" % (moduleName, moduleVarName))
|
||||||
def setPluginVar(self, moduleName, moduleVarName, value):
|
return (True, getattr(plugin, moduleVarName))
|
||||||
"""Set a property of an active module
|
|
||||||
|
def setPluginVar(self, moduleName, moduleVarName, value):
|
||||||
:param moduleName: Name of the target module
|
"""Set a property of an active module
|
||||||
:type moduleName: str
|
|
||||||
:param moduleVarName: Name of the target property
|
:param moduleName: Name of the target module
|
||||||
:type moduleVarName: str
|
:type moduleName: str
|
||||||
:param value: Value the target property will be set to
|
:param moduleVarName: Name of the target property
|
||||||
:type value: str"""
|
:type moduleVarName: str
|
||||||
plugin = self.bot.getmodulebyname(moduleName)
|
:param value: Value the target property will be set to
|
||||||
if moduleName == "_core":
|
:type value: str"""
|
||||||
plugin = self.bot
|
plugin = self.bot.getmodulebyname(moduleName)
|
||||||
if not plugin:
|
if moduleName == "_core":
|
||||||
return (False, "Plugin not found")
|
plugin = self.bot
|
||||||
self.log.info("RPC: setting %s.%s = %s )" % (moduleName, moduleVarName, value))
|
if not plugin:
|
||||||
setattr(plugin, moduleVarName, value)
|
return (False, "Plugin not found")
|
||||||
return (True, "Var set")
|
self.log.info("RPC: setting %s.%s = %s )" % (moduleName, moduleVarName, value))
|
||||||
|
setattr(plugin, moduleVarName, value)
|
||||||
def quit(self, message):
|
return (True, "Var set")
|
||||||
"""Tell the bot to quit IRC and exit
|
|
||||||
|
def eval(self, code):
|
||||||
:param message: Quit message
|
"""Execute arbitrary python code on the bot
|
||||||
:type moduleName: str"""
|
|
||||||
self.bot.act_QUIT(message)
|
:param code: Python code to pass to eval
|
||||||
self.bot.kill()
|
:type code: str"""
|
||||||
return (True, "Shutdown ordered")
|
return (True, eval(code))
|
||||||
|
|
||||||
|
def exec(self, code):
|
||||||
|
"""Execute arbitrary python code on the bot
|
||||||
|
|
||||||
|
:param code: Python code to pass to exec
|
||||||
|
:type code: str"""
|
||||||
|
return (True, exec(code))
|
||||||
|
|
||||||
|
def quit(self, message):
|
||||||
|
"""Tell the bot to quit IRC and exit
|
||||||
|
|
||||||
|
:param message: Quit message
|
||||||
|
:type moduleName: str"""
|
||||||
|
self.bot.act_QUIT(message)
|
||||||
|
self.bot.kill()
|
||||||
|
return (True, "Shutdown ordered")
|
||||||
|
|
Loading…
Reference in New Issue