1
0
mirror of https://github.com/hybridgroup/gobot.git synced 2025-04-24 13:48:49 +08:00

Isolates shutdown-logic to Robot/Robots/Gobot.Stop

Gobot no longer hijacks the os.Interrupt signal handler, leaving any
shutdown logic to the user.
This commit is contained in:
Kenny Levinsen 2015-07-21 22:20:02 +02:00
parent f25ef58c0a
commit 4b46228f67
3 changed files with 50 additions and 42 deletions

View File

@ -2,8 +2,6 @@ package gobot
import (
"log"
"os"
"os/signal"
)
// JSONGobot is a JSON representation of a Gobot.
@ -33,7 +31,6 @@ func NewJSONGobot(gobot *Gobot) *JSONGobot {
// Robots, API commands and Events.
type Gobot struct {
robots *Robots
trap func(chan os.Signal)
Commander
Eventer
}
@ -41,18 +38,15 @@ type Gobot struct {
// NewGobot returns a new Gobot
func NewGobot() *Gobot {
return &Gobot{
robots: &Robots{},
trap: func(c chan os.Signal) {
signal.Notify(c, os.Interrupt)
},
robots: &Robots{},
Commander: NewCommander(),
Eventer: NewEventer(),
}
}
// Start calls the Start method on each robot in it's collection of robots, and
// stops all robots on reception of a SIGINT. Start will block the execution of
// your main function until it receives the SIGINT.
// Start calls the Start method on each robot in its collection of robots. On
// error, call Stop to ensure that all robots are returned to a sane, stopped
// state.
func (g *Gobot) Start() (errs []error) {
if rerrs := g.robots.Start(); len(rerrs) > 0 {
for _, err := range rerrs {
@ -61,31 +55,18 @@ func (g *Gobot) Start() (errs []error) {
}
}
c := make(chan os.Signal, 1)
g.trap(c)
if len(errs) > 0 {
// there was an error during start, so we immediatly pass the interrupt
// in order to disconnect the initialized robots, connections and devices
c <- os.Interrupt
return errs
}
// Stop calls the Stop method on each robot in its collection of robots.
func (g *Gobot) Stop() (errs []error) {
if rerrs := g.robots.Stop(); len(rerrs) > 0 {
for _, err := range rerrs {
log.Println("Error:", err)
errs = append(errs, err)
}
}
// waiting for interrupt coming on the channel
_ = <-c
g.robots.Each(func(r *Robot) {
log.Println("Stopping Robot", r.Name, "...")
if herrs := r.Devices().Halt(); len(herrs) > 0 {
for _, err := range herrs {
log.Println("Error:", err)
errs = append(errs, err)
}
}
if cerrs := r.Connections().Finalize(); len(cerrs) > 0 {
for _, err := range cerrs {
log.Println("Error:", err)
errs = append(errs, err)
}
}
})
return errs
}

View File

@ -3,7 +3,6 @@ package gobot
import (
"errors"
"log"
"os"
"testing"
)
@ -20,9 +19,6 @@ func TestConnectionEach(t *testing.T) {
func initTestGobot() *Gobot {
log.SetOutput(&NullReadWriteCloser{})
g := NewGobot()
g.trap = func(c chan os.Signal) {
c <- os.Interrupt
}
g.AddRobot(newTestRobot("Robot1"))
g.AddRobot(newTestRobot("Robot2"))
g.AddRobot(newTestRobot(""))
@ -68,6 +64,7 @@ func TestGobotToJSON(t *testing.T) {
func TestGobotStart(t *testing.T) {
g := initTestGobot()
Assert(t, len(g.Start()), 0)
Assert(t, len(g.Stop()), 0)
}
func TestGobotStartErrors(t *testing.T) {
@ -90,6 +87,7 @@ func TestGobotStartErrors(t *testing.T) {
}
Assert(t, len(g.Start()), 1)
Assert(t, len(g.Stop()), 0)
testDriverStart = func() (errs []error) { return }
testAdaptorConnect = func() (errs []error) {
@ -99,14 +97,11 @@ func TestGobotStartErrors(t *testing.T) {
}
Assert(t, len(g.Start()), 1)
Assert(t, len(g.Stop()), 0)
testDriverStart = func() (errs []error) { return }
testAdaptorConnect = func() (errs []error) { return }
g.trap = func(c chan os.Signal) {
c <- os.Interrupt
}
testDriverHalt = func() (errs []error) {
return []error{
errors.New("driver halt error 1"),
@ -119,5 +114,6 @@ func TestGobotStartErrors(t *testing.T) {
}
}
Assert(t, len(g.Start()), 2)
Assert(t, len(g.Start()), 0)
Assert(t, len(g.Stop()), 2)
}

View File

@ -67,6 +67,19 @@ func (r *Robots) Start() (errs []error) {
return
}
// Stop calls the Stop method of each Robot in the collection
func (r *Robots) Stop() (errs []error) {
for _, robot := range *r {
if errs = robot.Stop(); len(errs) > 0 {
for i, err := range errs {
errs[i] = fmt.Errorf("Robot %q: %v", robot.Name, err)
}
return
}
}
return
}
// Each enumerates through the Robots and calls specified callback function.
func (r *Robots) Each(f func(*Robot)) {
for _, robot := range *r {
@ -136,6 +149,24 @@ func (r *Robot) Start() (errs []error) {
return
}
// Stop stops a Robot's connections and Devices
func (r *Robot) Stop() (errs []error) {
log.Println("Stopping Robot", r.Name, "...")
if heers := r.Devices().Halt(); len(heers) > 0 {
for _, err := range heers {
errs = append(errs, err)
}
}
if ceers := r.Connections().Finalize(); len(ceers) > 0 {
for _, err := range ceers {
errs = append(errs, err)
}
}
return errs
}
// Devices returns all devices associated with this Robot.
func (r *Robot) Devices() *Devices {
return r.devices