package swarm
import (
"context"
"errors"
"sync"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
)
type dialWorkerFunc func (peer .ID , <-chan dialRequest )
var errConcurrentDialSuccessful = errors .New ("concurrent dial successful" )
func newDialSync(worker dialWorkerFunc ) *dialSync {
return &dialSync {
dials : make (map [peer .ID ]*activeDial ),
dialWorker : worker ,
}
}
type dialSync struct {
mutex sync .Mutex
dials map [peer .ID ]*activeDial
dialWorker dialWorkerFunc
}
type activeDial struct {
refCnt int
ctx context .Context
cancelCause func (error )
reqch chan dialRequest
}
func (ad *activeDial ) dial (ctx context .Context ) (*Conn , error ) {
dialCtx := ad .ctx
if forceDirect , reason := network .GetForceDirectDial (ctx ); forceDirect {
dialCtx = network .WithForceDirectDial (dialCtx , reason )
}
if simConnect , isClient , reason := network .GetSimultaneousConnect (ctx ); simConnect {
dialCtx = network .WithSimultaneousConnect (dialCtx , isClient , reason )
}
resch := make (chan dialResponse , 1 )
select {
case ad .reqch <- dialRequest {ctx : dialCtx , resch : resch }:
case <- ctx .Done ():
return nil , ctx .Err ()
}
select {
case res := <- resch :
return res .conn , res .err
case <- ctx .Done ():
return nil , ctx .Err ()
}
}
func (ds *dialSync ) getActiveDial (p peer .ID ) (*activeDial , error ) {
ds .mutex .Lock ()
defer ds .mutex .Unlock ()
actd , ok := ds .dials [p ]
if !ok {
ctx , cancel := context .WithCancelCause (context .Background ())
actd = &activeDial {
ctx : ctx ,
cancelCause : cancel ,
reqch : make (chan dialRequest ),
}
go ds .dialWorker (p , actd .reqch )
ds .dials [p ] = actd
}
actd .refCnt ++
return actd , nil
}
func (ds *dialSync ) Dial (ctx context .Context , p peer .ID ) (*Conn , error ) {
ad , err := ds .getActiveDial (p )
if err != nil {
return nil , err
}
conn , err := ad .dial (ctx )
ds .mutex .Lock ()
defer ds .mutex .Unlock ()
ad .refCnt --
if ad .refCnt == 0 {
if err == nil {
ad .cancelCause (errConcurrentDialSuccessful )
} else {
ad .cancelCause (err )
}
close (ad .reqch )
delete (ds .dials , p )
}
return conn , err
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .