127 lines
2.5 KiB
Go
127 lines
2.5 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
|
|
}
|
|
|
|
// Close implements protocol.Operations.
|
|
func (c *Client) Close(ctx context.Context) error {
|
|
_, ops, err := c.getProtocol(ctx)
|
|
if err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
|
|
if err := ops.Close(ctx); err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Connect implements protocol.Operations.
|
|
func (c *Client) Connect(ctx context.Context) error {
|
|
_, ops, err := c.getProtocol(ctx)
|
|
if err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
|
|
if err := ops.Connect(ctx); err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) Protocol(ctx context.Context) (protocol.Identifier, error) {
|
|
id, _, err := c.getProtocol(ctx)
|
|
if err != nil {
|
|
return "", errors.WithStack(err)
|
|
}
|
|
|
|
return id, 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
|
|
}
|
|
|
|
var _ protocol.Operations = &Client{}
|