go-emlid/reach/client/client.go

104 lines
2.4 KiB
Go
Raw Normal View History

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() {
opts := []protocol.ProtocolOptionFunc{
protocol.WithProtocolLogger(c.opts.Logger),
protocol.WithProtocolDial(c.opts.Dial),
}
preferred, err := c.opts.Protocols.Get(c.opts.PreferredProtocol, opts...)
if err != nil && c.opts.FallbackProtocol == "" {
2024-07-30 14:28:39 +02:00
c.getProtocolOnceErr = errors.WithStack(err)
return
}
if preferred != nil {
preferredCtx, cancel := context.WithTimeout(ctx, c.opts.AvailableTimeout)
defer cancel()
2024-07-30 14:28:39 +02:00
ok, err := preferred.Available(preferredCtx, c.addr)
if err != nil && c.opts.FallbackProtocol == "" {
c.getProtocolOnceErr = errors.WithStack(err)
return
2024-07-30 14:28:39 +02:00
}
if ok {
c.proto = preferred.Identifier()
c.ops = preferred.Operations(c.addr)
return
2024-07-30 14:28:39 +02:00
}
}
if c.opts.FallbackProtocol == "" {
c.getProtocolOnceErr = errors.WithStack(err)
2024-07-30 14:28:39 +02:00
return
}
fallback, err := c.opts.Protocols.Get(c.opts.FallbackProtocol, opts...)
if err != nil {
c.getProtocolOnceErr = errors.WithStack(err)
2024-07-30 14:28:39 +02:00
return
}
fallbackCtx, cancel := context.WithTimeout(ctx, c.opts.AvailableTimeout)
defer cancel()
2024-07-30 14:28:39 +02:00
ok, err := fallback.Available(fallbackCtx, c.addr)
if err != nil && c.opts.FallbackProtocol == "" {
c.getProtocolOnceErr = errors.WithStack(err)
return
2024-07-30 14:28:39 +02:00
}
if ok {
c.proto = fallback.Identifier()
c.ops = fallback.Operations(c.addr)
2024-07-30 14:28:39 +02:00
return
}
c.getProtocolOnceErr = errors.Errorf("neither preferred protocol '%v' or fallback '%v' are available", c.opts.PreferredProtocol, c.opts.FallbackProtocol)
2024-07-30 14:28:39 +02:00
})
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
}