From c17dde3bcc2e559113d937c48dd93a7d13cf9eac Mon Sep 17 00:00:00 2001 From: dpedu Date: Sat, 18 Jul 2015 21:11:00 -0700 Subject: [PATCH] Add RPC client and docs --- docs/rpc/_rpc.rst | 81 ++++++++++++++++++++++++++++++++++++++++++- pyircbot/rpcclient.py | 14 ++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 pyircbot/rpcclient.py diff --git a/docs/rpc/_rpc.rst b/docs/rpc/_rpc.rst index dd158fc..2a693de 100644 --- a/docs/rpc/_rpc.rst +++ b/docs/rpc/_rpc.rst @@ -1,4 +1,83 @@ RPC Usage ========= -TODO: How to use RPC \ No newline at end of file +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 ` 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'}] + >>> + +Or 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'}] + >>> + +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 "", line 1, in + 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: + >>> + +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. diff --git a/pyircbot/rpcclient.py b/pyircbot/rpcclient.py new file mode 100644 index 0000000..43b0c31 --- /dev/null +++ b/pyircbot/rpcclient.py @@ -0,0 +1,14 @@ +from sys import argv,exit +from pyircbot import jsonrpc + +def connect(host, port): + return jsonrpc.ServerProxy(jsonrpc.JsonRpc20(), jsonrpc.TransportTcpIp(addr=(host, port), timeout=60.0)) + +if __name__=="__main__": + if len(argv) is not 3: + print("Expected ip and port arguments") + exit(1) + print("Connecting to pyircbot rpc on port %s:%s..." % (argv[1],argv[2])) + rpc = connect(argv[1], int(argv[2])) + print("Connected to rpc") + print("Loaded modules: %s" % rpc.getLoadedModules())