2024-07-30 14:28:39 +02:00
|
|
|
package client
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"forge.cadoles.com/cadoles/go-emlid/reach/client/protocol"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Client struct {
|
|
|
|
addr string
|
|
|
|
opts *Options
|
|
|
|
|
|
|
|
proto protocol.Identifier
|
|
|
|
ops protocol.Operations
|
|
|
|
|
|
|
|
getProtocolOnce sync.Once
|
|
|
|
getProtocolOnceErr error
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) Protocol(ctx context.Context) (protocol.Identifier, protocol.Operations, error) {
|
|
|
|
id, ops, err := c.getProtocol(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return "", nil, errors.WithStack(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return id, ops, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) getProtocol(ctx context.Context) (protocol.Identifier, protocol.Operations, error) {
|
|
|
|
c.getProtocolOnce.Do(func() {
|
2024-08-05 18:10:19 +02:00
|
|
|
availables, err := c.opts.Protocols.Availables(
|
|
|
|
ctx, c.addr, c.opts.AvailableTimeout,
|
|
|
|
protocol.WithProtocolLogger(c.opts.Logger),
|
|
|
|
protocol.WithProtocolDial(c.opts.Dial),
|
|
|
|
)
|
2024-07-30 14:28:39 +02:00
|
|
|
if err != nil {
|
|
|
|
c.getProtocolOnceErr = errors.WithStack(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var preferred protocol.Protocol
|
|
|
|
var fallback protocol.Protocol
|
|
|
|
|
|
|
|
for _, proto := range availables {
|
|
|
|
if proto.Identifier() == c.opts.FallbackProtocol {
|
|
|
|
fallback = proto
|
|
|
|
}
|
|
|
|
|
|
|
|
if proto.Identifier() == c.opts.PreferredProtocol {
|
|
|
|
preferred = proto
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if preferred != nil {
|
|
|
|
c.proto = preferred.Identifier()
|
|
|
|
c.ops = preferred.Operations(c.addr)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if fallback != nil {
|
|
|
|
c.proto = fallback.Identifier()
|
|
|
|
c.ops = fallback.Operations(c.addr)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, proto := range availables {
|
|
|
|
if proto.Identifier() != c.opts.FallbackProtocol {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
fallback = proto
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
if fallback == nil {
|
|
|
|
c.getProtocolOnceErr = errors.Errorf("neither preferred protocol '%v' or fallback '%v' are available", c.opts.PreferredProtocol, c.opts.FallbackProtocol)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
c.proto = fallback.Identifier()
|
|
|
|
c.ops = fallback.Operations(c.addr)
|
|
|
|
})
|
|
|
|
if c.getProtocolOnceErr != nil {
|
|
|
|
return "", nil, errors.WithStack(c.getProtocolOnceErr)
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.proto, c.ops, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewClient(addr string, funcs ...OptionFunc) *Client {
|
|
|
|
opts := NewOptions(funcs...)
|
|
|
|
client := &Client{
|
|
|
|
addr: addr,
|
|
|
|
opts: opts,
|
|
|
|
}
|
|
|
|
return client
|
|
|
|
}
|