Remote Procedure Call (RPC) sub-package¶
Dragonfly’s remote procedure call (RPC) sub-package allows for interaction with a dragonfly speech recognition engine running in a remote process. This is useful for building responsive GUI applications without having to integrate them into a loaded grammar or grammar rule.
Some use cases for this framework include:
- Listing available commands and grammars in the current context.
- Integrating and displaying documentation.
- Guiding the user through complex commands.
- A GUI for building dragonfly/third-party grammars.
RPC server¶
Dragonfly’s RPC server handles requests by processing each method through the current engine’s multiplexing timer interface. This allows engines to handle requests safely and keeps engine-specific implementation details out of the dragonfly.rpc sub-package.
Security tokens¶
The RPC server uses mandatory security tokens to authenticate client requests. This avoids some security issues where, for example, malicious web pages could send POST requests to the server, even if running on localhost.
If sending requests over an open network, please ensure that the connection is secure by using TLS or SSH port forwarding.
If the server’s security_token
constructor parameter is not
specified, a new token will be generated and printed to the console. Clients
must specify the security token either as the last positional argument or as
the security_token
keyword argument.
Errors will be raised if clients send no security token or a token that doesn’t match the server’s.
Class reference¶
-
exception
PermissionDeniedError
[source]¶ Error raised if clients send security tokens that don’t match the server’s.
-
class
RPCServer
(address='127.0.0.1', port=50051, ssl_context=None, threaded=True, security_token=None)[source]¶ RPC server class.
This class will run a local web server on port 50051 by default. The server expects requests using JSON-RPC 2.0.
Constructor arguments:
- address – address to use (str, default: “127.0.0.1”)
- port – port to use (int, default: 50051)
- ssl_context – SSL context object to pass to werkzeug.serving.run_simple (SSLContext, default: None).
- threaded – whether to use a separate thread to process each request (bool, default: True).
- security_token – security token for authenticating clients (str, default: None). A new token will be generated and printed if this parameter is unspecified.
The ssl_context parameter is explained in more detail in Werkzeug’s SSL serving documentation.
Secure connections can also be set up using OpenSSH port forwarding with a command such as:
$ ssh -NTf -L 50051:127.0.0.1:50051 <system-with-rpc-server>
Minor note: using an IP address instead of a hostname for the address parameter should increase performance somewhat, e.g. “127.0.0.1” instead of “localhost”.
Warning
Do not send requests to the server from the main engine thread; thread deadlocks will occur if you do this because the main thread cannot call timer functions and wait for a response at the same time. The RPC framework was designed to be used from remote processes.
Requests will not be processed if the engine is not connected and processing speech.
-
add_method
(method, name=None)[source]¶ Add an RPC method to the server.
Restarting the server is not required for the new method to be available.
This can be used to override method implementations if that is desirable.
This method can also be used as a decorator.
Parameters: - method (callable) – the implementation of the RPC method to add.
- name (str) – optional name of the RPC method to add. If this is
None, then
method.__name__
will be used instead.
-
remove_method
(name)[source]¶ Remove an RPC method from the server. This will not raise an error if the method does not exist.
Restarting the server is not required for the change to take effect.
Parameters: name (str) – the name of the RPC method to remove.
-
send_request
(method, params, id=0)[source]¶ Utility method to send a JSON-RPC request to the server. This will block the current thread until a response is received.
This method is mostly used for testing. If called from the engine’s main thread, a deadlock will occur.
This will raise an error if the request fails with an error or if the server is unreachable.
The server’s security token will automatically be added to the
params
list/dictionary.Parameters: - method (str) – name of the RPC method to call.
- params (list | dict) – parameters of the RPC method to call.
- id (int) – ID of the JSON-RPC request (default: 0).
Returns: JSON-RPC response
Return type: dict
Raises: RuntimeError
-
start
()[source]¶ Start the server.
This method is non-blocking, the RPC server will run on a separate daemon thread. This way it is not necessary to call
stop()
before the main thread terminates.
-
url
¶ The URL to send JSON-RPC requests to.
RPC methods¶
For RPC methods to work they must be added to the server with
add_method()
. For example:
from dragonfly.engines import get_engine
from dragonfly.rpc import RPCServer
# Initialise and start the server.
server = RPCServer()
server.start()
# Add the RPC method via decoration.
@server.add_method
def get_engine_language():
return get_engine().language
# add_method() can also be used normally.
server.add_method(get_engine_language)
Sending requests¶
Requests can be sent to the server using, the send_rpc_request()
function from Python:
send_rpc_request(
server.url, method="get_engine_language",
params=[server.security_token], id=0
)
Other tools such as curl can also be used.
Using positional arguments:
$ curl --data-binary '{"jsonrpc":"2.0","id": "0","method": "speak","params": ["hello world", "<security-token>"]}' -H 'content-type:text/json;' http://127.0.0.1:50051
Using key word arguments:
$ curl --data-binary '{"jsonrpc":"2.0","id": "0","method": "speak","params": {"text": "hello world", "security_token": "<security-token>"}}' -H 'content-type:text/json;' http://127.0.0.1:50051
Built-in RPC methods¶
-
get_engine_language
()[source]¶ Get the current engine’s language.
Returns: language code Return type: str
-
get_recognition_history
()[source]¶ Get the recognition history if an observer is registered.
The
register_history()
method must be called to register the observer first.Returns: history Return type: list
-
is_in_speech
()[source]¶ Whether the user is currently speaking.
The
register_history()
method must be called to register the observer first.Return type: bool
-
list_grammars
()[source]¶ Get a list of grammars loaded into the current engine.
This includes grammar rules and attributes.
-
mimic
(words)[source]¶ Mimic the given words.
Parameters: words – string or list of words to mimic Returns: whether the mimic was a success Return type: bool
-
register_history
(length=10, record_failures=False)[source]¶ Register an internal recognition observer.
Parameters: - length (int) – length to initialize the
RecognitionHistory
instance with (default10
). - record_failures (bool) – whether to record recognition failures
(default
False
).
- length (int) – length to initialize the
RPC utility functions¶
-
send_rpc_request
(url, method, params, id=0)[source]¶ Utility function to send a JSON-RPC request to a server.
This will raise an error if the request fails with an error or if the server is unreachable.
Parameters: - url (str) – the URL to send the JSON-RPC request to.
- method (str) – name of the RPC method to call.
- params (list) – parameters of the RPC method to call.
- id (int) – ID of the JSON-RPC request (default: 0).
Returns: JSON-RPC response
Return type: dict
Raises: RuntimeError