Merge remote-tracking branch 'lethosor/docs-remote' into develop

develop
lethosor 2020-07-22 02:05:34 -04:00
commit 73cb79d0ad
No known key found for this signature in database
GPG Key ID: 76A269552F4F58C1
5 changed files with 254 additions and 8 deletions

@ -82,7 +82,7 @@ dfhack-run
If DF and DFHack are already running, calling ``dfhack-run my command``
in an external terminal is equivalent to calling ``my command`` in the
DFHack console. Direct use of the DFhack console is generally easier,
DFHack console. Direct use of the DFHack console is generally easier,
but ``dfhack-run`` can be useful in a variety of circumstances:
- if the console is unavailable
@ -101,6 +101,14 @@ Examples::
The first (\*nix) example `checks for vampires <cursecheck>`; the
second (Windows) example uses `kill-lua` to stop a Lua script.
.. note::
``dfhack-run`` attempts to connect to a server on TCP port 5000. If DFHack
was unable to start this server, ``dfhack-run`` will not be able to connect.
This could happen if you have other software listening on port 5000, or if
you have multiple copies of DF running simultaneously. To assign a different
port, see `remote-server-config`.
Built-in Commands
=================
@ -442,6 +450,8 @@ Other init files
directory, will be run when any world or that save is loaded.
.. _env-vars:
Environment variables
=====================
@ -453,6 +463,7 @@ on UNIX-like systems::
- ``DFHACK_PORT``: the port to use for the RPC server (used by ``dfhack-run``
and `remotefortressreader` among others) instead of the default ``5000``. As
with the default, if this port cannot be used, the server is not started.
See `remote` for more details.
- ``DFHACK_DISABLE_CONSOLE``: if set, the DFHack console is not set up. This is
the default behavior if ``PRINT_MODE:TEXT`` is set in ``data/init/init.txt``.

@ -77,11 +77,6 @@ some functions (and some entire modules) are currently only available in C++.
Remote access interface
-----------------------
DFHack supports remote access by exchanging Google protobuf messages via a TCP
socket. Both the core and plugins can define remotely accessible methods. The
``dfhack-run`` command uses this interface to invoke ordinary console commands.
Currently the supported set of requests is limited, because the developers don't
know what exactly is most useful. `remotefortressreader` provides a fairly
comprehensive interface for visualisers such as :forums:`Armok Vision <146473>`.
DFHack provides a remote access interface that external tools can connect to and
use to interact with DF. See `remote` for more information.

@ -59,6 +59,11 @@ remotefortressreader
An in-development plugin for realtime fortress visualisation.
See :forums:`Armok Vision <146473>`.
.. _isoworldremote:
isoworldremote
==============
A plugin that implements a `remote API <remote>` used by Isoworld.
.. _cursecheck:

