Skip to content
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
104 lines (92 sloc) 2.5 KB
package routing
import (
// QueryEventType indicates the query event's type.
type QueryEventType int
// Number of events to buffer.
var QueryEventBufferSize = 16
const (
// Sending a query to a peer.
SendingQuery QueryEventType = iota
// Got a response from a peer.
// Found a "closest" peer (not currently used).
// Got an error when querying.
// Found a provider.
// Found a value.
// Adding a peer to the query.
// Dialing a peer.
// QueryEvent is emitted for every notable event that happens during a DHT query.
type QueryEvent struct {
ID peer.ID
Type QueryEventType
Responses []*peer.AddrInfo
Extra string
type routingQueryKey struct{}
type eventChannel struct {
mu sync.Mutex
ctx context.Context
ch chan<- *QueryEvent
// waitThenClose is spawned in a goroutine when the channel is registered. This
// safely cleans up the channel when the context has been canceled.
func (e *eventChannel) waitThenClose() {
// 1. Signals that we're done.
// 2. Frees memory (in case we end up hanging on to this for a while). = nil
// send sends an event on the event channel, aborting if either the passed or
// the internal context expire.
func (e *eventChannel) send(ctx context.Context, ev *QueryEvent) {
// Closed.
if == nil {
// in case the passed context is unrelated, wait on both.
select {
case <- ev:
case <-e.ctx.Done():
case <-ctx.Done():
// RegisterForQueryEvents registers a query event channel with the given
// context. The returned context can be passed to DHT queries to receive query
// events on the returned channels.
// The passed context MUST be canceled when the caller is no longer interested
// in query events.
func RegisterForQueryEvents(ctx context.Context) (context.Context, <-chan *QueryEvent) {
ch := make(chan *QueryEvent, QueryEventBufferSize)
ech := &eventChannel{ch: ch, ctx: ctx}
go ech.waitThenClose()
return context.WithValue(ctx, routingQueryKey{}, ech), ch
// PublishQueryEvent publishes a query event to the query event channel
// associated with the given context, if any.
func PublishQueryEvent(ctx context.Context, ev *QueryEvent) {
ich := ctx.Value(routingQueryKey{})
if ich == nil {
// We *want* to panic here.
ech := ich.(*eventChannel)
ech.send(ctx, ev)
You can’t perform that action at this time.