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,6 +11,7 @@ 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:
|
||||||
|
@ -279,7 +280,19 @@ class IRCCore(asynchat.async_chat):
|
||||||
@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"
|
||||||
|
code = []
|
||||||
|
for threadId, stack in sys._current_frames().items():
|
||||||
|
code.append("\n# ThreadID: %s" % threadId)
|
||||||
|
for filename, lineno, name, line in traceback.extract_stack(stack):
|
||||||
|
code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
|
||||||
|
if line:
|
||||||
|
code.append(" %s" % (line.strip()))
|
||||||
|
for line in code:
|
||||||
|
result += line + "\n"
|
||||||
|
result += "\n*** STACKTRACE - END ***\n"
|
||||||
|
return result
|
||||||
|
|
||||||
" Data Methods "
|
" Data Methods "
|
||||||
def get_nick(self):
|
def get_nick(self):
|
||||||
|
|
|
@ -41,6 +41,8 @@ class BotRPC(Thread):
|
||||||
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.server.register_function( self.exec )
|
||||||
|
|
||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
|
@ -157,6 +159,20 @@ class BotRPC(Thread):
|
||||||
setattr(plugin, moduleVarName, value)
|
setattr(plugin, moduleVarName, value)
|
||||||
return (True, "Var set")
|
return (True, "Var set")
|
||||||
|
|
||||||
|
def eval(self, code):
|
||||||
|
"""Execute arbitrary python code on the bot
|
||||||
|
|
||||||
|
:param code: Python code to pass to eval
|
||||||
|
:type code: str"""
|
||||||
|
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):
|
def quit(self, message):
|
||||||
"""Tell the bot to quit IRC and exit
|
"""Tell the bot to quit IRC and exit
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue