lib: Add util.Service as suture.Service template (fixes #5801) (#5806)

This commit is contained in:
Simon Frei
2019-07-09 11:40:30 +02:00
committed by GitHub
parent d0ab65a178
commit ba056578ec
21 changed files with 340 additions and 420 deletions

View File

@@ -12,6 +12,10 @@ import (
"reflect"
"strconv"
"strings"
"github.com/syncthing/syncthing/lib/sync"
"github.com/thejerf/suture"
)
type defaultParser interface {
@@ -170,3 +174,73 @@ func Address(network, host string) string {
}
return u.String()
}
// AsService wraps the given function to implement suture.Service by calling
// that function on serve and closing the passed channel when Stop is called.
func AsService(fn func(stop chan struct{})) suture.Service {
return AsServiceWithError(func(stop chan struct{}) error {
fn(stop)
return nil
})
}
type ServiceWithError interface {
suture.Service
Error() error
}
// AsServiceWithError does the same as AsService, except that it keeps track
// of an error returned by the given function.
func AsServiceWithError(fn func(stop chan struct{}) error) ServiceWithError {
s := &service{
serve: fn,
stop: make(chan struct{}),
stopped: make(chan struct{}),
mut: sync.NewMutex(),
}
close(s.stopped) // not yet started, don't block on Stop()
return s
}
type service struct {
serve func(stop chan struct{}) error
stop chan struct{}
stopped chan struct{}
err error
mut sync.Mutex
}
func (s *service) Serve() {
s.mut.Lock()
select {
case <-s.stop:
s.mut.Unlock()
return
default:
}
s.err = nil
s.stopped = make(chan struct{})
s.mut.Unlock()
var err error
defer func() {
s.mut.Lock()
s.err = err
close(s.stopped)
s.mut.Unlock()
}()
err = s.serve(s.stop)
}
func (s *service) Stop() {
s.mut.Lock()
close(s.stop)
s.mut.Unlock()
<-s.stopped
}
func (s *service) Error() error {
s.mut.Lock()
defer s.mut.Unlock()
return s.err
}