fix: protocol v1
This commit is contained in:
parent
8f89ed7e77
commit
b976bde363
@ -5,18 +5,22 @@ import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
reach "forge.cadoles.com/cadoles/go-emlid/reach/client"
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/logger"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
host string = "192.168.42.1"
|
||||
filter string = ""
|
||||
host string = "192.168.42.1"
|
||||
filter string = ""
|
||||
rawLogLevel string = "ERROR"
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&rawLogLevel, "log-level", rawLogLevel, "log level")
|
||||
flag.StringVar(&host, "host", host, "the reachrs module host")
|
||||
flag.StringVar(&filter, "filter", filter, "filter the broadcast messages by name")
|
||||
}
|
||||
@ -27,6 +31,14 @@ func main() {
|
||||
ctx := context.Background()
|
||||
client := reach.NewClient(host)
|
||||
|
||||
logLevel, err := logger.ParseLevel(rawLogLevel)
|
||||
if err != nil {
|
||||
fmt.Printf("[FATAL] %+v", errors.WithStack(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
slog.SetLogLoggerLevel(logLevel)
|
||||
|
||||
if err := client.Connect(ctx); err != nil {
|
||||
fmt.Printf("[FATAL] %+v", errors.WithStack(err))
|
||||
os.Exit(1)
|
||||
|
@ -5,9 +5,11 @@ import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
reach "forge.cadoles.com/cadoles/go-emlid/reach/client"
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/logger"
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/protocol"
|
||||
v1 "forge.cadoles.com/cadoles/go-emlid/reach/client/protocol/v1"
|
||||
v2 "forge.cadoles.com/cadoles/go-emlid/reach/client/protocol/v2"
|
||||
@ -18,9 +20,11 @@ var (
|
||||
host string = "192.168.42.1"
|
||||
preferredProtocol string = string(v2.Identifier)
|
||||
fallbackProtocol string = string(v1.Identifier)
|
||||
rawLogLevel string = "ERROR"
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&rawLogLevel, "log-level", rawLogLevel, "log level")
|
||||
flag.StringVar(&host, "host", host, "the reachrs module host")
|
||||
flag.StringVar(&preferredProtocol, "preferred-protocol", preferredProtocol, "preferred-protocol")
|
||||
flag.StringVar(&fallbackProtocol, "fallback-protocol", fallbackProtocol, "fallback-protocol")
|
||||
@ -29,6 +33,14 @@ func init() {
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
logLevel, err := logger.ParseLevel(rawLogLevel)
|
||||
if err != nil {
|
||||
fmt.Printf("[FATAL] %+v", errors.WithStack(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
slog.SetLogLoggerLevel(logLevel)
|
||||
|
||||
ctx := context.Background()
|
||||
client := reach.NewClient(
|
||||
host,
|
||||
|
35
cmd/discover/main.go
Normal file
35
cmd/discover/main.go
Normal file
@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/discovery"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func main() {
|
||||
services, err := discovery.Watch(context.Background())
|
||||
if err != nil {
|
||||
fmt.Printf("[FATAL] %+v", errors.WithStack(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
for srv := range services {
|
||||
data, err := json.MarshalIndent(struct {
|
||||
Addr string `json:"addr"`
|
||||
Name string `json:"name"`
|
||||
}{
|
||||
Name: srv.Name,
|
||||
Addr: fmt.Sprintf("%s:%d", srv.AddrV4.String(), srv.Port),
|
||||
}, "", " ")
|
||||
if err != nil {
|
||||
fmt.Printf("[FATAL] %+v", errors.WithStack(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n", data)
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
package example_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/discovery"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Exemple d'utilisation du package "discovery" pour identifier
|
||||
// les modules Reach présents sur le réseau
|
||||
func ExampleDiscovery() {
|
||||
timeout := 10 * time.Second
|
||||
|
||||
// Création d'un context avec un timeout de 10 secondes
|
||||
// pour limiter le temps de recherche des modules
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
// Recherche des modules annoncés sur le réseau
|
||||
// La recherche durerera 10 secondes, conformément au
|
||||
// timeout associé au context.Context
|
||||
services, err := discovery.Discover(ctx)
|
||||
if err != nil {
|
||||
fmt.Printf("could not discover reach modules: %+v\n", errors.WithStack(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Affichage des différents services Reach identifiés
|
||||
// sur le réseau
|
||||
for idx, srv := range services {
|
||||
fmt.Printf("Module #%d: %s:%d\n", idx, srv.AddrV4, srv.Port)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExampleDiscovery(t *testing.T) {
|
||||
if !testing.Verbose() {
|
||||
return
|
||||
}
|
||||
|
||||
ExampleDiscovery()
|
||||
}
|
@ -30,7 +30,7 @@ func (c *Client) Protocol(ctx context.Context) (protocol.Identifier, protocol.Op
|
||||
|
||||
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)
|
||||
availables, err := c.opts.Protocols.Availables(ctx, c.addr, c.opts.AvailableTimeout, protocol.WithProtocolLogger(c.opts.Logger))
|
||||
if err != nil {
|
||||
c.getProtocolOnceErr = errors.WithStack(err)
|
||||
return
|
||||
|
19
reach/client/logger/level.go
Normal file
19
reach/client/logger/level.go
Normal file
@ -0,0 +1,19 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Level = slog.Level
|
||||
|
||||
func ParseLevel(s string) (Level, error) {
|
||||
var level Level
|
||||
|
||||
if err := level.UnmarshalText([]byte(s)); err != nil {
|
||||
return level, errors.WithStack(err)
|
||||
}
|
||||
|
||||
return level, nil
|
||||
}
|
12
reach/client/logger/logger.go
Normal file
12
reach/client/logger/logger.go
Normal file
@ -0,0 +1,12 @@
|
||||
package logger
|
||||
|
||||
import "log/slog"
|
||||
|
||||
var Attr = slog.Any
|
||||
|
||||
type Logger interface {
|
||||
Debug(msg string, args ...any)
|
||||
Info(msg string, args ...any)
|
||||
Warn(msg string, args ...any)
|
||||
Error(msg string, args ...any)
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/logger"
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/protocol"
|
||||
v1 "forge.cadoles.com/cadoles/go-emlid/reach/client/protocol/v1"
|
||||
v2 "forge.cadoles.com/cadoles/go-emlid/reach/client/protocol/v2"
|
||||
@ -10,6 +14,8 @@ type Options struct {
|
||||
Protocols *protocol.Registry
|
||||
PreferredProtocol protocol.Identifier
|
||||
FallbackProtocol protocol.Identifier
|
||||
AvailableTimeout time.Duration
|
||||
Logger logger.Logger
|
||||
}
|
||||
|
||||
type OptionFunc func(opts *Options)
|
||||
@ -19,6 +25,8 @@ func NewOptions(funcs ...OptionFunc) *Options {
|
||||
PreferredProtocol: v2.Identifier,
|
||||
FallbackProtocol: v1.Identifier,
|
||||
Protocols: protocol.DefaultRegistry(),
|
||||
AvailableTimeout: 5 * time.Second,
|
||||
Logger: slog.Default(),
|
||||
}
|
||||
|
||||
for _, fn := range funcs {
|
||||
@ -45,3 +53,15 @@ func WithProtocols(protocols *protocol.Registry) OptionFunc {
|
||||
opts.Protocols = protocols
|
||||
}
|
||||
}
|
||||
|
||||
func WithLogger(logger logger.Logger) OptionFunc {
|
||||
return func(opts *Options) {
|
||||
opts.Logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
func WithAvailableTimeout(timeout time.Duration) OptionFunc {
|
||||
return func(opts *Options) {
|
||||
opts.AvailableTimeout = timeout
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,9 @@ package protocol
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/logger"
|
||||
)
|
||||
|
||||
type Identifier string
|
||||
@ -11,3 +14,29 @@ type Protocol interface {
|
||||
Available(ctx context.Context, addr string) (bool, error)
|
||||
Operations(addr string) Operations
|
||||
}
|
||||
|
||||
type ProtocolOptions struct {
|
||||
Logger logger.Logger
|
||||
}
|
||||
|
||||
type ProtocolFactory func(opts *ProtocolOptions) (Protocol, error)
|
||||
|
||||
type ProtocolOptionFunc func(opts *ProtocolOptions)
|
||||
|
||||
func NewProtocolOptions(funcs ...ProtocolOptionFunc) *ProtocolOptions {
|
||||
opts := &ProtocolOptions{
|
||||
Logger: slog.Default(),
|
||||
}
|
||||
|
||||
for _, fn := range funcs {
|
||||
fn(opts)
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
func WithProtocolLogger(logger logger.Logger) ProtocolOptionFunc {
|
||||
return func(opts *ProtocolOptions) {
|
||||
opts.Logger = logger
|
||||
}
|
||||
}
|
||||
|
@ -2,27 +2,39 @@ package protocol
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Registry struct {
|
||||
protocols map[Identifier]Protocol
|
||||
protocols map[Identifier]ProtocolFactory
|
||||
}
|
||||
|
||||
func (r *Registry) Register(protocol Protocol) {
|
||||
r.protocols[protocol.Identifier()] = protocol
|
||||
func (r *Registry) Register(identifier Identifier, factory ProtocolFactory) {
|
||||
r.protocols[identifier] = factory
|
||||
}
|
||||
|
||||
func (r *Registry) Availables(ctx context.Context, addr string) ([]Protocol, error) {
|
||||
func (r *Registry) Availables(ctx context.Context, addr string, timeout time.Duration, funcs ...ProtocolOptionFunc) ([]Protocol, error) {
|
||||
availables := make([]Protocol, 0)
|
||||
protocolOpts := NewProtocolOptions(funcs...)
|
||||
|
||||
for _, proto := range r.protocols {
|
||||
available, err := proto.Available(ctx, addr)
|
||||
for _, factory := range r.protocols {
|
||||
proto, err := factory(protocolOpts)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, timeout)
|
||||
|
||||
available, err := proto.Available(timeoutCtx, addr)
|
||||
if err != nil {
|
||||
cancel()
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
cancel()
|
||||
|
||||
if !available {
|
||||
continue
|
||||
}
|
||||
@ -35,7 +47,7 @@ func (r *Registry) Availables(ctx context.Context, addr string) ([]Protocol, err
|
||||
|
||||
func NewRegistry() *Registry {
|
||||
return &Registry{
|
||||
protocols: make(map[Identifier]Protocol),
|
||||
protocols: make(map[Identifier]ProtocolFactory),
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,10 +57,10 @@ func DefaultRegistry() *Registry {
|
||||
return defaultRegistry
|
||||
}
|
||||
|
||||
func Register(protocol Protocol) {
|
||||
defaultRegistry.Register(protocol)
|
||||
func Register(identifier Identifier, factory ProtocolFactory) {
|
||||
defaultRegistry.Register(identifier, factory)
|
||||
}
|
||||
|
||||
func Availables(ctx context.Context, addr string) ([]Protocol, error) {
|
||||
return defaultRegistry.Availables(ctx, addr)
|
||||
func Availables(ctx context.Context, addr string, timeout time.Duration) ([]Protocol, error) {
|
||||
return defaultRegistry.Availables(ctx, addr, timeout)
|
||||
}
|
||||
|
37
reach/client/protocol/testsuite/logger.go
Normal file
37
reach/client/protocol/testsuite/logger.go
Normal file
@ -0,0 +1,37 @@
|
||||
package testsuite
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/logger"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
// Debug implements logger.Logger.
|
||||
func (l *Logger) Debug(msg string, args ...any) {
|
||||
l.t.Logf(msg, args...)
|
||||
}
|
||||
|
||||
// Error implements logger.Logger.
|
||||
func (l *Logger) Error(msg string, args ...any) {
|
||||
l.t.Logf(msg, args...)
|
||||
}
|
||||
|
||||
// Info implements logger.Logger.
|
||||
func (l *Logger) Info(msg string, args ...any) {
|
||||
l.t.Logf(msg, args...)
|
||||
}
|
||||
|
||||
// Warn implements logger.Logger.
|
||||
func (l *Logger) Warn(msg string, args ...any) {
|
||||
l.t.Logf(msg, args...)
|
||||
}
|
||||
|
||||
func NewLogger(t *testing.T) *Logger {
|
||||
return &Logger{t}
|
||||
}
|
||||
|
||||
var _ logger.Logger = &Logger{}
|
@ -2,7 +2,9 @@ package testsuite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -52,6 +54,17 @@ var testCases = []operationTestCase{
|
||||
Run: func(t *testing.T, ops protocol.Operations) {
|
||||
ctx := context.Background()
|
||||
|
||||
if err := ops.Connect(ctx); err != nil {
|
||||
t.Errorf("%+v", errors.WithStack(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := ops.Close(ctx); err != nil {
|
||||
t.Errorf("%+v", errors.WithStack(err))
|
||||
}
|
||||
}()
|
||||
|
||||
version, stable, err := ops.Version(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("%+v", errors.WithStack(err))
|
||||
@ -104,6 +117,17 @@ var testCases = []operationTestCase{
|
||||
Run: func(t *testing.T, ops protocol.Operations) {
|
||||
ctx := context.Background()
|
||||
|
||||
if err := ops.Connect(ctx); err != nil {
|
||||
t.Errorf("%+v", errors.WithStack(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := ops.Close(ctx); err != nil {
|
||||
t.Errorf("%+v", errors.WithStack(err))
|
||||
}
|
||||
}()
|
||||
|
||||
config, err := ops.Configuration(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("%+v", errors.WithStack(err))
|
||||
@ -118,13 +142,32 @@ var testCases = []operationTestCase{
|
||||
Run: func(t *testing.T, ops protocol.Operations) {
|
||||
ctx := context.Background()
|
||||
|
||||
if err := ops.Connect(ctx); err != nil {
|
||||
t.Errorf("%+v", errors.WithStack(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := ops.Close(ctx); err != nil {
|
||||
t.Errorf("%+v", errors.WithStack(err))
|
||||
}
|
||||
}()
|
||||
|
||||
latitude := -90 + rand.Float64()*180
|
||||
longitude := -180 + rand.Float64()*360
|
||||
height := rand.Float64() * 1000
|
||||
antennaOffset := rand.Float64() * 2
|
||||
|
||||
opts := []protocol.SetBaseOptionFunc{
|
||||
protocol.WithBaseLatitude(47.72769),
|
||||
protocol.WithBaseLongitude(4.72783),
|
||||
protocol.WithBaseHeight(101),
|
||||
protocol.WithBaseLatitude(latitude),
|
||||
protocol.WithBaseLongitude(longitude),
|
||||
protocol.WithBaseHeight(height),
|
||||
protocol.WithBaseAntennaOffset(antennaOffset),
|
||||
protocol.WithBaseMode("manual"),
|
||||
}
|
||||
|
||||
t.Logf("setting base (latitude: %v, longitude: %v, height: %v, antennaOffset: %v", latitude, longitude, height, antennaOffset)
|
||||
|
||||
if err := ops.SetBase(ctx, opts...); err != nil {
|
||||
t.Errorf("%+v", errors.WithStack(err))
|
||||
return
|
||||
@ -132,10 +175,26 @@ var testCases = []operationTestCase{
|
||||
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Name: "Reboot",
|
||||
Run: func(t *testing.T, ops protocol.Operations) {
|
||||
const doRebootEnvVar = "DO_REBOOT"
|
||||
rawDoReboot := os.Getenv(doRebootEnvVar)
|
||||
if rawDoReboot == "" {
|
||||
rawDoReboot = "false"
|
||||
}
|
||||
|
||||
doReboot, err := strconv.ParseBool(rawDoReboot)
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse %s environment variable: %+v", doRebootEnvVar, errors.WithStack(err))
|
||||
return
|
||||
}
|
||||
|
||||
if !doReboot {
|
||||
t.Skipf("Reboot test case disabled. To enable, set environment variable %s=true", doRebootEnvVar)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
if err := ops.Connect(ctx); err != nil {
|
||||
|
@ -3,5 +3,9 @@ package v1
|
||||
import "forge.cadoles.com/cadoles/go-emlid/reach/client/protocol"
|
||||
|
||||
func init() {
|
||||
protocol.Register(&Protocol{})
|
||||
protocol.Register(Identifier, func(opts *protocol.ProtocolOptions) (protocol.Protocol, error) {
|
||||
return &Protocol{
|
||||
logger: opts.Logger,
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
|
@ -4,9 +4,11 @@ import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/logger"
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/protocol"
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/protocol/v1/model"
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/socketio"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@ -27,10 +29,15 @@ type configurationApplied struct {
|
||||
}
|
||||
|
||||
func (o *Operations) ApplyConfiguration(ctx context.Context, config *model.Configuration) (string, *model.Configuration, error) {
|
||||
o.logger.Debug("applying configuration", logger.Attr("configuration", spew.Sdump(config)))
|
||||
|
||||
res := &configurationApplied{}
|
||||
if err := o.ReqResp(ctx, eventApplyConfiguration, config, eventConfigurationApplied, res); err != nil {
|
||||
return configurationApplyFailed, nil, err
|
||||
}
|
||||
|
||||
o.logger.Debug("apply configuration response", logger.Attr("response", res))
|
||||
|
||||
return res.Result, res.Configuration, nil
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/logger"
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/protocol"
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/protocol/v1/model"
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/socketio"
|
||||
@ -16,6 +17,7 @@ type Operations struct {
|
||||
addr string
|
||||
client *socketio.Client
|
||||
mutex sync.RWMutex
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
// Close implements protocol.Operations.
|
||||
@ -54,6 +56,8 @@ func (o *Operations) Connect(ctx context.Context) error {
|
||||
|
||||
client := socketio.NewClient(endpoint)
|
||||
|
||||
o.logger.Debug("connecting", logger.Attr("endpoint", endpoint))
|
||||
|
||||
if err := client.Connect(); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
@ -67,6 +71,8 @@ func (o *Operations) Connect(ctx context.Context) error {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
o.logger.Debug("connected")
|
||||
|
||||
o.client = client
|
||||
|
||||
return nil
|
||||
@ -206,29 +212,58 @@ const (
|
||||
|
||||
// SetBase implements protocol.Operations.
|
||||
func (o *Operations) SetBase(ctx context.Context, funcs ...protocol.SetBaseOptionFunc) error {
|
||||
rawConfig, err := o.Configuration(ctx)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
config := rawConfig.(*model.Configuration)
|
||||
baseMode := config.BaseMode
|
||||
|
||||
var baseCoordinates *model.BaseCoordinates
|
||||
if baseMode != nil && baseMode.BaseCoordinates != nil {
|
||||
baseCoordinates = baseMode.BaseCoordinates
|
||||
}
|
||||
|
||||
opts := protocol.NewSetBaseOptions(funcs...)
|
||||
|
||||
var lat string
|
||||
if opts.Latitude != nil {
|
||||
lat = strconv.FormatFloat(*opts.Latitude, 'f', -1, 64)
|
||||
} else if baseCoordinates != nil && baseCoordinates.Coordinates != nil && len(baseCoordinates.Coordinates) > 1 {
|
||||
lat = *baseCoordinates.Coordinates[0]
|
||||
} else {
|
||||
lat = "0"
|
||||
}
|
||||
|
||||
var lon string
|
||||
if opts.Longitude != nil {
|
||||
lon = strconv.FormatFloat(*opts.Longitude, 'f', -1, 64)
|
||||
} else if baseCoordinates != nil && baseCoordinates.Coordinates != nil && len(baseCoordinates.Coordinates) > 1 {
|
||||
lon = *baseCoordinates.Coordinates[1]
|
||||
} else {
|
||||
lon = "0"
|
||||
}
|
||||
|
||||
var alt string
|
||||
if opts.Height != nil {
|
||||
alt = strconv.FormatFloat(*opts.Height, 'f', -1, 64)
|
||||
} else if baseCoordinates != nil && baseCoordinates.Coordinates != nil && len(baseCoordinates.Coordinates) > 1 {
|
||||
alt = *baseCoordinates.Coordinates[2]
|
||||
} else {
|
||||
alt = "0"
|
||||
}
|
||||
|
||||
var antennaHeight string
|
||||
if opts.AntennaOffset != nil {
|
||||
antennaHeight = strconv.FormatFloat(*opts.AntennaOffset, 'f', -1, 64)
|
||||
} else if baseCoordinates != nil && baseCoordinates.AntennaOffset != nil && baseCoordinates.AntennaOffset.Up != nil {
|
||||
antennaHeight = *baseCoordinates.AntennaOffset.Up
|
||||
} else {
|
||||
antennaHeight = "0"
|
||||
}
|
||||
|
||||
config := &model.Configuration{
|
||||
newConfig := &model.Configuration{
|
||||
BaseMode: &model.BaseMode{
|
||||
BaseCoordinates: &model.BaseCoordinates{
|
||||
Accumulation: model.String("1"),
|
||||
@ -248,7 +283,7 @@ func (o *Operations) SetBase(ctx context.Context, funcs ...protocol.SetBaseOptio
|
||||
},
|
||||
}
|
||||
|
||||
result, _, err := o.ApplyConfiguration(ctx, config)
|
||||
result, _, err := o.ApplyConfiguration(ctx, newConfig)
|
||||
if err != nil {
|
||||
return errors.New("configuration update failed")
|
||||
}
|
||||
|
@ -10,7 +10,9 @@ import (
|
||||
)
|
||||
|
||||
func TestProtocolV1Operations(t *testing.T) {
|
||||
proto := &Protocol{}
|
||||
proto := &Protocol{
|
||||
logger: testsuite.NewLogger(t),
|
||||
}
|
||||
|
||||
factory := func(addr string) (protocol.Operations, error) {
|
||||
ctx := context.Background()
|
||||
|
@ -2,17 +2,53 @@ package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/logger"
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/protocol"
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const Identifier protocol.Identifier = "v1"
|
||||
|
||||
const compatibleVersionConstraint = "^2.24"
|
||||
|
||||
type Protocol struct {
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
// Available implements protocol.Protocol.
|
||||
func (p *Protocol) Available(ctx context.Context, addr string) (bool, error) {
|
||||
ops := p.Operations(addr).(*Operations)
|
||||
|
||||
if err := ops.Connect(ctx); err != nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
defer ops.Close(ctx)
|
||||
|
||||
rawVersion, _, err := ops.Version(ctx)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
versionConstraint, err := semver.NewConstraint(compatibleVersionConstraint)
|
||||
if err != nil {
|
||||
return false, errors.WithStack(err)
|
||||
}
|
||||
|
||||
version, err := semver.NewVersion(rawVersion)
|
||||
if err != nil {
|
||||
return false, errors.WithStack(err)
|
||||
}
|
||||
|
||||
p.logger.Debug("checking version", slog.Any("version", rawVersion), slog.Any("constraint", compatibleVersionConstraint))
|
||||
|
||||
if !versionConstraint.Check(version) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@ -23,7 +59,7 @@ func (p *Protocol) Identifier() protocol.Identifier {
|
||||
|
||||
// Operations implements protocol.Protocol.
|
||||
func (p *Protocol) Operations(addr string) protocol.Operations {
|
||||
return &Operations{addr: addr}
|
||||
return &Operations{addr: addr, logger: p.logger}
|
||||
}
|
||||
|
||||
var _ protocol.Protocol = &Protocol{}
|
||||
|
@ -3,5 +3,9 @@ package v2
|
||||
import "forge.cadoles.com/cadoles/go-emlid/reach/client/protocol"
|
||||
|
||||
func init() {
|
||||
protocol.Register(&Protocol{})
|
||||
protocol.Register(Identifier, func(opts *protocol.ProtocolOptions) (protocol.Protocol, error) {
|
||||
return &Protocol{
|
||||
logger: opts.Logger,
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ type Configuration struct {
|
||||
Lora struct {
|
||||
AirRate float64 `json:"air_rate,omitempty"`
|
||||
Frequency int `json:"frequency,omitempty"`
|
||||
OutputPower int `json:"output_power,omitempty"`
|
||||
OutputPower float64 `json:"output_power,omitempty"`
|
||||
} `json:"lora,omitempty"`
|
||||
Ntripcaster struct {
|
||||
MountPoint string `json:"mount_point,omitempty"`
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/logger"
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/protocol"
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/protocol/v2/model"
|
||||
|
||||
@ -15,6 +16,7 @@ type Operations struct {
|
||||
addr string
|
||||
client *socketio.Client
|
||||
mutex sync.RWMutex
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
// Reboot implements protocol.Operations.
|
||||
|
@ -10,7 +10,9 @@ import (
|
||||
)
|
||||
|
||||
func TestProtocolV2Operations(t *testing.T) {
|
||||
proto := &Protocol{}
|
||||
proto := &Protocol{
|
||||
logger: testsuite.NewLogger(t),
|
||||
}
|
||||
|
||||
factory := func(addr string) (protocol.Operations, error) {
|
||||
ctx := context.Background()
|
||||
|
@ -3,6 +3,7 @@ package v2
|
||||
import (
|
||||
"context"
|
||||
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/logger"
|
||||
"forge.cadoles.com/cadoles/go-emlid/reach/client/protocol"
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/pkg/errors"
|
||||
@ -13,6 +14,7 @@ const Identifier protocol.Identifier = "v2"
|
||||
const compatibleVersionConstraint = ">= 32"
|
||||
|
||||
type Protocol struct {
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
// Available implements protocol.Protocol.
|
||||
@ -35,7 +37,7 @@ func (p *Protocol) Available(ctx context.Context, addr string) (bool, error) {
|
||||
}
|
||||
|
||||
if !versionConstraint.Check(version) {
|
||||
return false, errors.Errorf("reachview version '%s' does not match constraint '%s'", info.Reachview.Version, compatibleVersionConstraint)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
@ -48,7 +50,7 @@ func (p *Protocol) Identifier() protocol.Identifier {
|
||||
|
||||
// Operations implements protocol.Protocol.
|
||||
func (p *Protocol) Operations(addr string) protocol.Operations {
|
||||
return &Operations{addr: addr}
|
||||
return &Operations{addr: addr, logger: p.logger}
|
||||
}
|
||||
|
||||
var _ protocol.Protocol = &Protocol{}
|
||||
|
@ -3,9 +3,9 @@ package discovery
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/grandcat/zeroconf"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Service is a ReachRS service discovered via MDNS-SD
|
||||
@ -17,19 +17,34 @@ type Service struct {
|
||||
|
||||
// Discover tries to discover ReachRS services on the local network via mDNS-SD
|
||||
func Discover(ctx context.Context) ([]Service, error) {
|
||||
var wg sync.WaitGroup
|
||||
services := make([]Service, 0)
|
||||
|
||||
wg.Add(1)
|
||||
watch, err := Watch(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
for srv := range watch {
|
||||
services = append(services, srv)
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
// Watch watches ReachRS services on the local network via mDNS-SD
|
||||
func Watch(ctx context.Context) (chan Service, error) {
|
||||
out := make(chan Service, 0)
|
||||
|
||||
resolver, err := zeroconf.NewResolver()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
services := make([]Service, 0)
|
||||
entries := make(chan *zeroconf.ServiceEntry)
|
||||
|
||||
go func() {
|
||||
defer close(out)
|
||||
|
||||
for e := range entries {
|
||||
var addr *net.IP
|
||||
if len(e.AddrIPv4) > 0 {
|
||||
@ -40,17 +55,14 @@ func Discover(ctx context.Context) ([]Service, error) {
|
||||
AddrV4: addr,
|
||||
Port: e.Port,
|
||||
}
|
||||
services = append(services, srv)
|
||||
out <- srv
|
||||
}
|
||||
wg.Done()
|
||||
|
||||
}()
|
||||
|
||||
if err = resolver.Browse(ctx, "_reach._tcp", ".local", entries); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return services, nil
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user