dittolive_ditto/presence/connection_request_handler.rs
1use_prelude!();
2use std::sync::{Arc, OnceLock};
3
4use super::JsonObject;
5use crate::transport::ConnectionType;
6
7/// Contains information about a remote peer that has requested a connection.
8///
9/// Connection requests and their authorization are scoped to a specific Ditto
10/// peer and connection type.
11///
12/// Information about a peer Ditto is currently trying to connect to. This struct is used by the
13/// [`Presence::set_connection_request_handler()`] callback to decide whether the Ditto client
14/// should connect to a given peer or not.
15pub struct ConnectionRequest {
16 raw: Arc<repr_c::Box<ffi_sdk::FfiConnectionRequest>>,
17 // An optional map of peer-provided information, signed by the peer.
18 cached_peer_metadata: OnceLock<Arc<JsonObject>>,
19 // An optional map of identity service-provided information, signed by the identity
20 // service.
21 cached_identity_service_metadata: OnceLock<Arc<JsonObject>>,
22 // The connecting peer's (pub) key (can be empty for legacy peers).
23 cached_peer_key: OnceLock<Arc<str>>,
24}
25
26impl ConnectionRequest {
27 pub(crate) fn new(raw: repr_c::Box<ffi_sdk::FfiConnectionRequest>) -> Self {
28 Self {
29 raw: Arc::new(raw),
30 cached_peer_metadata: <_>::default(),
31 cached_identity_service_metadata: <_>::default(),
32 cached_peer_key: <_>::default(),
33 }
34 }
35
36 pub(crate) fn raw(&self) -> Arc<repr_c::Box<ffi_sdk::FfiConnectionRequest>> {
37 self.raw.retain()
38 }
39
40 /// JSON-encoded metadata associated with the remote peer.
41 ///
42 /// JSON string representing an empty dictionary if the remote peer has not
43 /// set any metadata.
44 ///
45 /// Set peer metadata for the local peer using
46 /// [`Presence::set_peer_metadata()`] or
47 /// [`Presence::set_peer_metadata_json_str()`].
48 pub fn peer_metadata_json_str(&self) -> String {
49 String::from_utf8(
50 ffi_sdk::dittoffi_connection_request_peer_metadata_json(&*self.raw).to_vec(),
51 )
52 .expect("UTF-8")
53 }
54
55 /// [`DeserializeOwned`] convenience wrapper around [`Self::peer_metadata_json_str()`].
56 pub fn peer_metadata_serde<T: DeserializeOwned>(&self) -> Result<T> {
57 let value = ::serde_json::from_str(&self.peer_metadata_json_str())?;
58 Ok(value)
59 }
60
61 /// Metadata associated with the remote peer.
62 ///
63 /// Empty dictionary if the remote peer has not set any metadata.
64 ///
65 /// Set peer metadata for the local peer using
66 /// [`Presence::set_peer_metadata()`] or
67 /// [`Presence::set_peer_metadata_json_str()`].
68 ///
69 /// Convenience property that wraps [`Self::peer_metadata_json_str()`].
70 pub fn peer_metadata(&self) -> Arc<JsonObject> {
71 self.cached_peer_metadata
72 .get_or_init(|| {
73 Arc::new(
74 self.peer_metadata_serde()
75 .expect("incorrect json from `dittoffi`"),
76 )
77 })
78 .retain()
79 }
80
81 /// JSON-encoded metadata for the remote peer that is provided by the
82 /// identity service.
83 ///
84 /// Use an authentication webhook to set this value. See Ditto's online
85 /// documentation for more information on how to configure an authentication
86 /// webhook.
87 pub fn identity_service_metadata_json_str(&self) -> String {
88 String::from_utf8(
89 ffi_sdk::dittoffi_connection_request_identity_service_metadata_json(&*self.raw)
90 .to_vec(),
91 )
92 .expect("UTF-8")
93 }
94
95 /// [`DeserializeOwned`] convenience wrapper around
96 /// [`Self::identity_service_metadata_json_str()`].
97 pub fn identity_service_metadata_serde<T: DeserializeOwned>(&self) -> Result<T> {
98 let value = ::serde_json::from_str(&self.identity_service_metadata_json_str())?;
99 Ok(value)
100 }
101
102 /// Metadata for the remote peer that is provided by the identity service.
103 ///
104 /// Use an authentication webhook to set this value. See Ditto's online
105 /// documentation for more information on how to configure an authentication
106 /// webhook.
107 ///
108 /// Convenience property that wraps [`Self::identity_service_metadata_json_str()`].
109 pub fn identity_service_metadata(&self) -> Arc<JsonObject> {
110 self.cached_identity_service_metadata
111 .get_or_init(|| {
112 Arc::new(
113 self.identity_service_metadata_serde()
114 .expect("incorrect json from `dittoffi`"),
115 )
116 })
117 .retain()
118 }
119
120 /// The unique peer key of the remote peer.
121 ///
122 /// - See also: [`crate::transport::Peer::peer_key_string`] for more information on peer keys.
123 pub fn peer_key_string(&self) -> Arc<str> {
124 self.cached_peer_key
125 .get_or_init(|| {
126 ffi_sdk::dittoffi_connection_request_peer_key_string(&*self.raw)
127 .to_str()
128 .into()
129 })
130 .retain()
131 }
132
133 /// The network transport of this connection request.
134 ///
135 /// Expect to receive separate connection requests for each network
136 /// transport that connects the local and remote peer.
137 pub fn connection_type(&self) -> ConnectionType {
138 ConnectionType::from_ffi(::ffi_sdk::dittoffi_connection_request_connection_type(
139 &*self.raw,
140 ))
141 }
142}
143
144#[derive(Debug)]
145/// Private, to future-proof the API (_e.g._, imagine `Deny { reason: … }` or whatnot).
146pub(crate) enum ConnectionRequestAuthorizationInner {
147 Allow { _future_fields: () },
148 Deny { _future_fields: () },
149}
150
151/// Indicates whether a connection request should be authorized.
152#[derive(Debug)]
153pub struct ConnectionRequestAuthorization(pub(crate) ConnectionRequestAuthorizationInner);
154
155impl ConnectionRequestAuthorization {
156 #![allow(non_upper_case_globals)]
157
158 /// The connection request will be allowed.
159 pub const Allow: Self = Self(ConnectionRequestAuthorizationInner::Allow { _future_fields: () });
160
161 /// The connection request will be denied.
162 pub const Deny: Self = Self(ConnectionRequestAuthorizationInner::Deny { _future_fields: () });
163
164 pub(crate) fn into_ffi(self, raw: &ffi_sdk::FfiConnectionRequest) {
165 let ffi_authorization = match self.0 {
166 ConnectionRequestAuthorizationInner::Allow { _future_fields: () } => {
167 ffi_sdk::ConnectionRequestAuthorization::Allow
168 }
169 ConnectionRequestAuthorizationInner::Deny { _future_fields: () } => {
170 ffi_sdk::ConnectionRequestAuthorization::Deny
171 }
172 };
173 ffi_sdk::dittoffi_connection_request_authorize(raw, ffi_authorization);
174 }
175}