@ -0,0 +1,234 @@
.. _remote:
=======================
DFHack Remote Interface
=======================
DFHack provides a remote access interface that external tools can connect to and
use to interact with DF. This is implemented with `Google protobuf`_ messages
exchanged over a TCP socket. Both the core and plugins can define
remotely-accessible methods, or **RPC methods**. The RPC methods currently
available are not comprehensive, but can be extended with plugins.
.. _Google protobuf: https://developers.google.com/protocol-buffers
.. contents::
:local:
.. _remote-server-config:
Server configuration
====================
DFHack attempts to start a TCP server to listen for remote connections on
startup. If this fails (due to the port being in use, for example), an error
message will be logged to stderr.log.
The server can be configured by setting options in ``dfhack-config/remote-server.json``:
- ``allow_remote`` (default: ``false``): if true, allows connections from hosts
other than the local machine. This is insecure and may allow arbitrary code
execution on your machine, so it is disabled by default.
- ``port`` (default: ``5000``): the port that the remote server listens on.
Overriding this will allow the server to work if you have multiple instances
of DF running, or if you have something else running on port 5000. Note that
the ``DFHACK_PORT`` `environment variable <env-vars>` takes precedence over
this setting and may be more useful for overriding the port temporarily.
Developing with the remote API
==============================
At a high level, the core and plugins define RPC methods, and external clients
can call these methods. Each method is assigned an ID internally, which clients
use to call it. These method IDs can be obtained using the special ``BindMethod``
method, which has an ID of 0.
Examples
--------
The `dfhack-run` command uses the RPC interface to invoke DFHack commands
(or Lua functions) externally.
Plugins that implement RPC methods include:
- `rename`
- `remotefortressreader`
- `isoworldremote`
Plugins that use the RPC API include:
- `stonesense`
Third-party tools that use the RPC API include:
- `Armok Vision <https://github.com/RosaryMala/armok-vision>`_ (:forums:`Bay12 forums thread <146473>`)
Client libraries
----------------
Some external libraries are available for interacting with the remote interface
from other (non-C++) languages, including:
- `RemoteClientDF-Net <https://github.com/RosaryMala/RemoteClientDF-Net>`_ for C#
- `dfhackrpc <https://github.com/BenLubar/dfhackrpc>`_ for Go
- `dfhack-remote <https://github.com/alexchandel/dfhack-remote>`_ for JavaScript
Protocol description
====================
This is a low-level description of the RPC protocol, which may be useful when
developing custom clients.
A WireShark dissector for this protocol is available in the
`df_misc repo <https://github.com/DFHack/df_misc/blob/master/wireshark_dfhack_rpc.lua>`_.
Built-in messages
-----------------
These messages have hardcoded IDs; all others must be obtained through ``BindMethod``.
=== ============ =============================== =======================
ID Method Input Output
=== ============ =============================== =======================
0 BindMethod dfproto.CoreBindRequest dfproto.CoreBindReply
1 RunCommand dfproto.CoreRunCommandRequest dfproto.EmptyMessage
=== ============ =============================== =======================
Conversation flow
-----------------
* Client → Server: `handshake request`_
* Server → Client: `handshake reply`_
* Repeated 0 or more times:
* Client → Server: `request`_
* Server → Client: `text`_ (0 or more times)
* Server → Client: `result`_ or `failure`_
* Client → Server: `quit`_
Raw message types
-----------------
* All numbers are little-endian
* All strings are ASCII
* A payload size of greater than 64MiB is an error
* See ``RemoteClient.h`` for definitions of constants starting with ``RPC``
handshake request
~~~~~~~~~~~~~~~~~
.. csv-table::
:align: left
:header-rows: 1
Type, Name, Value
char[8], magic, ``DFHack?\n``
int32_t, version, 1
handshake reply
~~~~~~~~~~~~~~~
.. csv-table::
:align: left
:header-rows: 1
Type, Name, Value
char[8], magic, ``DFHack!\n``
int32_t, version, 1
header
~~~~~~
**Note:** the two fields of this message are sometimes repurposed. Uses of this
message are represented as ``header(x, y)``, where ``x`` corresponds to the ``id``
field and ``y`` corresponds to ``size``.
.. csv-table::
:align: left
:header-rows: 1
Type, Name
int16_t, id
int16_t, (padding - unused)
int32_t, size
request
~~~~~~~
.. list-table::
:align: left
:header-rows: 1
:widths: 25 75
* - Type
- Description
* - `header`_
- ``header(id, size)``
* - buffer
- Protobuf-encoded payload of the input message type of the method specified by ``id``; length of ``size`` bytes
text
~~~~
.. list-table::
:align: left
:header-rows: 1
:widths: 25 75
* - Type
- Description
* - `header`_
- ``header(RPC_REPLY_TEXT, size)``
* - buffer
- Protobuf-encoded payload of type ``dfproto.CoreTextNotification``; length of ``size`` bytes
result
~~~~~~
.. list-table::
:align: left
:header-rows: 1
:widths: 25 75
* - Type
- Description
* - `header`_
- ``header(RPC_REPLY_RESULT, size)``
* - buffer
- Protobuf-encoded payload of the output message type of the oldest incomplete method call; when received,
that method call is considered completed. Length of ``size`` bytes.
failure
~~~~~~~
.. list-table::
:align: left
:header-rows: 1
:widths: 25 75
* - Type
- Description
* - `header`_
- ``header(RPC_REPLY_FAIL, command_result)``
* - command_result
- return code of the command (a constant starting with ``CR_``; see ``RemoteClient.h``)
quit
~~~~
**Note:** the server closes the connection after receiving this message.
.. list-table::
:align: left
:header-rows: 1
:widths: 25 75
:width: 100%
* - Type
- Description
* - `header`_
- ``header(RPC_REQUEST_QUIT, 0)``

@ -15,5 +15,6 @@ These are pages relevant to people developing for DFHack.
/docs/Documentation
/docs/Structures-intro
/docs/Memory-research
/docs/Remote
/docs/Binpatches