Skip to content

Commit a2b049b

Browse files
committed
[ADDED] CustomDialer interface/option setter
We recently added a Dialer option, however, we made it a *net.Dialer, which is very restrictive (since *net.Dialer is a struct, not an interface). One could imagine creating a Dialer that would create pipes between the client and an embedded server. Since Dial() returns a net.Conn, which is an interface, everything would work the same. Resolves #329
1 parent f0d9c59 commit a2b049b

File tree

2 files changed

+84
-2
lines changed

2 files changed

+84
-2
lines changed

nats.go

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ type asyncCB func()
123123
// Option is a function on the options for a connection.
124124
type Option func(*Options) error
125125

126+
// CustomDialer can be used to specify any dialer, not necessarily
127+
// a *net.Dialer.
128+
type CustomDialer interface {
129+
Dial(network, address string) (net.Conn, error)
130+
}
131+
126132
// Options can be used to create a customized connection.
127133
type Options struct {
128134

@@ -225,9 +231,14 @@ type Options struct {
225231
// Token sets the token to be used when connecting to a server.
226232
Token string
227233

228-
// Dialer allows a custom Dialer when forming connections.
234+
// Dialer allows a custom net.Dialer when forming connections.
235+
// DEPRECATED: should use CustomDialer instead.
229236
Dialer *net.Dialer
230237

238+
// CustomDialer allows to specify a custom dialer (not necessarily
239+
// a *net.Dialer).
240+
CustomDialer CustomDialer
241+
231242
// UseOldRequestStyle forces the old method of Requests that utilize
232243
// a new Inbox and a new Subscription for each request.
233244
UseOldRequestStyle bool
@@ -586,13 +597,24 @@ func Token(token string) Option {
586597

587598
// Dialer is an Option to set the dialer which will be used when
588599
// attempting to establish a connection.
600+
// DEPRECATED: Should use CustomDialer instead.
589601
func Dialer(dialer *net.Dialer) Option {
590602
return func(o *Options) error {
591603
o.Dialer = dialer
592604
return nil
593605
}
594606
}
595607

608+
// SetCustomDialer is an Option to set a custom dialer which will be
609+
// used when attempting to establish a connection. If both Dialer
610+
// and CustomDialer are specified, CustomDialer takes precedence.
611+
func SetCustomDialer(dialer CustomDialer) Option {
612+
return func(o *Options) error {
613+
o.CustomDialer = dialer
614+
return nil
615+
}
616+
}
617+
596618
// UseOldRequestyStyle is an Option to force usage of the old Request style.
597619
func UseOldRequestStyle() Option {
598620
return func(o *Options) error {
@@ -877,7 +899,13 @@ func (nc *Conn) createConn() (err error) {
877899
cur.lastAttempt = time.Now()
878900
}
879901

880-
dialer := nc.Opts.Dialer
902+
// CustomDialer takes precedence. If not set, use Opts.Dialer which
903+
// is set to a default *net.Dialer (in Connect()) if not explicitly
904+
// set by the user.
905+
dialer := nc.Opts.CustomDialer
906+
if dialer == nil {
907+
dialer = nc.Opts.Dialer
908+
}
881909
nc.conn, err = dialer.Dial("tcp", nc.url.Host)
882910
if err != nil {
883911
return err

test/conn_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,15 @@ func TestNoRaceOnLastError(t *testing.T) {
12661266
}
12671267
}
12681268

1269+
type customDialer struct {
1270+
ch chan bool
1271+
}
1272+
1273+
func (cd *customDialer) Dial(network, address string) (net.Conn, error) {
1274+
cd.ch <- true
1275+
return nil, fmt.Errorf("on purpose")
1276+
}
1277+
12691278
func TestUseCustomDialer(t *testing.T) {
12701279
s := RunDefaultServer()
12711280
defer s.Shutdown()
@@ -1310,6 +1319,51 @@ func TestUseCustomDialer(t *testing.T) {
13101319
if nc3.Opts.Dialer.Timeout != nats.DefaultTimeout {
13111320
t.Fatalf("Expected DialTimeout to be set to %v, got %v", nats.DefaultTimeout, nc.Opts.Dialer.Timeout)
13121321
}
1322+
1323+
// Create custom dialer that return error on Dial().
1324+
cdialer := &customDialer{ch: make(chan bool, 1)}
1325+
1326+
// When both Dialer and CustomDialer are set, CustomDialer
1327+
// should take precedence. That means that the connection
1328+
// should fail for these two set of options.
1329+
options := []*nats.Options{
1330+
&nats.Options{Dialer: dialer, CustomDialer: cdialer},
1331+
&nats.Options{CustomDialer: cdialer},
1332+
}
1333+
for _, o := range options {
1334+
o.Servers = []string{nats.DefaultURL}
1335+
nc, err := o.Connect()
1336+
// As of now, Connect() would not return the actual dialer error,
1337+
// instead it returns "no server available for connections".
1338+
// So use go channel to ensure that custom dialer's Dial() method
1339+
// was invoked.
1340+
if err == nil {
1341+
if nc != nil {
1342+
nc.Close()
1343+
}
1344+
t.Fatal("Expected error, got none")
1345+
}
1346+
if err := Wait(cdialer.ch); err != nil {
1347+
t.Fatal("Did not get our notification")
1348+
}
1349+
}
1350+
// Same with variadic
1351+
foptions := [][]nats.Option{
1352+
[]nats.Option{nats.Dialer(dialer), nats.SetCustomDialer(cdialer)},
1353+
[]nats.Option{nats.SetCustomDialer(cdialer)},
1354+
}
1355+
for _, fos := range foptions {
1356+
nc, err := nats.Connect(nats.DefaultURL, fos...)
1357+
if err == nil {
1358+
if nc != nil {
1359+
nc.Close()
1360+
}
1361+
t.Fatal("Expected error, got none")
1362+
}
1363+
if err := Wait(cdialer.ch); err != nil {
1364+
t.Fatal("Did not get our notification")
1365+
}
1366+
}
13131367
}
13141368

13151369
func TestDefaultOptionsDialer(t *testing.T) {

0 commit comments

Comments
 (0)