3
3
*/
4
4
import { AbortError , setMaxListeners } from '@libp2p/interface'
5
5
import { pbStream } from 'it-protobuf-stream'
6
+ import { URL } from './common/url.js'
6
7
import { HttpConstants } from './constants.js'
7
8
import { type HttpComponents } from './http-components-interface.js'
8
9
import { http } from './http-proto-api.js'
@@ -97,29 +98,66 @@ export class HttpClient implements Startable {
97
98
const result = JSON . parse ( contentString ) as ProtocolDiscoveryResult
98
99
this . log . trace ( 'discovered %d protocols from %p' , result . protocols . length , peer )
99
100
return result
100
- } catch ( err ) {
101
- throw new Error ( 'Invalid protocol discovery response: ' + err . message )
101
+ } catch ( err : unknown ) {
102
+ const errMessage = err instanceof Error ? err . message : String ( err )
103
+ throw new Error ( 'Invalid protocol discovery response: ' + errMessage )
102
104
}
103
- } catch ( err ) {
104
- this . log . error ( 'protocol discovery failed - %e' , err )
105
+ } catch ( err : any ) {
106
+ this . log . error ( 'protocol discovery failed - %e' , err ?. message )
105
107
throw err
106
108
}
107
109
}
108
110
109
- async fetch ( peer : PeerId , request : http . HttpRequest , options : AbortOptions = { } ) : Promise < http . HttpResponse > {
111
+ /**
112
+ * Send an HTTP request to a peer or URL
113
+ */
114
+ async fetch ( peerOrUrl : PeerId | string | URL , request : http . HttpRequest , options : AbortOptions = { } ) : Promise < http . HttpResponse > {
110
115
if ( ! this . isStarted ( ) ) {
111
116
// Auto-start the client if it hasn't been started
112
117
await this . start ( )
113
118
}
114
119
115
- this . log . trace ( 'sending %s request to %p for %s' , request . method , peer , request . targetUri )
120
+ // Handle URL version of the overload
121
+ if ( typeof peerOrUrl === 'string' || peerOrUrl instanceof URL ) {
122
+ const urlString = typeof peerOrUrl === 'string' ? peerOrUrl : peerOrUrl . toString ( )
123
+ const url = typeof peerOrUrl === 'string' ? new URL ( peerOrUrl ) : peerOrUrl
124
+ const hostname = url . hostname
125
+
126
+ if ( hostname === undefined || hostname === null || hostname === '' ) {
127
+ throw new Error ( `Invalid URL: ${ urlString } , missing hostname` )
128
+ }
129
+
130
+ try {
131
+ // Import PeerId dynamically to avoid circular dependencies
132
+ const { peerIdFromString } = await import ( '@libp2p/peer-id' )
133
+ const peer = peerIdFromString ( hostname )
134
+
135
+ // Set the target URI to the path and query of the URL
136
+ const targetUri = url . pathname + ( url . search !== '' ? url . search : '' )
137
+ const modifiedRequest = {
138
+ ...request ,
139
+ targetUri
140
+ }
141
+
142
+ this . log . trace ( 'sending %s request to peer %s for %s' , modifiedRequest . method , hostname , modifiedRequest . targetUri )
143
+ return await this . fetch ( peer , modifiedRequest , options )
144
+ } catch ( err ) {
145
+ // If we can't create a peer ID from the hostname, this is likely a regular web URL
146
+ // In this case, we should handle it as a clear web request or throw an appropriate error
147
+ this . log . error ( 'not a valid peer ID in URL hostname: %s' , hostname )
148
+ throw new Error ( `Cannot route to ${ urlString } : hostname is not a valid peer ID` )
149
+ }
150
+ }
151
+
152
+ // Original implementation for PeerId
153
+ this . log . trace ( 'sending %s request to %p for %s' , request . method , peerOrUrl , request . targetUri )
116
154
let connection
117
155
let stream : Stream | undefined
118
156
let signal = options . signal
119
157
let onAbort = ( ) : void => { }
120
158
121
159
try {
122
- connection = await this . components . connectionManager . openConnection ( peer , options )
160
+ connection = await this . components . connectionManager . openConnection ( peerOrUrl , options )
123
161
124
162
if ( signal == null ) {
125
163
const timeout = this . init . timeout ?? DEFAULT_TIMEOUT
@@ -143,10 +181,10 @@ export class HttpClient implements Startable {
143
181
const response = await pb . read ( http . HttpResponse , options )
144
182
await pb . unwrap ( ) . close ( options )
145
183
146
- this . log . trace ( 'received response with status %d from %p' , response . statusCode , peer )
184
+ this . log . trace ( 'received response with status %d from %p' , response . statusCode , peerOrUrl )
147
185
return response
148
186
} catch ( err : any ) {
149
- this . log . error ( 'error fetching from %p - %e' , peer , err )
187
+ this . log . error ( 'error fetching from %p - %e' , peerOrUrl , err )
150
188
if ( stream != null ) {
151
189
stream . abort ( err )
152
190
}
0 commit comments