1
1
// Copyright 2020-2024 IOTA Stiftung
2
2
// SPDX-License-Identifier: Apache-2.0
3
3
4
- use std:: collections:: { HashMap , HashSet } ;
4
+ use std:: collections:: HashSet ;
5
5
use std:: env;
6
6
use std:: str:: FromStr ;
7
7
use std:: sync:: Arc ;
@@ -13,14 +13,16 @@ use axum::routing::get;
13
13
use axum:: { Json , Router } ;
14
14
use identity_iota:: document:: CoreDocument ;
15
15
use identity_iota:: iota:: { IotaDID , IotaDocumentMetadata } ;
16
+ use identity_iota:: prelude:: Resolver ;
17
+ use identity_iota:: resolver:: ErrorCause ;
16
18
use identity_iota_core:: rebased:: client:: IdentityClientReadOnly ;
17
- use identity_iota_core:: rebased :: migration :: get_identity ;
19
+ use identity_iota_core:: IotaDocument ;
18
20
use iota_sdk:: types:: base_types:: ObjectID ;
19
21
use iota_sdk:: { IotaClient , IotaClientBuilder } ;
20
22
use serde:: { Deserialize , Serialize } ;
21
23
use tokio:: net:: TcpListener ;
22
24
23
- type NetworkClients = Arc < HashMap < String , IdentityClientReadOnly > > ;
25
+ type SharedResolver = Arc < Resolver < IotaDocument > > ;
24
26
25
27
/// Custom endpoint for the IOTA network.
26
28
pub const IOTA_CUSTOM_NODE_ENDPOINT : & str = "IOTA_CUSTOM_NODE_ENDPOINT" ;
@@ -105,21 +107,21 @@ impl Network {
105
107
}
106
108
#[ derive( Default ) ]
107
109
pub struct Server {
108
- clients : Option < NetworkClients > ,
110
+ resolver : Option < SharedResolver > ,
109
111
}
110
112
111
113
impl Server {
112
- pub fn with_clients ( mut self , clients : HashMap < String , IdentityClientReadOnly > ) -> Self {
113
- self . clients = Some ( Arc :: new ( clients ) ) ;
114
+ pub fn with_resolver ( mut self , resolver : Resolver < IotaDocument > ) -> Self {
115
+ self . resolver = Some ( Arc :: new ( resolver ) ) ;
114
116
self
115
117
}
116
118
117
119
pub async fn run ( self , listener : TcpListener ) -> anyhow:: Result < ( ) > {
118
- let clients = match self . clients {
119
- Some ( clients ) => clients ,
120
- None => init_clients ( ) . await ?,
120
+ let resolver = match self . resolver {
121
+ Some ( resolver ) => resolver ,
122
+ None => init_resolver ( ) . await ?,
121
123
} ;
122
- let app = app ( clients ) . await ?;
124
+ let app = app ( resolver ) . await ?;
123
125
let addr = listener. local_addr ( ) ?;
124
126
125
127
tracing:: debug!( "Server is starting at {addr}" ) ;
@@ -145,42 +147,34 @@ pub struct ResolutionResponse {
145
147
) ]
146
148
async fn resolve_did (
147
149
Path ( arg) : Path < String > ,
148
- State ( clients ) : State < NetworkClients > ,
150
+ State ( resolver ) : State < SharedResolver > ,
149
151
) -> Result < Json < ResolutionResponse > , ( StatusCode , String ) > {
150
152
let did = IotaDID :: parse ( & arg) . map_err ( |e| ( StatusCode :: BAD_REQUEST , e. to_string ( ) ) ) ?;
151
- let network = did. network_str ( ) . to_string ( ) ;
152
153
153
- let object_id = ObjectID :: from_str ( did. tag_str ( ) ) . map_err ( |e| ( StatusCode :: BAD_REQUEST , e. to_string ( ) ) ) ?;
154
+ let identity = resolver. resolve ( & did) . await . map_err ( |e| match e. error_cause ( ) {
155
+ ErrorCause :: HandlerError { source, .. } if source. to_string ( ) . contains ( "could not find" ) => (
156
+ StatusCode :: NOT_FOUND ,
157
+ "The requested DID document was not found" . to_owned ( ) ,
158
+ ) ,
154
159
155
- let client = clients
156
- . get ( & network)
157
- . ok_or_else ( || ( StatusCode :: BAD_REQUEST , format ! ( "Unsupported network: {}" , network) ) ) ?;
158
-
159
- let identity = get_identity ( client, object_id)
160
- . await
161
- . map_err ( |e| ( StatusCode :: INTERNAL_SERVER_ERROR , e. to_string ( ) ) ) ?
162
- . ok_or_else ( || {
163
- (
164
- StatusCode :: NOT_FOUND ,
165
- "The requested DID document was not found" . to_owned ( ) ,
166
- )
167
- } ) ?;
160
+ _ => ( StatusCode :: INTERNAL_SERVER_ERROR , e. to_string ( ) ) ,
161
+ } ) ?;
168
162
169
163
Ok ( Json ( ResolutionResponse {
170
164
did_document : identity. core_document ( ) . clone ( ) ,
171
165
did_resolution_metadata : identity. metadata . clone ( ) ,
172
166
} ) )
173
167
}
174
168
175
- async fn app ( clients : NetworkClients ) -> anyhow:: Result < Router > {
169
+ async fn app ( resolver : SharedResolver ) -> anyhow:: Result < Router > {
176
170
Ok ( Router :: new ( )
177
171
. route ( "/1.0/identifiers/:did" , get ( resolve_did) )
178
- . with_state ( clients ) )
172
+ . with_state ( resolver ) )
179
173
}
180
174
181
175
/// Initialize identity clients for all configured networks.
182
- async fn init_clients ( ) -> anyhow:: Result < NetworkClients > {
183
- let mut clients = HashMap :: new ( ) ;
176
+ async fn init_resolver ( ) -> anyhow:: Result < SharedResolver > {
177
+ let mut clients = vec ! [ ] ;
184
178
let networks = Network :: from_env ( ) ?;
185
179
186
180
for network in networks {
@@ -201,13 +195,18 @@ async fn init_clients() -> anyhow::Result<NetworkClients> {
201
195
202
196
let network_name = identity_client. network ( ) . to_string ( ) ;
203
197
tracing:: debug!( "Initialized client for network: {}" , network_name) ;
204
-
205
- if clients. insert ( network_name. clone ( ) , identity_client) . is_some ( ) {
206
- tracing:: warn!( "Overwrote existing client for network: {}" , network_name) ;
207
- }
198
+ let network_name: & ' static str = Box :: leak ( network_name. into_boxed_str ( ) ) ;
199
+ clients. push ( ( network_name, identity_client) ) ;
208
200
}
209
201
210
- ensure ! ( !clients. is_empty( ) , "No identity clients were created" ) ;
202
+ ensure ! (
203
+ !clients. is_empty( ) ,
204
+ "No clients were created. Make sure you provide a configuration for at least one network"
205
+ ) ;
206
+
207
+ let mut resolver = Resolver :: < IotaDocument > :: new ( ) ;
208
+
209
+ resolver. attach_multiple_iota_handlers ( clients) ;
211
210
212
- Ok ( Arc :: new ( clients ) )
211
+ Ok ( Arc :: new ( resolver ) )
213
212
}
0 commit comments