Skip to content

Commit e70d7cf

Browse files
Merge pull request #1205 from libp2p/transport-options
make it possible to pass options to a transport constructor
2 parents 79a2100 + 605f189 commit e70d7cf

File tree

4 files changed

+71
-10
lines changed

4 files changed

+71
-10
lines changed

config/reflection_magic.go

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package config
22

33
import (
4+
"errors"
45
"fmt"
56
"reflect"
67
"runtime"
@@ -97,11 +98,38 @@ func makeArgumentConstructors(fnType reflect.Type, argTypes map[reflect.Type]con
9798
return out, nil
9899
}
99100

101+
func getConstructorOpts(t reflect.Type, opts ...interface{}) ([]reflect.Value, error) {
102+
if !t.IsVariadic() {
103+
if len(opts) > 0 {
104+
return nil, errors.New("constructor doesn't accept any options")
105+
}
106+
return nil, nil
107+
}
108+
if len(opts) == 0 {
109+
return nil, nil
110+
}
111+
// variadic parameters always go last
112+
wantType := t.In(t.NumIn() - 1).Elem()
113+
values := make([]reflect.Value, 0, len(opts))
114+
for _, opt := range opts {
115+
val := reflect.ValueOf(opt)
116+
if opt == nil {
117+
return nil, errors.New("expected a transport option, got nil")
118+
}
119+
if val.Type() != wantType {
120+
return nil, fmt.Errorf("expected option of type %s, got %s", wantType, reflect.TypeOf(opt))
121+
}
122+
values = append(values, val.Convert(wantType))
123+
}
124+
return values, nil
125+
}
126+
100127
// makes a transport constructor.
101128
func makeConstructor(
102129
tpt interface{},
103130
tptType reflect.Type,
104131
argTypes map[reflect.Type]constructor,
132+
opts ...interface{},
105133
) (func(host.Host, *tptu.Upgrader, connmgr.ConnectionGater) (interface{}, error), error) {
106134
v := reflect.ValueOf(tpt)
107135
// avoid panicing on nil/zero value.
@@ -121,19 +149,24 @@ func makeConstructor(
121149
if err != nil {
122150
return nil, err
123151
}
152+
optValues, err := getConstructorOpts(t, opts...)
153+
if err != nil {
154+
return nil, err
155+
}
124156

125157
return func(h host.Host, u *tptu.Upgrader, cg connmgr.ConnectionGater) (interface{}, error) {
126-
arguments := make([]reflect.Value, len(argConstructors))
158+
arguments := make([]reflect.Value, 0, len(argConstructors)+len(opts))
127159
for i, makeArg := range argConstructors {
128160
if arg := makeArg(h, u, cg); arg != nil {
129-
arguments[i] = reflect.ValueOf(arg)
161+
arguments = append(arguments, reflect.ValueOf(arg))
130162
} else {
131163
// ValueOf an un-typed nil yields a zero reflect
132164
// value. However, we _want_ the zero value of
133165
// the _type_.
134-
arguments[i] = reflect.Zero(t.In(i))
166+
arguments = append(arguments, reflect.Zero(t.In(i)))
135167
}
136168
}
169+
arguments = append(arguments, optValues...)
137170
return callConstructor(v, arguments)
138171
}, nil
139172
}

config/transport.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ var transportArgTypes = argTypes
3636
//
3737
// And returns a type implementing transport.Transport and, optionally, an error
3838
// (as the second argument).
39-
func TransportConstructor(tpt interface{}) (TptC, error) {
39+
func TransportConstructor(tpt interface{}, opts ...interface{}) (TptC, error) {
4040
// Already constructed?
4141
if t, ok := tpt.(transport.Transport); ok {
4242
return func(_ host.Host, _ *tptu.Upgrader, _ connmgr.ConnectionGater) (transport.Transport, error) {
4343
return t, nil
4444
}, nil
4545
}
46-
ctor, err := makeConstructor(tpt, transportType, transportArgTypes)
46+
ctor, err := makeConstructor(tpt, transportType, transportArgTypes, opts...)
4747
if err != nil {
4848
return nil, err
4949
}

config/transport_test.go

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,39 @@ import (
55

66
"github.com/libp2p/go-libp2p-core/peer"
77
"github.com/libp2p/go-libp2p-core/transport"
8+
tptu "github.com/libp2p/go-libp2p-transport-upgrader"
9+
"github.com/libp2p/go-tcp-transport"
10+
11+
"github.com/stretchr/testify/require"
812
)
913

1014
func TestTransportVariadicOptions(t *testing.T) {
1115
_, err := TransportConstructor(func(_ peer.ID, _ ...int) transport.Transport { return nil })
12-
if err != nil {
13-
t.Fatal(err)
14-
}
16+
require.NoError(t, err)
17+
}
18+
19+
func TestConstructorWithoutOptsCalledWithOpts(t *testing.T) {
20+
_, err := TransportConstructor(func(_ *tptu.Upgrader) transport.Transport {
21+
return nil
22+
}, 42)
23+
require.EqualError(t, err, "constructor doesn't accept any options")
24+
}
25+
26+
func TestConstructorWithOptsTypeMismatch(t *testing.T) {
27+
_, err := TransportConstructor(func(_ *tptu.Upgrader, opts ...int) transport.Transport {
28+
return nil
29+
}, 42, "foo")
30+
require.EqualError(t, err, "expected option of type int, got string")
31+
}
32+
33+
func TestConstructorWithOpts(t *testing.T) {
34+
var options []int
35+
c, err := TransportConstructor(func(_ *tptu.Upgrader, opts ...int) transport.Transport {
36+
options = opts
37+
return tcp.NewTCPTransport(nil)
38+
}, 42, 1337)
39+
require.NoError(t, err)
40+
_, err = c(nil, nil, nil)
41+
require.NoError(t, err)
42+
require.Equal(t, []int{42, 1337}, options)
1543
}

options.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ func Muxer(name string, tpt interface{}) Option {
125125
// * Public Key
126126
// * Address filter (filter.Filter)
127127
// * Peerstore
128-
func Transport(tpt interface{}) Option {
129-
tptc, err := config.TransportConstructor(tpt)
128+
func Transport(tpt interface{}, opts ...interface{}) Option {
129+
tptc, err := config.TransportConstructor(tpt, opts...)
130130
err = traceError(err, 1)
131131
return func(cfg *Config) error {
132132
if err != nil {

0 commit comments

Comments
 (0)