|
9 | 9 | "runtime" |
10 | 10 | "strconv" |
11 | 11 | "strings" |
| 12 | + "time" |
12 | 13 |
|
13 | 14 | "github.com/ipfs/boxo/blockstore" |
14 | 15 | leveldb "github.com/ipfs/go-ds-leveldb" |
@@ -393,6 +394,9 @@ func setupGatewayHandler(cfg Config, nd *Node) (http.Handler, error) { |
393 | 394 | // Add tracing. |
394 | 395 | handler = withTracingAndDebug(handler, cfg.TracingAuthToken) |
395 | 396 |
|
| 397 | + // Add peer hint support (X-PEER-ID). |
| 398 | + handler = withPeerHint(nd, handler) |
| 399 | + |
396 | 400 | return handler, nil |
397 | 401 | } |
398 | 402 |
|
@@ -429,6 +433,34 @@ const NoBlockcacheHeader = "Rainbow-No-Blockcache" |
429 | 433 |
|
430 | 434 | type NoBlockcache struct{} |
431 | 435 |
|
| 436 | +const PeerHintHeader = "X-PEER-ID" |
| 437 | + |
| 438 | +// withPeerHint inspects the request for a Peer hint header and, if present, |
| 439 | +// attempts a short, best-effort libp2p connect to the provided multiaddress. |
| 440 | +// This increases the likelihood that Bitswap can retrieve content directly |
| 441 | +// from the hinted peer even if it is not advertising on DHT/IPNI. |
| 442 | +func withPeerHint(nd *Node, next http.Handler) http.Handler { |
| 443 | + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 444 | + if nd != nil && nd.host != nil { |
| 445 | + if maStr := r.Header.Get(PeerHintHeader); maStr != "" { |
| 446 | + if ai, err := peer.AddrInfoFromString(maStr); err != nil { |
| 447 | + goLog.Warnw("Invalid X-PEER-ID header", "value", maStr, "err", err) |
| 448 | + } else { |
| 449 | + ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) |
| 450 | + defer cancel() |
| 451 | + // Best-effort connect; do not fail the request on error. |
| 452 | + if err := nd.host.Connect(ctx, *ai); err != nil { |
| 453 | + goLog.Debugw("Failed to connect to hinted peer", "peer", ai.ID, "err", err) |
| 454 | + } else { |
| 455 | + goLog.Debugw("Connected to hinted peer", "peer", ai.ID) |
| 456 | + } |
| 457 | + } |
| 458 | + } |
| 459 | + } |
| 460 | + next.ServeHTTP(w, r) |
| 461 | + }) |
| 462 | +} |
| 463 | + |
432 | 464 | // MutexFractionOption allows to set runtime.SetMutexProfileFraction via HTTP |
433 | 465 | // using POST request with parameter 'fraction'. |
434 | 466 | func MutexFractionOption(path string, mux *http.ServeMux) *http.ServeMux { |
|
0 commit comments