Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple IOTA networks in the Resolver #1304

Merged
merged 13 commits into from
Feb 21, 2024
3 changes: 3 additions & 0 deletions identity_resolver/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,7 @@ pub enum ErrorCause {
/// The method that is unsupported.
method: String,
},
/// No client attached to the specific network.
#[error("none of the attached clients support the netowk {0}")]
UnsupportedNetowrk(String),
abdulmth marked this conversation as resolved.
Show resolved Hide resolved
}
53 changes: 53 additions & 0 deletions identity_resolver/src/resolution/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ impl<DOC: 'static> Resolver<DOC, SingleThreadedCommand<DOC>> {

#[cfg(feature = "iota")]
mod iota_handler {
use crate::ErrorCause;

use super::Resolver;
use identity_document::document::CoreDocument;
use identity_iota_core::IotaClientExt;
Expand Down Expand Up @@ -277,6 +279,57 @@ mod iota_handler {

self.attach_handler(IotaDID::METHOD.to_owned(), handler);
}

/// Convenience method for attaching multiple handlers responsible for resolving IOTA DIDs
/// on multiple networks.
///
///
/// # Arguments
///
/// * `clients` - A vector of tuples where each tuple contains the name of the network name and its corresponding
abdulmth marked this conversation as resolved.
Show resolved Hide resolved
/// client.
///
/// # Examples
///
/// ```ignore
/// // Assume `smr_client` and `iota_client` are instances IOTA clients `iota_sdk::client::Client`.
/// attach_multiple_iota_handlers(vec![("smr", smr_client), ("iota", iota_client)]);
/// ```
///
/// # See Also
/// - [`attach_handler`](Self::attach_handler).
///
/// # Note
///
/// Using `attach_iota_handler` or `attach_handler` for the IOTA method would override all
/// clients added in this method.
abdulmth marked this conversation as resolved.
Show resolved Hide resolved
pub fn attach_multiple_iota_handlers<CLI>(&mut self, clients: Vec<(&'static str, CLI)>)
where
CLI: IotaClientExt + Send + Sync + 'static,
{
let arc_clients: Arc<Vec<(&str, CLI)>> = Arc::new(clients);

let handler = move |did: IotaDID| {
let future_client = arc_clients.clone();
async move {
let did_network = did.network_str();
let client: &CLI = future_client
.as_ref()
.iter()
.find(|(netowrk, _)| *netowrk == did_network)
.map(|(_, client)| client)
.ok_or(crate::Error::new(ErrorCause::UnsupportedNetowrk(
did_network.to_string(),
)))?;
client
.resolve_did(&did)
.await
.map_err(|err| crate::Error::new(ErrorCause::HandlerError { source: Box::new(err) }))
}
};

self.attach_handler(IotaDID::METHOD.to_owned(), handler);
}
Copy link
Contributor

@UMR1352 UMR1352 Feb 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make the input generic over the actual collection, use an HashMap instead of checking all entries one by one

Suggested change
pub fn attach_multiple_iota_handlers<CLI>(&mut self, clients: Vec<(&'static str, CLI)>)
where
CLI: IotaClientExt + Send + Sync + 'static,
{
let arc_clients: Arc<Vec<(&str, CLI)>> = Arc::new(clients);
let handler = move |did: IotaDID| {
let future_client = arc_clients.clone();
async move {
let did_network = did.network_str();
let client: &CLI = future_client
.as_ref()
.iter()
.find(|(netowrk, _)| *netowrk == did_network)
.map(|(_, client)| client)
.ok_or(crate::Error::new(ErrorCause::UnsupportedNetowrk(
did_network.to_string(),
)))?;
client
.resolve_did(&did)
.await
.map_err(|err| crate::Error::new(ErrorCause::HandlerError { source: Box::new(err) }))
}
};
self.attach_handler(IotaDID::METHOD.to_owned(), handler);
}
pub fn attach_multiple_iota_handlers<CLI, I>(&mut self, clients: I)
where
CLI: IotaClientExt + Send + Sync + 'static,
I: IntoIterator<Item = (&'static str, CLI)>,
{
let clients = Arc::new(clients.into_iter().collect::<HashMap<_, _>>());
let handler = move |did: IotaDID| {
let clients = clients.clone();
async move {
let did_network = did.network_str();
let client: &CLI = clients
.get(did_network)
.ok_or(crate::Error::new(ErrorCause::UnsupportedNetwork(
did_network.to_string(),
)))?;
client
.resolve_did(&did)
.await
.map_err(|err| crate::Error::new(ErrorCause::HandlerError { source: Box::new(err) }))
}
};
self.attach_handler(IotaDID::METHOD.to_owned(), handler);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think collecting the elements back into a Hashmap defeats the purpose of using generics here, and I prefer the cleaner function signature since users will most likely create the vector specifically for this function, Also the hash map will not bring any measurable performance benefits since it's very unlikely that the user will add more than 2 or 3 clients.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that using an HashMap won't result in a performance improvement (probably it deteriorates it if the number of entries is very small) but I still think it is the right collection for the job as it has an implicit "lookup" implication - which is what the method does. I also agree that users will probably simply use a Vec 99% of the time but it doesn't hurt to account for other possible collections. I'm down for whatever you choose

}
}

Expand Down
Loading