Skip to content

Commit

Permalink
feat use resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
itsyaasir committed Dec 9, 2024
1 parent ea67dc7 commit 3d43c65
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 41 deletions.
71 changes: 35 additions & 36 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2020-2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use std::collections::{HashMap, HashSet};
use std::collections::HashSet;
use std::env;
use std::str::FromStr;
use std::sync::Arc;
Expand All @@ -13,14 +13,16 @@ use axum::routing::get;
use axum::{Json, Router};
use identity_iota::document::CoreDocument;
use identity_iota::iota::{IotaDID, IotaDocumentMetadata};
use identity_iota::prelude::Resolver;
use identity_iota::resolver::ErrorCause;
use identity_iota_core::rebased::client::IdentityClientReadOnly;
use identity_iota_core::rebased::migration::get_identity;
use identity_iota_core::IotaDocument;
use iota_sdk::types::base_types::ObjectID;
use iota_sdk::{IotaClient, IotaClientBuilder};
use serde::{Deserialize, Serialize};
use tokio::net::TcpListener;

type NetworkClients = Arc<HashMap<String, IdentityClientReadOnly>>;
type SharedResolver = Arc<Resolver<IotaDocument>>;

/// Custom endpoint for the IOTA network.
pub const IOTA_CUSTOM_NODE_ENDPOINT: &str = "IOTA_CUSTOM_NODE_ENDPOINT";
Expand Down Expand Up @@ -105,21 +107,21 @@ impl Network {
}
#[derive(Default)]
pub struct Server {
clients: Option<NetworkClients>,
resolver: Option<SharedResolver>,
}

impl Server {
pub fn with_clients(mut self, clients: HashMap<String, IdentityClientReadOnly>) -> Self {
self.clients = Some(Arc::new(clients));
pub fn with_resolver(mut self, resolver: Resolver<IotaDocument>) -> Self {
self.resolver = Some(Arc::new(resolver));
self
}

pub async fn run(self, listener: TcpListener) -> anyhow::Result<()> {
let clients = match self.clients {
Some(clients) => clients,
None => init_clients().await?,
let resolver = match self.resolver {
Some(resolver) => resolver,
None => init_resolver().await?,
};
let app = app(clients).await?;
let app = app(resolver).await?;
let addr = listener.local_addr()?;

tracing::debug!("Server is starting at {addr}");
Expand All @@ -145,42 +147,34 @@ pub struct ResolutionResponse {
)]
async fn resolve_did(
Path(arg): Path<String>,
State(clients): State<NetworkClients>,
State(resolver): State<SharedResolver>,
) -> Result<Json<ResolutionResponse>, (StatusCode, String)> {
let did = IotaDID::parse(&arg).map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?;
let network = did.network_str().to_string();

let object_id = ObjectID::from_str(did.tag_str()).map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?;
let identity = resolver.resolve(&did).await.map_err(|e| match e.error_cause() {
ErrorCause::HandlerError { source, .. } if source.to_string().contains("could not find") => (
StatusCode::NOT_FOUND,
"The requested DID document was not found".to_owned(),
),

let client = clients
.get(&network)
.ok_or_else(|| (StatusCode::BAD_REQUEST, format!("Unsupported network: {}", network)))?;

let identity = get_identity(client, object_id)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.ok_or_else(|| {
(
StatusCode::NOT_FOUND,
"The requested DID document was not found".to_owned(),
)
})?;
_ => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
})?;

Ok(Json(ResolutionResponse {
did_document: identity.core_document().clone(),
did_resolution_metadata: identity.metadata.clone(),
}))
}

async fn app(clients: NetworkClients) -> anyhow::Result<Router> {
async fn app(resolver: SharedResolver) -> anyhow::Result<Router> {
Ok(Router::new()
.route("/1.0/identifiers/:did", get(resolve_did))
.with_state(clients))
.with_state(resolver))
}

/// Initialize identity clients for all configured networks.
async fn init_clients() -> anyhow::Result<NetworkClients> {
let mut clients = HashMap::new();
async fn init_resolver() -> anyhow::Result<SharedResolver> {
let mut clients = vec![];
let networks = Network::from_env()?;

for network in networks {
Expand All @@ -201,13 +195,18 @@ async fn init_clients() -> anyhow::Result<NetworkClients> {

let network_name = identity_client.network().to_string();
tracing::debug!("Initialized client for network: {}", network_name);

if clients.insert(network_name.clone(), identity_client).is_some() {
tracing::warn!("Overwrote existing client for network: {}", network_name);
}
let network_name: &'static str = Box::leak(network_name.into_boxed_str());
clients.push((network_name, identity_client));
}

ensure!(!clients.is_empty(), "No identity clients were created");
ensure!(
!clients.is_empty(),
"No clients were created. Make sure you provide a configuration for at least one network"
);

let mut resolver = Resolver::<IotaDocument>::new();

resolver.attach_multiple_iota_handlers(clients);

Ok(Arc::new(clients))
Ok(Arc::new(resolver))
}
10 changes: 5 additions & 5 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// Copyright 2020-2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::{Arc, OnceLock};

use anyhow::Context;
use fastcrypto::ed25519::Ed25519PublicKey;
use fastcrypto::traits::ToFromBytes;
use identity_iota::iota::{IotaDocument, NetworkName};
use identity_iota::prelude::Resolver;
use identity_iota::storage::{JwkDocumentExt, Storage, StorageSigner};
use identity_iota::verification::jwk::Jwk;
use identity_iota::verification::jws::JwsAlgorithm;
Expand Down Expand Up @@ -57,17 +57,17 @@ impl TestServer {

let client = IdentityClientReadOnly::new(client).await?;

let mut clients = HashMap::new();
let mut resolver = Resolver::<IotaDocument>::new();

clients.insert(client.network().to_string(), client.clone());
resolver.attach_iota_handler(client.clone());

let server = Server::default().with_clients(clients);
let server = Server::default().with_resolver(resolver);

let listener = TcpListener::bind("127.0.0.1:0")
.await
.context("failed to bind to random port")?;
let address = listener.local_addr()?;

println!("Server running on: {}", address);
Ok(Self {
client,
storage,
Expand Down
1 change: 1 addition & 0 deletions tests/did_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use uni_resolver_driver_iota::ResolutionResponse;
// Creates and fetches a DID document using the resolver server.
async fn did_resolution_works() -> anyhow::Result<()> {
let mut server = TestServer::new().await?;

let target_doc = server.create_did().await?;

let client = Client::default();
Expand Down

0 comments on commit 3d43c65

Please sign in to comment.