Module: Roby::Interface
- Extended by:
- Logger::Hierarchy
- Includes:
- V1
- Defined in:
- lib/roby/interface/base.rb,
lib/roby/interface.rb,
lib/roby/interface/v1.rb,
lib/roby/interface/v2.rb,
lib/roby/interface/job.rb,
lib/roby/interface/core.rb,
lib/roby/interface/async.rb,
lib/roby/interface/async.rb,
lib/roby/interface/v1/tcp.rb,
lib/roby/interface/v2/tcp.rb,
lib/roby/interface/command.rb,
lib/roby/interface/rest/api.rb,
lib/roby/interface/v1/async.rb,
lib/roby/interface/v2/async.rb,
lib/roby/interface/interface.rb,
lib/roby/interface/rest/task.rb,
lib/roby/interface/rest/test.rb,
lib/roby/interface/v1/client.rb,
lib/roby/interface/v1/server.rb,
lib/roby/interface/v2/client.rb,
lib/roby/interface/v2/server.rb,
lib/roby/interface/exceptions.rb,
lib/roby/interface/v2/channel.rb,
lib/roby/interface/rest/server.rb,
lib/roby/interface/v2/protocol.rb,
lib/roby/interface/rest/helpers.rb,
lib/roby/interface/v1/async/log.rb,
lib/roby/interface/v2/async/log.rb,
lib/roby/interface/command_library.rb,
lib/roby/interface/v1/shell_client.rb,
lib/roby/interface/v2/shell_client.rb,
lib/roby/interface/command_argument.rb,
lib/roby/interface/v1/droby_channel.rb,
lib/roby/interface/v1/async/interface.rb,
lib/roby/interface/v2/async/interface.rb,
lib/roby/interface/v1/shell_subcommand.rb,
lib/roby/interface/v2/shell_subcommand.rb,
lib/roby/interface/v1/async/job_monitor.rb,
lib/roby/interface/v1/subcommand_client.rb,
lib/roby/interface/v2/async/job_monitor.rb,
lib/roby/interface/v2/subcommand_client.rb,
lib/roby/interface/v1/async/ui_connector.rb,
lib/roby/interface/v2/async/ui_connector.rb,
lib/roby/interface/v1/async/action_monitor.rb,
lib/roby/interface/v2/async/action_monitor.rb,
lib/roby/interface/v1/async/new_job_listener.rb,
lib/roby/interface/v2/async/new_job_listener.rb
Overview
High-level command and control of a Roby controller
The Interface module provides a high-level control interface to a running Roby controller. It is the basis for all remote Roby UIs such as the Syskit IDE or the Roby shell. The following documentation aims at giving a bird eye’s view of the module’s structure
Jobs
The high-level construct used in the Roby interface is the job. Jobs are representation of the high-level goals that a user gave to the system. A task represents a job if:
-
it provides the Interface::Job service
-
it has a non-nil Interface::Job#job_id argument
-
itself or its planned task is a mission
In case a job task is a planning task, the job itself will be represented by the job’s planned task. Across the job-related APIs, one will see that jobs are therefore associated with two tasks: the task or placeholder task, and the job task itself.
The interface APIs provide ways to track the progress of jobs. Each job transition is represented by a Interface::JOB_* constant (e.g. JOB_READY), and notifications are sent to remote endpoints about the current state and progress of jobs.
Synchronous Client/Server API
A Roby application will in most cases create an Interface object, which is the endpoint for all interface-related matters. A client/server mechanism allows to access the app’s interface. V1::Server provides the server-side and V1::Client the client-side. Both classes are independent of the communication channel used. The communication is based on marshalling and demarshalling of an array that represents a method name and arguments on the Interface class. The marshalling/demarshalling and the exact packet format is left to the channel class given to Client and Server at construction time (see below)
The core of the method calls on V1::Client are the calls available on Interface. Check the latter to figure out what you can do with the former. In addition, it supports starting actions (and jobs) using an action_name!(arguments) syntax. This is meant as syntactic sugar for use in interactive implementations, but one should use Interface#start_job when starting jobs programmatically.
In addition to the remote method calls, the Client API provides notifications pushed by the interface:
-
V1::Client#pop_notification: general log messages from Application#notify. By default, all log messages generated from Robot are forwarded this way
-
V1::Client#pop_job_progress: job progress
-
V1::Client#pop_exception: about exceptions
Asynchronous API
To connect to the client/server API, one has to have a remote Roby app to connect to. Moreoover, the API is really designed as a request/response scheme, which is not a very nice format to build UIs from.
For these, reasons, a higher level, event-based API has been built on top of the client/server functionality. The main entrypoint for this asynchronous API is V1::Async::Interface. In addition to properly handling (re)connections, this API provides also a nicer interface to job tracking.
Jobs are represented by V1::Async::JobMonitor objects, which track the job state and provide operations on them such as killing, dropping and restarting them as well as registering hooks to track their progress. One usually gets these job monitor objects by listening for new jobs using V1::Async::Interface#on_job.
Note that in most cases, new job monitor objects are inactive (i.e. won’t get notifications) until you explicitely call V1::Async::JobMonitor#start on them. Whether this is the case or not is documented on each method that return or yield a job monitor object.
Asynchronous log stream API
In addition to the notifications provided by V1::Client, one can use the Roby logging to build a complete representation of a plan. The V1::Async::Log class gives easy-to-use access to such a rebuilt plan, along with the ability to disconnect and reconnect to a remote Roby app.
Event Loop Integration
Interface hooks itself in the app’s main event loop, as does V1::TCPServer. On the client side, processing is done in V1::Client#poll which therefore needs to be called periodically within your app’s main loop. In Qt, it usually means starting a timer
timer = Qt::Timer.new(self)
timer.connect(SIGNAL('timeout()')) do
client.poll
end
Communication Channel
V1::DRobyChannel provides a default implementation, using the DRoby marshalling/demarshalling for object-to-binary translation, WebSockets for framing and a subclass of IO as the underlying communication medium. The most common usage is to spawn a TCP server based on this channel with V1::TCPServer, and connect to it from the client side with Interface.connect_with_tcp_to. A Roby application spawns such a server automatically by calling Application#setup_shell_interface if Application#public_shell_interface? is true.
Defined Under Namespace
Modules: Async, REST, V1, V2 Classes: ComError, Command, CommandArgument, CommandLibrary, ConnectionError, Interface, InvalidState, ProtocolError
Constant Summary collapse
- DEFAULT_PORT =
20_201
- DEFAULT_REST_PORT =
20_202
- DEFAULT_PORT_V2 =
20_203
- JOB_PLANNING_READY =
The job’s planning task is ready to be executed
:planning_ready
- JOB_PLANNING =
The job’s planning task is running
:planning
- JOB_PLANNING_FAILED =
The job’s planning task has failed
:planning_failed
- JOB_READY =
The job’s main task is ready to be executed
:ready
- JOB_STARTED =
The job is started
:started
- JOB_SUCCESS =
The job has finished successfully
:success
- JOB_FAILED =
The job has failed
:failed
- JOB_FINISHED =
The job has finished
:finished
- JOB_FINALIZED =
The job has been finalized (i.e. removed from plan)
:finalized
- JOB_DROPPED =
The job has been dropped, i.e. its mission status has been removed
:dropped
- JOB_MONITORED =
Initial notification, when the interface starts monitoring a job
:monitored
- JOB_LOST =
The job got replaced by a task that is not this job
:lost
- JOB_REPLACED =
The job placeholder task got replaced, and the replacement is managed under the same job
:replaced
Class Method Summary collapse
- .connect_with_tcp_to(host, port = DEFAULT_PORT, marshaller: DRoby::Marshal.new(auto_create_plans: true), handshake: %i[actions commands]) ⇒ Object
-
.error_state?(state) ⇒ Boolean
Tests if the given state (one of the JOB_ constants) means that the job finished with error.
-
.finalized_state?(state) ⇒ Boolean
Tests if the given state (one of the JOB_ constants) means that the job has been finalized (removed from plan).
-
.planning_finished_state?(state) ⇒ Boolean
Whether the given state indicates that the job’s planning is finished.
-
.running_state?(state) ⇒ Boolean
Tests if the given state (one of the JOB_ constants) means that the job is still running.
-
.success_state?(state) ⇒ Boolean
Tests if the given state (one of the JOB_ constants) means that the job finished successfully.
-
.terminal_state?(state) ⇒ Boolean
Tests if the given state (one of the JOB_ constants) is terminal, e.g.
Class Method Details
.connect_with_tcp_to(host, port = DEFAULT_PORT, marshaller: DRoby::Marshal.new(auto_create_plans: true), handshake: %i[actions commands]) ⇒ Object
23 24 25 26 27 28 29 30 31 |
# File 'lib/roby/interface.rb', line 23 def self.connect_with_tcp_to( host, port = DEFAULT_PORT, marshaller: DRoby::Marshal.new(auto_create_plans: true), handshake: %i[actions commands] ) V1.connect_with_tcp_to( host, port, marshaller: marshaller, handshake: handshake ) end |
.error_state?(state) ⇒ Boolean
Tests if the given state (one of the JOB_ constants) means that the job finished with error
54 55 56 |
# File 'lib/roby/interface/interface.rb', line 54 def self.error_state?(state) [JOB_PLANNING_FAILED, JOB_FAILED].include?(state) end |
.finalized_state?(state) ⇒ Boolean
Tests if the given state (one of the JOB_ constants) means that the job has been finalized (removed from plan)
66 67 68 |
# File 'lib/roby/interface/interface.rb', line 66 def self.finalized_state?(state) [JOB_FINALIZED].include?(state) end |
.planning_finished_state?(state) ⇒ Boolean
Whether the given state indicates that the job’s planning is finished
36 37 38 |
# File 'lib/roby/interface/interface.rb', line 36 def self.planning_finished_state?(state) ![JOB_PLANNING_READY, JOB_PLANNING, JOB_FINALIZED].include?(state) end |
.running_state?(state) ⇒ Boolean
Tests if the given state (one of the JOB_ constants) means that the job is still running
60 61 62 |
# File 'lib/roby/interface/interface.rb', line 60 def self.running_state?(state) [JOB_STARTED].include?(state) end |
.success_state?(state) ⇒ Boolean
Tests if the given state (one of the JOB_ constants) means that the job finished successfully
48 49 50 |
# File 'lib/roby/interface/interface.rb', line 48 def self.success_state?(state) [JOB_SUCCESS].include?(state) end |
.terminal_state?(state) ⇒ Boolean
Tests if the given state (one of the JOB_ constants) is terminal, e.g. means that the job is finished
42 43 44 |
# File 'lib/roby/interface/interface.rb', line 42 def self.terminal_state?(state) [JOB_PLANNING_FAILED, JOB_FAILED, JOB_SUCCESS, JOB_FINISHED, JOB_FINALIZED].include?(state) end |