Skip to content

Commit 65e5445

Browse files
committed
commands: client/server - refactor maddr+log flags
The `-api-server` flag no longer uses a magic type to distinguish default values. Instead, client+server code will check if the flag was left unset, and provides a default value if so. The `-verbose` flag is no longer shared through embedding. It is still present in client and server commands, but the implementations initialize optional values (like `log` interfaces) at parse time rather at execution time.
1 parent 7c7ad95 commit 65e5445

File tree

8 files changed

+142
-166
lines changed

8 files changed

+142
-166
lines changed

internal/commands/client.go

Lines changed: 93 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -17,59 +17,74 @@ import (
1717
"github.com/djdv/p9/p9"
1818
"github.com/multiformats/go-multiaddr"
1919
manet "github.com/multiformats/go-multiaddr/net"
20+
"github.com/u-root/uio/ulog"
2021
)
2122

2223
type (
2324
Client p9.Client
2425
clientSettings struct {
2526
serviceMaddr multiaddr.Multiaddr
27+
log ulog.Logger
2628
exitInterval time.Duration
27-
sharedSettings
2829
}
2930
clientOption func(*clientSettings) error
3031
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 }
3732
)
3833

3934
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")
4238
)
4339

4440
func (cs *clientSettings) getClient(autoLaunchDaemon bool) (*Client, error) {
4541
var (
4642
serviceMaddr = cs.serviceMaddr
47-
clientOpts []p9.ClientOpt
43+
options []p9.ClientOpt
4844
)
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))
5347
}
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+
)
5759
}
5860
}
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
6070
}
6171

6272
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+
})
7388
const (
7489
exitName = exitAfterFlagName
7590
exitUsage = "passed to the daemon command if we launch it" +
@@ -88,8 +103,19 @@ func (co *clientOptions) BindFlags(flagSet *flag.FlagSet) {
88103
settings.serviceMaddr = value
89104
return nil
90105
})
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+
}
91114
flagSet.Lookup(serverFlagName).
92-
DefValue = defaultServerMaddr().String()
115+
DefValue = fmt.Sprintf(
116+
"one of: %s",
117+
strings.Join(maddrStrings, ", "),
118+
)
93119
}
94120

95121
func (co clientOptions) make() (clientSettings, error) {
@@ -99,19 +125,9 @@ func (co clientOptions) make() (clientSettings, error) {
99125
if err := generic.ApplyOptions(&settings, co...); err != nil {
100126
return clientSettings{}, err
101127
}
102-
if err := settings.fillDefaults(); err != nil {
103-
return clientSettings{}, err
104-
}
105128
return settings, nil
106129
}
107130

108-
func (cs *clientSettings) fillDefaults() error {
109-
if cs.serviceMaddr == nil {
110-
cs.serviceMaddr = defaultServerMaddr()
111-
}
112-
return nil
113-
}
114-
115131
func (c *Client) getListeners() ([]multiaddr.Multiaddr, error) {
116132
listenersDir, err := (*p9.Client)(c).Attach(listenersFileName)
117133
if err != nil {
@@ -124,44 +140,26 @@ func (c *Client) getListeners() ([]multiaddr.Multiaddr, error) {
124140
return maddrs, listenersDir.Close()
125141
}
126142

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-
138143
func launchAndConnect(exitInterval time.Duration, options ...p9.ClientOpt) (*Client, error) {
139144
daemon, ipc, stderr, err := spawnDaemonProc(exitInterval)
140145
if err != nil {
141146
return nil, err
142147
}
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+
}
152154
maddrs, err := getListenersFromProc(ipc, stderr, options...)
153155
if err != nil {
154-
errs = append(errs, err)
156+
errs := []error{err}
155157
if err := killProc(); err != nil {
156158
errs = append(errs, err)
157159
}
158160
return nil, errors.Join(errs...)
159161
}
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)
165163
if err != nil {
166164
return nil, errors.Join(err, killProc())
167165
}
@@ -182,39 +180,44 @@ func launchAndConnect(exitInterval time.Duration, options ...p9.ClientOpt) (*Cli
182180
}
183181

184182
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...)
186188
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+
)
188193
}
189194
return newClient(conn, options...)
190195
}
191196

192197
func newClient(conn io.ReadWriteCloser, options ...p9.ClientOpt) (*Client, error) {
193198
client, err := p9.NewClient(conn, options...)
194199
if err != nil {
195-
return nil, err
200+
return nil, fmt.Errorf(
201+
"could not create client: %w",
202+
err,
203+
)
196204
}
197205
return (*Client)(client), nil
198206
}
199207

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-
211208
func allServiceMaddrs() ([]multiaddr.Multiaddr, error) {
212209
var (
213210
userMaddrs, uErr = userServiceMaddrs()
214211
systemMaddrs, sErr = systemServiceMaddrs()
215212
serviceMaddrs = append(userMaddrs, systemMaddrs...)
216213
)
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
218221
}
219222

220223
// TODO: [Ame] docs.
@@ -231,21 +234,25 @@ func systemServiceMaddrs() ([]multiaddr.Multiaddr, error) {
231234
return hostServiceMaddrs()
232235
}
233236

234-
func firstDialable(maddrs []multiaddr.Multiaddr) (manet.Conn, error) {
237+
func firstDialable(maddrs ...multiaddr.Multiaddr) (manet.Conn, error) {
235238
for _, maddr := range maddrs {
236239
if conn, err := manet.Dial(maddr); err == nil {
237240
return conn, nil
238241
}
239242
}
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 {
240251
maddrStrings := make([]string, len(maddrs))
241252
for i, maddr := range maddrs {
242253
maddrStrings[i] = maddr.String()
243254
}
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, ", ")
249256
}
250257

251258
func servicePathsToServiceMaddrs(servicePaths ...string) ([]multiaddr.Multiaddr, error) {

0 commit comments

Comments
 (0)