rstango
An implementation of the Tango distributed control system, written from scratch in Rust, for writing clients and device servers.
The protocol actually used to reach a device is a detail of the crate rather than of the
code using it: a dev::DevProxy talks to whatever backend can reach its target, and a
server::Server serves its devices on every backend able to serve them.
Every call is blocking, up to the timeout of the proxy or the deadline of the request:
there is no runtime to install. Each one also has an asynchronous *_async form, which
runs on any executor, so that a single thread can wait on many devices at once; either
way, the backend multiplexes the concurrent requests over the connection it shares.
Example: client
A client asks a device for what it wants and says which type it expects, one name giving one value and a tuple of names giving as many, in a single request.
use DevProxy;
use Result;
Example: server
A device server is a plain Rust struct, its model, and the functions of it that the attributes and the commands of the device are defined from. Nothing is implemented on the model and no macro is involved: a read function is given a shared access to it, a write or an exclusive command an exclusive one, and the server takes care of the lock.
use Result;
use ;
/// The model of one device, owned by the server serving it.
/// Serve the devices the database lists for this server until it is stopped.
The server is named after its executable, as cppTango does, and its instance is taken
from the command line, so that a Counter executable is launched as the Counter/test
server with:
-v logs more, once per level, and --host and --port say where to listen. With
--dev, the server serves a database of its own for testing, with those devices and the
--prop properties in it, so that it runs with no Tango database at all:
from_args comes with the default cli feature. A server with options of its own
flattens ServerArgs into its own clap parser and builds itself with
ServerBuilder::from_raw_args, and one without the feature names itself with
ServerBuilder::new("Counter", "test").
More complete examples are in examples/:
server.rs is a Motor device server with properties, events and
a failing init, and every other example is a client of it showing one feature:
client.rs the basics, info.rs introspection,
errors.rs failures, props.rs properties,
events.rs events and concurrent.rs
asynchronous requests.
Modules
dev—DevProxy, the client handle to a device: names, state/status,Init, commands, attributes and their configuration, properties, events and the black box.database—DatabaseProxy, aDevProxyto the Tango database device, plus what is specific to it: free/class/device/attribute properties, lookups, and the registration of servers and devices.server—ServerBuilder/Server,ClassDef/AttrDef/CommandDefandDev<M>: the server-side API for defining classes and serving devices, theDServeradmin device every server exposes and, with theclifeature,ServerArgs.backend— theBackend/BackendDev/BackendServertraits every protocol implements, and the process-global default backend devices connect through when none is given explicitly. A device served in the same process is reached directly, without going through any protocol.corba— the CORBA/GIOP backend: a from-scratch implementation of the subset of GIOP/IIOP that Tango needs, so no omniORB is linked in. The ZMQ event system (seeZMQ.md) is part of it, built over the C library binding and reusing its CDR layer for marshalling.value—Valueand theFromValue/IntoValueconversions, what commands, attributes and events carry,DevEncodedincluded (decoded as an image with theimagefeature).buf—Buf, the typed N-dimensional buffer aValueholds, sharing the octets a message was received into rather than copying them.prop— parsing and serializing of property values, which Tango always represents as an array of strings.name— case-insensitive names andTrl, a validated Tango Resource Locator (tango://host:port/...).error—Error/ErrorKind/Result, the error type shared by every layer, including the fullDevFailedreason catalogue from cppTango.testing—TestDatabaseandTestContext, for running servers and clients in a test with no Tango database.
Feature status
This is an experimental, from-scratch implementation; it covers what a well-behaved client and a straightforward device server need, but it is not a complete cppTango replacement yet.
Available:
- Device and database proxies: names, state/status,
Init, ping, black box, admin device, with lazy reconnection of a device that went away. - Typed command execution and attribute read/write, including the multi-name and
all-names (
All) forms. - Command and attribute info queries, attribute configuration changes, and free/class/device/attribute property get/set/delete.
- Event subscriptions on
DevProxy: attribute values (change, periodic, archive, user, alarm), data ready and attribute configuration. - Device servers: class/attribute/command definitions, synchronous or asynchronous handlers with shared or exclusive access to the model, dynamic devices, attributes and commands, memorized attributes, alarm and warning levels, and properties read from the database.
- Events pushed by a device (change, archive, user, alarm, data ready, and the state and status), and attribute configuration events sent on every change of it.
- Servers exporting their devices to the database, or serving a test database of their
own with
--dev, so that they run with no Tango database at all. - The
DServeradmin commands of the server itself (DevRestart,RestartServer,Kill,QueryClass,QueryDevice) and of the event system. - The CORBA backend (GIOP/IIOP subset), with no omniORB dependency.
- The ZMQ event system (protocol per
ZMQ.md), as client and as server, including the negotiation/subscription/heartbeat/confirmation phases; not implemented from cppTango: multicast (epgm://) endpoints, multi-TANGO_HOSTtopic variants, and active reconnection (a stopped heartbeat is reported, but resubscription only happens if the server comes back on the same endpoints).
Not yet implemented:
- Polling: the polling triggered by the device itself (a period of 0), the change and archive events of a polled attribute, which need their criteria, and the client-side polling fallback strategy.
- The criteria of change and archive events: everything a device pushes is sent.
- Command and attribute history, which the server does not marshal yet, and property
history (
DbGetPropertyHistoryand friends). DevVarEncodedArraydata, and Tango pipes.Group-style fan-out proxies, forwarded attributes, the logging service (its admin commands are declared only), and the OpenTelemetry trace-context extensions from Tango IDL v6.
Testing
cargo test needs no Tango database: besides the unit tests of the CDR/GIOP wire layer
and of the server-side model, the integration tests in tests/ run servers and
their clients in the test itself, each of them twice — once reaching the device directly
in the process, and once through the CORBA and ZMQ backends over the loopback.
The examples/ run against a real Tango database given by TANGO_HOST, or
against the one the server example serves itself with --dev.