Properly shut down EEBUS mdns entry (#2493)

This commit is contained in:
Andreas Linde 2022-02-06 18:26:15 +01:00 • committed by GitHub
parent 518f937055
commit 10ac20f7e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 119 additions and 22 deletions

View file

@ -2,6 +2,7 @@ package cmd
import (
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/cmd/shutdown"
"github.com/evcc-io/evcc/server"
"github.com/evcc-io/evcc/util"
"github.com/spf13/cobra"
@ -38,6 +39,9 @@ func runCharger(cmd *cobra.Command, args []string) {
log.FATAL.Fatal(err)
}
stopC := make(chan struct{})
go shutdown.Run(stopC)
chargers := cp.chargers
if len(args) == 1 {
arg := args[0]
@ -48,4 +52,7 @@ func runCharger(cmd *cobra.Command, args []string) {
for name, v := range chargers {
d.DumpWithHeader(name, v)
}
close(stopC)
<-shutdown.Done()
}

View file

@ -2,8 +2,12 @@ package cmd
import (
_ "embed"
"os"
"os/signal"
"syscall"
"github.com/evcc-io/evcc/cmd/configure"
"github.com/evcc-io/evcc/cmd/shutdown"
"github.com/evcc-io/evcc/util"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@ -43,5 +47,24 @@ func runConfigure(cmd *cobra.Command, args []string) {
util.LogLevel(viper.GetString("log"), nil)
stopC := make(chan struct{})
go shutdown.Run(stopC)
// catch signals
go func() {
signalC := make(chan os.Signal, 1)
signal.Notify(signalC, os.Interrupt, syscall.SIGTERM)
<-signalC // wait for signal
close(stopC) // signal loop to end
<-shutdown.Done()
os.Exit(1)
}()
impl.Run(log, lang, advanced, expand)
close(stopC)
<-shutdown.Done()
}

View file

@ -5,6 +5,7 @@ import (
"fmt"
certhelper "github.com/evcc-io/eebus/cert"
"github.com/evcc-io/evcc/cmd/shutdown"
"github.com/evcc-io/evcc/server"
)
@ -13,13 +14,13 @@ func (c *CmdConfigure) configureEEBus(conf map[string]interface{}) error {
var err error
if server.EEBusInstance, err = server.NewEEBus(conf); err == nil {
go server.EEBusInstance.Run()
shutdown.Register(server.EEBusInstance.Shutdown)
}
return nil
}
// eebusCertificate setup EEBUS certificate
// returns privagte key, public key and error
// eebusCertificate creates EEBUS certificate and returns private/public key
func (c *CmdConfigure) eebusCertificate() (map[string]interface{}, error) {
details := server.EEBUSDetails

View file

@ -161,8 +161,7 @@ func (c *CmdConfigure) processDeviceRequirements(templateItem templates.Template
return fmt.Errorf("%s: %s", c.localizedString("Requirements_EEBUS_Cert_Error", nil), err)
}
err = c.configureEEBus(eebusConfig)
if err != nil {
if err := c.configureEEBus(eebusConfig); err != nil {
return err
}
@ -170,6 +169,7 @@ func (c *CmdConfigure) processDeviceRequirements(templateItem templates.Template
if err != nil {
return err
}
c.configuration.config.EEBUS = string(eebusYaml)
fmt.Println()
fmt.Println("--------------------------------------------")

View file

@ -39,7 +39,7 @@ func (c *CmdConfigure) askConfigFailureNextStep() bool {
}
// select item from list
func (c *CmdConfigure) askSelection(message string, items []string) (error, string, int) {
func (c *CmdConfigure) askSelection(message string, items []string) (string, int, error) {
selection := ""
prompt := &survey.Select{
Message: message,
@ -47,19 +47,11 @@ func (c *CmdConfigure) askSelection(message string, items []string) (error, stri
}
err := c.surveyAskOne(prompt, &selection)
if err != nil {
return err, "", 0
if err == nil {
return selection, funk.IndexOf(items, selection), nil
}
var selectedIndex int
for index, item := range items {
if item == selection {
selectedIndex = index
break
}
}
return err, selection, selectedIndex
return "", 0, err
}
// selectItem selects item from list
@ -78,7 +70,7 @@ func (c *CmdConfigure) selectItem(deviceCategory DeviceCategory) templates.Templ
}
text := fmt.Sprintf("%s %s %s:", c.localizedString("Choose", nil), DeviceCategories[deviceCategory].article, DeviceCategories[deviceCategory].title)
err, _, selected := c.askSelection(text, items)
_, selected, err := c.askSelection(text, items)
if err != nil {
c.log.FATAL.Fatal(err)
}
@ -88,7 +80,7 @@ func (c *CmdConfigure) selectItem(deviceCategory DeviceCategory) templates.Templ
// askChoice selects item from list
func (c *CmdConfigure) askChoice(label string, choices []string) (int, string) {
err, selection, index := c.askSelection(label, choices)
selection, index, err := c.askSelection(label, choices)
if err != nil {
c.log.FATAL.Fatal(err)
}

View file

@ -6,9 +6,11 @@ import (
_ "net/http/pprof" // pprof handler
"os"
"os/signal"
"sync"
"syscall"
"time"
"github.com/evcc-io/evcc/cmd/shutdown"
"github.com/evcc-io/evcc/server"
"github.com/evcc-io/evcc/server/updater"
"github.com/evcc-io/evcc/util"
@ -233,15 +235,16 @@ func run(cmd *cobra.Command, args []string) {
site.Prepare(valueChan, pushChan)
stopC := make(chan struct{})
exitC := make(chan struct{})
go shutdown.Run(stopC)
siteC := make(chan struct{})
go func() {
site.Run(stopC, conf.Interval)
close(exitC)
close(siteC)
}()
// uds health check listener
go server.HealthListener(site, exitC)
go server.HealthListener(site, siteC)
// catch signals
go func() {
@ -251,6 +254,15 @@ func run(cmd *cobra.Command, args []string) {
<-signalC // wait for signal
close(stopC) // signal loop to end
exitC := make(chan struct{})
wg := new(sync.WaitGroup)
wg.Add(2)
// wait for main loop and shutdown functions to finish
go func() { <-shutdown.Done(conf.Interval); wg.Done() }()
go func() { <-siteC; wg.Done() }()
go func() { wg.Wait(); close(exitC) }()
select {
case <-exitC: // wait for loop to end
case <-time.NewTimer(conf.Interval).C: // wait max 1 period

View file

@ -11,6 +11,7 @@ import (
paho "github.com/eclipse/paho.mqtt.golang"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/api/proto/pb"
"github.com/evcc-io/evcc/cmd/shutdown"
"github.com/evcc-io/evcc/core"
"github.com/evcc-io/evcc/core/loadpoint"
"github.com/evcc-io/evcc/hems"
@ -164,6 +165,7 @@ func configureEEBus(conf map[string]interface{}) error {
var err error
if server.EEBusInstance, err = server.NewEEBus(conf); err == nil {
go server.EEBusInstance.Run()
shutdown.Register(server.EEBusInstance.Shutdown)
}
return nil

53
cmd/shutdown/shutdown.go Normal file
View file

@ -0,0 +1,53 @@
package shutdown
import (
"sync"
"time"
)
var (
mu sync.Mutex
handlers = make([]func(), 0)
exitC = make(chan struct{})
)
func Register(cb func()) {
mu.Lock()
handlers = append(handlers, cb)
mu.Unlock()
}
func Run(stopC <-chan struct{}) {
<-stopC
wg := new(sync.WaitGroup)
mu.Lock()
for _, cb := range handlers {
wg.Add(1)
go func(cb func()) {
cb()
wg.Done()
}(cb)
}
mu.Unlock()
wg.Wait()
close(exitC)
}
func Done(timeout ...time.Duration) <-chan struct{} {
to := time.Second
if len(timeout) == 1 {
to = timeout[0]
}
select {
case <-exitC:
return exitC
case <-time.After(to):
exitC := make(chan struct{})
close(exitC)
return exitC
}
}

View file

@ -37,6 +37,7 @@ type EEBus struct {
log *util.Logger
srv *server.Server
id string
zc *zeroconf.Server
clients map[string]EEBusClientCBs
connectedClients map[string]ship.Conn
discoveredClients map[string]*zeroconf.ServiceEntry
@ -90,11 +91,13 @@ func NewEEBus(other map[string]interface{}) (*EEBus, error) {
Register: true,
}
if _, err = srv.Announce(); err != nil {
zc, err := srv.Announce()
if err != nil {
return nil, err
}
c := &EEBus{
zc: zc,
log: log,
srv: srv,
id: id,
@ -152,6 +155,10 @@ func (c *EEBus) Run() {
}
}
func (c *EEBus) Shutdown() {
c.zc.Shutdown()
}
func (c *EEBus) addDisoveredEntry(entry *zeroconf.ServiceEntry) {
// we need to get the SKI only
svc, err := mdns.NewFromDNSEntry(entry)