pub struct Handle { /* private fields */ }
Expand description
Handle to a client.
After connecting a Client
to a broker, Handle
s are used to
interact with it. The first Handle
can be acquired with
Client::handle
. After that, Handle
s can be cloned
cheaply.
The Client
will automatically shut down when the last Handle
has been
dropped.
§Examples
use aldrin::Client;
// Connect to the broker:
let client = Client::connect(async_transport).await?;
// Acquire the first handle:
let handle = client.handle().clone();
// Run the client, which consumes it and leaves only the handle for interacting with it:
tokio::spawn(client.run());
// Handles are cheap to clone:
let handle2 = handle.clone();
Implementations§
source§impl Handle
impl Handle
sourcepub fn shutdown(&self)
pub fn shutdown(&self)
Shuts down the client.
Shutdown happens asynchronously, in the sense that when this function returns, the
Client
has only been requested to shut down and not yet necessarily done
so. As soon as Client::run
returns, it has fully shut down.
If the Client
has already shut down (due to any reason), this function
will not treat that as an error. This is different than most other functions, which would
return Error::Shutdown
instead.
sourcepub async fn create_object(
&self,
uuid: impl Into<ObjectUuid>
) -> Result<Object, Error>
pub async fn create_object( &self, uuid: impl Into<ObjectUuid> ) -> Result<Object, Error>
Creates a new object on the bus.
The uuid
must not yet exists on the bus, or else Error::DuplicateObject
will be
returned. Use ObjectUuid::new_v4
to create a new random v4 UUID.
§Examples
use aldrin::Error;
use aldrin::core::ObjectUuid;
use uuid::uuid;
const OBJECT2_UUID: ObjectUuid = ObjectUuid(uuid!("6173e119-8066-4776-989b-145a5f16ed4c"));
// Create an object with a random UUID:
let object1 = handle.create_object(ObjectUuid::new_v4()).await?;
// Create an object with a fixed UUID:
let object2 = handle.create_object(OBJECT2_UUID).await?;
// Using the same UUID again will cause an error:
assert_eq!(
handle.create_object(OBJECT2_UUID).await.unwrap_err(),
Error::DuplicateObject,
);
sourcepub fn call_function<Args, T, E>(
&self,
service_id: ServiceId,
function: u32,
args: &Args
) -> Result<PendingFunctionResult<T, E>, Error>
pub fn call_function<Args, T, E>( &self, service_id: ServiceId, function: u32, args: &Args ) -> Result<PendingFunctionResult<T, E>, Error>
Calls a function on a service.
The function with id function
will be called with the arguments args
on the service
identified by service_id
.
The returned value of type PendingFunctionResult
is a future which will resolve to the
result of the function call.
§Examples
use aldrin::core::Value;
// Call function 1 with "1 + 2 = ?" as the argument.
let result = handle.call_function::<_, u32, String>(service_id, 1, "1 + 2 = ?")?;
// Await the result. The `?` here checks for errors on the protocol level, such as a
// intermediate shutdown, or whether the function call was aborted by the callee.
let result = result.await?;
// Now, result is of type `Result<u32, String>`, directly representing the result of the
// function call.
match result {
Ok(ok) => assert_eq!(ok, 3),
Err(err) => panic!("Function call failed: {}.", err),
}
sourcepub fn call_infallible_function<Args, T>(
&self,
service_id: ServiceId,
function: u32,
args: &Args
) -> Result<PendingFunctionValue<T>, Error>
pub fn call_infallible_function<Args, T>( &self, service_id: ServiceId, function: u32, args: &Args ) -> Result<PendingFunctionValue<T>, Error>
Calls an infallible function on a service.
Use this method if the called function is guaranteed to never fail. If this is not true, and
the function fails, then Error::InvalidReply
will be returned.
The returned value of type PendingFunctionValue
is a future which will resolve to the
value of the function call.
§Examples
// Call function 1 with "1 + 2 = ?" as the argument.
let result = handle.call_infallible_function::<_, u32>(service_id, 1, "1 + 2 = ?")?;
assert_eq!(result.await?, 3);
sourcepub fn events(&self) -> Events
pub fn events(&self) -> Events
Creates an Events object used to subscribe to service events.
See Events
for more information and usage examples.
sourcepub fn emit_event<T>(
&self,
service_id: ServiceId,
event: u32,
value: &T
) -> Result<(), Error>
pub fn emit_event<T>( &self, service_id: ServiceId, event: u32, value: &T ) -> Result<(), Error>
Emits an events to subscribed clients.
The event with the id event
of the service identified by service_id
will be emitted with
the arguments args
to all subscribed clients.
Use Handle::events
to subscribe to events.
§Examples
// Emit event 1 with argument "Hello, world!":
handle.emit_event(service_id, 1, "Hello, world!")?;
sourcepub async fn query_service_version(
&self,
service_id: ServiceId
) -> Result<u32, Error>
pub async fn query_service_version( &self, service_id: ServiceId ) -> Result<u32, Error>
Queries the version of a service.
§Examples
use aldrin::core::{ObjectUuid, ServiceUuid};
use aldrin::Error;
let object = handle.create_object(ObjectUuid::new_v4()).await?;
let service = object.create_service(ServiceUuid::new_v4(), 2).await?;
let version = handle.query_service_version(service.id()).await;
assert_eq!(version, Ok(2));
service.destroy().await?;
let version = handle.query_service_version(service.id()).await;
assert_eq!(version, Err(Error::InvalidService));
sourcepub async fn create_channel_with_claimed_sender<T>(
&self
) -> Result<(PendingSender<T>, UnclaimedReceiver<T>), Error>where
T: Serialize + Deserialize,
pub async fn create_channel_with_claimed_sender<T>(
&self
) -> Result<(PendingSender<T>, UnclaimedReceiver<T>), Error>where
T: Serialize + Deserialize,
Creates a channel and automatically claims the sender.
When creating a channel, one of the two end must be claimed immediately. This function
claims the sender. Use
create_channel_with_claimed_receiver
to
claim the receiver instead.
§Examples
This example assumes that there are 2 clients, represented here by handle1
and handle2
.
// Client 1 creates the channel. It then unbinds the receiver and makes it available to
// client 2. This will typically happen by returning it from a function call.
let (sender, receiver) = handle1.create_channel_with_claimed_sender().await?;
let receiver = receiver.unbind();
// Client 2 gets access to the receiver, and then binds and claims it.
let mut receiver = receiver.claim(handle2.clone(), 16).await?;
// Meanwhile, client 1 waits for the receiver to be claimed.
let mut sender = sender.established().await?;
// The channel is now fully established and client 1 can send items to client 2.
sender.send_item(&1).await?;
sender.send_item(&2).await?;
sender.send_item(&3).await?;
// Client 1 will close (or drop) the channel when it has nothing to send anymore.
sender.close().await?;
// Client 2 receives all values in order. The Result in the return values can indicate
// conversion errors when an item isn't a u32.
assert_eq!(receiver.next_item().await, Ok(Some(1)));
assert_eq!(receiver.next_item().await, Ok(Some(2)));
assert_eq!(receiver.next_item().await, Ok(Some(3)));
// Client 2 can observe that the sender has been closed by receiving None. It follows by
// also closing (or dropping) the receiver.
assert_eq!(receiver.next_item().await, Ok(None));
receiver.close().await?;
sourcepub async fn create_channel_with_claimed_receiver<T>(
&self,
capacity: u32
) -> Result<(UnclaimedSender<T>, PendingReceiver<T>), Error>where
T: Serialize + Deserialize,
pub async fn create_channel_with_claimed_receiver<T>(
&self,
capacity: u32
) -> Result<(UnclaimedSender<T>, PendingReceiver<T>), Error>where
T: Serialize + Deserialize,
Creates a channel and automatically claims the receiver.
When creating a channel, one of the two end must be claimed immediately. This function
claims the receiver. Use
create_channel_with_claimed_sender
to claim
the sender instead.
A capacity
of 0 is treated as if 1 was specificed instead.
§Examples
See create_channel_with_claimed_sender
for an
example.
sourcepub async fn sync_client(&self) -> Result<(), Error>
pub async fn sync_client(&self) -> Result<(), Error>
Synchronizes with the client.
This function ensures that all previous requests to the client have been processed. There
are some occasions in which requests are sent outside of an async context, e.g. when
dropping values such as Object
. By synchronizing with the client, it is possible to
ensure that it has processed such a non-async request.
See also sync_broker
, which ensures that such requests have been
processed by the broker.
§Examples
use aldrin::core::ObjectUuid;
use std::mem;
let obj = handle.create_object(ObjectUuid::new_v4()).await?;
// Dropping obj will request the client to destroy the object.
mem::drop(obj);
// Ensure the request has actually been processed by the client.
handle.sync_client().await?;
sourcepub async fn sync_broker(&self) -> Result<(), Error>
pub async fn sync_broker(&self) -> Result<(), Error>
Synchronizes with the broker.
Certain requests such as emitting an event or sending an item on a channel don’t synchronize with the broker in the same way as e.g. creating an object does. This function can be used to ensure that such a request has been processed by the broker.
See also sync_client
, which ensures only that such requests have been
processed by the client.
§Examples
handle.emit_event(service.id(), 0, "Hi!")?;
// Synchronize with the broker to ensure that the event has actually been processed.
handle.sync_broker().await?;
sourcepub async fn create_bus_listener(&self) -> Result<BusListener, Error>
pub async fn create_bus_listener(&self) -> Result<BusListener, Error>
Creates a new bus listener.
Bus listeners enable monitoring the bus for events about the creation and destruction of
objects and services. See BusListener
for more information and usage examples.
sourcepub fn create_discoverer<Key>(&self) -> DiscovererBuilder<'_, Key>
pub fn create_discoverer<Key>(&self) -> DiscovererBuilder<'_, Key>
Create a new DiscovererBuilder
.
sourcepub async fn find_object<const N: usize>(
&self,
object: Option<ObjectUuid>,
services: &[ServiceUuid; N]
) -> Result<Option<(ObjectId, [ServiceId; N])>, Error>
pub async fn find_object<const N: usize>( &self, object: Option<ObjectUuid>, services: &[ServiceUuid; N] ) -> Result<Option<(ObjectId, [ServiceId; N])>, Error>
Find an object with a specific set of services.
If object
is None
, then any object that has all required services may be
returned. Repeated calls to this function can return different objects.
This is a convenience function for using a Discoverer
to find a single object among all
current objects on the bus.
§Examples
// Create an object and 2 services to find.
let obj = client.create_object(ObjectUuid::new_v4()).await?;
let svc1 = obj.create_service(ServiceUuid::new_v4(), 0).await?;
let svc2 = obj.create_service(ServiceUuid::new_v4(), 0).await?;
// Find the object.
let (object_id, service_ids) = client
.find_object(Some(obj.id().uuid), &[svc1.id().uuid, svc2.id().uuid])
.await?
.unwrap();
assert_eq!(object_id, obj.id());
assert_eq!(service_ids[0], svc1.id());
assert_eq!(service_ids[1], svc2.id());
Without specifying an ObjectUuid
:
// Create 2 objects and sets of services to find.
let obj1 = client.create_object(ObjectUuid::new_v4()).await?;
let svc11 = obj1.create_service(ServiceUuid::new_v4(), 0).await?;
let svc12 = obj1.create_service(ServiceUuid::new_v4(), 0).await?;
let obj2 = client.create_object(ObjectUuid::new_v4()).await?;
let svc21 = obj2.create_service(svc11.id().uuid, 0).await?;
let svc22 = obj2.create_service(svc12.id().uuid, 0).await?;
// Find any one of the objects above.
let (object_id, service_ids) = client
.find_object(None, &[svc11.id().uuid, svc12.id().uuid])
.await?
.unwrap();
assert!((object_id == obj1.id()) || (object_id == obj2.id()));
assert!((service_ids[0] == svc11.id()) || (service_ids[0] == svc21.id()));
assert!((service_ids[1] == svc12.id()) || (service_ids[1] == svc22.id()));
sourcepub async fn find_any_object<const N: usize>(
&self,
services: &[ServiceUuid; N]
) -> Result<Option<(ObjectId, [ServiceId; N])>, Error>
pub async fn find_any_object<const N: usize>( &self, services: &[ServiceUuid; N] ) -> Result<Option<(ObjectId, [ServiceId; N])>, Error>
Finds any object implementing a set of services.
This is a shorthand for calling find_object(None, services)
.
sourcepub async fn find_specific_object<const N: usize>(
&self,
object: impl Into<ObjectUuid>,
services: &[ServiceUuid; N]
) -> Result<Option<(ObjectId, [ServiceId; N])>, Error>
pub async fn find_specific_object<const N: usize>( &self, object: impl Into<ObjectUuid>, services: &[ServiceUuid; N] ) -> Result<Option<(ObjectId, [ServiceId; N])>, Error>
Finds a specific object implementing a set of services.
This is a shorthand for calling find_object(Some(object), services)
.
sourcepub async fn wait_for_object<const N: usize>(
&self,
object: Option<ObjectUuid>,
services: &[ServiceUuid; N]
) -> Result<(ObjectId, [ServiceId; N]), Error>
pub async fn wait_for_object<const N: usize>( &self, object: Option<ObjectUuid>, services: &[ServiceUuid; N] ) -> Result<(ObjectId, [ServiceId; N]), Error>
Waits for an object with a specific set of services.
If object
is None
, then any object that has all required services may be
returned. Repeated calls to this function can return different objects.
This is a convenience function for using a Discoverer
to find a single object.
sourcepub async fn wait_for_any_object<const N: usize>(
&self,
services: &[ServiceUuid; N]
) -> Result<(ObjectId, [ServiceId; N]), Error>
pub async fn wait_for_any_object<const N: usize>( &self, services: &[ServiceUuid; N] ) -> Result<(ObjectId, [ServiceId; N]), Error>
Wait for any object implementing a set of services.
This is a shorthand for calling wait_for_object(None, services)
.
sourcepub async fn wait_for_specific_object<const N: usize>(
&self,
object: impl Into<ObjectUuid>,
services: &[ServiceUuid; N]
) -> Result<(ObjectId, [ServiceId; N]), Error>
pub async fn wait_for_specific_object<const N: usize>( &self, object: impl Into<ObjectUuid>, services: &[ServiceUuid; N] ) -> Result<(ObjectId, [ServiceId; N]), Error>
Wait for a specific object implementing a set of services.
This is a shorthand for calling wait_for_object(Some(object), services)
.
sourcepub async fn create_lifetime_scope(&self) -> Result<LifetimeScope, Error>
pub async fn create_lifetime_scope(&self) -> Result<LifetimeScope, Error>
Creates a new lifetime scope.
sourcepub async fn create_lifetime(&self, id: LifetimeId) -> Result<Lifetime, Error>
pub async fn create_lifetime(&self, id: LifetimeId) -> Result<Lifetime, Error>
Create a Lifetime
from an id.
sourcepub async fn version(&self) -> Result<ProtocolVersion, Error>
pub async fn version(&self) -> Result<ProtocolVersion, Error>
Returns the protocol version that was negotiated with the broker.