97 lines
2.0 KiB
Go
97 lines
2.0 KiB
Go
|
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() {
|
||
|
availables, err := c.opts.Protocols.Availables(ctx, c.addr)
|
||
|
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
|
||
|
}
|