158 lines
6.2 KiB
ReStructuredText
158 lines
6.2 KiB
ReStructuredText
RPC Usage
|
|
=========
|
|
|
|
By default ``pyircbot`` starts a JSON RPC that has some abilities to control
|
|
the bot. A list of methods can be found in the :doc:`BotRPC </api/rpc>` class.
|
|
|
|
The RPC interface can be used interactively:
|
|
|
|
.. code-block:: bash
|
|
|
|
$ python3 -i -m pyircbot.rpcclient 127.0.0.1 1876
|
|
Connecting to rpc....
|
|
Connected to rpc
|
|
Loaded modules: ['NickUser', 'LinkTitler', 'SQLite', 'RandQuote', 'AttributeStorageLite', 'Tell', 'Seen', 'Calc', 'Inventory', 'Urban', 'Services', 'PingResponder', 'Weather', 'Remind']
|
|
>>>
|
|
|
|
Now, you have a python shell. An object named "rpc" is the JSON RPC client. A
|
|
basic command lets us get a list naming the currently loaded modules:
|
|
|
|
.. code-block:: python
|
|
|
|
>>> modules = rpc.getLoadedModules()
|
|
>>> for m in modules:
|
|
... print(m)
|
|
...
|
|
NickUser
|
|
LinkTitler
|
|
SQLite
|
|
RandQuote
|
|
AttributeStorageLite
|
|
Tell
|
|
Seen
|
|
Calc
|
|
Inventory
|
|
Urban
|
|
Services
|
|
PingResponder
|
|
Weather
|
|
Remind
|
|
>>>
|
|
|
|
We can retrieve an arbitrary property from a module:
|
|
|
|
.. code-block:: python
|
|
|
|
>>> rpc.getPluginVar("Weather", "config")
|
|
[True, {'apikey': 'deadbeefcafe', 'defaultUnit': 'f'}]
|
|
>>>
|
|
|
|
Run a method in a module, passing args:
|
|
|
|
.. code-block:: python
|
|
|
|
>>> rpc.pluginCommand("Calc", "getRandomCalc", ["#jesusandhacking"])
|
|
[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.fulltrace()")[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
|
|
basic types can be passed over the RPC connection. Trying to access anything
|
|
extra results in an error:
|
|
|
|
.. code-block:: python
|
|
|
|
>>> rpc.getPluginVar("Calc", "sql")
|
|
Traceback (most recent call last):
|
|
File "<stdin>", line 1, in <module>
|
|
File "/usr/local/lib/python3.4/dist-packages/pyircbot-4.0.0_r02-py3.4.egg/pyircbot/jsonrpc.py", line 970, in __call__
|
|
return self.__req(self.__name, args, kwargs)
|
|
File "/usr/local/lib/python3.4/dist-packages/pyircbot-4.0.0_r02-py3.4.egg/pyircbot/jsonrpc.py", line 943, in __req
|
|
resp = self.__data_serializer.loads_response( resp_str )
|
|
File "/usr/local/lib/python3.4/dist-packages/pyircbot-4.0.0_r02-py3.4.egg/pyircbot/jsonrpc.py", line 647, in loads_response
|
|
raise RPCInternalError(error_data)
|
|
pyircbot.jsonrpc.RPCInternalError: <RPCFault -32603: 'Internal error.' (None)>
|
|
>>>
|
|
|
|
Adding an RPC "interface" to your module is automatic - the bot's RPC already
|
|
has access to your module's internals via the methods in ``BotRPC``. However,
|
|
as a convention, it is recommended to prefix methods intended to be called via
|
|
rpc with ``rpc_``.
|
|
|
|
Since only basic types (like string, integer, dict, etc) can be passed over
|
|
RPC, a well-written module should have helper rpc methods to express and
|
|
manipulate the module's state using only these types.
|
|
|
|
Using the RPC client in python code is very easy. The above shows how to use
|
|
an existing RPC client using python; rpc clients can be created as so:
|
|
|
|
.. code-block:: python
|
|
|
|
#!/usr/bin/env python3
|
|
from pyircbot.rpcclient import connect
|
|
rpc = connect("127.0.0.1", 1876)
|