Struct dittolive_ditto::transport::Presence
source · pub struct Presence { /* private fields */ }
Expand description
Presence
to visualize the mesh.
Even if Ditto works as a standalone, other peers are needed to exploit it at its maximum extend : syncing data and merging it.
The Presence
struct allows you to get and monitor known peers.
The peers are regrouped inside a PresenceGraph
.
You can get Presence
using the Ditto::presence
method.
To have an immediate graph of peers, use Presence::graph
:
let presence_graph = ditto.presence().graph();
To monitor peers, use Presence::observe
to call a callback each time peers are updated:
let handle = ditto.presence().observe(|presence_graph| {
// Do something with peers
});
Implementations§
source§impl Presence
impl Presence
sourcepub fn observe(
self: &Arc<Self>,
callback: impl Fn(&PresenceGraph) + Send + Sync + 'static
) -> PresenceObserver
pub fn observe( self: &Arc<Self>, callback: impl Fn(&PresenceGraph) + Send + Sync + 'static ) -> PresenceObserver
Allow to call a callback each time there is a change in known peers.
The returned PresenceObserver
must be kept in scope to keep receiving updates.
sourcepub fn graph(&self) -> PresenceGraph
pub fn graph(&self) -> PresenceGraph
Return an immediate representation of known peers
source§impl Presence
impl Presence
sourcepub fn set_peer_metadata(
&self,
peer_metadata: &impl Serialize
) -> Result<(), DittoError>
pub fn set_peer_metadata( &self, peer_metadata: &impl Serialize ) -> Result<(), DittoError>
Set a dictionary of arbitrary data about this device to be shared with peers in the mesh.
This data is gossiped in the presence collection across the mesh. This can be useful to include extra metadata like app versions,capabilities, etc., to help peers decide who to interact with.
This peer information is persisted in the SDK, and thus needn’t be set at every start of Ditto.
Security (and caveats)
This peer info will be signed by your peer key to prevent forgery of this info by other peers.
However, for compatibility, there is no attestation of the lack of peer info – that is, participants in the mesh could maliciously remove peer info. If this is a concern for your application, a workaround for this is to have your application require that peers have a signed peer info dictionary present.
Similarly, as there is no monotonic version counter or timestamp/expiration of the signed peer info, replay attacks (replacing the current info with previously, possibly outdated, signed info) are possible without counter-measures. If this is a concern for your application, you might consider including a counter or creation timestamp to prevent replays, depending on your use-case.
When a peer is only connected via WebSocket, peer metadata is not available.
Performance caveats
Because this information is included in the presence data that is gossiped among peers, the size of this peer info and the frequency it is updated can drastically affect performance if it is too large.
Errors
Because of the performance implications, the serialized info dictionary is currently limited to 4KiB.
Examples
use dittolive_ditto::prelude::*;
use serde_json::json;
ditto.presence().set_peer_metadata(&json!({
"app_version": "1.0.0",
}))?;
sourcepub fn set_peer_metadata_json_str(&self, json: &str) -> Result<(), DittoError>
pub fn set_peer_metadata_json_str(&self, json: &str) -> Result<(), DittoError>
Set arbitrary metadata formatted as JSON to be associated with the current peer.
The metadata must not exceed 4 KB in size. Expects JSON.
- See also:
Self::set_peer_metadata()
for details on usage of metadata.
sourcepub fn peer_metadata_json_str(&self) -> String
pub fn peer_metadata_json_str(&self) -> String
Metadata associated with the current peer as JSON-encoded data.
Other peers in the same mesh can access this user-provided dictionary of
metadata via the presence graph at Self::graph()
and when
evaluating connection requests using
Self::set_connection_request_handler()
. Use Self::set_peer_metadata()
or Self::set_peer_metadata_json_str()
to set this value.
sourcepub fn peer_metadata_serde<T: DeserializeOwned>(&self) -> Result<T>
pub fn peer_metadata_serde<T: DeserializeOwned>(&self) -> Result<T>
DeserializeOwned
convenience around Self::peer_metadata_json_str()
.
sourcepub fn peer_metadata(&self) -> Arc<Map<String, Value>>
pub fn peer_metadata(&self) -> Arc<Map<String, Value>>
Metadata associated with the current peer.
Other peers in the same mesh can access this user-provided dictionary of
metadata via the presence graph at Self::graph()
and when
evaluating connection requests using
Self::set_connection_request_handler()
. Use Self::set_peer_metadata()
or Self::set_peer_metadata_json_str()
to set this value.
This is a convenience property that wraps Self::peer_metadata_json_str()
.
sourcepub fn set_connection_request_handler<F: IntoOption<impl 'static + Send + Sync + Fn(ConnectionRequest) -> ConnectionRequestAuthorization>>(
&self,
handler_or_none: F
)
pub fn set_connection_request_handler<F: IntoOption<impl 'static + Send + Sync + Fn(ConnectionRequest) -> ConnectionRequestAuthorization>>( &self, handler_or_none: F )
Set this handler to control which peers in a Ditto mesh can connect to the current peer.
Each peer in a Ditto mesh will attempt to connect to other peers that it can reach. By default, the mesh will try and establish connections that optimize for the best overall connectivity between peers. However, you can set this handler to assert some control over which peers you connect to.
If set, this handler is called for every incoming connection request
from a remote peer and is passed the other peer’s peer_key
,
peer_metadata
, and identity_service_metadata
. The handler can then
accept or reject the request by returning an according
ConnectionRequestAuthorization
value. When the connection
request is rejected, the remote peer may retry the connection request
after a short delay.
Connection request handlers must reliably respond to requests within a short time: if a handler takes too long to return, the connection request will fall back to being denied. The response –currently— times out after 10 seconds, but this exact value may be subject to change in future releases.
- Note: the handler is called from a different thread (“background hook”).
- See also:
Self::peer_metadata()
Example
/// Let's imagine the app we are maintaining has a bug in `1.2.3`:
const BUGGY_VERSION: &str = "1.2.3";
// We avoid problems in updated versions of our app with these ones by
// rejecting connections to them, like so:
ditto
.presence()
.set_connection_request_handler(|connection_request: ConnectionRequest| {
match connection_request
.peer_metadata()
.get("app_version")
.and_then(|it| it.as_str())
{
// Reject peers reporting a known buggy version or reporting no
// version at all.
Some(BUGGY_VERSION) | None => return ConnectionRequestAuthorization::Deny,
Some(_non_buggy_version) => { /* no reason to reject here */ }
}
// Potentially other checks/reasons to reject…
// Eventually:
ConnectionRequestAuthorization::Allow
});
// You can also unset the `connection_request_handler` by setting it to `None`.
// This uses the default handler, which accepts all requests.
ditto.presence().set_connection_request_handler(None);
sourcepub fn set_connection_request_handler_async<ConnectionRequestAuthorizationFut>(
&self,
async_callback: impl 'static + Send + Sync + Fn(ConnectionRequest) -> ConnectionRequestAuthorizationFut
)where
ConnectionRequestAuthorizationFut: 'static + Send + Future<Output = ConnectionRequestAuthorization>,
pub fn set_connection_request_handler_async<ConnectionRequestAuthorizationFut>( &self, async_callback: impl 'static + Send + Sync + Fn(ConnectionRequest) -> ConnectionRequestAuthorizationFut )where ConnectionRequestAuthorizationFut: 'static + Send + Future<Output = ConnectionRequestAuthorization>,
Convenience around Self::set_connection_request_handler()
that allows the callback to be
async
.
Not responding in time will lead to a handshake timeout, effectively rejecting the peer.