diff --git a/README.md b/README.md index 9e5e174b..389dcc87 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ This includes example code for sending an LPC limit 5 seconds after connecting t #### First Run ```sh -go run examples/controlbox/main.go 4713 +go run examples/controlbox/main.go -port 4713 ``` `4713` is the example server port that this process should listen on @@ -53,12 +53,13 @@ The certificate and key and the local SKI will be generated and printed. You sho #### General Usage ```sh -Usage: go run examples/controlbox/main.go +Usage: go run examples/controlbox/main.go -port [-certpath ] [-keypath ] [-remoteski ] [-target ] [-target ...] ``` - `remoteski` is the SKI of the remote device or service you want to connect to - `certfile` is a local file containing the generated certificate in the first usage run - `keyfile` is a local file containing the generated key in the first usage run +- `pairing target` can be a SHIP QR Code or in this format: `SKI=...,Fingerprint=...,ShipID=...,Secret=hex` ### HEMS @@ -67,7 +68,7 @@ This includes example code for accepting LPC and LPP limits from a control box, #### First Run ```sh -go run examples/hems/main.go 4714 +go run examples/hems/main.go -port 4714 ``` `4714` is the example server port that this process should listen on @@ -77,12 +78,13 @@ The certificate and key and the local SKI will be generated and printed. You sho #### General Usage ```sh -Usage: go run examples/hems/main.go +Usage: go run examples/hems/main.go -port [-certpath ] [-keypath ] [-remoteski ] [-secret ] ``` - `remoteski` is the SKI of the remote device or service you want to connect to - `certfile` is a local file containing the generated certificate in the first usage run - `keyfile` is a local file containing the generated key in the first usage run +- `secret` is a hexadecimal secret key as specified by SHIP Pairing Service Specificiation ### EVSE @@ -91,7 +93,7 @@ This includes example code for accepting LPC from a control box. #### First Run ```sh -go run examples/hems/main.go 4715 +go run examples/hems/main.go -port 4715 ``` `4715` is the example server port that this process should listen on @@ -101,12 +103,13 @@ The certificate and key and the local SKI will be generated and printed. You sho #### General Usage ```sh -Usage: go run examples/evse/main.go +Usage: go run examples/evse/main.go -port [-certpath ] [-keypath ] [-remoteski ] [-secret ] ``` - `remoteski` is the SKI of the remote device or service you want to connect to - `certfile` is a local file containing the generated certificate in the first usage run - `keyfile` is a local file containing the generated key in the first usage run +- `secret` is a hexadecimal secret key as specified by SHIP Pairing Service Specificiation ### Explanation diff --git a/api/api.go b/api/api.go index 8b1fc95e..1dc14a7c 100644 --- a/api/api.go +++ b/api/api.go @@ -15,11 +15,15 @@ import ( // // implemented by service, used by the eebus service implementation type ServiceInterface interface { - // setup the service + // Setup the service + // + // Returns error with description of the error that cannot be recovered from Setup() error // start the service - Start() + // + // Returns error with description of the error that cannot be recovered from + Start() error // shutdown the service Shutdown() @@ -44,8 +48,11 @@ type ServiceInterface interface { // Passthough functions to HubInterface - // Provide the current pairing state for a SKI - PairingDetailForSki(ski string) *shipapi.ConnectionStateDetail + // Provide the current pairing state for a ServiceIdentity + PairingDetailFor(identity shipapi.ServiceIdentity) *shipapi.ConnectionStateDetail + + // Return the remote service details for a given ServiceIdentity + RemoteServiceFor(identity shipapi.ServiceIdentity) *shipapi.ServiceDetails // Defines wether incoming pairing requests should be automatically accepted or not // @@ -55,36 +62,36 @@ type ServiceInterface interface { // Returns if the service has auto accept enabled or not IsAutoAcceptEnabled() bool - // Returns the QR code text for the service - // as defined in SHIP Requirements for Installation Process V1.0.0 - QRCodeText() string - - // Returns the Service detail of a remote SKI - RemoteServiceForSKI(ski string) *shipapi.ServiceDetails + // Generate a QR code string + // + // If a pairing config with a secret is set: generates SHIP Pairing Service QR format + // Otherwise: generates standard SHIP QR format + // + // Must be called after Setup() as it requires the hub to be initialized. + QRCodeText() (string, error) - // Pair a remote service based on the SKI + // Pair a remote service using ServiceIdentity // // Parameters: - // - ski: the SKI of the remote service (required) - // - shipID: the SHIP ID of the remote service (optional) + // - identity: ServiceIdentity containing SKI, fingerprint, and/or SHIP ID // // Note: The SHIP ID is optional, but should be provided if available. // if provided, it will be used to validate the remote service is // providing this SHIP ID during the handshake process and will reject // the connection if it does not match. - RegisterRemoteSKI(ski, shipID string) + RegisterRemoteService(identity shipapi.ServiceIdentity) - // Sets the SKI as not being paired - UnregisterRemoteSKI(ski string) + // Unpair a remote service using ServiceIdentity + UnregisterRemoteService(identity shipapi.ServiceIdentity) - // Disconnect from a connected remote SKI - DisconnectSKI(ski string, reason string) + // Disconnect a connection using ServiceIdentity + DisconnectService(identity shipapi.ServiceIdentity, reason string) - // Cancels the pairing process for a SKI + // Cancels the pairing process for a ServiceIdentity // // This should be called while the service is running and the end // user wants to cancel/disallow an incoming pairing request - CancelPairingWithSKI(ski string) + CancelPairing(identity shipapi.ServiceIdentity) // Define wether the user is able to react to an incoming pairing request // @@ -94,6 +101,46 @@ type ServiceInterface interface { // Default is set to false, meaning every incoming pairing request will be // automatically denied UserIsAbleToApproveOrCancelPairingRequests(allow bool) + + // Calculate SHA-256 fingerprint of local certificate + GetLocalCertificateFingerprint() (string, error) + + // ************************** + // SHIP Pairing Service APIs + // ************************** + + // Start announcing pairing to a specific target device + // Used by devZ only. + // + // Parameters: + // - target: Pairing target + StartAnnouncementTo(target shipapi.PairingTarget) error + + // Stop announcing pairing to a specific target device + // Used by devZ only. + // + // Parameters: + // - shipID: Target SHIP ID + StopAnnouncementTo(shipID string) error + + // Return true if currently announcing to a specific target device + // Used by devZ only. + // + // Parameters: + // - shipID: Target SHIP ID + IsAnnouncingTo(shipID string) bool + + // SHIP Pairing: Get Active Announcements. + // Used by devZ only. + // + // Returns: List of SHIP IDs currently being announced to + GetActiveAnnouncements() []string + + // SHIP Pairing: Get the SHIP ID and Fingerprint of controlbox paired via SHIP Pairing + // Used by devA only. + // + // Returns: the ServiceDetails of any trusted AddCu device. Or nil if none + GetTrustedAddCuDevice() *shipapi.ServiceDetails } // interface for receiving data for specific events from Service @@ -103,22 +150,36 @@ type ServiceInterface interface { // // implemented by the eebus service implementation, used by service type ServiceReaderInterface interface { - // report a connection to a SKI - RemoteSKIConnected(service ServiceInterface, ski string) + // report a connection to a remote service + RemoteServiceConnected(service ServiceInterface, identity shipapi.ServiceIdentity) - // report a disconnection to a SKI - RemoteSKIDisconnected(service ServiceInterface, ski string) + // report a disconnection from a remote service + RemoteServiceDisconnected(service ServiceInterface, identity shipapi.ServiceIdentity) // report all currently visible EEBUS services - VisibleRemoteServicesUpdated(service ServiceInterface, entries []shipapi.RemoteService) + VisibleRemoteMdnsServicesUpdated(service ServiceInterface, entries []shipapi.RemoteMdnsService) - // Provides the SHIP ID the remote service reported during the handshake process - // This needs to be persisted and passed on for future remote service connections - // when using `PairRemoteService` - ServiceShipIDUpdate(ski string, shipdID string) + // report that service information has been updated + // This includes updates to ShipID, fingerprint, or other service details + // discovered during handshake + ServiceUpdated(identity shipapi.ServiceIdentity) // Provides the current pairing state for the remote service // This is called whenever the state changes and can be used to // provide user information for the pairing/connection process - ServicePairingDetailUpdate(ski string, detail *shipapi.ConnectionStateDetail) + ServicePairingDetailUpdate(identity shipapi.ServiceIdentity, detail *shipapi.ConnectionStateDetail) + + // **************************** + // SHIP Pairing Service Events + // **************************** + + // Called when a device is automatically trusted via SHIP pairing + ServiceAutoTrusted(service ServiceInterface, identity shipapi.ServiceIdentity) + + // Called when SHIP pairing fails for a device + ServiceAutoTrustFailed(service ServiceInterface, identity shipapi.ServiceIdentity, reason error) + + // Called when device trust is automatically removed + // This can happen due to device replacement timeout or new device pairing + ServiceAutoTrustRemoved(service ServiceInterface, identity shipapi.ServiceIdentity, reason string) } diff --git a/api/configuration.go b/api/configuration.go index 061da0dd..69ecf35d 100644 --- a/api/configuration.go +++ b/api/configuration.go @@ -93,6 +93,12 @@ type Configuration struct { // Optional set which mDNS providers should be used mdnsProviderSelection mdns.MdnsProviderSelection + + // SHIP pairing configuration (optional, set before Setup) + pairingConfig *shipapi.PairingConfig + + // Ring buffer persistence for SHIP pairing replay protection (optional, set before Setup) + ringBufferPersistence shipapi.RingBufferPersistence } // Setup a Configuration with the required parameters @@ -108,7 +114,8 @@ type Configuration struct { // - port: The port address of the websocket server, required // - certificate: The certificate used for the service and its connections, required // - heartbeatTimeout: The timeout to be used for sending heartbeats and applied to all local entities created on setup of the service -// - mdnsProviderSelection: Optional set which mDNS providers should be used, default is `mdns.MdnsProviderSelectionAll` +// - pairingConfig: Optional SHIP Pairing configuration. Pass nil if SHIP Pairing should not be used +// - ringBufferPersistence: Interface to Pairing ring buffer persistence. SHALL be set if pairingConfig is set to listener mode (i.e. devA). See ship-go examples on how to create an implementation of this interface // // Returns: // - *Configuration: The created configuration @@ -124,6 +131,8 @@ func NewConfiguration( port int, certificate tls.Certificate, heartbeatTimeout time.Duration, + pairingConfig *shipapi.PairingConfig, + ringBufferPersistence shipapi.RingBufferPersistence, ) (*Configuration, error) { configuration := &Configuration{ certificate: certificate, @@ -176,6 +185,14 @@ func NewConfiguration( // set default configuration.featureSet = model.NetworkManagementFeatureSetTypeSmart + configuration.pairingConfig = pairingConfig + if pc := configuration.pairingConfig; pc != nil && + (pc.Mode == shipapi.PairingModeListener || pc.Mode == shipapi.PairingModeBoth) && + ringBufferPersistence == nil { + return nil, fmt.Errorf("ringBufferPersistence interface %s for pairing mode listener", isRequired) + } + configuration.ringBufferPersistence = ringBufferPersistence + return configuration, nil } @@ -304,3 +321,11 @@ func (s *Configuration) SetCertificate(cert tls.Certificate) { func (s *Configuration) HeartbeatTimeout() time.Duration { return s.heartbeatTimeout } + +func (s *Configuration) PairingConfig() *shipapi.PairingConfig { + return s.pairingConfig +} + +func (s *Configuration) RingBufferPersistence() shipapi.RingBufferPersistence { + return s.ringBufferPersistence +} diff --git a/api/configuration_test.go b/api/configuration_test.go index 4b0c40db..e00529f5 100644 --- a/api/configuration_test.go +++ b/api/configuration_test.go @@ -35,7 +35,7 @@ func (s *ConfigurationSuite) Test_Configuration() { config, err := NewConfiguration("", brand, model, serial, categories, spinemodel.DeviceTypeTypeEnergyManagementSystem, - entityTypes, 0, certificate, heartbeatTimeout) + entityTypes, 0, certificate, heartbeatTimeout, nil, nil) assert.Nil(s.T(), config) assert.NotNil(s.T(), err) @@ -43,7 +43,7 @@ func (s *ConfigurationSuite) Test_Configuration() { config, err = NewConfiguration("", brand, model, serial, categories, spinemodel.DeviceTypeTypeEnergyManagementSystem, - entityTypes, port, certificate, heartbeatTimeout) + entityTypes, port, certificate, heartbeatTimeout, nil, nil) assert.Nil(s.T(), config) assert.NotNil(s.T(), err) @@ -51,7 +51,7 @@ func (s *ConfigurationSuite) Test_Configuration() { config, err = NewConfiguration(vendor, "", model, serial, categories, spinemodel.DeviceTypeTypeEnergyManagementSystem, - entityTypes, port, certificate, heartbeatTimeout) + entityTypes, port, certificate, heartbeatTimeout, nil, nil) assert.Nil(s.T(), config) assert.NotNil(s.T(), err) @@ -59,7 +59,7 @@ func (s *ConfigurationSuite) Test_Configuration() { config, err = NewConfiguration(vendor, brand, "", serial, categories, spinemodel.DeviceTypeTypeEnergyManagementSystem, - entityTypes, port, certificate, heartbeatTimeout) + entityTypes, port, certificate, heartbeatTimeout, nil, nil) assert.Nil(s.T(), config) assert.NotNil(s.T(), err) @@ -67,7 +67,7 @@ func (s *ConfigurationSuite) Test_Configuration() { config, err = NewConfiguration(vendor, brand, model, "", categories, spinemodel.DeviceTypeTypeEnergyManagementSystem, - entityTypes, port, certificate, heartbeatTimeout) + entityTypes, port, certificate, heartbeatTimeout, nil, nil) assert.Nil(s.T(), config) assert.NotNil(s.T(), err) @@ -75,7 +75,7 @@ func (s *ConfigurationSuite) Test_Configuration() { config, err = NewConfiguration(vendor, brand, model, serial, nil, spinemodel.DeviceTypeTypeEnergyManagementSystem, - entityTypes, port, certificate, heartbeatTimeout) + entityTypes, port, certificate, heartbeatTimeout, nil, nil) assert.Nil(s.T(), config) assert.NotNil(s.T(), err) @@ -83,7 +83,7 @@ func (s *ConfigurationSuite) Test_Configuration() { config, err = NewConfiguration(vendor, brand, model, serial, categories, "", - entityTypes, port, certificate, heartbeatTimeout) + entityTypes, port, certificate, heartbeatTimeout, nil, nil) assert.Nil(s.T(), config) assert.NotNil(s.T(), err) @@ -91,7 +91,7 @@ func (s *ConfigurationSuite) Test_Configuration() { config, err = NewConfiguration(vendor, brand, model, serial, categories, spinemodel.DeviceTypeTypeEnergyManagementSystem, - []spinemodel.EntityTypeType{}, port, certificate, heartbeatTimeout) + []spinemodel.EntityTypeType{}, port, certificate, heartbeatTimeout, nil, nil) assert.Nil(s.T(), config) assert.NotNil(s.T(), err) @@ -99,7 +99,7 @@ func (s *ConfigurationSuite) Test_Configuration() { config, err = NewConfiguration(vendor, brand, model, serial, categories, spinemodel.DeviceTypeTypeEnergyManagementSystem, - entityTypes, port, certificate, heartbeatTimeout) + entityTypes, port, certificate, heartbeatTimeout, nil, nil) assert.NotNil(s.T(), config) assert.Nil(s.T(), err) @@ -169,3 +169,69 @@ func (s *ConfigurationSuite) Test_Configuration() { certValue := config.Certificate() assert.Equal(s.T(), testCert, certValue) } + +func (s *ConfigurationSuite) Test_PairingConfig() { + certificate, _ := cert.CreateCertificate("unit", "org", "DE", "CN") + vendor := "vendor" + brand := "brand" + model := "model" + serial := "serial" + categories := []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem} + port := 4567 + heartbeatTimeout := time.Second * 4 + entityTypes := []spinemodel.EntityTypeType{spinemodel.EntityTypeTypeCEM} + + // nil pairing config should work + config, err := NewConfiguration(vendor, brand, model, serial, + categories, spinemodel.DeviceTypeTypeEnergyManagementSystem, + entityTypes, port, certificate, heartbeatTimeout, nil, nil) + assert.NotNil(s.T(), config) + assert.Nil(s.T(), err) + assert.Nil(s.T(), config.PairingConfig()) + assert.Nil(s.T(), config.RingBufferPersistence()) + + // PairingModeListener without RingBufferPersistence should error + pairingConfig := &shipapi.PairingConfig{ + Mode: shipapi.PairingModeListener, + } + config, err = NewConfiguration(vendor, brand, model, serial, + categories, spinemodel.DeviceTypeTypeEnergyManagementSystem, + entityTypes, port, certificate, heartbeatTimeout, pairingConfig, nil) + assert.Nil(s.T(), config) + assert.NotNil(s.T(), err) + assert.Contains(s.T(), err.Error(), "ringBufferPersistence") + + // PairingModeBoth without RingBufferPersistence should error + pairingConfigBoth := &shipapi.PairingConfig{ + Mode: shipapi.PairingModeBoth, + } + config, err = NewConfiguration(vendor, brand, model, serial, + categories, spinemodel.DeviceTypeTypeEnergyManagementSystem, + entityTypes, port, certificate, heartbeatTimeout, pairingConfigBoth, nil) + assert.Nil(s.T(), config) + assert.NotNil(s.T(), err) + assert.Contains(s.T(), err.Error(), "ringBufferPersistence") + + // PairingModeAnnouncer without RingBufferPersistence should succeed + pairingConfigAnnouncer := &shipapi.PairingConfig{ + Mode: shipapi.PairingModeAnnouncer, + } + config, err = NewConfiguration(vendor, brand, model, serial, + categories, spinemodel.DeviceTypeTypeEnergyManagementSystem, + entityTypes, port, certificate, heartbeatTimeout, pairingConfigAnnouncer, nil) + assert.NotNil(s.T(), config) + assert.Nil(s.T(), err) + assert.NotNil(s.T(), config.PairingConfig()) + assert.Equal(s.T(), shipapi.PairingModeAnnouncer, config.PairingConfig().Mode) + assert.Nil(s.T(), config.RingBufferPersistence()) + + // PairingModeOff without RingBufferPersistence should succeed + pairingConfigOff := &shipapi.PairingConfig{ + Mode: shipapi.PairingModeOff, + } + config, err = NewConfiguration(vendor, brand, model, serial, + categories, spinemodel.DeviceTypeTypeEnergyManagementSystem, + entityTypes, port, certificate, heartbeatTimeout, pairingConfigOff, nil) + assert.NotNil(s.T(), config) + assert.Nil(s.T(), err) +} diff --git a/examples/ced/main.go b/examples/ced/main.go index 114c5d14..1d2e1014 100644 --- a/examples/ced/main.go +++ b/examples/ced/main.go @@ -4,13 +4,14 @@ import ( "crypto/ecdsa" "crypto/tls" "crypto/x509" + "encoding/hex" "encoding/pem" + "flag" "fmt" "log" "os" "os/signal" "slices" - "strconv" "syscall" "time" @@ -25,7 +26,27 @@ import ( "github.com/enbility/spine-go/model" ) -var remoteSki string +type configuration struct { + port uint + certPath string + keyPath string + remoteSKI string + secret string +} + +func (c configuration) String() string { + return fmt.Sprintf("port: %v\ncertPath: %v\nkeyPath: %v\nremoteSKI: %v\nsecret: %v", + c.port, c.certPath, c.keyPath, c.remoteSKI, c.secret) +} + +func (c configuration) Valid() bool { + return (c.port > 0 && c.port < 65536) //&& + // c.certPath != "" && // they can be empty to generate new certificate + // c.keyPath != "" && + // (len(c.remoteSKI) > 0) +} + +var config configuration type controlbox struct { myService *service.Service @@ -35,22 +56,21 @@ type controlbox struct { ucmpc ucapi.MaMPCInterface isConnected bool + + ringBuffer *ExampleRingBufferPersistence } func (h *controlbox) run() { var err error var certificate tls.Certificate - if len(os.Args) == 5 { - remoteSki = os.Args[2] - - certificate, err = tls.LoadX509KeyPair(os.Args[3], os.Args[4]) + if config.certPath != "" && config.keyPath != "" { + certificate, err = tls.LoadX509KeyPair(config.certPath, config.keyPath) if err != nil { - usage() log.Fatal(err) } } else { - certificate, err = cert.CreateCertificate("Demo", "Demo", "DE", "Demo-Unit-01") + certificate, err = cert.CreateCertificate("Demo", "Demo", "DE", "Demo-Unit-02") if err != nil { log.Fatal(err) } @@ -69,12 +89,19 @@ func (h *controlbox) run() { fmt.Println(string(pemdata)) } - port, err := strconv.Atoi(os.Args[1]) - if err != nil { - usage() - log.Fatal(err) + var pairingConfig *shipapi.PairingConfig + if len(config.secret) == 0 { + fmt.Println("Secret not specified.. PairingConfig not set") + } else { + secretBytes, err := hex.DecodeString(config.secret) + if err != nil { + log.Fatal(err) + } + pairingConfig = shipapi.NewPairingConfig(shipapi.PairingModeListener, shipapi.PairingSecret(secretBytes)) } + h.ringBuffer = &ExampleRingBufferPersistence{} + configuration, err := api.NewConfiguration( "Bosch", "eebus-go", "myHP", "12345678", []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeHVAC}, @@ -82,7 +109,7 @@ func (h *controlbox) run() { model.DeviceTypeTypeGeneric, // []model.EntityTypeType{model.EntityTypeTypeGridGuard}, []model.EntityTypeType{model.EntityTypeTypeHeatPumpAppliance}, - port, certificate, time.Second*60) + int(config.port), certificate, time.Second*60, pairingConfig, nil) if err != nil { log.Fatal(err) } @@ -106,43 +133,67 @@ func (h *controlbox) run() { h.ucmpc = mpc.NewMPC(localEntity, h.OnMPCEvent) h.myService.AddUseCase(h.ucmpc) - if len(remoteSki) == 0 { + if len(config.remoteSKI) == 0 && pairingConfig == nil { os.Exit(0) } - h.myService.RegisterRemoteSKI(remoteSki, "") + if len(config.remoteSKI) == 40 { + h.myService.RegisterRemoteService(shipapi.NewServiceIdentity(config.remoteSKI, "", "")) + } - h.myService.Start() + _ = h.myService.Start() + if qrCodeText, err := h.myService.QRCodeText(); err == nil { + fmt.Println("Service QR Code:", qrCodeText) + } // defer h.myService.Shutdown() } // EEBUSServiceHandler -func (h *controlbox) RemoteSKIConnected(service api.ServiceInterface, ski string) { +func (h *controlbox) RemoteServiceConnected(service api.ServiceInterface, identity shipapi.ServiceIdentity) { h.isConnected = true } -func (h *controlbox) RemoteSKIDisconnected(service api.ServiceInterface, ski string) { +func (h *controlbox) RemoteServiceDisconnected(service api.ServiceInterface, identity shipapi.ServiceIdentity) { h.isConnected = false } -func (h *controlbox) VisibleRemoteServicesUpdated(service api.ServiceInterface, entries []shipapi.RemoteService) { +func (h *controlbox) VisibleRemoteMdnsServicesUpdated(service api.ServiceInterface, entries []shipapi.RemoteMdnsService) { } -func (h *controlbox) ServiceShipIDUpdate(ski string, shipdID string) {} +func (h *controlbox) ServiceUpdated(identity shipapi.ServiceIdentity) {} -func (h *controlbox) ServicePairingDetailUpdate(ski string, detail *shipapi.ConnectionStateDetail) { - if ski == remoteSki && detail.State() == shipapi.ConnectionStateRemoteDeniedTrust { +func (h *controlbox) ServicePairingDetailUpdate(identity shipapi.ServiceIdentity, detail *shipapi.ConnectionStateDetail) { + if identity.SKI == config.remoteSKI && detail.State() == shipapi.ConnectionStateRemoteDeniedTrust { fmt.Println("The remote service denied trust. Exiting.") - h.myService.CancelPairingWithSKI(ski) - h.myService.UnregisterRemoteSKI(ski) + h.myService.CancelPairing(identity) + h.myService.UnregisterRemoteService(identity) h.myService.Shutdown() os.Exit(0) } } -func (h *controlbox) AllowWaitingForTrust(ski string) bool { - return ski == remoteSki +func (h *controlbox) AllowWaitingForTrust(identity shipapi.ServiceIdentity) bool { + if len(config.remoteSKI) != 40 { + // no remoteSki given, give a chance for automatic pairing + return true + } + return identity.SKI == config.remoteSKI +} + +// ServiceAutoTrustFailed implements api.ServiceReaderInterface. +func (h *controlbox) ServiceAutoTrustFailed(service api.ServiceInterface, identity shipapi.ServiceIdentity, reason error) { + log.Printf("Auto Trust failed for identity %v: %v\n", identity.String(), reason) +} + +// ServiceAutoTrustRemoved implements api.ServiceReaderInterface. +func (h *controlbox) ServiceAutoTrustRemoved(service api.ServiceInterface, identity shipapi.ServiceIdentity, reason string) { + log.Printf("Auto Trust removed for identity %v: %v\n", identity.String(), reason) +} + +// ServiceAutoTrusted implements api.ServiceReaderInterface. +func (h *controlbox) ServiceAutoTrusted(service api.ServiceInterface, identity shipapi.ServiceIdentity) { + log.Printf("Auto Trust successful for identity %v\n", identity.String()) } // LPC Event Handler @@ -234,20 +285,25 @@ func (h *controlbox) OnMPCEvent(ski string, device spineapi.DeviceRemoteInterfac // JH experimental ---------------------------------------- // main app -func usage() { - fmt.Println("First Run:") - fmt.Println(" go run /examples/controlbox/main.go ") - fmt.Println() - fmt.Println("General Usage:") - fmt.Println(" go run /examples/controlbox/main.go ") -} func main() { - if len(os.Args) < 2 { - usage() - return + flag.StringVar(&config.certPath, "certpath", "", "./path/to/cert.pem") + flag.StringVar(&config.keyPath, "keypath", "", "./path/to/key.pem") + flag.StringVar(&config.remoteSKI, "remoteski", "", "remote SKI") + flag.UintVar(&config.port, "port", 0, "server port") + flag.StringVar(&config.secret, "secret", "", "secret hexadecimal") + flag.Parse() + + if !config.Valid() { + flag.Usage() + log.Fatal("invalid configuration") } + fmt.Println("--------------") + fmt.Println("Configuration") + fmt.Println(config) + fmt.Println("--------------") + h := controlbox{} h.run() @@ -255,6 +311,9 @@ func main() { sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, syscall.SIGTERM) <-sig + if h.myService != nil { + h.myService.Shutdown() + } // User exit } @@ -305,3 +364,71 @@ func (h *controlbox) printFormat(msgType, format string, args ...interface{}) { value := fmt.Sprintf(format, args...) fmt.Println(h.currentTimestamp(), msgType, value) } + +// Ring buffer persistence + +type ExampleRingBufferPersistence struct { +} + +// LoadRingBuffer implements api.RingBufferPersistence. +func (r *ExampleRingBufferPersistence) LoadRingBuffer() ([]shipapi.DigestEntry, int, error) { + fmt.Printf(" 📂 Loading ring buffer from...\n") + + // For demonstration: return empty state (no previous storage) + // Real applications should load from persistent storage: + // + // data, err := os.ReadFile(r.filename) + // if os.IsNotExist(err) { + // // No previous data - return empty buffer (library will initialize) + // return make([]api.DigestEntry, 100), 0, nil + // } + // if err != nil { + // return nil, 0, fmt.Errorf("failed to read ring buffer: %w", err) + // } + // + // var state struct { + // Entries []api.DigestEntry `json:"entries"` + // NextIndex int `json:"nextIndex"` + // } + // if err := json.Unmarshal(data, &state); err != nil { + // return nil, 0, fmt.Errorf("failed to parse ring buffer: %w", err) + // } + // + // return state.Entries, state.NextIndex, nil + + // Demo: return empty buffer (library will manage the ring buffer logic) + fmt.Printf(" 📂 No previous data, library will create fresh ring buffer\n") + return make([]shipapi.DigestEntry, 100), 0, nil +} + +// SaveRingBuffer implements api.RingBufferPersistence. +func (r *ExampleRingBufferPersistence) SaveRingBuffer(entries []shipapi.DigestEntry, nextIndex int) error { + fmt.Printf(" 💾 Library requests save: %d entries, nextIndex=%d to\n", len(entries), nextIndex) + + // For demonstration: just log what the library is providing + // Real applications should save the library's data to persistent storage: + // + // state := struct { + // Entries []api.DigestEntry `json:"entries"` + // NextIndex int `json:"nextIndex"` + // }{ + // Entries: entries, // Complete ring buffer from library + // NextIndex: nextIndex, // Current position from library + // } + // + // data, err := json.Marshal(state) + // if err != nil { + // return fmt.Errorf("failed to marshal ring buffer: %w", err) + // } + // + // // Atomic write pattern for safety + // tempFile := r.filename + ".tmp" + // if err := os.WriteFile(tempFile, data, 0600); err != nil { + // return fmt.Errorf("failed to write ring buffer: %w", err) + // } + // + // return os.Rename(tempFile, r.filename) + + fmt.Printf(" 💾 Demo: Would save library's ring buffer state to\n") + return nil +} diff --git a/examples/controlbox/main.go b/examples/controlbox/main.go index 75a12386..d323061f 100644 --- a/examples/controlbox/main.go +++ b/examples/controlbox/main.go @@ -4,13 +4,16 @@ import ( "crypto/ecdsa" "crypto/tls" "crypto/x509" + "encoding/base64" + "encoding/hex" "encoding/pem" + "flag" "fmt" "log" "os" "os/signal" "slices" - "strconv" + "strings" "syscall" "time" @@ -25,8 +28,6 @@ import ( "github.com/enbility/spine-go/model" ) -var remoteSki string - type controlbox struct { myService *service.Service @@ -36,16 +37,113 @@ type controlbox struct { isConnected bool } +type configuration struct { + port uint + certPath string + keyPath string + remoteSKIs remoteSKIList + pairingTargets targetList +} + +func (c configuration) String() string { + return fmt.Sprintf("port: %v\ncertPath: %v\nkeyPath: %v\nremoteSKIs: %v\npairingTargets: %v", + c.port, c.certPath, c.keyPath, c.remoteSKIs, c.pairingTargets) +} + +func (c configuration) Valid() bool { + return (c.port > 0 && c.port < 65536) //&& + // c.certPath != "" && // they can be empty to generate new certificate + // c.keyPath != "" && + // (len(c.remoteSKIs) > 0 || len(c.pairingTargets) > 0) +} + +var config configuration + +type remoteSKIList []string + +func (r *remoteSKIList) String() string { + return fmt.Sprint(*r) +} + +func (r *remoteSKIList) Set(value string) error { + if len(value) != 40 { + return fmt.Errorf("invalid SKI") + } + _, err := hex.DecodeString(value) + if err != nil { + return err + } + *r = append(*r, value) + return nil +} + +type targetList []shipapi.PairingTarget + +func (t *targetList) String() string { + return fmt.Sprint(*t) +} + +func (t *targetList) Set(value string) error { + value = strings.TrimSpace(value) + + // Case 1: QR input + if strings.HasPrefix(value, "SHIP;") { + pt, err := NewPairingTargetFromQrCode(value) + if err != nil { + return fmt.Errorf("failed to decode QR input: %v", err) + } + + *t = append(*t, pt) + return nil + } + + // Case 2: key=value parsing (existing logic) + pt := shipapi.PairingTarget{} + + parts := strings.Split(value, ",") + for _, p := range parts { + kv := strings.SplitN(p, "=", 2) + if len(kv) != 2 { + return fmt.Errorf("invalid key=value pair: %q", p) + } + + key := strings.ToLower(strings.TrimSpace(kv[0])) + val := strings.TrimSpace(kv[1]) + + switch key { + case "ski": + pt.SKI = val + case "fingerprint": + pt.Fingerprint = val + case "shipid": + pt.ShipID = val + case "secret": + decoded, err := base64.StdEncoding.DecodeString(val) + if err != nil { + return fmt.Errorf("invalid base64 for secret: %v", err) + } + pt.Secret = decoded + default: + return fmt.Errorf("unknown field: %s", key) + } + } + + // Validation + if len(pt.Secret) != 16 || pt.Fingerprint == "" || pt.ShipID == "" { + return fmt.Errorf("missing required fields (Secret, Fingerprint, ShipID)") + } + + *t = append(*t, pt) + return nil +} + func (h *controlbox) run() { var err error var certificate tls.Certificate - if len(os.Args) == 5 { - remoteSki = os.Args[2] - - certificate, err = tls.LoadX509KeyPair(os.Args[3], os.Args[4]) + if config.certPath != "" && config.keyPath != "" { + certificate, err = tls.LoadX509KeyPair(config.certPath, config.keyPath) if err != nil { - usage() log.Fatal(err) } } else { @@ -68,18 +166,14 @@ func (h *controlbox) run() { fmt.Println(string(pemdata)) } - port, err := strconv.Atoi(os.Args[1]) - if err != nil { - usage() - log.Fatal(err) - } + pairingConfig := shipapi.NewPairingConfig(shipapi.PairingModeAnnouncer, nil) configuration, err := api.NewConfiguration( "Demo", "Demo", "ControlBox", "123456789", []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeGridConnectionHub}, model.DeviceTypeTypeElectricitySupplySystem, []model.EntityTypeType{model.EntityTypeTypeGridGuard}, - port, certificate, time.Second*60) + int(config.port), certificate, time.Second*60, pairingConfig, nil) if err != nil { log.Fatal(err) } @@ -100,43 +194,59 @@ func (h *controlbox) run() { h.uclpp = lpp.NewLPP(localEntity, h.OnLPPEvent) h.myService.AddUseCase(h.uclpp) - if len(remoteSki) == 0 { - os.Exit(0) + for _, remoteSki := range config.remoteSKIs { + h.myService.RegisterRemoteService(shipapi.NewServiceIdentity(remoteSki, "", "")) } - h.myService.RegisterRemoteSKI(remoteSki, "") - - h.myService.Start() + _ = h.myService.Start() + for _, pairingTarget := range config.pairingTargets { + identity := shipapi.NewServiceIdentity("", pairingTarget.Fingerprint, pairingTarget.ShipID) + h.myService.RegisterRemoteService(identity) + h.myService.StartAnnouncementTo(pairingTarget) + } // defer h.myService.Shutdown() } // EEBUSServiceHandler -func (h *controlbox) RemoteSKIConnected(service api.ServiceInterface, ski string) { +func (h *controlbox) RemoteServiceConnected(service api.ServiceInterface, identity shipapi.ServiceIdentity) { h.isConnected = true } -func (h *controlbox) RemoteSKIDisconnected(service api.ServiceInterface, ski string) { +func (h *controlbox) RemoteServiceDisconnected(service api.ServiceInterface, identity shipapi.ServiceIdentity) { h.isConnected = false } -func (h *controlbox) VisibleRemoteServicesUpdated(service api.ServiceInterface, entries []shipapi.RemoteService) { +func (h *controlbox) VisibleRemoteMdnsServicesUpdated(service api.ServiceInterface, entries []shipapi.RemoteMdnsService) { } -func (h *controlbox) ServiceShipIDUpdate(ski string, shipdID string) {} +func (h *controlbox) ServiceUpdated(identity shipapi.ServiceIdentity) { +} -func (h *controlbox) ServicePairingDetailUpdate(ski string, detail *shipapi.ConnectionStateDetail) { - if ski == remoteSki && detail.State() == shipapi.ConnectionStateRemoteDeniedTrust { +func (h *controlbox) ServicePairingDetailUpdate(identity shipapi.ServiceIdentity, detail *shipapi.ConnectionStateDetail) { + if slices.Contains(config.remoteSKIs, identity.SKI) && detail.State() == shipapi.ConnectionStateRemoteDeniedTrust { fmt.Println("The remote service denied trust. Exiting.") - h.myService.CancelPairingWithSKI(ski) - h.myService.UnregisterRemoteSKI(ski) + h.myService.CancelPairing(identity) + h.myService.UnregisterRemoteService(identity) h.myService.Shutdown() os.Exit(0) } } -func (h *controlbox) AllowWaitingForTrust(ski string) bool { - return ski == remoteSki +func (h *controlbox) AllowWaitingForTrust(identity shipapi.ServiceIdentity) bool { + return slices.Contains(config.remoteSKIs, identity.SKI) +} + +// ServiceAutoTrustFailed implements api.ServiceReaderInterface. +func (h *controlbox) ServiceAutoTrustFailed(service api.ServiceInterface, identity shipapi.ServiceIdentity, reason error) { +} + +// ServiceAutoTrustRemoved implements api.ServiceReaderInterface. +func (h *controlbox) ServiceAutoTrustRemoved(service api.ServiceInterface, identity shipapi.ServiceIdentity, reason string) { +} + +// ServiceAutoTrusted implements api.ServiceReaderInterface. +func (h *controlbox) ServiceAutoTrusted(service api.ServiceInterface, identity shipapi.ServiceIdentity) { } // LPC Event Handler @@ -238,20 +348,25 @@ func (h *controlbox) OnLPPEvent(ski string, device spineapi.DeviceRemoteInterfac } // main app -func usage() { - fmt.Println("First Run:") - fmt.Println(" go run /examples/controlbox/main.go ") - fmt.Println() - fmt.Println("General Usage:") - fmt.Println(" go run /examples/controlbox/main.go ") -} func main() { - if len(os.Args) < 2 { - usage() - return + flag.Var(&config.pairingTargets, "target", "target in format SKI=...,Fingerprint=...,ShipID=...,Secret=hex") + flag.StringVar(&config.certPath, "certpath", "", "./path/to/cert.pem") + flag.StringVar(&config.keyPath, "keypath", "", "./path/to/key.pem") + flag.Var(&config.remoteSKIs, "remoteski", "remote SKI") + flag.UintVar(&config.port, "port", 0, "server port") + flag.Parse() + + if !config.Valid() { + flag.Usage() + log.Fatal("invalid configuration") } + fmt.Println("--------------") + fmt.Println("Configuration") + fmt.Println(config) + fmt.Println("--------------") + h := controlbox{} h.run() @@ -259,6 +374,9 @@ func main() { sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, syscall.SIGTERM) <-sig + if h.myService != nil { + h.myService.Shutdown() + } // User exit } @@ -309,3 +427,74 @@ func (h *controlbox) printFormat(msgType, format string, args ...interface{}) { value := fmt.Sprintf(format, args...) fmt.Println(h.currentTimestamp(), msgType, value) } + +func NewPairingTargetFromQrCode(qrString string) (shipapi.PairingTarget, error) { + var ret shipapi.PairingTarget + + // Clean up the input + qrString = strings.TrimSpace(qrString) + + // Validate SHIP format + if !strings.HasPrefix(qrString, "SHIP;") { + return ret, fmt.Errorf("QR string must start with 'SHIP;', got: %s", qrString) + } + + if !strings.HasSuffix(qrString, "ENDSHIP;") { + return ret, fmt.Errorf("QR string must end with 'ENDSHIP;', got: %s", qrString) + } + + // Remove SHIP; prefix and ENDSHIP; suffix + content := qrString[5 : len(qrString)-8] // Remove "SHIP;" and "ENDSHIP;" + + // Split into key-value pairs + fields := strings.Split(content, ";") + + for _, field := range fields { + if field == "" { + continue + } + + parts := strings.SplitN(field, ":", 2) + if len(parts) != 2 { + continue // Skip malformed fields + } + + key := strings.ToUpper(strings.TrimSpace(parts[0])) + value := strings.TrimSpace(parts[1]) + + switch key { + case "SKI": + ret.SKI = value + case "ID": + ret.ShipID = value + case "FPH256": + ret.Fingerprint = value + case "SPSEC": + // Validate and decode secret + secret, err := hex.DecodeString(value) + if err != nil { + return ret, fmt.Errorf("invalid secret: %w", err) + } + ret.Secret = secret + default: + // ignore unknown keys + continue + } + } + + // Validate required fields + if ret.SKI == "" { + return ret, fmt.Errorf("missing required 'SKI' field") + } + if ret.ShipID == "" { + return ret, fmt.Errorf("missing required 'ID' field (SHIP ID)") + } + if ret.Fingerprint == "" { + return ret, fmt.Errorf("missing required 'FPH256' field (certificate fingerprint)") + } + if len(ret.Secret) == 0 { + return ret, fmt.Errorf("missing required 'SPSEC' field (pairing secret)") + } + + return ret, nil +} diff --git a/examples/evse/main.go b/examples/evse/main.go index 26256724..209fa7c4 100644 --- a/examples/evse/main.go +++ b/examples/evse/main.go @@ -4,12 +4,13 @@ import ( "crypto/ecdsa" "crypto/tls" "crypto/x509" + "encoding/hex" "encoding/pem" + "flag" "fmt" "log" "os" "os/signal" - "strconv" "syscall" "time" @@ -23,7 +24,27 @@ import ( "github.com/enbility/spine-go/model" ) -var remoteSki string +type configuration struct { + port uint + certPath string + keyPath string + remoteSKI string + secret string +} + +func (c configuration) String() string { + return fmt.Sprintf("port: %v\ncertPath: %v\nkeyPath: %v\nremoteSKI: %v\nsecret: %v", + c.port, c.certPath, c.keyPath, c.remoteSKI, c.secret) +} + +func (c configuration) Valid() bool { + return (c.port > 0 && c.port < 65536) //&& + // c.certPath != "" && // they can be empty to generate new certificate + // c.keyPath != "" && + // (len(c.remoteSKI) > 0) +} + +var config configuration type evse struct { myService *service.Service @@ -31,18 +52,17 @@ type evse struct { uclpc *lpc.LPC isConnected bool + + ringBuffer *ExampleRingBufferPersistence } func (h *evse) run() { var err error var certificate tls.Certificate - if len(os.Args) == 5 { - remoteSki = os.Args[2] - - certificate, err = tls.LoadX509KeyPair(os.Args[3], os.Args[4]) + if config.certPath != "" && config.keyPath != "" { + certificate, err = tls.LoadX509KeyPair(config.certPath, config.keyPath) if err != nil { - usage() log.Fatal(err) } } else { @@ -65,18 +85,25 @@ func (h *evse) run() { fmt.Println(string(pemdata)) } - port, err := strconv.Atoi(os.Args[1]) - if err != nil { - usage() - log.Fatal(err) + var pairingConfig *shipapi.PairingConfig + if len(config.secret) == 0 { + fmt.Println("Secret not specified.. PairingConfig not set") + } else { + secretBytes, err := hex.DecodeString(config.secret) + if err != nil { + log.Fatal(err) + } + pairingConfig = shipapi.NewPairingConfig(shipapi.PairingModeListener, shipapi.PairingSecret(secretBytes)) } + h.ringBuffer = &ExampleRingBufferPersistence{} + configuration, err := api.NewConfiguration( "Demo", "Demo", "EVSE", "234567890", []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEMobility}, model.DeviceTypeTypeChargingStation, []model.EntityTypeType{model.EntityTypeTypeEVSE}, - port, certificate, time.Second*4) + int(config.port), certificate, time.Second*4, pairingConfig, h.ringBuffer) if err != nil { log.Fatal(err) } @@ -104,43 +131,72 @@ func (h *evse) run() { _ = h.uclpc.SetFailsafeConsumptionActivePowerLimit(4200, true) _ = h.uclpc.SetFailsafeDurationMinimum(2*time.Hour, true) - if len(remoteSki) == 0 { + if len(config.remoteSKI) == 0 && pairingConfig == nil { os.Exit(0) } - h.myService.RegisterRemoteSKI(remoteSki, "") + if len(config.remoteSKI) == 40 { + h.myService.RegisterRemoteService(shipapi.NewServiceIdentity(config.remoteSKI, "", "")) + } - h.myService.Start() + _ = h.myService.Start() + if qrCodeText, err := h.myService.QRCodeText(); err == nil { + fmt.Println("Service QR Code:", qrCodeText) + } // defer h.myService.Shutdown() } // EEBUSServiceHandler -func (h *evse) RemoteSKIConnected(service api.ServiceInterface, ski string) { +func (h *evse) RemoteServiceConnected(service api.ServiceInterface, identity shipapi.ServiceIdentity) { + log.Println("Remote Service Connected:", identity.String()) h.isConnected = true } -func (h *evse) RemoteSKIDisconnected(service api.ServiceInterface, ski string) { +func (h *evse) RemoteServiceDisconnected(service api.ServiceInterface, identity shipapi.ServiceIdentity) { + log.Println("Remote Service Disconnected:", identity.String()) h.isConnected = false } -func (h *evse) VisibleRemoteServicesUpdated(service api.ServiceInterface, entries []shipapi.RemoteService) { +func (h *evse) VisibleRemoteMdnsServicesUpdated(service api.ServiceInterface, entries []shipapi.RemoteMdnsService) { } -func (h *evse) ServiceShipIDUpdate(ski string, shipdID string) {} +func (h *evse) ServiceUpdated(identity shipapi.ServiceIdentity) { + log.Println("Service Updated:", identity.String()) +} -func (h *evse) ServicePairingDetailUpdate(ski string, detail *shipapi.ConnectionStateDetail) { - if ski == remoteSki && detail.State() == shipapi.ConnectionStateRemoteDeniedTrust { +func (h *evse) ServicePairingDetailUpdate(identity shipapi.ServiceIdentity, detail *shipapi.ConnectionStateDetail) { + log.Println("Remote Service Pairing Detail Update:", identity.String()) + if identity.SKI == config.remoteSKI && detail.State() == shipapi.ConnectionStateRemoteDeniedTrust { fmt.Println("The remote service denied trust. Exiting.") - h.myService.CancelPairingWithSKI(ski) - h.myService.UnregisterRemoteSKI(ski) + h.myService.CancelPairing(identity) + h.myService.UnregisterRemoteService(identity) h.myService.Shutdown() os.Exit(0) } } -func (h *evse) AllowWaitingForTrust(ski string) bool { - return ski == remoteSki +func (h *evse) AllowWaitingForTrust(identity shipapi.ServiceIdentity) bool { + if len(config.remoteSKI) != 40 { + // no remoteSki given, give a chance for automatic pairing + return true + } + return identity.SKI == config.remoteSKI +} + +// ServiceAutoTrustFailed implements api.ServiceReaderInterface. +func (h *evse) ServiceAutoTrustFailed(service api.ServiceInterface, identity shipapi.ServiceIdentity, reason error) { + log.Printf("Auto Trust failed for identity %v: %v\n", identity.String(), reason) +} + +// ServiceAutoTrustRemoved implements api.ServiceReaderInterface. +func (h *evse) ServiceAutoTrustRemoved(service api.ServiceInterface, identity shipapi.ServiceIdentity, reason string) { + log.Printf("Auto Trust removed for identity %v: %v\n", identity.String(), reason) +} + +// ServiceAutoTrusted implements api.ServiceReaderInterface. +func (h *evse) ServiceAutoTrusted(service api.ServiceInterface, identity shipapi.ServiceIdentity) { + log.Printf("Auto Trust successful for identity %v\n", identity.String()) } // LPC Event Handler @@ -168,20 +224,25 @@ func (h *evse) OnLPCEvent(ski string, device spineapi.DeviceRemoteInterface, ent } // main app -func usage() { - fmt.Println("First Run:") - fmt.Println(" go run /examples/evse/main.go ") - fmt.Println() - fmt.Println("General Usage:") - fmt.Println(" go run /examples/evse/main.go ") -} func main() { - if len(os.Args) < 2 { - usage() - return + flag.StringVar(&config.certPath, "certpath", "", "./path/to/cert.pem") + flag.StringVar(&config.keyPath, "keypath", "", "./path/to/key.pem") + flag.StringVar(&config.remoteSKI, "remoteski", "", "remote SKI") + flag.UintVar(&config.port, "port", 0, "server port") + flag.StringVar(&config.secret, "secret", "", "secret hexadecimal") + flag.Parse() + + if !config.Valid() { + flag.Usage() + log.Fatal("invalid configuration") } + fmt.Println("--------------") + fmt.Println("Configuration") + fmt.Println(config) + fmt.Println("--------------") + h := evse{} h.run() @@ -189,6 +250,9 @@ func main() { sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, syscall.SIGTERM) <-sig + if h.myService != nil { + h.myService.Shutdown() + } // User exit } @@ -239,3 +303,71 @@ func (h *evse) printFormat(msgType, format string, args ...interface{}) { value := fmt.Sprintf(format, args...) fmt.Println(h.currentTimestamp(), msgType, value) } + +// Ring buffer persistence + +type ExampleRingBufferPersistence struct { +} + +// LoadRingBuffer implements api.RingBufferPersistence. +func (r *ExampleRingBufferPersistence) LoadRingBuffer() ([]shipapi.DigestEntry, int, error) { + fmt.Printf(" 📂 Loading ring buffer from...\n") + + // For demonstration: return empty state (no previous storage) + // Real applications should load from persistent storage: + // + // data, err := os.ReadFile(r.filename) + // if os.IsNotExist(err) { + // // No previous data - return empty buffer (library will initialize) + // return make([]api.DigestEntry, 100), 0, nil + // } + // if err != nil { + // return nil, 0, fmt.Errorf("failed to read ring buffer: %w", err) + // } + // + // var state struct { + // Entries []api.DigestEntry `json:"entries"` + // NextIndex int `json:"nextIndex"` + // } + // if err := json.Unmarshal(data, &state); err != nil { + // return nil, 0, fmt.Errorf("failed to parse ring buffer: %w", err) + // } + // + // return state.Entries, state.NextIndex, nil + + // Demo: return empty buffer (library will manage the ring buffer logic) + fmt.Printf(" 📂 No previous data, library will create fresh ring buffer\n") + return make([]shipapi.DigestEntry, 100), 0, nil +} + +// SaveRingBuffer implements api.RingBufferPersistence. +func (r *ExampleRingBufferPersistence) SaveRingBuffer(entries []shipapi.DigestEntry, nextIndex int) error { + fmt.Printf(" 💾 Library requests save: %d entries, nextIndex=%d to\n", len(entries), nextIndex) + + // For demonstration: just log what the library is providing + // Real applications should save the library's data to persistent storage: + // + // state := struct { + // Entries []api.DigestEntry `json:"entries"` + // NextIndex int `json:"nextIndex"` + // }{ + // Entries: entries, // Complete ring buffer from library + // NextIndex: nextIndex, // Current position from library + // } + // + // data, err := json.Marshal(state) + // if err != nil { + // return fmt.Errorf("failed to marshal ring buffer: %w", err) + // } + // + // // Atomic write pattern for safety + // tempFile := r.filename + ".tmp" + // if err := os.WriteFile(tempFile, data, 0600); err != nil { + // return fmt.Errorf("failed to write ring buffer: %w", err) + // } + // + // return os.Rename(tempFile, r.filename) + + fmt.Printf(" 💾 Demo: Would save library's ring buffer state to\n") + return nil +} diff --git a/examples/heatpump/main.go b/examples/heatpump/main.go index 962ea2a5..81dc5eab 100644 --- a/examples/heatpump/main.go +++ b/examples/heatpump/main.go @@ -4,12 +4,13 @@ import ( "crypto/ecdsa" "crypto/tls" "crypto/x509" + "encoding/hex" "encoding/pem" + "flag" "fmt" "log" "os" "os/signal" - "strconv" "syscall" "time" @@ -24,22 +25,41 @@ import ( "github.com/enbility/spine-go/spine" ) -var remoteSki string +type configuration struct { + port uint + certPath string + keyPath string + remoteSKI string + secret string +} + +func (c configuration) String() string { + return fmt.Sprintf("port: %v\ncertPath: %v\nkeyPath: %v\nremoteSKI: %v\nsecret: %v", + c.port, c.certPath, c.keyPath, c.remoteSKI, c.secret) +} + +func (c configuration) Valid() bool { + return (c.port > 0 && c.port < 65536) //&& + // c.certPath != "" && // they can be empty to generate new certificate + // c.keyPath != "" && + // (len(c.remoteSKI) > 0) +} + +var config configuration type heatpump struct { myService *service.Service + + ringBuffer *ExampleRingBufferPersistence } func (h *heatpump) run() { var err error var certificate tls.Certificate - if len(os.Args) == 5 { - remoteSki = os.Args[2] - - certificate, err = tls.LoadX509KeyPair(os.Args[3], os.Args[4]) + if config.certPath != "" && config.keyPath != "" { + certificate, err = tls.LoadX509KeyPair(config.certPath, config.keyPath) if err != nil { - usage() log.Fatal(err) } } else { @@ -62,18 +82,25 @@ func (h *heatpump) run() { fmt.Println(string(pemdata)) } - port, err := strconv.Atoi(os.Args[1]) - if err != nil { - usage() - log.Fatal(err) + var pairingConfig *shipapi.PairingConfig + if len(config.secret) == 0 { + fmt.Println("Secret not specified.. PairingConfig not set") + } else { + secretBytes, err := hex.DecodeString(config.secret) + if err != nil { + log.Fatal(err) + } + pairingConfig = shipapi.NewPairingConfig(shipapi.PairingModeListener, shipapi.PairingSecret(secretBytes)) } + h.ringBuffer = &ExampleRingBufferPersistence{} + configuration, err := api.NewConfiguration( "Demo", "Demo", "HeatPump", "234567890", []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeHVAC}, model.DeviceTypeTypeGeneric, []model.EntityTypeType{model.EntityTypeTypeHeatPumpAppliance}, - port, certificate, time.Second*4) + int(config.port), certificate, time.Second*4, pairingConfig, h.ringBuffer) if err != nil { log.Fatal(err) } @@ -87,42 +114,68 @@ func (h *heatpump) run() { return } - if len(remoteSki) == 0 { - os.Exit(0) - } - h.AddFeatures() _ = spine.Events.Subscribe(h) - h.myService.RegisterRemoteSKI(remoteSki, "") + if len(config.remoteSKI) == 0 && pairingConfig == nil { + os.Exit(0) + } - h.myService.Start() + if len(config.remoteSKI) == 40 { + h.myService.RegisterRemoteService(shipapi.NewServiceIdentity(config.remoteSKI, "", "")) + } + + _ = h.myService.Start() + if qrCodeText, err := h.myService.QRCodeText(); err == nil { + fmt.Println("Service QR Code:", qrCodeText) + } // defer h.myService.Shutdown() } // EEBUSServiceHandler -func (h *heatpump) RemoteSKIConnected(service api.ServiceInterface, ski string) {} +func (h *heatpump) RemoteServiceConnected(service api.ServiceInterface, identity shipapi.ServiceIdentity) { +} -func (h *heatpump) RemoteSKIDisconnected(service api.ServiceInterface, ski string) {} +func (h *heatpump) RemoteServiceDisconnected(service api.ServiceInterface, identity shipapi.ServiceIdentity) { +} -func (h *heatpump) VisibleRemoteServicesUpdated(service api.ServiceInterface, entries []shipapi.RemoteService) { +func (h *heatpump) VisibleRemoteMdnsServicesUpdated(service api.ServiceInterface, entries []shipapi.RemoteMdnsService) { } -func (h *heatpump) ServiceShipIDUpdate(ski string, shipdID string) {} +func (h *heatpump) ServiceUpdated(identity shipapi.ServiceIdentity) {} -func (h *heatpump) ServicePairingDetailUpdate(ski string, detail *shipapi.ConnectionStateDetail) { - if ski == remoteSki && detail.State() == shipapi.ConnectionStateRemoteDeniedTrust { +func (h *heatpump) ServicePairingDetailUpdate(identity shipapi.ServiceIdentity, detail *shipapi.ConnectionStateDetail) { + if identity.SKI == config.remoteSKI && detail.State() == shipapi.ConnectionStateRemoteDeniedTrust { fmt.Println("The remote service denied trust. Exiting.") - h.myService.CancelPairingWithSKI(ski) - h.myService.UnregisterRemoteSKI(ski) + h.myService.CancelPairing(identity) + h.myService.UnregisterRemoteService(identity) h.myService.Shutdown() os.Exit(0) } } -func (h *heatpump) AllowWaitingForTrust(ski string) bool { - return ski == remoteSki +func (h *heatpump) AllowWaitingForTrust(identity shipapi.ServiceIdentity) bool { + if len(config.remoteSKI) != 40 { + // no remoteSki given, give a chance for automatic pairing + return true + } + return identity.SKI == config.remoteSKI +} + +// ServiceAutoTrustFailed implements api.ServiceReaderInterface. +func (h *heatpump) ServiceAutoTrustFailed(service api.ServiceInterface, identity shipapi.ServiceIdentity, reason error) { + log.Printf("Auto Trust failed for identity %v: %v\n", identity.String(), reason) +} + +// ServiceAutoTrustRemoved implements api.ServiceReaderInterface. +func (h *heatpump) ServiceAutoTrustRemoved(service api.ServiceInterface, identity shipapi.ServiceIdentity, reason string) { + log.Printf("Auto Trust removed for identity %v: %v\n", identity.String(), reason) +} + +// ServiceAutoTrusted implements api.ServiceReaderInterface. +func (h *heatpump) ServiceAutoTrusted(service api.ServiceInterface, identity shipapi.ServiceIdentity) { + log.Printf("Auto Trust successful for identity %v\n", identity.String()) } func (h *heatpump) AddFeatures() { @@ -170,20 +223,24 @@ func (h *heatpump) deviceInformationConnected(remoteEntity spineapi.EntityRemote func (h *heatpump) hemsConnected(entity spineapi.EntityRemoteInterface) {} // main app -func usage() { - fmt.Println("First Run:") - fmt.Println(" go run /examples/heatpump/main.go ") - fmt.Println() - fmt.Println("General Usage:") - fmt.Println(" go run /examples/heatpump/main.go ") -} - func main() { - if len(os.Args) < 2 { - usage() - return + flag.StringVar(&config.certPath, "certpath", "", "./path/to/cert.pem") + flag.StringVar(&config.keyPath, "keypath", "", "./path/to/key.pem") + flag.StringVar(&config.remoteSKI, "remoteski", "", "remote SKI") + flag.UintVar(&config.port, "port", 0, "server port") + flag.StringVar(&config.secret, "secret", "", "secret hexadecimal") + flag.Parse() + + if !config.Valid() { + flag.Usage() + log.Fatal("invalid configuration") } + fmt.Println("--------------") + fmt.Println("Configuration") + fmt.Println(config) + fmt.Println("--------------") + h := heatpump{} h.run() @@ -191,6 +248,9 @@ func main() { sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, syscall.SIGTERM) <-sig + if h.myService != nil { + h.myService.Shutdown() + } // User exit } @@ -241,3 +301,71 @@ func (h *heatpump) printFormat(msgType, format string, args ...interface{}) { value := fmt.Sprintf(format, args...) fmt.Println(h.currentTimestamp(), msgType, value) } + +// Ring buffer persistence + +type ExampleRingBufferPersistence struct { +} + +// LoadRingBuffer implements api.RingBufferPersistence. +func (r *ExampleRingBufferPersistence) LoadRingBuffer() ([]shipapi.DigestEntry, int, error) { + fmt.Printf(" 📂 Loading ring buffer from...\n") + + // For demonstration: return empty state (no previous storage) + // Real applications should load from persistent storage: + // + // data, err := os.ReadFile(r.filename) + // if os.IsNotExist(err) { + // // No previous data - return empty buffer (library will initialize) + // return make([]api.DigestEntry, 100), 0, nil + // } + // if err != nil { + // return nil, 0, fmt.Errorf("failed to read ring buffer: %w", err) + // } + // + // var state struct { + // Entries []api.DigestEntry `json:"entries"` + // NextIndex int `json:"nextIndex"` + // } + // if err := json.Unmarshal(data, &state); err != nil { + // return nil, 0, fmt.Errorf("failed to parse ring buffer: %w", err) + // } + // + // return state.Entries, state.NextIndex, nil + + // Demo: return empty buffer (library will manage the ring buffer logic) + fmt.Printf(" 📂 No previous data, library will create fresh ring buffer\n") + return make([]shipapi.DigestEntry, 100), 0, nil +} + +// SaveRingBuffer implements api.RingBufferPersistence. +func (r *ExampleRingBufferPersistence) SaveRingBuffer(entries []shipapi.DigestEntry, nextIndex int) error { + fmt.Printf(" 💾 Library requests save: %d entries, nextIndex=%d to\n", len(entries), nextIndex) + + // For demonstration: just log what the library is providing + // Real applications should save the library's data to persistent storage: + // + // state := struct { + // Entries []api.DigestEntry `json:"entries"` + // NextIndex int `json:"nextIndex"` + // }{ + // Entries: entries, // Complete ring buffer from library + // NextIndex: nextIndex, // Current position from library + // } + // + // data, err := json.Marshal(state) + // if err != nil { + // return fmt.Errorf("failed to marshal ring buffer: %w", err) + // } + // + // // Atomic write pattern for safety + // tempFile := r.filename + ".tmp" + // if err := os.WriteFile(tempFile, data, 0600); err != nil { + // return fmt.Errorf("failed to write ring buffer: %w", err) + // } + // + // return os.Rename(tempFile, r.filename) + + fmt.Printf(" 💾 Demo: Would save library's ring buffer state to\n") + return nil +} diff --git a/examples/hems/main.go b/examples/hems/main.go index 73ec2451..b809ec33 100644 --- a/examples/hems/main.go +++ b/examples/hems/main.go @@ -4,12 +4,13 @@ import ( "crypto/ecdsa" "crypto/tls" "crypto/x509" + "encoding/hex" "encoding/pem" + "flag" "fmt" "log" "os" "os/signal" - "strconv" "syscall" "time" @@ -29,7 +30,27 @@ import ( "github.com/enbility/spine-go/model" ) -var remoteSki string +type configuration struct { + port uint + certPath string + keyPath string + remoteSKI string + secret string +} + +func (c configuration) String() string { + return fmt.Sprintf("port: %v\ncertPath: %v\nkeyPath: %v\nremoteSKI: %v\nsecret: %v", + c.port, c.certPath, c.keyPath, c.remoteSKI, c.secret) +} + +func (c configuration) Valid() bool { + return (c.port > 0 && c.port < 65536) //&& + // c.certPath != "" && // they can be empty to generate new certificate + // c.keyPath != "" && + // (len(c.remoteSKI) > 0) +} + +var config configuration type hems struct { myService *service.Service @@ -41,18 +62,17 @@ type hems struct { ucmamgcp ucapi.MaMGCPInterface uccemvabd ucapi.CemVABDInterface uccemvapd ucapi.CemVAPDInterface + + ringBuffer *ExampleRingBufferPersistence } func (h *hems) run() { var err error var certificate tls.Certificate - if len(os.Args) == 5 { - remoteSki = os.Args[2] - - certificate, err = tls.LoadX509KeyPair(os.Args[3], os.Args[4]) + if config.certPath != "" && config.keyPath != "" { + certificate, err = tls.LoadX509KeyPair(config.certPath, config.keyPath) if err != nil { - usage() log.Fatal(err) } } else { @@ -75,18 +95,25 @@ func (h *hems) run() { fmt.Println(string(pemdata)) } - port, err := strconv.Atoi(os.Args[1]) - if err != nil { - usage() - log.Fatal(err) + var pairingConfig *shipapi.PairingConfig + if len(config.secret) == 0 { + fmt.Println("Secret not specified.. PairingConfig not set") + } else { + secretBytes, err := hex.DecodeString(config.secret) + if err != nil { + log.Fatal(err) + } + pairingConfig = shipapi.NewPairingConfig(shipapi.PairingModeListener, shipapi.PairingSecret(secretBytes)) } + h.ringBuffer = &ExampleRingBufferPersistence{} + configuration, err := api.NewConfiguration( "Demo", "Demo", "HEMS", "123456789", []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - port, certificate, time.Second*4) + int(config.port), certificate, time.Second*4, pairingConfig, h.ringBuffer) if err != nil { log.Fatal(err) } @@ -135,13 +162,18 @@ func (h *hems) run() { _ = h.uccslpp.SetFailsafeProductionActivePowerLimit(4200, true) _ = h.uccslpp.SetFailsafeDurationMinimum(2*time.Hour, true) - if len(remoteSki) == 0 { + if len(config.remoteSKI) == 0 && pairingConfig == nil { os.Exit(0) } - h.myService.RegisterRemoteSKI(remoteSki, "") + if len(config.remoteSKI) == 40 { + h.myService.RegisterRemoteService(shipapi.NewServiceIdentity(config.remoteSKI, "", "")) + } - h.myService.Start() + _ = h.myService.Start() + if qrCodeText, err := h.myService.QRCodeText(); err == nil { + fmt.Println("Service QR Code:", qrCodeText) + } // defer h.myService.Shutdown() } @@ -264,27 +296,48 @@ func (h *hems) OnMGCPEvent(ski string, device spineapi.DeviceRemoteInterface, en // EEBUSServiceHandler -func (h *hems) RemoteSKIConnected(service api.ServiceInterface, ski string) {} +func (h *hems) RemoteServiceConnected(service api.ServiceInterface, identity shipapi.ServiceIdentity) { +} -func (h *hems) RemoteSKIDisconnected(service api.ServiceInterface, ski string) {} +func (h *hems) RemoteServiceDisconnected(service api.ServiceInterface, identity shipapi.ServiceIdentity) { +} -func (h *hems) VisibleRemoteServicesUpdated(service api.ServiceInterface, entries []shipapi.RemoteService) { +func (h *hems) VisibleRemoteMdnsServicesUpdated(service api.ServiceInterface, entries []shipapi.RemoteMdnsService) { } -func (h *hems) ServiceShipIDUpdate(ski string, shipdID string) {} +func (h *hems) ServiceUpdated(identity shipapi.ServiceIdentity) {} -func (h *hems) ServicePairingDetailUpdate(ski string, detail *shipapi.ConnectionStateDetail) { - if ski == remoteSki && detail.State() == shipapi.ConnectionStateRemoteDeniedTrust { +func (h *hems) ServicePairingDetailUpdate(identity shipapi.ServiceIdentity, detail *shipapi.ConnectionStateDetail) { + if identity.SKI == config.remoteSKI && detail.State() == shipapi.ConnectionStateRemoteDeniedTrust { fmt.Println("The remote service denied trust. Exiting.") - h.myService.CancelPairingWithSKI(ski) - h.myService.UnregisterRemoteSKI(ski) + h.myService.CancelPairing(identity) + h.myService.UnregisterRemoteService(identity) h.myService.Shutdown() os.Exit(0) } } -func (h *hems) AllowWaitingForTrust(ski string) bool { - return ski == remoteSki +func (h *hems) AllowWaitingForTrust(identity shipapi.ServiceIdentity) bool { + if len(config.remoteSKI) != 40 { + // no remoteSki given, give a chance for automatic pairing + return true + } + return identity.SKI == config.remoteSKI +} + +// ServiceAutoTrustFailed implements api.ServiceReaderInterface. +func (h *hems) ServiceAutoTrustFailed(service api.ServiceInterface, identity shipapi.ServiceIdentity, reason error) { + log.Printf("Auto Trust failed for identity %v: %v\n", identity.String(), reason) +} + +// ServiceAutoTrustRemoved implements api.ServiceReaderInterface. +func (h *hems) ServiceAutoTrustRemoved(service api.ServiceInterface, identity shipapi.ServiceIdentity, reason string) { + log.Printf("Auto Trust removed for identity %v: %v\n", identity.String(), reason) +} + +// ServiceAutoTrusted implements api.ServiceReaderInterface. +func (h *hems) ServiceAutoTrusted(service api.ServiceInterface, identity shipapi.ServiceIdentity) { + log.Printf("Auto Trust successful for identity %v\n", identity.String()) } // UCEvseCommisioningConfigurationCemDelegate @@ -295,20 +348,25 @@ func (h *hems) HandleEVSEDeviceState(ski string, failure bool, errorCode string) } // main app -func usage() { - fmt.Println("First Run:") - fmt.Println(" go run /examples/hems/main.go ") - fmt.Println() - fmt.Println("General Usage:") - fmt.Println(" go run /examples/hems/main.go ") -} func main() { - if len(os.Args) < 2 { - usage() - return + flag.StringVar(&config.certPath, "certpath", "", "./path/to/cert.pem") + flag.StringVar(&config.keyPath, "keypath", "", "./path/to/key.pem") + flag.StringVar(&config.remoteSKI, "remoteski", "", "remote SKI") + flag.UintVar(&config.port, "port", 0, "server port") + flag.StringVar(&config.secret, "secret", "", "secret hexadecimal") + flag.Parse() + + if !config.Valid() { + flag.Usage() + log.Fatal("invalid configuration") } + fmt.Println("--------------") + fmt.Println("Configuration") + fmt.Println(config) + fmt.Println("--------------") + h := hems{} h.run() @@ -316,6 +374,9 @@ func main() { sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, syscall.SIGTERM) <-sig + if h.myService != nil { + h.myService.Shutdown() + } // User exit } @@ -366,3 +427,71 @@ func (h *hems) printFormat(msgType, format string, args ...interface{}) { value := fmt.Sprintf(format, args...) fmt.Println(h.currentTimestamp(), msgType, value) } + +// Ring buffer persistence + +type ExampleRingBufferPersistence struct { +} + +// LoadRingBuffer implements api.RingBufferPersistence. +func (r *ExampleRingBufferPersistence) LoadRingBuffer() ([]shipapi.DigestEntry, int, error) { + fmt.Printf(" 📂 Loading ring buffer from...\n") + + // For demonstration: return empty state (no previous storage) + // Real applications should load from persistent storage: + // + // data, err := os.ReadFile(r.filename) + // if os.IsNotExist(err) { + // // No previous data - return empty buffer (library will initialize) + // return make([]api.DigestEntry, 100), 0, nil + // } + // if err != nil { + // return nil, 0, fmt.Errorf("failed to read ring buffer: %w", err) + // } + // + // var state struct { + // Entries []api.DigestEntry `json:"entries"` + // NextIndex int `json:"nextIndex"` + // } + // if err := json.Unmarshal(data, &state); err != nil { + // return nil, 0, fmt.Errorf("failed to parse ring buffer: %w", err) + // } + // + // return state.Entries, state.NextIndex, nil + + // Demo: return empty buffer (library will manage the ring buffer logic) + fmt.Printf(" 📂 No previous data, library will create fresh ring buffer\n") + return make([]shipapi.DigestEntry, 100), 0, nil +} + +// SaveRingBuffer implements api.RingBufferPersistence. +func (r *ExampleRingBufferPersistence) SaveRingBuffer(entries []shipapi.DigestEntry, nextIndex int) error { + fmt.Printf(" 💾 Library requests save: %d entries, nextIndex=%d to\n", len(entries), nextIndex) + + // For demonstration: just log what the library is providing + // Real applications should save the library's data to persistent storage: + // + // state := struct { + // Entries []api.DigestEntry `json:"entries"` + // NextIndex int `json:"nextIndex"` + // }{ + // Entries: entries, // Complete ring buffer from library + // NextIndex: nextIndex, // Current position from library + // } + // + // data, err := json.Marshal(state) + // if err != nil { + // return fmt.Errorf("failed to marshal ring buffer: %w", err) + // } + // + // // Atomic write pattern for safety + // tempFile := r.filename + ".tmp" + // if err := os.WriteFile(tempFile, data, 0600); err != nil { + // return fmt.Errorf("failed to write ring buffer: %w", err) + // } + // + // return os.Rename(tempFile, r.filename) + + fmt.Printf(" 💾 Demo: Would save library's ring buffer state to\n") + return nil +} diff --git a/examples/remote/main.go b/examples/remote/main.go index 611baaff..c2e445b8 100644 --- a/examples/remote/main.go +++ b/examples/remote/main.go @@ -86,7 +86,7 @@ func main() { model.EntityTypeTypeGridGuard, model.EntityTypeTypeCEM, }, - 23292, certificate, time.Second*4) + 23292, certificate, time.Second*4, nil, nil) if *iface != "" { configuration.SetInterfaces([]string{*iface}) log.Printf("waiting until %v is up", iface) diff --git a/examples/remote/rpc.go b/examples/remote/rpc.go index 7d4f6803..3e77a4d1 100644 --- a/examples/remote/rpc.go +++ b/examples/remote/rpc.go @@ -17,16 +17,16 @@ type Remote struct { rpc *jsonrpc2.Server service *service.Service - connections []*jsonrpc2.Connection - remoteServices []shipapi.RemoteService + connections []*jsonrpc2.Connection + remoteMdnsServices []shipapi.RemoteMdnsService rpcServices map[string]rpcServiceFunc } func NewRemote(configuration *api.Configuration) (*Remote, error) { r := Remote{ - connections: []*jsonrpc2.Connection{}, - remoteServices: []shipapi.RemoteService{}, + connections: []*jsonrpc2.Connection{}, + remoteMdnsServices: []shipapi.RemoteMdnsService{}, rpcServices: make(map[string]rpcServiceFunc), } @@ -76,8 +76,8 @@ func (r *Remote) registerDynamicReceiverProxy(name string) error { return nil } -func (r Remote) RemoteServices() []shipapi.RemoteService { - return r.remoteServices +func (r Remote) RemoteMdnsServices() []shipapi.RemoteMdnsService { + return r.remoteMdnsServices } func (r Remote) ConnectedDevices() []string { @@ -164,15 +164,15 @@ func (r *Remote) handleRPC(ctx context.Context, req *jsonrpc2.Request) (interfac } // Implement api.ServiceReaderInterface -func (r Remote) RemoteSKIConnected(service api.ServiceInterface, ski string) { - // necessary because RemoteSKIConnected is called before remote device actually exists +func (r Remote) RemoteServiceConnected(service api.ServiceInterface, identity shipapi.ServiceIdentity) { + // necessary because RemoteServiceConnected is called before remote device actually exists go func() { params := make(map[string]interface{}, 1) - params["ski"] = ski + params["identity"] = identity for { // wait until RemoteDevice available for SKI - device := service.LocalDevice().RemoteDeviceForSki(ski) + device := service.LocalDevice().RemoteDeviceForSki(identity.SKI) if device != nil && device.Address() != nil { params["device"] = *device.Address() break @@ -181,38 +181,63 @@ func (r Remote) RemoteSKIConnected(service api.ServiceInterface, ski string) { } for _, conn := range r.connections { - _ = conn.Notify(context.Background(), "remote/RemoteSKIConnected", params) + _ = conn.Notify(context.Background(), "remote/RemoteServiceConnected", params) } }() } -func (r Remote) RemoteSKIDisconnected(service api.ServiceInterface, ski string) { +func (r Remote) RemoteServiceDisconnected(service api.ServiceInterface, identity shipapi.ServiceIdentity) { params := make(map[string]interface{}, 1) - params["ski"] = ski + params["identity"] = identity for _, conn := range r.connections { - _ = conn.Notify(context.Background(), "remote/RemoteSKIDisconnected", params) + _ = conn.Notify(context.Background(), "remote/RemoteServiceDisconnected", params) } } -func (r *Remote) VisibleRemoteServicesUpdated(service api.ServiceInterface, entries []shipapi.RemoteService) { - r.remoteServices = entries +func (r *Remote) VisibleRemoteMdnsServicesUpdated(service api.ServiceInterface, entries []shipapi.RemoteMdnsService) { + r.remoteMdnsServices = entries for _, conn := range r.connections { - _ = conn.Notify(context.Background(), "remote/VisibleRemoteServicesUpdated", entries) + _ = conn.Notify(context.Background(), "remote/VisibleRemoteMdnsServicesUpdated", entries) } } -func (r Remote) ServiceShipIDUpdate(ski string, shipID string) { - params := make(map[string]interface{}, 2) - params["ski"] = ski - params["shipID"] = shipID +func (r Remote) ServiceUpdated(identity shipapi.ServiceIdentity) { + params := make(map[string]interface{}, 1) + params["identity"] = identity + + for _, conn := range r.connections { + _ = conn.Notify(context.Background(), "remote/ServiceUpdated", params) + } +} + +func (r Remote) ServicePairingDetailUpdate(identity shipapi.ServiceIdentity, detail *shipapi.ConnectionStateDetail) { +} + +func (r Remote) ServiceAutoTrustFailed(service api.ServiceInterface, identity shipapi.ServiceIdentity, reason error) { + params := make(map[string]interface{}, 1) + params["identity"] = identity + params["reason"] = reason.Error() + for _, conn := range r.connections { + _ = conn.Notify(context.Background(), "remote/ServiceAutoTrustFailed", params) + } +} +func (r Remote) ServiceAutoTrustRemoved(service api.ServiceInterface, identity shipapi.ServiceIdentity, reason string) { + params := make(map[string]interface{}, 1) + params["identity"] = identity + params["reason"] = reason for _, conn := range r.connections { - _ = conn.Notify(context.Background(), "remote/ServiceShipIDUpdate", params) + _ = conn.Notify(context.Background(), "remote/ServiceAutoTrustRemoved", params) } } -func (r Remote) ServicePairingDetailUpdate(ski string, detail *shipapi.ConnectionStateDetail) { +func (r Remote) ServiceAutoTrusted(service api.ServiceInterface, identity shipapi.ServiceIdentity) { + params := make(map[string]interface{}, 1) + params["identity"] = identity + for _, conn := range r.connections { + _ = conn.Notify(context.Background(), "remote/ServiceAutoTrusted", params) + } } // Logging interface diff --git a/features/server/deviceconfiguration_test.go b/features/server/deviceconfiguration_test.go index f78375d2..f62e1ac3 100644 --- a/features/server/deviceconfiguration_test.go +++ b/features/server/deviceconfiguration_test.go @@ -44,7 +44,7 @@ func (s *DeviceConfigurationSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/features/server/devicediagnosis_test.go b/features/server/devicediagnosis_test.go index 1a097d9f..bfa074e1 100644 --- a/features/server/devicediagnosis_test.go +++ b/features/server/devicediagnosis_test.go @@ -44,7 +44,7 @@ func (s *DeviceDiagnosisSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/features/server/electricalconnection_test.go b/features/server/electricalconnection_test.go index b89e4172..bb8187cc 100644 --- a/features/server/electricalconnection_test.go +++ b/features/server/electricalconnection_test.go @@ -44,7 +44,7 @@ func (s *ElectricalConnectionSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/features/server/feature_test.go b/features/server/feature_test.go index f5e4e930..a25c46cc 100644 --- a/features/server/feature_test.go +++ b/features/server/feature_test.go @@ -48,7 +48,7 @@ func (s *FeatureSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/features/server/loadcontrol_test.go b/features/server/loadcontrol_test.go index eeec1ab5..404d1e3c 100644 --- a/features/server/loadcontrol_test.go +++ b/features/server/loadcontrol_test.go @@ -44,7 +44,7 @@ func (s *LoadControlSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/features/server/measurement_test.go b/features/server/measurement_test.go index bc8ba58a..e5573cdc 100644 --- a/features/server/measurement_test.go +++ b/features/server/measurement_test.go @@ -44,7 +44,7 @@ func (s *MeasurementSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/go.mod b/go.mod index 54dbb123..49548ca8 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ go 1.24.1 toolchain go1.24.4 require ( - github.com/enbility/ship-go v0.0.0-20250703120135-5a60c7a2e4e5 + github.com/enbility/ship-go v0.6.1-0.20260406133610-1aef1cfdb552 github.com/enbility/spine-go v0.0.0-20250703115254-5468324c5be5 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.11.1 golang.org/x/exp/jsonrpc2 v0.0.0-20240909161429-701f63a606c0 ) @@ -15,23 +15,23 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/enbility/go-avahi v0.0.0-20240909195612-d5de6b280d7a // indirect github.com/enbility/zeroconf/v2 v2.0.0-20240920094356-be1cae74fda6 // indirect - github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/godbus/dbus/v5 v5.2.2 // indirect github.com/golanguzb70/lrucache v1.2.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/govalues/decimal v0.1.36 // indirect - github.com/miekg/dns v1.1.66 // indirect + github.com/miekg/dns v1.1.72 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rickb777/period v1.0.15 // indirect github.com/rickb777/plural v1.4.4 // indirect - github.com/stretchr/objx v0.5.2 // indirect + github.com/stretchr/objx v0.5.3 // indirect gitlab.com/c0b/go-ordered-json v0.0.0-20201030195603-febf46534d5a // indirect - go.uber.org/mock v0.5.2 // indirect + go.uber.org/mock v0.6.0 // indirect golang.org/x/exp/event v0.0.0-20220217172124-1812c5b45e43 // indirect - golang.org/x/mod v0.25.0 // indirect - golang.org/x/net v0.41.0 // indirect - golang.org/x/sync v0.15.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/tools v0.34.0 // indirect + golang.org/x/mod v0.33.0 // indirect + golang.org/x/net v0.50.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/tools v0.42.0 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 7d21d4b4..73ac5492 100644 --- a/go.sum +++ b/go.sum @@ -2,14 +2,14 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/enbility/go-avahi v0.0.0-20240909195612-d5de6b280d7a h1:foChWb8lhzqa6lWDRs6COYMdp649YlUirFP8GqoT0JQ= github.com/enbility/go-avahi v0.0.0-20240909195612-d5de6b280d7a/go.mod h1:H64mhYcAQUGUUnVqMdZQf93kPecH4M79xwH95Lddt3U= -github.com/enbility/ship-go v0.0.0-20250703120135-5a60c7a2e4e5 h1:Fg/FM/+P+AdVk9F/AWfOmzvgIpE6cVScVFZl/nMfMcY= -github.com/enbility/ship-go v0.0.0-20250703120135-5a60c7a2e4e5/go.mod h1:bqNU9+YnSeZ+FLMYTOyx0SBu+B/gRos1Usf9Hw+n4OM= +github.com/enbility/ship-go v0.6.1-0.20260406133610-1aef1cfdb552 h1:ZqLB3VxXcKSUnWL+IxRK8rHElwxyRo67Ygl3UCVDAKY= +github.com/enbility/ship-go v0.6.1-0.20260406133610-1aef1cfdb552/go.mod h1:EvRFx83phCwPQrOuWw2CX5t0c6mcFVzIk6gQEz4Lijg= github.com/enbility/spine-go v0.0.0-20250703115254-5468324c5be5 h1:KyXpPKEOQ05f7NT4QKmvuEXjctHJ63t0Zfh5DVTEYIQ= github.com/enbility/spine-go v0.0.0-20250703115254-5468324c5be5/go.mod h1:JDbMWRaMtTS6dkPbzBLfBSvSs4eS32K1kk2EUrQCmcw= github.com/enbility/zeroconf/v2 v2.0.0-20240920094356-be1cae74fda6 h1:XOYvxKtT1oxT37w/5oEiRLuPbm9FuJPt3fiYhX0h8Po= github.com/enbility/zeroconf/v2 v2.0.0-20240920094356-be1cae74fda6/go.mod h1:BszP9qFV14mPXgyIREbgIdQtWxbAj3OKqvK02HihMoM= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= +github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= github.com/golanguzb70/lrucache v1.2.0 h1:VjpjmB4VTf9VXBtZTJGcgcN0CNFM5egDrrSjkGyQOlg= github.com/golanguzb70/lrucache v1.2.0/go.mod h1:zc2GD26KwGEDdTHsCCTcJorv/11HyKwQVS9gqg2bizc= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -18,8 +18,10 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/govalues/decimal v0.1.36 h1:dojDpsSvrk0ndAx8+saW5h9WDIHdWpIwrH/yhl9olyU= github.com/govalues/decimal v0.1.36/go.mod h1:Ee7eI3Llf7hfqDZtpj8Q6NCIgJy1iY3kH1pSwDrNqlM= -github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE= -github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE= +github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= +github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rickb777/expect v0.24.0 h1:IzFxn4jINkVuCmx4jdQP7LxaIBhG60bDVbeGWk3xnzo= @@ -28,28 +30,30 @@ github.com/rickb777/period v1.0.15 h1:nWR4rgCtImT0CXw5kAsjHv+ExCEFt/18zAySOi7pWI github.com/rickb777/period v1.0.15/go.mod h1:3lWluyeZEk6n1jfLCPG4dH3C0N3NxjmYL4Dmcxip3es= github.com/rickb777/plural v1.4.4 h1:OpZU8uRr9P2NkYAbkLMwlKNVJyJ5HvRcRBFyXGJtKGI= github.com/rickb777/plural v1.4.4/go.mod h1:DB19dtrplGS5s6VJVHn7tvmFYPoE83p1xqio3oVnNRM= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= +github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= +github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= gitlab.com/c0b/go-ordered-json v0.0.0-20201030195603-febf46534d5a h1:DxppxFKRqJ8WD6oJ3+ZXKDY0iMONQDl5UTg2aTyHh8k= gitlab.com/c0b/go-ordered-json v0.0.0-20201030195603-febf46534d5a/go.mod h1:NREvu3a57BaK0R1+ztrEzHWiZAihohNLQ6trPxlIqZI= -go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= golang.org/x/exp/event v0.0.0-20220217172124-1812c5b45e43 h1:Yn6OLQDombmcne/0Jf2GiY4qPS5ML2W4KYFyx2uYxGY= golang.org/x/exp/event v0.0.0-20220217172124-1812c5b45e43/go.mod h1:AVlZHjhWbW/3yOcmKMtJiObwBPJajBlUpQXRijFNrNc= golang.org/x/exp/jsonrpc2 v0.0.0-20240909161429-701f63a606c0 h1:L2RG+rjAzNncYJI2U7v3rw3Fl2Hk4J27mEjWx6jQhuI= golang.org/x/exp/jsonrpc2 v0.0.0-20240909161429-701f63a606c0/go.mod h1:Enk5TnT9VR4uKJW7nj3TlYv+R4GOM2KELhqCJxnXVN8= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/mocks/ServiceInterface.go b/mocks/ServiceInterface.go index c728485e..05dd00e5 100644 --- a/mocks/ServiceInterface.go +++ b/mocks/ServiceInterface.go @@ -6,9 +6,9 @@ package mocks import ( "github.com/enbility/eebus-go/api" - api1 "github.com/enbility/ship-go/api" + api0 "github.com/enbility/ship-go/api" "github.com/enbility/ship-go/logging" - api0 "github.com/enbility/spine-go/api" + api1 "github.com/enbility/spine-go/api" mock "github.com/stretchr/testify/mock" ) @@ -79,28 +79,28 @@ func (_c *ServiceInterface_AddUseCase_Call) RunAndReturn(run func(useCase api.Us return _c } -// CancelPairingWithSKI provides a mock function for the type ServiceInterface -func (_mock *ServiceInterface) CancelPairingWithSKI(ski string) { - _mock.Called(ski) +// CancelPairing provides a mock function for the type ServiceInterface +func (_mock *ServiceInterface) CancelPairing(identity api0.ServiceIdentity) { + _mock.Called(identity) return } -// ServiceInterface_CancelPairingWithSKI_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CancelPairingWithSKI' -type ServiceInterface_CancelPairingWithSKI_Call struct { +// ServiceInterface_CancelPairing_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CancelPairing' +type ServiceInterface_CancelPairing_Call struct { *mock.Call } -// CancelPairingWithSKI is a helper method to define mock.On call -// - ski string -func (_e *ServiceInterface_Expecter) CancelPairingWithSKI(ski interface{}) *ServiceInterface_CancelPairingWithSKI_Call { - return &ServiceInterface_CancelPairingWithSKI_Call{Call: _e.mock.On("CancelPairingWithSKI", ski)} +// CancelPairing is a helper method to define mock.On call +// - identity api0.ServiceIdentity +func (_e *ServiceInterface_Expecter) CancelPairing(identity interface{}) *ServiceInterface_CancelPairing_Call { + return &ServiceInterface_CancelPairing_Call{Call: _e.mock.On("CancelPairing", identity)} } -func (_c *ServiceInterface_CancelPairingWithSKI_Call) Run(run func(ski string)) *ServiceInterface_CancelPairingWithSKI_Call { +func (_c *ServiceInterface_CancelPairing_Call) Run(run func(identity api0.ServiceIdentity)) *ServiceInterface_CancelPairing_Call { _c.Call.Run(func(args mock.Arguments) { - var arg0 string + var arg0 api0.ServiceIdentity if args[0] != nil { - arg0 = args[0].(string) + arg0 = args[0].(api0.ServiceIdentity) } run( arg0, @@ -109,12 +109,12 @@ func (_c *ServiceInterface_CancelPairingWithSKI_Call) Run(run func(ski string)) return _c } -func (_c *ServiceInterface_CancelPairingWithSKI_Call) Return() *ServiceInterface_CancelPairingWithSKI_Call { +func (_c *ServiceInterface_CancelPairing_Call) Return() *ServiceInterface_CancelPairing_Call { _c.Call.Return() return _c } -func (_c *ServiceInterface_CancelPairingWithSKI_Call) RunAndReturn(run func(ski string)) *ServiceInterface_CancelPairingWithSKI_Call { +func (_c *ServiceInterface_CancelPairing_Call) RunAndReturn(run func(identity api0.ServiceIdentity)) *ServiceInterface_CancelPairing_Call { _c.Run(run) return _c } @@ -165,29 +165,29 @@ func (_c *ServiceInterface_Configuration_Call) RunAndReturn(run func() *api.Conf return _c } -// DisconnectSKI provides a mock function for the type ServiceInterface -func (_mock *ServiceInterface) DisconnectSKI(ski string, reason string) { - _mock.Called(ski, reason) +// DisconnectService provides a mock function for the type ServiceInterface +func (_mock *ServiceInterface) DisconnectService(identity api0.ServiceIdentity, reason string) { + _mock.Called(identity, reason) return } -// ServiceInterface_DisconnectSKI_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisconnectSKI' -type ServiceInterface_DisconnectSKI_Call struct { +// ServiceInterface_DisconnectService_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisconnectService' +type ServiceInterface_DisconnectService_Call struct { *mock.Call } -// DisconnectSKI is a helper method to define mock.On call -// - ski string +// DisconnectService is a helper method to define mock.On call +// - identity api0.ServiceIdentity // - reason string -func (_e *ServiceInterface_Expecter) DisconnectSKI(ski interface{}, reason interface{}) *ServiceInterface_DisconnectSKI_Call { - return &ServiceInterface_DisconnectSKI_Call{Call: _e.mock.On("DisconnectSKI", ski, reason)} +func (_e *ServiceInterface_Expecter) DisconnectService(identity interface{}, reason interface{}) *ServiceInterface_DisconnectService_Call { + return &ServiceInterface_DisconnectService_Call{Call: _e.mock.On("DisconnectService", identity, reason)} } -func (_c *ServiceInterface_DisconnectSKI_Call) Run(run func(ski string, reason string)) *ServiceInterface_DisconnectSKI_Call { +func (_c *ServiceInterface_DisconnectService_Call) Run(run func(identity api0.ServiceIdentity, reason string)) *ServiceInterface_DisconnectService_Call { _c.Call.Run(func(args mock.Arguments) { - var arg0 string + var arg0 api0.ServiceIdentity if args[0] != nil { - arg0 = args[0].(string) + arg0 = args[0].(api0.ServiceIdentity) } var arg1 string if args[1] != nil { @@ -201,16 +201,212 @@ func (_c *ServiceInterface_DisconnectSKI_Call) Run(run func(ski string, reason s return _c } -func (_c *ServiceInterface_DisconnectSKI_Call) Return() *ServiceInterface_DisconnectSKI_Call { +func (_c *ServiceInterface_DisconnectService_Call) Return() *ServiceInterface_DisconnectService_Call { _c.Call.Return() return _c } -func (_c *ServiceInterface_DisconnectSKI_Call) RunAndReturn(run func(ski string, reason string)) *ServiceInterface_DisconnectSKI_Call { +func (_c *ServiceInterface_DisconnectService_Call) RunAndReturn(run func(identity api0.ServiceIdentity, reason string)) *ServiceInterface_DisconnectService_Call { _c.Run(run) return _c } +// GetActiveAnnouncements provides a mock function for the type ServiceInterface +func (_mock *ServiceInterface) GetActiveAnnouncements() []string { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for GetActiveAnnouncements") + } + + var r0 []string + if returnFunc, ok := ret.Get(0).(func() []string); ok { + r0 = returnFunc() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + return r0 +} + +// ServiceInterface_GetActiveAnnouncements_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetActiveAnnouncements' +type ServiceInterface_GetActiveAnnouncements_Call struct { + *mock.Call +} + +// GetActiveAnnouncements is a helper method to define mock.On call +func (_e *ServiceInterface_Expecter) GetActiveAnnouncements() *ServiceInterface_GetActiveAnnouncements_Call { + return &ServiceInterface_GetActiveAnnouncements_Call{Call: _e.mock.On("GetActiveAnnouncements")} +} + +func (_c *ServiceInterface_GetActiveAnnouncements_Call) Run(run func()) *ServiceInterface_GetActiveAnnouncements_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ServiceInterface_GetActiveAnnouncements_Call) Return(strings []string) *ServiceInterface_GetActiveAnnouncements_Call { + _c.Call.Return(strings) + return _c +} + +func (_c *ServiceInterface_GetActiveAnnouncements_Call) RunAndReturn(run func() []string) *ServiceInterface_GetActiveAnnouncements_Call { + _c.Call.Return(run) + return _c +} + +// GetLocalCertificateFingerprint provides a mock function for the type ServiceInterface +func (_mock *ServiceInterface) GetLocalCertificateFingerprint() (string, error) { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for GetLocalCertificateFingerprint") + } + + var r0 string + var r1 error + if returnFunc, ok := ret.Get(0).(func() (string, error)); ok { + return returnFunc() + } + if returnFunc, ok := ret.Get(0).(func() string); ok { + r0 = returnFunc() + } else { + r0 = ret.Get(0).(string) + } + if returnFunc, ok := ret.Get(1).(func() error); ok { + r1 = returnFunc() + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// ServiceInterface_GetLocalCertificateFingerprint_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLocalCertificateFingerprint' +type ServiceInterface_GetLocalCertificateFingerprint_Call struct { + *mock.Call +} + +// GetLocalCertificateFingerprint is a helper method to define mock.On call +func (_e *ServiceInterface_Expecter) GetLocalCertificateFingerprint() *ServiceInterface_GetLocalCertificateFingerprint_Call { + return &ServiceInterface_GetLocalCertificateFingerprint_Call{Call: _e.mock.On("GetLocalCertificateFingerprint")} +} + +func (_c *ServiceInterface_GetLocalCertificateFingerprint_Call) Run(run func()) *ServiceInterface_GetLocalCertificateFingerprint_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ServiceInterface_GetLocalCertificateFingerprint_Call) Return(s string, err error) *ServiceInterface_GetLocalCertificateFingerprint_Call { + _c.Call.Return(s, err) + return _c +} + +func (_c *ServiceInterface_GetLocalCertificateFingerprint_Call) RunAndReturn(run func() (string, error)) *ServiceInterface_GetLocalCertificateFingerprint_Call { + _c.Call.Return(run) + return _c +} + +// GetTrustedAddCuDevice provides a mock function for the type ServiceInterface +func (_mock *ServiceInterface) GetTrustedAddCuDevice() *api0.ServiceDetails { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for GetTrustedAddCuDevice") + } + + var r0 *api0.ServiceDetails + if returnFunc, ok := ret.Get(0).(func() *api0.ServiceDetails); ok { + r0 = returnFunc() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*api0.ServiceDetails) + } + } + return r0 +} + +// ServiceInterface_GetTrustedAddCuDevice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTrustedAddCuDevice' +type ServiceInterface_GetTrustedAddCuDevice_Call struct { + *mock.Call +} + +// GetTrustedAddCuDevice is a helper method to define mock.On call +func (_e *ServiceInterface_Expecter) GetTrustedAddCuDevice() *ServiceInterface_GetTrustedAddCuDevice_Call { + return &ServiceInterface_GetTrustedAddCuDevice_Call{Call: _e.mock.On("GetTrustedAddCuDevice")} +} + +func (_c *ServiceInterface_GetTrustedAddCuDevice_Call) Run(run func()) *ServiceInterface_GetTrustedAddCuDevice_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ServiceInterface_GetTrustedAddCuDevice_Call) Return(serviceDetails *api0.ServiceDetails) *ServiceInterface_GetTrustedAddCuDevice_Call { + _c.Call.Return(serviceDetails) + return _c +} + +func (_c *ServiceInterface_GetTrustedAddCuDevice_Call) RunAndReturn(run func() *api0.ServiceDetails) *ServiceInterface_GetTrustedAddCuDevice_Call { + _c.Call.Return(run) + return _c +} + +// IsAnnouncingTo provides a mock function for the type ServiceInterface +func (_mock *ServiceInterface) IsAnnouncingTo(shipID string) bool { + ret := _mock.Called(shipID) + + if len(ret) == 0 { + panic("no return value specified for IsAnnouncingTo") + } + + var r0 bool + if returnFunc, ok := ret.Get(0).(func(string) bool); ok { + r0 = returnFunc(shipID) + } else { + r0 = ret.Get(0).(bool) + } + return r0 +} + +// ServiceInterface_IsAnnouncingTo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsAnnouncingTo' +type ServiceInterface_IsAnnouncingTo_Call struct { + *mock.Call +} + +// IsAnnouncingTo is a helper method to define mock.On call +// - shipID string +func (_e *ServiceInterface_Expecter) IsAnnouncingTo(shipID interface{}) *ServiceInterface_IsAnnouncingTo_Call { + return &ServiceInterface_IsAnnouncingTo_Call{Call: _e.mock.On("IsAnnouncingTo", shipID)} +} + +func (_c *ServiceInterface_IsAnnouncingTo_Call) Run(run func(shipID string)) *ServiceInterface_IsAnnouncingTo_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + run( + arg0, + ) + }) + return _c +} + +func (_c *ServiceInterface_IsAnnouncingTo_Call) Return(b bool) *ServiceInterface_IsAnnouncingTo_Call { + _c.Call.Return(b) + return _c +} + +func (_c *ServiceInterface_IsAnnouncingTo_Call) RunAndReturn(run func(shipID string) bool) *ServiceInterface_IsAnnouncingTo_Call { + _c.Call.Return(run) + return _c +} + // IsAutoAcceptEnabled provides a mock function for the type ServiceInterface func (_mock *ServiceInterface) IsAutoAcceptEnabled() bool { ret := _mock.Called() @@ -300,19 +496,19 @@ func (_c *ServiceInterface_IsRunning_Call) RunAndReturn(run func() bool) *Servic } // LocalDevice provides a mock function for the type ServiceInterface -func (_mock *ServiceInterface) LocalDevice() api0.DeviceLocalInterface { +func (_mock *ServiceInterface) LocalDevice() api1.DeviceLocalInterface { ret := _mock.Called() if len(ret) == 0 { panic("no return value specified for LocalDevice") } - var r0 api0.DeviceLocalInterface - if returnFunc, ok := ret.Get(0).(func() api0.DeviceLocalInterface); ok { + var r0 api1.DeviceLocalInterface + if returnFunc, ok := ret.Get(0).(func() api1.DeviceLocalInterface); ok { r0 = returnFunc() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(api0.DeviceLocalInterface) + r0 = ret.Get(0).(api1.DeviceLocalInterface) } } return r0 @@ -335,30 +531,30 @@ func (_c *ServiceInterface_LocalDevice_Call) Run(run func()) *ServiceInterface_L return _c } -func (_c *ServiceInterface_LocalDevice_Call) Return(deviceLocalInterface api0.DeviceLocalInterface) *ServiceInterface_LocalDevice_Call { +func (_c *ServiceInterface_LocalDevice_Call) Return(deviceLocalInterface api1.DeviceLocalInterface) *ServiceInterface_LocalDevice_Call { _c.Call.Return(deviceLocalInterface) return _c } -func (_c *ServiceInterface_LocalDevice_Call) RunAndReturn(run func() api0.DeviceLocalInterface) *ServiceInterface_LocalDevice_Call { +func (_c *ServiceInterface_LocalDevice_Call) RunAndReturn(run func() api1.DeviceLocalInterface) *ServiceInterface_LocalDevice_Call { _c.Call.Return(run) return _c } // LocalService provides a mock function for the type ServiceInterface -func (_mock *ServiceInterface) LocalService() *api1.ServiceDetails { +func (_mock *ServiceInterface) LocalService() *api0.ServiceDetails { ret := _mock.Called() if len(ret) == 0 { panic("no return value specified for LocalService") } - var r0 *api1.ServiceDetails - if returnFunc, ok := ret.Get(0).(func() *api1.ServiceDetails); ok { + var r0 *api0.ServiceDetails + if returnFunc, ok := ret.Get(0).(func() *api0.ServiceDetails); ok { r0 = returnFunc() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*api1.ServiceDetails) + r0 = ret.Get(0).(*api0.ServiceDetails) } } return r0 @@ -381,51 +577,51 @@ func (_c *ServiceInterface_LocalService_Call) Run(run func()) *ServiceInterface_ return _c } -func (_c *ServiceInterface_LocalService_Call) Return(serviceDetails *api1.ServiceDetails) *ServiceInterface_LocalService_Call { +func (_c *ServiceInterface_LocalService_Call) Return(serviceDetails *api0.ServiceDetails) *ServiceInterface_LocalService_Call { _c.Call.Return(serviceDetails) return _c } -func (_c *ServiceInterface_LocalService_Call) RunAndReturn(run func() *api1.ServiceDetails) *ServiceInterface_LocalService_Call { +func (_c *ServiceInterface_LocalService_Call) RunAndReturn(run func() *api0.ServiceDetails) *ServiceInterface_LocalService_Call { _c.Call.Return(run) return _c } -// PairingDetailForSki provides a mock function for the type ServiceInterface -func (_mock *ServiceInterface) PairingDetailForSki(ski string) *api1.ConnectionStateDetail { - ret := _mock.Called(ski) +// PairingDetailFor provides a mock function for the type ServiceInterface +func (_mock *ServiceInterface) PairingDetailFor(identity api0.ServiceIdentity) *api0.ConnectionStateDetail { + ret := _mock.Called(identity) if len(ret) == 0 { - panic("no return value specified for PairingDetailForSki") + panic("no return value specified for PairingDetailFor") } - var r0 *api1.ConnectionStateDetail - if returnFunc, ok := ret.Get(0).(func(string) *api1.ConnectionStateDetail); ok { - r0 = returnFunc(ski) + var r0 *api0.ConnectionStateDetail + if returnFunc, ok := ret.Get(0).(func(api0.ServiceIdentity) *api0.ConnectionStateDetail); ok { + r0 = returnFunc(identity) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*api1.ConnectionStateDetail) + r0 = ret.Get(0).(*api0.ConnectionStateDetail) } } return r0 } -// ServiceInterface_PairingDetailForSki_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PairingDetailForSki' -type ServiceInterface_PairingDetailForSki_Call struct { +// ServiceInterface_PairingDetailFor_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PairingDetailFor' +type ServiceInterface_PairingDetailFor_Call struct { *mock.Call } -// PairingDetailForSki is a helper method to define mock.On call -// - ski string -func (_e *ServiceInterface_Expecter) PairingDetailForSki(ski interface{}) *ServiceInterface_PairingDetailForSki_Call { - return &ServiceInterface_PairingDetailForSki_Call{Call: _e.mock.On("PairingDetailForSki", ski)} +// PairingDetailFor is a helper method to define mock.On call +// - identity api0.ServiceIdentity +func (_e *ServiceInterface_Expecter) PairingDetailFor(identity interface{}) *ServiceInterface_PairingDetailFor_Call { + return &ServiceInterface_PairingDetailFor_Call{Call: _e.mock.On("PairingDetailFor", identity)} } -func (_c *ServiceInterface_PairingDetailForSki_Call) Run(run func(ski string)) *ServiceInterface_PairingDetailForSki_Call { +func (_c *ServiceInterface_PairingDetailFor_Call) Run(run func(identity api0.ServiceIdentity)) *ServiceInterface_PairingDetailFor_Call { _c.Call.Run(func(args mock.Arguments) { - var arg0 string + var arg0 api0.ServiceIdentity if args[0] != nil { - arg0 = args[0].(string) + arg0 = args[0].(api0.ServiceIdentity) } run( arg0, @@ -434,18 +630,18 @@ func (_c *ServiceInterface_PairingDetailForSki_Call) Run(run func(ski string)) * return _c } -func (_c *ServiceInterface_PairingDetailForSki_Call) Return(connectionStateDetail *api1.ConnectionStateDetail) *ServiceInterface_PairingDetailForSki_Call { +func (_c *ServiceInterface_PairingDetailFor_Call) Return(connectionStateDetail *api0.ConnectionStateDetail) *ServiceInterface_PairingDetailFor_Call { _c.Call.Return(connectionStateDetail) return _c } -func (_c *ServiceInterface_PairingDetailForSki_Call) RunAndReturn(run func(ski string) *api1.ConnectionStateDetail) *ServiceInterface_PairingDetailForSki_Call { +func (_c *ServiceInterface_PairingDetailFor_Call) RunAndReturn(run func(identity api0.ServiceIdentity) *api0.ConnectionStateDetail) *ServiceInterface_PairingDetailFor_Call { _c.Call.Return(run) return _c } // QRCodeText provides a mock function for the type ServiceInterface -func (_mock *ServiceInterface) QRCodeText() string { +func (_mock *ServiceInterface) QRCodeText() (string, error) { ret := _mock.Called() if len(ret) == 0 { @@ -453,12 +649,21 @@ func (_mock *ServiceInterface) QRCodeText() string { } var r0 string + var r1 error + if returnFunc, ok := ret.Get(0).(func() (string, error)); ok { + return returnFunc() + } if returnFunc, ok := ret.Get(0).(func() string); ok { r0 = returnFunc() } else { r0 = ret.Get(0).(string) } - return r0 + if returnFunc, ok := ret.Get(1).(func() error); ok { + r1 = returnFunc() + } else { + r1 = ret.Error(1) + } + return r0, r1 } // ServiceInterface_QRCodeText_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'QRCodeText' @@ -478,97 +683,91 @@ func (_c *ServiceInterface_QRCodeText_Call) Run(run func()) *ServiceInterface_QR return _c } -func (_c *ServiceInterface_QRCodeText_Call) Return(s string) *ServiceInterface_QRCodeText_Call { - _c.Call.Return(s) +func (_c *ServiceInterface_QRCodeText_Call) Return(s string, err error) *ServiceInterface_QRCodeText_Call { + _c.Call.Return(s, err) return _c } -func (_c *ServiceInterface_QRCodeText_Call) RunAndReturn(run func() string) *ServiceInterface_QRCodeText_Call { +func (_c *ServiceInterface_QRCodeText_Call) RunAndReturn(run func() (string, error)) *ServiceInterface_QRCodeText_Call { _c.Call.Return(run) return _c } -// RegisterRemoteSKI provides a mock function for the type ServiceInterface -func (_mock *ServiceInterface) RegisterRemoteSKI(ski string, shipID string) { - _mock.Called(ski, shipID) +// RegisterRemoteService provides a mock function for the type ServiceInterface +func (_mock *ServiceInterface) RegisterRemoteService(identity api0.ServiceIdentity) { + _mock.Called(identity) return } -// ServiceInterface_RegisterRemoteSKI_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RegisterRemoteSKI' -type ServiceInterface_RegisterRemoteSKI_Call struct { +// ServiceInterface_RegisterRemoteService_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RegisterRemoteService' +type ServiceInterface_RegisterRemoteService_Call struct { *mock.Call } -// RegisterRemoteSKI is a helper method to define mock.On call -// - ski string -// - shipID string -func (_e *ServiceInterface_Expecter) RegisterRemoteSKI(ski interface{}, shipID interface{}) *ServiceInterface_RegisterRemoteSKI_Call { - return &ServiceInterface_RegisterRemoteSKI_Call{Call: _e.mock.On("RegisterRemoteSKI", ski, shipID)} +// RegisterRemoteService is a helper method to define mock.On call +// - identity api0.ServiceIdentity +func (_e *ServiceInterface_Expecter) RegisterRemoteService(identity interface{}) *ServiceInterface_RegisterRemoteService_Call { + return &ServiceInterface_RegisterRemoteService_Call{Call: _e.mock.On("RegisterRemoteService", identity)} } -func (_c *ServiceInterface_RegisterRemoteSKI_Call) Run(run func(ski string, shipID string)) *ServiceInterface_RegisterRemoteSKI_Call { +func (_c *ServiceInterface_RegisterRemoteService_Call) Run(run func(identity api0.ServiceIdentity)) *ServiceInterface_RegisterRemoteService_Call { _c.Call.Run(func(args mock.Arguments) { - var arg0 string + var arg0 api0.ServiceIdentity if args[0] != nil { - arg0 = args[0].(string) - } - var arg1 string - if args[1] != nil { - arg1 = args[1].(string) + arg0 = args[0].(api0.ServiceIdentity) } run( arg0, - arg1, ) }) return _c } -func (_c *ServiceInterface_RegisterRemoteSKI_Call) Return() *ServiceInterface_RegisterRemoteSKI_Call { +func (_c *ServiceInterface_RegisterRemoteService_Call) Return() *ServiceInterface_RegisterRemoteService_Call { _c.Call.Return() return _c } -func (_c *ServiceInterface_RegisterRemoteSKI_Call) RunAndReturn(run func(ski string, shipID string)) *ServiceInterface_RegisterRemoteSKI_Call { +func (_c *ServiceInterface_RegisterRemoteService_Call) RunAndReturn(run func(identity api0.ServiceIdentity)) *ServiceInterface_RegisterRemoteService_Call { _c.Run(run) return _c } -// RemoteServiceForSKI provides a mock function for the type ServiceInterface -func (_mock *ServiceInterface) RemoteServiceForSKI(ski string) *api1.ServiceDetails { - ret := _mock.Called(ski) +// RemoteServiceFor provides a mock function for the type ServiceInterface +func (_mock *ServiceInterface) RemoteServiceFor(identity api0.ServiceIdentity) *api0.ServiceDetails { + ret := _mock.Called(identity) if len(ret) == 0 { - panic("no return value specified for RemoteServiceForSKI") + panic("no return value specified for RemoteServiceFor") } - var r0 *api1.ServiceDetails - if returnFunc, ok := ret.Get(0).(func(string) *api1.ServiceDetails); ok { - r0 = returnFunc(ski) + var r0 *api0.ServiceDetails + if returnFunc, ok := ret.Get(0).(func(api0.ServiceIdentity) *api0.ServiceDetails); ok { + r0 = returnFunc(identity) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*api1.ServiceDetails) + r0 = ret.Get(0).(*api0.ServiceDetails) } } return r0 } -// ServiceInterface_RemoteServiceForSKI_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoteServiceForSKI' -type ServiceInterface_RemoteServiceForSKI_Call struct { +// ServiceInterface_RemoteServiceFor_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoteServiceFor' +type ServiceInterface_RemoteServiceFor_Call struct { *mock.Call } -// RemoteServiceForSKI is a helper method to define mock.On call -// - ski string -func (_e *ServiceInterface_Expecter) RemoteServiceForSKI(ski interface{}) *ServiceInterface_RemoteServiceForSKI_Call { - return &ServiceInterface_RemoteServiceForSKI_Call{Call: _e.mock.On("RemoteServiceForSKI", ski)} +// RemoteServiceFor is a helper method to define mock.On call +// - identity api0.ServiceIdentity +func (_e *ServiceInterface_Expecter) RemoteServiceFor(identity interface{}) *ServiceInterface_RemoteServiceFor_Call { + return &ServiceInterface_RemoteServiceFor_Call{Call: _e.mock.On("RemoteServiceFor", identity)} } -func (_c *ServiceInterface_RemoteServiceForSKI_Call) Run(run func(ski string)) *ServiceInterface_RemoteServiceForSKI_Call { +func (_c *ServiceInterface_RemoteServiceFor_Call) Run(run func(identity api0.ServiceIdentity)) *ServiceInterface_RemoteServiceFor_Call { _c.Call.Run(func(args mock.Arguments) { - var arg0 string + var arg0 api0.ServiceIdentity if args[0] != nil { - arg0 = args[0].(string) + arg0 = args[0].(api0.ServiceIdentity) } run( arg0, @@ -577,12 +776,12 @@ func (_c *ServiceInterface_RemoteServiceForSKI_Call) Run(run func(ski string)) * return _c } -func (_c *ServiceInterface_RemoteServiceForSKI_Call) Return(serviceDetails *api1.ServiceDetails) *ServiceInterface_RemoteServiceForSKI_Call { +func (_c *ServiceInterface_RemoteServiceFor_Call) Return(serviceDetails *api0.ServiceDetails) *ServiceInterface_RemoteServiceFor_Call { _c.Call.Return(serviceDetails) return _c } -func (_c *ServiceInterface_RemoteServiceForSKI_Call) RunAndReturn(run func(ski string) *api1.ServiceDetails) *ServiceInterface_RemoteServiceForSKI_Call { +func (_c *ServiceInterface_RemoteServiceFor_Call) RunAndReturn(run func(identity api0.ServiceIdentity) *api0.ServiceDetails) *ServiceInterface_RemoteServiceFor_Call { _c.Call.Return(run) return _c } @@ -745,9 +944,20 @@ func (_c *ServiceInterface_Shutdown_Call) RunAndReturn(run func()) *ServiceInter } // Start provides a mock function for the type ServiceInterface -func (_mock *ServiceInterface) Start() { - _mock.Called() - return +func (_mock *ServiceInterface) Start() error { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for Start") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func() error); ok { + r0 = returnFunc() + } else { + r0 = ret.Error(0) + } + return r0 } // ServiceInterface_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start' @@ -767,34 +977,96 @@ func (_c *ServiceInterface_Start_Call) Run(run func()) *ServiceInterface_Start_C return _c } -func (_c *ServiceInterface_Start_Call) Return() *ServiceInterface_Start_Call { - _c.Call.Return() +func (_c *ServiceInterface_Start_Call) Return(err error) *ServiceInterface_Start_Call { + _c.Call.Return(err) return _c } -func (_c *ServiceInterface_Start_Call) RunAndReturn(run func()) *ServiceInterface_Start_Call { - _c.Run(run) +func (_c *ServiceInterface_Start_Call) RunAndReturn(run func() error) *ServiceInterface_Start_Call { + _c.Call.Return(run) return _c } -// UnregisterRemoteSKI provides a mock function for the type ServiceInterface -func (_mock *ServiceInterface) UnregisterRemoteSKI(ski string) { - _mock.Called(ski) - return +// StartAnnouncementTo provides a mock function for the type ServiceInterface +func (_mock *ServiceInterface) StartAnnouncementTo(target api0.PairingTarget) error { + ret := _mock.Called(target) + + if len(ret) == 0 { + panic("no return value specified for StartAnnouncementTo") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(api0.PairingTarget) error); ok { + r0 = returnFunc(target) + } else { + r0 = ret.Error(0) + } + return r0 } -// ServiceInterface_UnregisterRemoteSKI_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UnregisterRemoteSKI' -type ServiceInterface_UnregisterRemoteSKI_Call struct { +// ServiceInterface_StartAnnouncementTo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StartAnnouncementTo' +type ServiceInterface_StartAnnouncementTo_Call struct { *mock.Call } -// UnregisterRemoteSKI is a helper method to define mock.On call -// - ski string -func (_e *ServiceInterface_Expecter) UnregisterRemoteSKI(ski interface{}) *ServiceInterface_UnregisterRemoteSKI_Call { - return &ServiceInterface_UnregisterRemoteSKI_Call{Call: _e.mock.On("UnregisterRemoteSKI", ski)} +// StartAnnouncementTo is a helper method to define mock.On call +// - target api0.PairingTarget +func (_e *ServiceInterface_Expecter) StartAnnouncementTo(target interface{}) *ServiceInterface_StartAnnouncementTo_Call { + return &ServiceInterface_StartAnnouncementTo_Call{Call: _e.mock.On("StartAnnouncementTo", target)} } -func (_c *ServiceInterface_UnregisterRemoteSKI_Call) Run(run func(ski string)) *ServiceInterface_UnregisterRemoteSKI_Call { +func (_c *ServiceInterface_StartAnnouncementTo_Call) Run(run func(target api0.PairingTarget)) *ServiceInterface_StartAnnouncementTo_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 api0.PairingTarget + if args[0] != nil { + arg0 = args[0].(api0.PairingTarget) + } + run( + arg0, + ) + }) + return _c +} + +func (_c *ServiceInterface_StartAnnouncementTo_Call) Return(err error) *ServiceInterface_StartAnnouncementTo_Call { + _c.Call.Return(err) + return _c +} + +func (_c *ServiceInterface_StartAnnouncementTo_Call) RunAndReturn(run func(target api0.PairingTarget) error) *ServiceInterface_StartAnnouncementTo_Call { + _c.Call.Return(run) + return _c +} + +// StopAnnouncementTo provides a mock function for the type ServiceInterface +func (_mock *ServiceInterface) StopAnnouncementTo(shipID string) error { + ret := _mock.Called(shipID) + + if len(ret) == 0 { + panic("no return value specified for StopAnnouncementTo") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(string) error); ok { + r0 = returnFunc(shipID) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// ServiceInterface_StopAnnouncementTo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StopAnnouncementTo' +type ServiceInterface_StopAnnouncementTo_Call struct { + *mock.Call +} + +// StopAnnouncementTo is a helper method to define mock.On call +// - shipID string +func (_e *ServiceInterface_Expecter) StopAnnouncementTo(shipID interface{}) *ServiceInterface_StopAnnouncementTo_Call { + return &ServiceInterface_StopAnnouncementTo_Call{Call: _e.mock.On("StopAnnouncementTo", shipID)} +} + +func (_c *ServiceInterface_StopAnnouncementTo_Call) Run(run func(shipID string)) *ServiceInterface_StopAnnouncementTo_Call { _c.Call.Run(func(args mock.Arguments) { var arg0 string if args[0] != nil { @@ -807,12 +1079,52 @@ func (_c *ServiceInterface_UnregisterRemoteSKI_Call) Run(run func(ski string)) * return _c } -func (_c *ServiceInterface_UnregisterRemoteSKI_Call) Return() *ServiceInterface_UnregisterRemoteSKI_Call { +func (_c *ServiceInterface_StopAnnouncementTo_Call) Return(err error) *ServiceInterface_StopAnnouncementTo_Call { + _c.Call.Return(err) + return _c +} + +func (_c *ServiceInterface_StopAnnouncementTo_Call) RunAndReturn(run func(shipID string) error) *ServiceInterface_StopAnnouncementTo_Call { + _c.Call.Return(run) + return _c +} + +// UnregisterRemoteService provides a mock function for the type ServiceInterface +func (_mock *ServiceInterface) UnregisterRemoteService(identity api0.ServiceIdentity) { + _mock.Called(identity) + return +} + +// ServiceInterface_UnregisterRemoteService_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UnregisterRemoteService' +type ServiceInterface_UnregisterRemoteService_Call struct { + *mock.Call +} + +// UnregisterRemoteService is a helper method to define mock.On call +// - identity api0.ServiceIdentity +func (_e *ServiceInterface_Expecter) UnregisterRemoteService(identity interface{}) *ServiceInterface_UnregisterRemoteService_Call { + return &ServiceInterface_UnregisterRemoteService_Call{Call: _e.mock.On("UnregisterRemoteService", identity)} +} + +func (_c *ServiceInterface_UnregisterRemoteService_Call) Run(run func(identity api0.ServiceIdentity)) *ServiceInterface_UnregisterRemoteService_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 api0.ServiceIdentity + if args[0] != nil { + arg0 = args[0].(api0.ServiceIdentity) + } + run( + arg0, + ) + }) + return _c +} + +func (_c *ServiceInterface_UnregisterRemoteService_Call) Return() *ServiceInterface_UnregisterRemoteService_Call { _c.Call.Return() return _c } -func (_c *ServiceInterface_UnregisterRemoteSKI_Call) RunAndReturn(run func(ski string)) *ServiceInterface_UnregisterRemoteSKI_Call { +func (_c *ServiceInterface_UnregisterRemoteService_Call) RunAndReturn(run func(identity api0.ServiceIdentity)) *ServiceInterface_UnregisterRemoteService_Call { _c.Run(run) return _c } diff --git a/mocks/ServiceReaderInterface.go b/mocks/ServiceReaderInterface.go index 4a18e808..c39a64a2 100644 --- a/mocks/ServiceReaderInterface.go +++ b/mocks/ServiceReaderInterface.go @@ -37,33 +37,33 @@ func (_m *ServiceReaderInterface) EXPECT() *ServiceReaderInterface_Expecter { return &ServiceReaderInterface_Expecter{mock: &_m.Mock} } -// RemoteSKIConnected provides a mock function for the type ServiceReaderInterface -func (_mock *ServiceReaderInterface) RemoteSKIConnected(service api.ServiceInterface, ski string) { - _mock.Called(service, ski) +// RemoteServiceConnected provides a mock function for the type ServiceReaderInterface +func (_mock *ServiceReaderInterface) RemoteServiceConnected(service api.ServiceInterface, identity api0.ServiceIdentity) { + _mock.Called(service, identity) return } -// ServiceReaderInterface_RemoteSKIConnected_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoteSKIConnected' -type ServiceReaderInterface_RemoteSKIConnected_Call struct { +// ServiceReaderInterface_RemoteServiceConnected_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoteServiceConnected' +type ServiceReaderInterface_RemoteServiceConnected_Call struct { *mock.Call } -// RemoteSKIConnected is a helper method to define mock.On call +// RemoteServiceConnected is a helper method to define mock.On call // - service api.ServiceInterface -// - ski string -func (_e *ServiceReaderInterface_Expecter) RemoteSKIConnected(service interface{}, ski interface{}) *ServiceReaderInterface_RemoteSKIConnected_Call { - return &ServiceReaderInterface_RemoteSKIConnected_Call{Call: _e.mock.On("RemoteSKIConnected", service, ski)} +// - identity api0.ServiceIdentity +func (_e *ServiceReaderInterface_Expecter) RemoteServiceConnected(service interface{}, identity interface{}) *ServiceReaderInterface_RemoteServiceConnected_Call { + return &ServiceReaderInterface_RemoteServiceConnected_Call{Call: _e.mock.On("RemoteServiceConnected", service, identity)} } -func (_c *ServiceReaderInterface_RemoteSKIConnected_Call) Run(run func(service api.ServiceInterface, ski string)) *ServiceReaderInterface_RemoteSKIConnected_Call { +func (_c *ServiceReaderInterface_RemoteServiceConnected_Call) Run(run func(service api.ServiceInterface, identity api0.ServiceIdentity)) *ServiceReaderInterface_RemoteServiceConnected_Call { _c.Call.Run(func(args mock.Arguments) { var arg0 api.ServiceInterface if args[0] != nil { arg0 = args[0].(api.ServiceInterface) } - var arg1 string + var arg1 api0.ServiceIdentity if args[1] != nil { - arg1 = args[1].(string) + arg1 = args[1].(api0.ServiceIdentity) } run( arg0, @@ -73,43 +73,43 @@ func (_c *ServiceReaderInterface_RemoteSKIConnected_Call) Run(run func(service a return _c } -func (_c *ServiceReaderInterface_RemoteSKIConnected_Call) Return() *ServiceReaderInterface_RemoteSKIConnected_Call { +func (_c *ServiceReaderInterface_RemoteServiceConnected_Call) Return() *ServiceReaderInterface_RemoteServiceConnected_Call { _c.Call.Return() return _c } -func (_c *ServiceReaderInterface_RemoteSKIConnected_Call) RunAndReturn(run func(service api.ServiceInterface, ski string)) *ServiceReaderInterface_RemoteSKIConnected_Call { +func (_c *ServiceReaderInterface_RemoteServiceConnected_Call) RunAndReturn(run func(service api.ServiceInterface, identity api0.ServiceIdentity)) *ServiceReaderInterface_RemoteServiceConnected_Call { _c.Run(run) return _c } -// RemoteSKIDisconnected provides a mock function for the type ServiceReaderInterface -func (_mock *ServiceReaderInterface) RemoteSKIDisconnected(service api.ServiceInterface, ski string) { - _mock.Called(service, ski) +// RemoteServiceDisconnected provides a mock function for the type ServiceReaderInterface +func (_mock *ServiceReaderInterface) RemoteServiceDisconnected(service api.ServiceInterface, identity api0.ServiceIdentity) { + _mock.Called(service, identity) return } -// ServiceReaderInterface_RemoteSKIDisconnected_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoteSKIDisconnected' -type ServiceReaderInterface_RemoteSKIDisconnected_Call struct { +// ServiceReaderInterface_RemoteServiceDisconnected_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoteServiceDisconnected' +type ServiceReaderInterface_RemoteServiceDisconnected_Call struct { *mock.Call } -// RemoteSKIDisconnected is a helper method to define mock.On call +// RemoteServiceDisconnected is a helper method to define mock.On call // - service api.ServiceInterface -// - ski string -func (_e *ServiceReaderInterface_Expecter) RemoteSKIDisconnected(service interface{}, ski interface{}) *ServiceReaderInterface_RemoteSKIDisconnected_Call { - return &ServiceReaderInterface_RemoteSKIDisconnected_Call{Call: _e.mock.On("RemoteSKIDisconnected", service, ski)} +// - identity api0.ServiceIdentity +func (_e *ServiceReaderInterface_Expecter) RemoteServiceDisconnected(service interface{}, identity interface{}) *ServiceReaderInterface_RemoteServiceDisconnected_Call { + return &ServiceReaderInterface_RemoteServiceDisconnected_Call{Call: _e.mock.On("RemoteServiceDisconnected", service, identity)} } -func (_c *ServiceReaderInterface_RemoteSKIDisconnected_Call) Run(run func(service api.ServiceInterface, ski string)) *ServiceReaderInterface_RemoteSKIDisconnected_Call { +func (_c *ServiceReaderInterface_RemoteServiceDisconnected_Call) Run(run func(service api.ServiceInterface, identity api0.ServiceIdentity)) *ServiceReaderInterface_RemoteServiceDisconnected_Call { _c.Call.Run(func(args mock.Arguments) { var arg0 api.ServiceInterface if args[0] != nil { arg0 = args[0].(api.ServiceInterface) } - var arg1 string + var arg1 api0.ServiceIdentity if args[1] != nil { - arg1 = args[1].(string) + arg1 = args[1].(api0.ServiceIdentity) } run( arg0, @@ -119,19 +119,169 @@ func (_c *ServiceReaderInterface_RemoteSKIDisconnected_Call) Run(run func(servic return _c } -func (_c *ServiceReaderInterface_RemoteSKIDisconnected_Call) Return() *ServiceReaderInterface_RemoteSKIDisconnected_Call { +func (_c *ServiceReaderInterface_RemoteServiceDisconnected_Call) Return() *ServiceReaderInterface_RemoteServiceDisconnected_Call { _c.Call.Return() return _c } -func (_c *ServiceReaderInterface_RemoteSKIDisconnected_Call) RunAndReturn(run func(service api.ServiceInterface, ski string)) *ServiceReaderInterface_RemoteSKIDisconnected_Call { +func (_c *ServiceReaderInterface_RemoteServiceDisconnected_Call) RunAndReturn(run func(service api.ServiceInterface, identity api0.ServiceIdentity)) *ServiceReaderInterface_RemoteServiceDisconnected_Call { + _c.Run(run) + return _c +} + +// ServiceAutoTrustFailed provides a mock function for the type ServiceReaderInterface +func (_mock *ServiceReaderInterface) ServiceAutoTrustFailed(service api.ServiceInterface, identity api0.ServiceIdentity, reason error) { + _mock.Called(service, identity, reason) + return +} + +// ServiceReaderInterface_ServiceAutoTrustFailed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ServiceAutoTrustFailed' +type ServiceReaderInterface_ServiceAutoTrustFailed_Call struct { + *mock.Call +} + +// ServiceAutoTrustFailed is a helper method to define mock.On call +// - service api.ServiceInterface +// - identity api0.ServiceIdentity +// - reason error +func (_e *ServiceReaderInterface_Expecter) ServiceAutoTrustFailed(service interface{}, identity interface{}, reason interface{}) *ServiceReaderInterface_ServiceAutoTrustFailed_Call { + return &ServiceReaderInterface_ServiceAutoTrustFailed_Call{Call: _e.mock.On("ServiceAutoTrustFailed", service, identity, reason)} +} + +func (_c *ServiceReaderInterface_ServiceAutoTrustFailed_Call) Run(run func(service api.ServiceInterface, identity api0.ServiceIdentity, reason error)) *ServiceReaderInterface_ServiceAutoTrustFailed_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 api.ServiceInterface + if args[0] != nil { + arg0 = args[0].(api.ServiceInterface) + } + var arg1 api0.ServiceIdentity + if args[1] != nil { + arg1 = args[1].(api0.ServiceIdentity) + } + var arg2 error + if args[2] != nil { + arg2 = args[2].(error) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *ServiceReaderInterface_ServiceAutoTrustFailed_Call) Return() *ServiceReaderInterface_ServiceAutoTrustFailed_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceReaderInterface_ServiceAutoTrustFailed_Call) RunAndReturn(run func(service api.ServiceInterface, identity api0.ServiceIdentity, reason error)) *ServiceReaderInterface_ServiceAutoTrustFailed_Call { + _c.Run(run) + return _c +} + +// ServiceAutoTrustRemoved provides a mock function for the type ServiceReaderInterface +func (_mock *ServiceReaderInterface) ServiceAutoTrustRemoved(service api.ServiceInterface, identity api0.ServiceIdentity, reason string) { + _mock.Called(service, identity, reason) + return +} + +// ServiceReaderInterface_ServiceAutoTrustRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ServiceAutoTrustRemoved' +type ServiceReaderInterface_ServiceAutoTrustRemoved_Call struct { + *mock.Call +} + +// ServiceAutoTrustRemoved is a helper method to define mock.On call +// - service api.ServiceInterface +// - identity api0.ServiceIdentity +// - reason string +func (_e *ServiceReaderInterface_Expecter) ServiceAutoTrustRemoved(service interface{}, identity interface{}, reason interface{}) *ServiceReaderInterface_ServiceAutoTrustRemoved_Call { + return &ServiceReaderInterface_ServiceAutoTrustRemoved_Call{Call: _e.mock.On("ServiceAutoTrustRemoved", service, identity, reason)} +} + +func (_c *ServiceReaderInterface_ServiceAutoTrustRemoved_Call) Run(run func(service api.ServiceInterface, identity api0.ServiceIdentity, reason string)) *ServiceReaderInterface_ServiceAutoTrustRemoved_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 api.ServiceInterface + if args[0] != nil { + arg0 = args[0].(api.ServiceInterface) + } + var arg1 api0.ServiceIdentity + if args[1] != nil { + arg1 = args[1].(api0.ServiceIdentity) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *ServiceReaderInterface_ServiceAutoTrustRemoved_Call) Return() *ServiceReaderInterface_ServiceAutoTrustRemoved_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceReaderInterface_ServiceAutoTrustRemoved_Call) RunAndReturn(run func(service api.ServiceInterface, identity api0.ServiceIdentity, reason string)) *ServiceReaderInterface_ServiceAutoTrustRemoved_Call { + _c.Run(run) + return _c +} + +// ServiceAutoTrusted provides a mock function for the type ServiceReaderInterface +func (_mock *ServiceReaderInterface) ServiceAutoTrusted(service api.ServiceInterface, identity api0.ServiceIdentity) { + _mock.Called(service, identity) + return +} + +// ServiceReaderInterface_ServiceAutoTrusted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ServiceAutoTrusted' +type ServiceReaderInterface_ServiceAutoTrusted_Call struct { + *mock.Call +} + +// ServiceAutoTrusted is a helper method to define mock.On call +// - service api.ServiceInterface +// - identity api0.ServiceIdentity +func (_e *ServiceReaderInterface_Expecter) ServiceAutoTrusted(service interface{}, identity interface{}) *ServiceReaderInterface_ServiceAutoTrusted_Call { + return &ServiceReaderInterface_ServiceAutoTrusted_Call{Call: _e.mock.On("ServiceAutoTrusted", service, identity)} +} + +func (_c *ServiceReaderInterface_ServiceAutoTrusted_Call) Run(run func(service api.ServiceInterface, identity api0.ServiceIdentity)) *ServiceReaderInterface_ServiceAutoTrusted_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 api.ServiceInterface + if args[0] != nil { + arg0 = args[0].(api.ServiceInterface) + } + var arg1 api0.ServiceIdentity + if args[1] != nil { + arg1 = args[1].(api0.ServiceIdentity) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *ServiceReaderInterface_ServiceAutoTrusted_Call) Return() *ServiceReaderInterface_ServiceAutoTrusted_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceReaderInterface_ServiceAutoTrusted_Call) RunAndReturn(run func(service api.ServiceInterface, identity api0.ServiceIdentity)) *ServiceReaderInterface_ServiceAutoTrusted_Call { _c.Run(run) return _c } // ServicePairingDetailUpdate provides a mock function for the type ServiceReaderInterface -func (_mock *ServiceReaderInterface) ServicePairingDetailUpdate(ski string, detail *api0.ConnectionStateDetail) { - _mock.Called(ski, detail) +func (_mock *ServiceReaderInterface) ServicePairingDetailUpdate(identity api0.ServiceIdentity, detail *api0.ConnectionStateDetail) { + _mock.Called(identity, detail) return } @@ -141,17 +291,17 @@ type ServiceReaderInterface_ServicePairingDetailUpdate_Call struct { } // ServicePairingDetailUpdate is a helper method to define mock.On call -// - ski string +// - identity api0.ServiceIdentity // - detail *api0.ConnectionStateDetail -func (_e *ServiceReaderInterface_Expecter) ServicePairingDetailUpdate(ski interface{}, detail interface{}) *ServiceReaderInterface_ServicePairingDetailUpdate_Call { - return &ServiceReaderInterface_ServicePairingDetailUpdate_Call{Call: _e.mock.On("ServicePairingDetailUpdate", ski, detail)} +func (_e *ServiceReaderInterface_Expecter) ServicePairingDetailUpdate(identity interface{}, detail interface{}) *ServiceReaderInterface_ServicePairingDetailUpdate_Call { + return &ServiceReaderInterface_ServicePairingDetailUpdate_Call{Call: _e.mock.On("ServicePairingDetailUpdate", identity, detail)} } -func (_c *ServiceReaderInterface_ServicePairingDetailUpdate_Call) Run(run func(ski string, detail *api0.ConnectionStateDetail)) *ServiceReaderInterface_ServicePairingDetailUpdate_Call { +func (_c *ServiceReaderInterface_ServicePairingDetailUpdate_Call) Run(run func(identity api0.ServiceIdentity, detail *api0.ConnectionStateDetail)) *ServiceReaderInterface_ServicePairingDetailUpdate_Call { _c.Call.Run(func(args mock.Arguments) { - var arg0 string + var arg0 api0.ServiceIdentity if args[0] != nil { - arg0 = args[0].(string) + arg0 = args[0].(api0.ServiceIdentity) } var arg1 *api0.ConnectionStateDetail if args[1] != nil { @@ -170,84 +320,78 @@ func (_c *ServiceReaderInterface_ServicePairingDetailUpdate_Call) Return() *Serv return _c } -func (_c *ServiceReaderInterface_ServicePairingDetailUpdate_Call) RunAndReturn(run func(ski string, detail *api0.ConnectionStateDetail)) *ServiceReaderInterface_ServicePairingDetailUpdate_Call { +func (_c *ServiceReaderInterface_ServicePairingDetailUpdate_Call) RunAndReturn(run func(identity api0.ServiceIdentity, detail *api0.ConnectionStateDetail)) *ServiceReaderInterface_ServicePairingDetailUpdate_Call { _c.Run(run) return _c } -// ServiceShipIDUpdate provides a mock function for the type ServiceReaderInterface -func (_mock *ServiceReaderInterface) ServiceShipIDUpdate(ski string, shipdID string) { - _mock.Called(ski, shipdID) +// ServiceUpdated provides a mock function for the type ServiceReaderInterface +func (_mock *ServiceReaderInterface) ServiceUpdated(identity api0.ServiceIdentity) { + _mock.Called(identity) return } -// ServiceReaderInterface_ServiceShipIDUpdate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ServiceShipIDUpdate' -type ServiceReaderInterface_ServiceShipIDUpdate_Call struct { +// ServiceReaderInterface_ServiceUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ServiceUpdated' +type ServiceReaderInterface_ServiceUpdated_Call struct { *mock.Call } -// ServiceShipIDUpdate is a helper method to define mock.On call -// - ski string -// - shipdID string -func (_e *ServiceReaderInterface_Expecter) ServiceShipIDUpdate(ski interface{}, shipdID interface{}) *ServiceReaderInterface_ServiceShipIDUpdate_Call { - return &ServiceReaderInterface_ServiceShipIDUpdate_Call{Call: _e.mock.On("ServiceShipIDUpdate", ski, shipdID)} +// ServiceUpdated is a helper method to define mock.On call +// - identity api0.ServiceIdentity +func (_e *ServiceReaderInterface_Expecter) ServiceUpdated(identity interface{}) *ServiceReaderInterface_ServiceUpdated_Call { + return &ServiceReaderInterface_ServiceUpdated_Call{Call: _e.mock.On("ServiceUpdated", identity)} } -func (_c *ServiceReaderInterface_ServiceShipIDUpdate_Call) Run(run func(ski string, shipdID string)) *ServiceReaderInterface_ServiceShipIDUpdate_Call { +func (_c *ServiceReaderInterface_ServiceUpdated_Call) Run(run func(identity api0.ServiceIdentity)) *ServiceReaderInterface_ServiceUpdated_Call { _c.Call.Run(func(args mock.Arguments) { - var arg0 string + var arg0 api0.ServiceIdentity if args[0] != nil { - arg0 = args[0].(string) - } - var arg1 string - if args[1] != nil { - arg1 = args[1].(string) + arg0 = args[0].(api0.ServiceIdentity) } run( arg0, - arg1, ) }) return _c } -func (_c *ServiceReaderInterface_ServiceShipIDUpdate_Call) Return() *ServiceReaderInterface_ServiceShipIDUpdate_Call { +func (_c *ServiceReaderInterface_ServiceUpdated_Call) Return() *ServiceReaderInterface_ServiceUpdated_Call { _c.Call.Return() return _c } -func (_c *ServiceReaderInterface_ServiceShipIDUpdate_Call) RunAndReturn(run func(ski string, shipdID string)) *ServiceReaderInterface_ServiceShipIDUpdate_Call { +func (_c *ServiceReaderInterface_ServiceUpdated_Call) RunAndReturn(run func(identity api0.ServiceIdentity)) *ServiceReaderInterface_ServiceUpdated_Call { _c.Run(run) return _c } -// VisibleRemoteServicesUpdated provides a mock function for the type ServiceReaderInterface -func (_mock *ServiceReaderInterface) VisibleRemoteServicesUpdated(service api.ServiceInterface, entries []api0.RemoteService) { +// VisibleRemoteMdnsServicesUpdated provides a mock function for the type ServiceReaderInterface +func (_mock *ServiceReaderInterface) VisibleRemoteMdnsServicesUpdated(service api.ServiceInterface, entries []api0.RemoteMdnsService) { _mock.Called(service, entries) return } -// ServiceReaderInterface_VisibleRemoteServicesUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VisibleRemoteServicesUpdated' -type ServiceReaderInterface_VisibleRemoteServicesUpdated_Call struct { +// ServiceReaderInterface_VisibleRemoteMdnsServicesUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VisibleRemoteMdnsServicesUpdated' +type ServiceReaderInterface_VisibleRemoteMdnsServicesUpdated_Call struct { *mock.Call } -// VisibleRemoteServicesUpdated is a helper method to define mock.On call +// VisibleRemoteMdnsServicesUpdated is a helper method to define mock.On call // - service api.ServiceInterface -// - entries []api0.RemoteService -func (_e *ServiceReaderInterface_Expecter) VisibleRemoteServicesUpdated(service interface{}, entries interface{}) *ServiceReaderInterface_VisibleRemoteServicesUpdated_Call { - return &ServiceReaderInterface_VisibleRemoteServicesUpdated_Call{Call: _e.mock.On("VisibleRemoteServicesUpdated", service, entries)} +// - entries []api0.RemoteMdnsService +func (_e *ServiceReaderInterface_Expecter) VisibleRemoteMdnsServicesUpdated(service interface{}, entries interface{}) *ServiceReaderInterface_VisibleRemoteMdnsServicesUpdated_Call { + return &ServiceReaderInterface_VisibleRemoteMdnsServicesUpdated_Call{Call: _e.mock.On("VisibleRemoteMdnsServicesUpdated", service, entries)} } -func (_c *ServiceReaderInterface_VisibleRemoteServicesUpdated_Call) Run(run func(service api.ServiceInterface, entries []api0.RemoteService)) *ServiceReaderInterface_VisibleRemoteServicesUpdated_Call { +func (_c *ServiceReaderInterface_VisibleRemoteMdnsServicesUpdated_Call) Run(run func(service api.ServiceInterface, entries []api0.RemoteMdnsService)) *ServiceReaderInterface_VisibleRemoteMdnsServicesUpdated_Call { _c.Call.Run(func(args mock.Arguments) { var arg0 api.ServiceInterface if args[0] != nil { arg0 = args[0].(api.ServiceInterface) } - var arg1 []api0.RemoteService + var arg1 []api0.RemoteMdnsService if args[1] != nil { - arg1 = args[1].([]api0.RemoteService) + arg1 = args[1].([]api0.RemoteMdnsService) } run( arg0, @@ -257,12 +401,12 @@ func (_c *ServiceReaderInterface_VisibleRemoteServicesUpdated_Call) Run(run func return _c } -func (_c *ServiceReaderInterface_VisibleRemoteServicesUpdated_Call) Return() *ServiceReaderInterface_VisibleRemoteServicesUpdated_Call { +func (_c *ServiceReaderInterface_VisibleRemoteMdnsServicesUpdated_Call) Return() *ServiceReaderInterface_VisibleRemoteMdnsServicesUpdated_Call { _c.Call.Return() return _c } -func (_c *ServiceReaderInterface_VisibleRemoteServicesUpdated_Call) RunAndReturn(run func(service api.ServiceInterface, entries []api0.RemoteService)) *ServiceReaderInterface_VisibleRemoteServicesUpdated_Call { +func (_c *ServiceReaderInterface_VisibleRemoteMdnsServicesUpdated_Call) RunAndReturn(run func(service api.ServiceInterface, entries []api0.RemoteMdnsService)) *ServiceReaderInterface_VisibleRemoteMdnsServicesUpdated_Call { _c.Run(run) return _c } diff --git a/service/service.go b/service/service.go index 070a9d3b..e9ebb058 100644 --- a/service/service.go +++ b/service/service.go @@ -77,6 +77,11 @@ func (s *Service) Setup() error { return err } + fingerprint, err := cert.FingerprintFromCertificate(leaf) + if err != nil { + return err + } + // Initialize the local service // The ShipID is defined in SHIP Spec 3. as // Each SHIP node has a globally unique SHIP ID. The SHIP ID is used to uniquely identify a SHIP node, @@ -85,9 +90,7 @@ func (s *Service) Setup() error { // The originator's unique ID // I assume those two to mean the same. // TODO: clarify - s.localService = shipapi.NewServiceDetails(ski) - s.localService.SetShipID(sd.Identifier()) - s.localService.SetDeviceType(string(sd.DeviceType())) + s.localService = shipapi.NewServiceDetails(ski, fingerprint, sd.Identifier()) logging.Log().Info("Local SKI:", ski) @@ -148,24 +151,32 @@ func (s *Service) Setup() error { ) // Setup connections hub with mDNS and websocket connection handling - s.connectionsHub = hub.NewHub(s, s.mdns, s.configuration.Port(), s.configuration.Certificate(), s.localService) + s.connectionsHub, err = hub.NewHub(s, s.mdns, s.configuration.Port(), s.configuration.Certificate(), s.localService, sd.PairingConfig(), sd.RingBufferPersistence()) + if err != nil { + return err + } return nil } // Starts the service -func (s *Service) Start() { +// +// Returns error with description of the error that cannot be recovered from +func (s *Service) Start() error { s.muxRunning.Lock() defer s.muxRunning.Unlock() // make sure we do not start twice while the service is already running if s.isRunning { - return + return nil } - s.connectionsHub.Start() + if err := s.connectionsHub.Start(); err != nil { + return err + } s.isRunning = true + return nil } // Shutdown all services and stop the server. @@ -221,14 +232,13 @@ func (s *Service) SetLogging(logger logging.LoggingInterface) { logging.SetLogging(logger) } -// Get the current pairing details for a given SKI -func (s *Service) PairingDetailForSki(ski string) *shipapi.ConnectionStateDetail { - return s.connectionsHub.PairingDetailForSki(ski) +// Get the current pairing details for a given ServiceIdentity +func (s *Service) PairingDetailFor(identity shipapi.ServiceIdentity) *shipapi.ConnectionStateDetail { + return s.connectionsHub.PairingDetailFor(identity) } -// Returns the Service detail of a given remote SKI -func (s *Service) RemoteServiceForSKI(ski string) *shipapi.ServiceDetails { - return s.connectionsHub.ServiceForSKI(ski) +func (s *Service) RemoteServiceFor(identity shipapi.ServiceIdentity) *shipapi.ServiceDetails { + return s.connectionsHub.ServiceFor(identity) } func (s *Service) SetAutoAccept(value bool) { @@ -240,32 +250,34 @@ func (s *Service) IsAutoAcceptEnabled() bool { return s.localService.AutoAccept() } -// Returns the QR code text for the service -// as defined in SHIP Requirements for Installation Process V1.0.0 -func (s *Service) QRCodeText() string { - return s.mdns.QRCodeText() +// Generate a QR code string. +// Must be called after Setup(). +func (s *Service) QRCodeText() (string, error) { + if s.connectionsHub == nil { + return "", errors.New("service not set up, call Setup() first") + } + + return s.connectionsHub.GeneratePairingQR() } -// Sets the SKI as being paired -// and connect it if paired and not currently being connected -func (s *Service) RegisterRemoteSKI(ski, shipID string) { - s.connectionsHub.RegisterRemoteSKI(ski, shipID) +// Pair a remote service using ServiceIdentity +func (s *Service) RegisterRemoteService(identity shipapi.ServiceIdentity) { + s.connectionsHub.RegisterRemoteService(identity) } -// Sets the SKI as not being paired -// and disconnects it if connected -func (s *Service) UnregisterRemoteSKI(ski string) { - s.connectionsHub.UnregisterRemoteSKI(ski) +// Unpair a remote service using ServiceIdentity +func (s *Service) UnregisterRemoteService(identity shipapi.ServiceIdentity) { + s.connectionsHub.UnregisterRemoteService(identity) } -// Close a connection to a remote SKI -func (s *Service) DisconnectSKI(ski string, reason string) { - s.connectionsHub.DisconnectSKI(ski, reason) +// Disconnect a connection using ServiceIdentity +func (s *Service) DisconnectService(identity shipapi.ServiceIdentity, reason string) { + s.connectionsHub.DisconnectService(identity, reason) } -// Cancels the pairing process for a SKI -func (s *Service) CancelPairingWithSKI(ski string) { - s.connectionsHub.CancelPairingWithSKI(ski) +// Cancels the pairing process for a ServiceIdentity +func (s *Service) CancelPairing(identity shipapi.ServiceIdentity) { + s.connectionsHub.CancelPairing(identity) } // Define wether the user is able to react to an incoming pairing request @@ -281,3 +293,38 @@ func (s *Service) UserIsAbleToApproveOrCancelPairingRequests(allow bool) { s.isPairingPossible = allow } + +// Calculate SHA-256 fingerprint of local certificate +func (s *Service) GetLocalCertificateFingerprint() (string, error) { + return s.connectionsHub.GetLocalCertificateFingerprint() +} + +// Start announcing pairing to a specific target device +// Used by devZ only. +func (s *Service) StartAnnouncementTo(target shipapi.PairingTarget) error { + return s.connectionsHub.StartAnnouncementTo(target) +} + +// Stop announcing pairing to a specific target device +// Used by devZ only. +func (s *Service) StopAnnouncementTo(shipID string) error { + return s.connectionsHub.StopAnnouncementTo(shipID) +} + +// Return true if currently announcing to a specific target device +// Used by devZ only. +func (s *Service) IsAnnouncingTo(shipID string) bool { + return s.connectionsHub.IsAnnouncingTo(shipID) +} + +// SHIP Pairing: Get Active Announcements. +// Used by devZ only. +func (s *Service) GetActiveAnnouncements() []string { + return s.connectionsHub.GetActiveAnnouncements() +} + +// SHIP Pairing: Get the SHIP ID and Fingerprint of controlbox paired via SHIP Pairing +// Used by devA only. +func (s *Service) GetTrustedAddCuDevice() *shipapi.ServiceDetails { + return s.connectionsHub.GetTrustedAddCuDevice() +} diff --git a/service/service_hub.go b/service/service_hub.go index 90745b96..325a2f88 100644 --- a/service/service_hub.go +++ b/service/service_hub.go @@ -6,55 +6,70 @@ import ( var _ shipapi.HubReaderInterface = (*Service)(nil) -// report a connection to a SKI +// report a connection to a remote service // // is triggered whenever a SHIP connected was successful completed -func (s *Service) RemoteSKIConnected(ski string) { - s.serviceHandler.RemoteSKIConnected(s, ski) +func (s *Service) RemoteServiceConnected(identity shipapi.ServiceIdentity) { + s.serviceHandler.RemoteServiceConnected(s, identity) } -// report a disconnection to a SKI +// report a disconnection from a remote service // // is triggered whenever a SHIP connect was closed, is also triggered when the SHIP // process wasn't successfully completed // // NOTE: The connection may not have been reported as connected before! -func (s *Service) RemoteSKIDisconnected(ski string) { +func (s *Service) RemoteServiceDisconnected(identity shipapi.ServiceIdentity) { if s.spineLocalDevice != nil { - s.spineLocalDevice.RemoveRemoteDeviceConnection(ski) + s.spineLocalDevice.RemoveRemoteDeviceConnection(identity.SKI) } - s.serviceHandler.RemoteSKIDisconnected(s, ski) + s.serviceHandler.RemoteServiceDisconnected(s, identity) } // report an approved handshake by a remote device -func (s *Service) SetupRemoteDevice(ski string, writeI shipapi.ShipConnectionDataWriterInterface) shipapi.ShipConnectionDataReaderInterface { - return s.LocalDevice().SetupRemoteDevice(ski, writeI) +func (s *Service) SetupRemoteService(identity shipapi.ServiceIdentity, writeI shipapi.ShipConnectionDataWriterInterface) shipapi.ShipConnectionDataReaderInterface { + return s.LocalDevice().SetupRemoteDevice(identity.SKI, writeI) } // report all currently visible EEBUS services -func (s *Service) VisibleRemoteServicesUpdated(entries []shipapi.RemoteService) { - s.serviceHandler.VisibleRemoteServicesUpdated(s, entries) +func (s *Service) VisibleRemoteMdnsServicesUpdated(entries []shipapi.RemoteMdnsService) { + s.serviceHandler.VisibleRemoteMdnsServicesUpdated(s, entries) } -// Provides the SHIP ID the remote service reported during the handshake process -// This needs to be persisted and passed on for future remote service connections -// when using `PairRemoteService` -func (s *Service) ServiceShipIDUpdate(ski string, shipdID string) { - s.serviceHandler.ServiceShipIDUpdate(ski, shipdID) +// report that service information has been updated +// This includes updates to ShipID, fingerprint, or other service details +// discovered during handshake +func (s *Service) ServiceUpdated(identity shipapi.ServiceIdentity) { + s.serviceHandler.ServiceUpdated(identity) } // Provides the current pairing state for the remote service // This is called whenever the state changes and can be used to // provide user information for the pairing/connection process -func (s *Service) ServicePairingDetailUpdate(ski string, detail *shipapi.ConnectionStateDetail) { - s.serviceHandler.ServicePairingDetailUpdate(ski, detail) +func (s *Service) ServicePairingDetailUpdate(identity shipapi.ServiceIdentity, detail *shipapi.ConnectionStateDetail) { + s.serviceHandler.ServicePairingDetailUpdate(identity, detail) } // return if the user is still able to trust the connection -func (s *Service) AllowWaitingForTrust(ski string) bool { +func (s *Service) AllowWaitingForTrust(identity shipapi.ServiceIdentity) bool { s.mux.Lock() defer s.mux.Unlock() return s.isPairingPossible } + +// Called when a device is automatically trusted via SHIP pairing +func (s *Service) ServiceAutoTrusted(identity shipapi.ServiceIdentity) { + s.serviceHandler.ServiceAutoTrusted(s, identity) +} + +// Called when SHIP pairing fails for a device +func (s *Service) ServiceAutoTrustFailed(identity shipapi.ServiceIdentity, reason error) { + s.serviceHandler.ServiceAutoTrustFailed(s, identity, reason) +} + +// Called when device trust is automatically removed This can happen due to device replacement timeout or new device pairing +func (s *Service) ServiceAutoTrustRemoved(identity shipapi.ServiceIdentity, reason string) { + s.serviceHandler.ServiceAutoTrustRemoved(s, identity, reason) +} diff --git a/service/service_test.go b/service/service_test.go index 2b661599..318482b0 100644 --- a/service/service_test.go +++ b/service/service_test.go @@ -2,6 +2,7 @@ package service import ( "crypto/tls" + "errors" "testing" "time" @@ -55,7 +56,7 @@ func (s *ServiceSuite) BeforeTest(suiteName, testName string) { "vendor", "brand", "model", "serial", []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, - []model.EntityTypeType{model.EntityTypeTypeCEM}, 4729, certificate, time.Second*4) + []model.EntityTypeType{model.EntityTypeTypeCEM}, 4729, certificate, time.Second*4, nil, nil) assert.Nil(s.T(), nil, err) s.sut = NewService(s.config, s.serviceReader) @@ -74,32 +75,52 @@ func (s *ServiceSuite) Test_EEBUSHandler() { s.sut.spineLocalDevice = s.localDevice - entry := shipapi.RemoteService{ + testIdentity := shipapi.NewServiceIdentity(testSki, "", "") + + entry := shipapi.RemoteMdnsService{ Ski: testSki, } - entries := []shipapi.RemoteService{entry} - s.serviceReader.EXPECT().VisibleRemoteServicesUpdated(mock.Anything, mock.Anything).Return() - s.sut.VisibleRemoteServicesUpdated(entries) + entries := []shipapi.RemoteMdnsService{entry} + s.serviceReader.EXPECT().VisibleRemoteMdnsServicesUpdated(mock.Anything, mock.Anything).Return() + s.sut.VisibleRemoteMdnsServicesUpdated(entries) - s.serviceReader.EXPECT().RemoteSKIConnected(mock.Anything, mock.Anything).Return() - s.sut.RemoteSKIConnected(testSki) + s.serviceReader.EXPECT().RemoteServiceConnected(mock.Anything, mock.Anything).Return() + s.sut.RemoteServiceConnected(testIdentity) - s.serviceReader.EXPECT().RemoteSKIDisconnected(mock.Anything, mock.Anything).Return() + s.serviceReader.EXPECT().RemoteServiceDisconnected(mock.Anything, mock.Anything).Return() s.localDevice.EXPECT().RemoveRemoteDeviceConnection(testSki).Return() - s.sut.RemoteSKIDisconnected(testSki) + s.sut.RemoteServiceDisconnected(testIdentity) - s.serviceReader.EXPECT().ServiceShipIDUpdate(mock.Anything, mock.Anything).Return() - s.sut.ServiceShipIDUpdate(testSki, "shipid") + s.serviceReader.EXPECT().ServiceUpdated(mock.Anything).Return() + s.sut.ServiceUpdated(testIdentity) s.serviceReader.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return() detail := &shipapi.ConnectionStateDetail{} - s.sut.ServicePairingDetailUpdate(testSki, detail) + s.sut.ServicePairingDetailUpdate(testIdentity, detail) s.sut.UserIsAbleToApproveOrCancelPairingRequests(true) - result := s.sut.AllowWaitingForTrust(testSki) + result := s.sut.AllowWaitingForTrust(testIdentity) assert.Equal(s.T(), true, result) + // Test AllowWaitingForTrust returns false when pairing not possible + s.sut.UserIsAbleToApproveOrCancelPairingRequests(false) + result = s.sut.AllowWaitingForTrust(testIdentity) + assert.Equal(s.T(), false, result) + + // Test ServiceAutoTrusted + s.serviceReader.EXPECT().ServiceAutoTrusted(mock.Anything, mock.Anything).Return() + s.sut.ServiceAutoTrusted(testIdentity) + + // Test ServiceAutoTrustFailed + testErr := errors.New("pairing failed") + s.serviceReader.EXPECT().ServiceAutoTrustFailed(mock.Anything, mock.Anything, mock.Anything).Return() + s.sut.ServiceAutoTrustFailed(testIdentity, testErr) + + // Test ServiceAutoTrustRemoved + s.serviceReader.EXPECT().ServiceAutoTrustRemoved(mock.Anything, mock.Anything, mock.Anything).Return() + s.sut.ServiceAutoTrustRemoved(testIdentity, "device replaced") + conf := s.sut.Configuration() assert.Equal(s.T(), s.sut.configuration, conf) @@ -109,40 +130,78 @@ func (s *ServiceSuite) Test_EEBUSHandler() { func (s *ServiceSuite) Test_ConnectionsHub() { testSki := "test" + testIdentity := shipapi.NewServiceIdentity(testSki, "", "") s.sut.connectionsHub = s.conHub s.sut.mdns = s.mdns s.sut.spineLocalDevice = s.localDevice - s.sut.localService = shipapi.NewServiceDetails(testSki) + s.sut.localService = shipapi.NewServiceDetails(testSki, "", "") - s.conHub.EXPECT().PairingDetailForSki(mock.Anything).Return(nil) - s.sut.PairingDetailForSki(testSki) + s.conHub.EXPECT().PairingDetailFor(mock.Anything).Return(nil) + s.sut.PairingDetailFor(testIdentity) - s.conHub.EXPECT().ServiceForSKI(mock.Anything).Return(nil) - details := s.sut.RemoteServiceForSKI(testSki) + s.conHub.EXPECT().ServiceFor(mock.Anything).Return(nil) + details := s.sut.RemoteServiceFor(testIdentity) assert.Nil(s.T(), details) s.localDevice.EXPECT().SetupRemoteDevice(mock.Anything, s).Return(nil) - s.sut.SetupRemoteDevice(testSki, s) + s.sut.SetupRemoteService(testIdentity, s) s.conHub.EXPECT().SetAutoAccept(mock.Anything).Return() s.sut.SetAutoAccept(true) assert.True(s.T(), s.sut.IsAutoAcceptEnabled()) - s.mdns.EXPECT().QRCodeText().Return("text") - assert.Equal(s.T(), "text", s.sut.QRCodeText()) + s.conHub.EXPECT().GeneratePairingQR().Return("text", nil) + qrCode, err := s.sut.QRCodeText() + assert.Nil(s.T(), err) + assert.Equal(s.T(), "text", qrCode) + s.conHub.EXPECT().RegisterRemoteService(mock.Anything).Return() + s.sut.RegisterRemoteService(testIdentity) + + s.conHub.EXPECT().UnregisterRemoteService(mock.Anything).Return() + s.sut.UnregisterRemoteService(testIdentity) + + s.conHub.EXPECT().CancelPairing(mock.Anything).Return() + s.sut.CancelPairing(testIdentity) + + s.conHub.EXPECT().DisconnectService(mock.Anything, mock.Anything).Return() + s.sut.DisconnectService(testIdentity, "reason") - s.conHub.EXPECT().RegisterRemoteSKI(mock.Anything, "").Return() - s.sut.RegisterRemoteSKI(testSki, "") + // Test GetLocalCertificateFingerprint + s.conHub.EXPECT().GetLocalCertificateFingerprint().Return("fingerprint123", nil) + fp, err := s.sut.GetLocalCertificateFingerprint() + assert.Nil(s.T(), err) + assert.Equal(s.T(), "fingerprint123", fp) - s.conHub.EXPECT().UnregisterRemoteSKI(mock.Anything).Return() - s.sut.UnregisterRemoteSKI(testSki) + // Test StartAnnouncementTo + target := shipapi.PairingTarget{ + SKI: "targetSki", + ShipID: "targetShipId", + } + s.conHub.EXPECT().StartAnnouncementTo(mock.Anything).Return(nil) + err = s.sut.StartAnnouncementTo(target) + assert.Nil(s.T(), err) - s.conHub.EXPECT().CancelPairingWithSKI(mock.Anything).Return() - s.sut.CancelPairingWithSKI(testSki) + // Test StopAnnouncementTo + s.conHub.EXPECT().StopAnnouncementTo("targetShipId").Return(nil) + err = s.sut.StopAnnouncementTo("targetShipId") + assert.Nil(s.T(), err) - s.conHub.EXPECT().DisconnectSKI(mock.Anything, mock.Anything).Return() - s.sut.DisconnectSKI(testSki, "reason") + // Test IsAnnouncingTo + s.conHub.EXPECT().IsAnnouncingTo("targetShipId").Return(true) + isAnnouncing := s.sut.IsAnnouncingTo("targetShipId") + assert.True(s.T(), isAnnouncing) + + // Test GetActiveAnnouncements + s.conHub.EXPECT().GetActiveAnnouncements().Return([]string{"ship1", "ship2"}) + announcements := s.sut.GetActiveAnnouncements() + assert.Equal(s.T(), []string{"ship1", "ship2"}, announcements) + + // Test GetTrustedAddCuDevice + s.conHub.EXPECT().GetTrustedAddCuDevice().Return(shipapi.NewServiceDetails("", "fpValue", "shipIdValue")) + svc := s.sut.GetTrustedAddCuDevice() + assert.Equal(s.T(), "fpValue", svc.Fingerprint()) + assert.Equal(s.T(), "shipIdValue", svc.ShipID()) } func (s *ServiceSuite) Test_SetLogging() { @@ -171,8 +230,8 @@ func (s *ServiceSuite) Test_Setup() { assert.Equal(s.T(), "d:_n:vendor_model-serial", string(*address)) s.sut.connectionsHub = s.conHub - s.conHub.EXPECT().Start().Once() - s.sut.Start() + s.conHub.EXPECT().Start().Return(nil).Once() + _ = s.sut.Start() time.Sleep(time.Millisecond * 200) @@ -180,7 +239,7 @@ func (s *ServiceSuite) Test_Setup() { assert.True(s.T(), isRunning) // nothing should happen - s.sut.Start() + _ = s.sut.Start() s.conHub.EXPECT().Shutdown().Once() s.sut.Shutdown() @@ -199,7 +258,7 @@ func (s *ServiceSuite) Test_Setup_IANA() { "12345", "brand", "model", "serial", []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, - []model.EntityTypeType{model.EntityTypeTypeCEM}, 4729, certificate, time.Second*4) + []model.EntityTypeType{model.EntityTypeTypeCEM}, 4729, certificate, time.Second*4, nil, nil) assert.Nil(s.T(), nil, err) s.sut = NewService(s.config, s.serviceReader) @@ -218,8 +277,8 @@ func (s *ServiceSuite) Test_Setup_IANA() { assert.Equal(s.T(), "d:_i:12345_model-serial", string(*address)) s.sut.connectionsHub = s.conHub - s.conHub.EXPECT().Start() - s.sut.Start() + s.conHub.EXPECT().Start().Return(nil) + _ = s.sut.Start() time.Sleep(time.Millisecond * 200) @@ -240,7 +299,7 @@ func (s *ServiceSuite) Test_Setup_Error_DeviceName() { "serialserialserialserialserialserialserialserialserialserialserialserialserialserialserialserialserial", []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, - []model.EntityTypeType{model.EntityTypeTypeCEM}, 4729, certificate, time.Second*4) + []model.EntityTypeType{model.EntityTypeTypeCEM}, 4729, certificate, time.Second*4, nil, nil) assert.Nil(s.T(), nil, err) s.sut = NewService(s.config, s.serviceReader) @@ -255,3 +314,93 @@ func (s *ServiceSuite) Test_Setup_Error_DeviceName() { err = s.sut.Setup() assert.NotNil(s.T(), err) } + +func (s *ServiceSuite) Test_QRCodeText_NoSetup() { + // QRCodeText should return error when connectionsHub is nil (not set up) + qr, err := s.sut.QRCodeText() + assert.NotNil(s.T(), err) + assert.Empty(s.T(), qr) +} + +func (s *ServiceSuite) Test_QRCodeText_Error() { + // QRCodeText should propagate errors from connectionsHub + s.sut.connectionsHub = s.conHub + expectedError := errors.New("qr generation failed") + s.conHub.EXPECT().GeneratePairingQR().Return("", expectedError) + qr, err := s.sut.QRCodeText() + assert.NotNil(s.T(), err) + assert.Empty(s.T(), qr) + assert.Equal(s.T(), err.Error(), expectedError.Error()) +} + +func (s *ServiceSuite) Test_Start_Error() { + // Start should propagate errors from connectionsHub.Start() + s.sut.connectionsHub = s.conHub + expectedError := errors.New("start failed") + s.conHub.EXPECT().Start().Return(expectedError).Once() + err := s.sut.Start() + assert.NotNil(s.T(), err) + assert.Equal(s.T(), err.Error(), expectedError.Error()) + assert.False(s.T(), s.sut.IsRunning()) +} + +func (s *ServiceSuite) Test_RemoteServiceDisconnected_NilLocalDevice() { + // RemoteServiceDisconnected should not panic when spineLocalDevice is nil + testIdentity := shipapi.NewServiceIdentity("test", "", "") + s.sut.spineLocalDevice = nil + s.serviceReader.EXPECT().RemoteServiceDisconnected(mock.Anything, mock.Anything).Return() + s.sut.RemoteServiceDisconnected(testIdentity) +} + +func (s *ServiceSuite) Test_IsAnnouncingTo_False() { + s.sut.connectionsHub = s.conHub + s.conHub.EXPECT().IsAnnouncingTo("nonexistent").Return(false) + result := s.sut.IsAnnouncingTo("nonexistent") + assert.False(s.T(), result) +} + +func (s *ServiceSuite) Test_GetActiveAnnouncements_Empty() { + s.sut.connectionsHub = s.conHub + s.conHub.EXPECT().GetActiveAnnouncements().Return([]string{}) + announcements := s.sut.GetActiveAnnouncements() + assert.Empty(s.T(), announcements) +} + +func (s *ServiceSuite) Test_GetTrustedAddCuDevice_Empty() { + s.sut.connectionsHub = s.conHub + s.conHub.EXPECT().GetTrustedAddCuDevice().Return(nil) + svc := s.sut.GetTrustedAddCuDevice() + assert.Nil(s.T(), svc) +} + +func (s *ServiceSuite) Test_StartAnnouncementTo_Error() { + s.sut.connectionsHub = s.conHub + target := shipapi.PairingTarget{ + SKI: "ski", + ShipID: "shipId", + } + expectedError := errors.New("announcement failed") + s.conHub.EXPECT().StartAnnouncementTo(mock.Anything).Return(expectedError) + err := s.sut.StartAnnouncementTo(target) + assert.NotNil(s.T(), err) + assert.Equal(s.T(), err.Error(), expectedError.Error()) +} + +func (s *ServiceSuite) Test_StopAnnouncementTo_Error() { + s.sut.connectionsHub = s.conHub + expectedError := errors.New("stop failed") + s.conHub.EXPECT().StopAnnouncementTo("ship1").Return(expectedError) + err := s.sut.StopAnnouncementTo("ship1") + assert.NotNil(s.T(), err) + assert.Equal(s.T(), err.Error(), expectedError.Error()) +} + +func (s *ServiceSuite) Test_GetLocalCertificateFingerprint_Error() { + s.sut.connectionsHub = s.conHub + expectedError := errors.New("fingerprint error") + s.conHub.EXPECT().GetLocalCertificateFingerprint().Return("", expectedError) + fp, err := s.sut.GetLocalCertificateFingerprint() + assert.NotNil(s.T(), err) + assert.Equal(s.T(), err.Error(), expectedError.Error()) + assert.Empty(s.T(), fp) +} diff --git a/usecases/cem/cevc/testhelper_test.go b/usecases/cem/cevc/testhelper_test.go index a6c17238..2ff55e74 100644 --- a/usecases/cem/cevc/testhelper_test.go +++ b/usecases/cem/cevc/testhelper_test.go @@ -50,7 +50,7 @@ func (s *CemCEVCSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/cem/evcc/results.go b/usecases/cem/evcc/results.go index bff5581c..ba950507 100644 --- a/usecases/cem/evcc/results.go +++ b/usecases/cem/evcc/results.go @@ -3,6 +3,7 @@ package evcc import ( "fmt" + shipapi "github.com/enbility/ship-go/api" "github.com/enbility/spine-go/api" "github.com/enbility/spine-go/model" ) @@ -52,6 +53,7 @@ func (e *EVCC) handleResultDeviceDiagnosis(responseMsg api.ResponseMessage) { if result.Description != nil { errorText = fmt.Sprintf("%s - %s", errorText, string(*result.Description)) } - e.service.DisconnectSKI(responseMsg.DeviceRemote.Ski(), errorText) + identity := shipapi.NewServiceIdentity(responseMsg.DeviceRemote.Ski(), "", "") + e.service.DisconnectService(identity, errorText) } } diff --git a/usecases/cem/evcc/testhelper_test.go b/usecases/cem/evcc/testhelper_test.go index 59052696..3d2b35be 100644 --- a/usecases/cem/evcc/testhelper_test.go +++ b/usecases/cem/evcc/testhelper_test.go @@ -50,7 +50,7 @@ func (s *CemEVCCSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/cem/evcem/testhelper_test.go b/usecases/cem/evcem/testhelper_test.go index 85da2303..c1d43c55 100644 --- a/usecases/cem/evcem/testhelper_test.go +++ b/usecases/cem/evcem/testhelper_test.go @@ -50,7 +50,7 @@ func (s *CemEVCEMSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/cem/evsecc/testhelper_test.go b/usecases/cem/evsecc/testhelper_test.go index d8738822..4ab305a5 100644 --- a/usecases/cem/evsecc/testhelper_test.go +++ b/usecases/cem/evsecc/testhelper_test.go @@ -50,7 +50,7 @@ func (s *CemEVSECCSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/cem/evsoc/testhelper_test.go b/usecases/cem/evsoc/testhelper_test.go index 1cea9b00..8ce937d7 100644 --- a/usecases/cem/evsoc/testhelper_test.go +++ b/usecases/cem/evsoc/testhelper_test.go @@ -50,7 +50,7 @@ func (s *CemEVSOCSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/cem/opev/testhelper_test.go b/usecases/cem/opev/testhelper_test.go index 55308a53..67c19a79 100644 --- a/usecases/cem/opev/testhelper_test.go +++ b/usecases/cem/opev/testhelper_test.go @@ -50,7 +50,7 @@ func (s *CemOPEVSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/cem/oscev/testhelper_test.go b/usecases/cem/oscev/testhelper_test.go index 741ffb91..a771abc8 100644 --- a/usecases/cem/oscev/testhelper_test.go +++ b/usecases/cem/oscev/testhelper_test.go @@ -49,7 +49,7 @@ func (s *CemOSCEVSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/cem/vabd/testhelper_test.go b/usecases/cem/vabd/testhelper_test.go index 056a8713..7f39eba1 100644 --- a/usecases/cem/vabd/testhelper_test.go +++ b/usecases/cem/vabd/testhelper_test.go @@ -50,7 +50,7 @@ func (s *CemVABDSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/cem/vapd/testhelper_test.go b/usecases/cem/vapd/testhelper_test.go index 21ae36cd..cc05e217 100644 --- a/usecases/cem/vapd/testhelper_test.go +++ b/usecases/cem/vapd/testhelper_test.go @@ -50,7 +50,7 @@ func (s *CemVAPDSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/cs/lpc/testhelper_test.go b/usecases/cs/lpc/testhelper_test.go index 839828b6..c155de57 100644 --- a/usecases/cs/lpc/testhelper_test.go +++ b/usecases/cs/lpc/testhelper_test.go @@ -53,7 +53,7 @@ func (s *CsLPCSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/cs/lpp/testhelper_test.go b/usecases/cs/lpp/testhelper_test.go index c1ae590f..539c5c9a 100644 --- a/usecases/cs/lpp/testhelper_test.go +++ b/usecases/cs/lpp/testhelper_test.go @@ -53,7 +53,7 @@ func (s *CsLPPSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/eg/lpc/testhelper_test.go b/usecases/eg/lpc/testhelper_test.go index 13612bad..1b55ceef 100644 --- a/usecases/eg/lpc/testhelper_test.go +++ b/usecases/eg/lpc/testhelper_test.go @@ -50,7 +50,7 @@ func (s *EgLPCSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/eg/lpp/testhelper_test.go b/usecases/eg/lpp/testhelper_test.go index 6df60afe..0b083652 100644 --- a/usecases/eg/lpp/testhelper_test.go +++ b/usecases/eg/lpp/testhelper_test.go @@ -50,7 +50,7 @@ func (s *EgLPPSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/internal/testhelper_test.go b/usecases/internal/testhelper_test.go index 55c061f3..e5ddde38 100644 --- a/usecases/internal/testhelper_test.go +++ b/usecases/internal/testhelper_test.go @@ -50,7 +50,7 @@ func (s *InternalSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/ma/mgcp/testhelper_test.go b/usecases/ma/mgcp/testhelper_test.go index 878a3d62..83fb2f85 100644 --- a/usecases/ma/mgcp/testhelper_test.go +++ b/usecases/ma/mgcp/testhelper_test.go @@ -50,7 +50,7 @@ func (s *GcpMGCPSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/ma/mpc/testhelper_test.go b/usecases/ma/mpc/testhelper_test.go index 272947d8..1cdc9cf5 100644 --- a/usecases/ma/mpc/testhelper_test.go +++ b/usecases/ma/mpc/testhelper_test.go @@ -50,7 +50,7 @@ func (s *MaMPCSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() diff --git a/usecases/usecase/testhelper_test.go b/usecases/usecase/testhelper_test.go index df37c8f6..3579a95d 100644 --- a/usecases/usecase/testhelper_test.go +++ b/usecases/usecase/testhelper_test.go @@ -59,7 +59,7 @@ func (s *UseCaseSuite) BeforeTest(suiteName, testName string) { []shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, model.DeviceTypeTypeEnergyManagementSystem, []model.EntityTypeType{model.EntityTypeTypeCEM}, - 9999, cert, time.Second*4) + 9999, cert, time.Second*4, nil, nil) serviceHandler := mocks.NewServiceReaderInterface(s.T()) serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe()