@@ -17,59 +17,74 @@ import (
17
17
"github.com/djdv/p9/p9"
18
18
"github.com/multiformats/go-multiaddr"
19
19
manet "github.com/multiformats/go-multiaddr/net"
20
+ "github.com/u-root/uio/ulog"
20
21
)
21
22
22
23
type (
23
24
Client p9.Client
24
25
clientSettings struct {
25
26
serviceMaddr multiaddr.Multiaddr
27
+ log ulog.Logger
26
28
exitInterval time.Duration
27
- sharedSettings
28
29
}
29
30
clientOption func (* clientSettings ) error
30
31
clientOptions []clientOption
31
- // defaultClientMaddr distinguishes
32
- // the default maddr value, from an arbitrary maddr value.
33
- // I.e. even if the underlying multiaddrs are the same
34
- // only the flag's default value should be of this type.
35
- // Implying the flag was not provided/set explicitly.
36
- defaultClientMaddr struct { multiaddr.Multiaddr }
37
32
)
38
33
39
34
const (
40
- exitIntervalDefault = 30 * time .Second
41
- errServiceNotFound = generic .ConstError ("could not find service instance" )
35
+ exitIntervalDefault = 30 * time .Second
36
+ errServiceConnection = generic .ConstError ("could not connect to service" )
37
+ errCouldNotDial = generic .ConstError ("could not dial" )
42
38
)
43
39
44
40
func (cs * clientSettings ) getClient (autoLaunchDaemon bool ) (* Client , error ) {
45
41
var (
46
42
serviceMaddr = cs .serviceMaddr
47
- clientOpts []p9.ClientOpt
43
+ options []p9.ClientOpt
48
44
)
49
- if cs .verbose {
50
- // TODO: less fancy prefix and/or out+prefix from CLI flags
51
- clientLog := log .New (os .Stdout , "⬇️ client - " , log .Lshortfile )
52
- clientOpts = append (clientOpts , p9 .WithClientLogger (clientLog ))
45
+ if log := cs .log ; log != nil {
46
+ options = append (options , p9 .WithClientLogger (log ))
53
47
}
54
- if autoLaunchDaemon {
55
- if _ , wasUnset := serviceMaddr .(defaultClientMaddr ); wasUnset {
56
- return connectOrLaunchLocal (cs .exitInterval , clientOpts ... )
48
+ var serviceMaddrs []multiaddr.Multiaddr
49
+ if serviceMaddr != nil {
50
+ autoLaunchDaemon = false
51
+ serviceMaddrs = []multiaddr.Multiaddr {serviceMaddr }
52
+ } else {
53
+ var err error
54
+ if serviceMaddrs , err = allServiceMaddrs (); err != nil {
55
+ return nil , fmt .Errorf (
56
+ "%w: %w" ,
57
+ errServiceConnection , err ,
58
+ )
57
59
}
58
60
}
59
- return Connect (serviceMaddr , clientOpts ... )
61
+ client , err := connect (serviceMaddrs , options ... )
62
+ if err == nil {
63
+ return client , nil
64
+ }
65
+ if autoLaunchDaemon &&
66
+ errors .Is (err , errCouldNotDial ) {
67
+ return launchAndConnect (cs .exitInterval , options ... )
68
+ }
69
+ return nil , err
60
70
}
61
71
62
72
func (co * clientOptions ) BindFlags (flagSet * flag.FlagSet ) {
63
- var sharedOptions sharedOptions
64
- (& sharedOptions ).BindFlags (flagSet )
65
- * co = append (* co , func (cs * clientSettings ) error {
66
- subset , err := sharedOptions .make ()
67
- if err != nil {
68
- return err
69
- }
70
- cs .sharedSettings = subset
71
- return nil
72
- })
73
+ const (
74
+ verboseName = "verbose"
75
+ verboseUsage = "enable client message logging"
76
+ )
77
+ flagSetFunc (flagSet , verboseName , verboseUsage , co ,
78
+ func (verbose bool , settings * clientSettings ) error {
79
+ if verbose {
80
+ const (
81
+ prefix = "⬇️ client - "
82
+ flags = 0
83
+ )
84
+ settings .log = log .New (os .Stderr , prefix , flags )
85
+ }
86
+ return nil
87
+ })
73
88
const (
74
89
exitName = exitAfterFlagName
75
90
exitUsage = "passed to the daemon command if we launch it" +
@@ -88,8 +103,19 @@ func (co *clientOptions) BindFlags(flagSet *flag.FlagSet) {
88
103
settings .serviceMaddr = value
89
104
return nil
90
105
})
106
+ serviceMaddrs , err := allServiceMaddrs ()
107
+ if err != nil {
108
+ panic (err )
109
+ }
110
+ maddrStrings := make ([]string , len (serviceMaddrs ))
111
+ for i , maddr := range serviceMaddrs {
112
+ maddrStrings [i ] = "`" + maddr .String () + "`"
113
+ }
91
114
flagSet .Lookup (serverFlagName ).
92
- DefValue = defaultServerMaddr ().String ()
115
+ DefValue = fmt .Sprintf (
116
+ "one of: %s" ,
117
+ strings .Join (maddrStrings , ", " ),
118
+ )
93
119
}
94
120
95
121
func (co clientOptions ) make () (clientSettings , error ) {
@@ -99,19 +125,9 @@ func (co clientOptions) make() (clientSettings, error) {
99
125
if err := generic .ApplyOptions (& settings , co ... ); err != nil {
100
126
return clientSettings {}, err
101
127
}
102
- if err := settings .fillDefaults (); err != nil {
103
- return clientSettings {}, err
104
- }
105
128
return settings , nil
106
129
}
107
130
108
- func (cs * clientSettings ) fillDefaults () error {
109
- if cs .serviceMaddr == nil {
110
- cs .serviceMaddr = defaultServerMaddr ()
111
- }
112
- return nil
113
- }
114
-
115
131
func (c * Client ) getListeners () ([]multiaddr.Multiaddr , error ) {
116
132
listenersDir , err := (* p9 .Client )(c ).Attach (listenersFileName )
117
133
if err != nil {
@@ -124,44 +140,26 @@ func (c *Client) getListeners() ([]multiaddr.Multiaddr, error) {
124
140
return maddrs , listenersDir .Close ()
125
141
}
126
142
127
- func connectOrLaunchLocal (exitInterval time.Duration , options ... p9.ClientOpt ) (* Client , error ) {
128
- conn , err := findLocalServer ()
129
- if err == nil {
130
- return newClient (conn , options ... )
131
- }
132
- if ! errors .Is (err , errServiceNotFound ) {
133
- return nil , err
134
- }
135
- return launchAndConnect (exitInterval , options ... )
136
- }
137
-
138
143
func launchAndConnect (exitInterval time.Duration , options ... p9.ClientOpt ) (* Client , error ) {
139
144
daemon , ipc , stderr , err := spawnDaemonProc (exitInterval )
140
145
if err != nil {
141
146
return nil , err
142
147
}
143
- var (
144
- errs []error
145
- killProc = func () error {
146
- return errors .Join (
147
- maybeKill (daemon ),
148
- daemon .Process .Release (),
149
- )
150
- }
151
- )
148
+ killProc := func () error {
149
+ return errors .Join (
150
+ maybeKill (daemon ),
151
+ daemon .Process .Release (),
152
+ )
153
+ }
152
154
maddrs , err := getListenersFromProc (ipc , stderr , options ... )
153
155
if err != nil {
154
- errs = append ( errs , err )
156
+ errs := [] error { err }
155
157
if err := killProc (); err != nil {
156
158
errs = append (errs , err )
157
159
}
158
160
return nil , errors .Join (errs ... )
159
161
}
160
- conn , err := firstDialable (maddrs )
161
- if err != nil {
162
- return nil , errors .Join (err , killProc ())
163
- }
164
- client , err := newClient (conn , options ... )
162
+ client , err := connect (maddrs )
165
163
if err != nil {
166
164
return nil , errors .Join (err , killProc ())
167
165
}
@@ -182,39 +180,44 @@ func launchAndConnect(exitInterval time.Duration, options ...p9.ClientOpt) (*Cli
182
180
}
183
181
184
182
func Connect (serverMaddr multiaddr.Multiaddr , options ... p9.ClientOpt ) (* Client , error ) {
185
- conn , err := manet .Dial (serverMaddr )
183
+ return connect ([]multiaddr.Multiaddr {serverMaddr }, options ... )
184
+ }
185
+
186
+ func connect (maddrs []multiaddr.Multiaddr , options ... p9.ClientOpt ) (* Client , error ) {
187
+ conn , err := firstDialable (maddrs ... )
186
188
if err != nil {
187
- return nil , fmt .Errorf ("could not connect to service: %w" , err )
189
+ return nil , fmt .Errorf (
190
+ "%w: %w" ,
191
+ errServiceConnection , err ,
192
+ )
188
193
}
189
194
return newClient (conn , options ... )
190
195
}
191
196
192
197
func newClient (conn io.ReadWriteCloser , options ... p9.ClientOpt ) (* Client , error ) {
193
198
client , err := p9 .NewClient (conn , options ... )
194
199
if err != nil {
195
- return nil , err
200
+ return nil , fmt .Errorf (
201
+ "could not create client: %w" ,
202
+ err ,
203
+ )
196
204
}
197
205
return (* Client )(client ), nil
198
206
}
199
207
200
- // findLocalServer searches a set of local addresses
201
- // and returns the first dialable maddr it finds.
202
- // [errServiceNotFound] will be returned if none are dialable.
203
- func findLocalServer () (manet.Conn , error ) {
204
- allMaddrs , err := allServiceMaddrs ()
205
- if err != nil {
206
- return nil , err
207
- }
208
- return firstDialable (allMaddrs )
209
- }
210
-
211
208
func allServiceMaddrs () ([]multiaddr.Multiaddr , error ) {
212
209
var (
213
210
userMaddrs , uErr = userServiceMaddrs ()
214
211
systemMaddrs , sErr = systemServiceMaddrs ()
215
212
serviceMaddrs = append (userMaddrs , systemMaddrs ... )
216
213
)
217
- return serviceMaddrs , errors .Join (uErr , sErr )
214
+ if err := errors .Join (uErr , sErr ); err != nil {
215
+ return nil , fmt .Errorf (
216
+ "could not retrieve service maddrs: %w" ,
217
+ err ,
218
+ )
219
+ }
220
+ return serviceMaddrs , nil
218
221
}
219
222
220
223
// TODO: [Ame] docs.
@@ -231,21 +234,25 @@ func systemServiceMaddrs() ([]multiaddr.Multiaddr, error) {
231
234
return hostServiceMaddrs ()
232
235
}
233
236
234
- func firstDialable (maddrs [] multiaddr.Multiaddr ) (manet.Conn , error ) {
237
+ func firstDialable (maddrs ... multiaddr.Multiaddr ) (manet.Conn , error ) {
235
238
for _ , maddr := range maddrs {
236
239
if conn , err := manet .Dial (maddr ); err == nil {
237
240
return conn , nil
238
241
}
239
242
}
243
+ return nil , fmt .Errorf (
244
+ "%w any of: %s" ,
245
+ errCouldNotDial ,
246
+ formatMaddrs (maddrs ),
247
+ )
248
+ }
249
+
250
+ func formatMaddrs (maddrs []multiaddr.Multiaddr ) string {
240
251
maddrStrings := make ([]string , len (maddrs ))
241
252
for i , maddr := range maddrs {
242
253
maddrStrings [i ] = maddr .String ()
243
254
}
244
- var (
245
- cErr error = errServiceNotFound
246
- fmtString = strings .Join (maddrStrings , ", " )
247
- )
248
- return nil , fmt .Errorf ("%w: tried: %s" , cErr , fmtString )
255
+ return strings .Join (maddrStrings , ", " )
249
256
}
250
257
251
258
func servicePathsToServiceMaddrs (servicePaths ... string ) ([]multiaddr.Multiaddr , error ) {
0 commit comments