github.com/anacrolix/torrent@v1.61.0/tracker/udp/dispatcher.go (about)

     1  package udp
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"net"
     7  	"sync"
     8  )
     9  
    10  // Maintains a mapping of transaction IDs to handlers.
    11  type Dispatcher struct {
    12  	mu           sync.RWMutex
    13  	transactions map[TransactionId]Transaction
    14  }
    15  
    16  // The caller owns b.
    17  func (me *Dispatcher) Dispatch(b []byte, addr net.Addr) error {
    18  	buf := bytes.NewBuffer(b)
    19  	var rh ResponseHeader
    20  	err := Read(buf, &rh)
    21  	if err != nil {
    22  		return err
    23  	}
    24  	me.mu.RLock()
    25  	defer me.mu.RUnlock()
    26  	if t, ok := me.transactions[rh.TransactionId]; ok {
    27  		t.h(DispatchedResponse{
    28  			Header: rh,
    29  			Body:   append([]byte(nil), buf.Bytes()...),
    30  			Addr:   addr,
    31  		})
    32  		return nil
    33  	} else {
    34  		return fmt.Errorf("unknown transaction id %v", rh.TransactionId)
    35  	}
    36  }
    37  
    38  func (me *Dispatcher) forgetTransaction(id TransactionId) {
    39  	me.mu.Lock()
    40  	defer me.mu.Unlock()
    41  	delete(me.transactions, id)
    42  }
    43  
    44  func (me *Dispatcher) NewTransaction(h TransactionResponseHandler) Transaction {
    45  	me.mu.Lock()
    46  	defer me.mu.Unlock()
    47  	for {
    48  		id := RandomTransactionId()
    49  		if _, ok := me.transactions[id]; ok {
    50  			continue
    51  		}
    52  		t := Transaction{
    53  			d:  me,
    54  			h:  h,
    55  			id: id,
    56  		}
    57  		if me.transactions == nil {
    58  			me.transactions = make(map[TransactionId]Transaction)
    59  		}
    60  		me.transactions[id] = t
    61  		return t
    62  	}
    63  }
    64  
    65  type DispatchedResponse struct {
    66  	Header ResponseHeader
    67  	// Response payload, after the header.
    68  	Body []byte
    69  	// Response source address
    70  	Addr net.Addr
    71  }