package v1 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" ) const ( eventGetConfiguration = "get configuration" eventCurrentConfiguration = "current configuration" eventApplyConfiguration = "apply configuration" eventConfigurationApplied = "configuration applied" eventResetConfiguration = "reset configuration to default" eventSettingsResetToDefault = "settings reset to default" ) type configurationApplied struct { Configuration *model.Configuration `mapstructure:"configuration,omitempty"` Result string `mapstructure:"result"` Constraints *model.Constraints `mapstructure:"constraints,omitempty"` } 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 } func (o *Operations) RequestConfiguration(ctx context.Context) (*model.Configuration, error) { configuration := &model.Configuration{} if err := o.ReqResp(ctx, eventGetConfiguration, nil, eventCurrentConfiguration, configuration); err != nil { return nil, err } return configuration, nil } // ReqResp emits an event with the given data and waits for a response func (o *Operations) ReqResp(ctx context.Context, requestEvent string, requestData any, responseEvent string, res any) error { o.mutex.RLock() defer o.mutex.RUnlock() if o.client == nil || !o.client.Alive() { return errors.WithStack(protocol.ErrClosed) } var err error var wg sync.WaitGroup var once sync.Once done := func() { o.client.Off(responseEvent) wg.Done() } wg.Add(1) go func() { <-ctx.Done() err = ctx.Err() once.Do(done) }() err = o.client.On(responseEvent, func(_ *socketio.Channel, data interface{}) { if res != nil { err = mapstructure.WeakDecode(data, res) } once.Do(done) }) if err != nil { return errors.Wrapf(err, "error while binding to '%s' event", responseEvent) } if err = o.client.Emit(requestEvent, requestData); err != nil { return errors.Wrapf(err, "error while emitting event '%s'", requestEvent) } wg.Wait() return err }