mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-18 19:15:19 +00:00
lib/ur: Send unreported failures on shutdown (#7164)
This commit is contained in:
parent
4bcc38cf63
commit
a20a5f61f0
@ -39,10 +39,10 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
"github.com/syncthing/syncthing/lib/osutil"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
"github.com/syncthing/syncthing/lib/syncthing"
|
||||
"github.com/syncthing/syncthing/lib/tlsutil"
|
||||
"github.com/syncthing/syncthing/lib/upgrade"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@ -323,7 +323,7 @@ func main() {
|
||||
}
|
||||
if err != nil {
|
||||
l.Warnln("Command line options:", err)
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
if options.logFile == "default" || options.logFile == "" {
|
||||
@ -360,7 +360,7 @@ func main() {
|
||||
)
|
||||
if err != nil {
|
||||
l.Warnln("Error reading device ID:", err)
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
fmt.Println(protocol.NewDeviceID(cert.Certificate[0]))
|
||||
@ -370,7 +370,7 @@ func main() {
|
||||
if options.browserOnly {
|
||||
if err := openGUI(protocol.EmptyDeviceID); err != nil {
|
||||
l.Warnln("Failed to open web UI:", err)
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -378,7 +378,7 @@ func main() {
|
||||
if options.generateDir != "" {
|
||||
if err := generate(options.generateDir); err != nil {
|
||||
l.Warnln("Failed to generate config and keys:", err)
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -386,14 +386,14 @@ func main() {
|
||||
// Ensure that our home directory exists.
|
||||
if err := ensureDir(locations.GetBaseDir(locations.ConfigBaseDir), 0700); err != nil {
|
||||
l.Warnln("Failure on home directory:", err)
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
if options.upgradeTo != "" {
|
||||
err := upgrade.ToURL(options.upgradeTo)
|
||||
if err != nil {
|
||||
l.Warnln("Error while Upgrading:", err)
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
l.Infoln("Upgraded from", options.upgradeTo)
|
||||
return
|
||||
@ -424,13 +424,13 @@ func main() {
|
||||
os.Exit(exitCodeForUpgrade(err))
|
||||
}
|
||||
l.Infof("Upgraded to %q", release.Tag)
|
||||
os.Exit(util.ExitUpgrade.AsInt())
|
||||
os.Exit(svcutil.ExitUpgrade.AsInt())
|
||||
}
|
||||
|
||||
if options.resetDatabase {
|
||||
if err := resetDB(); err != nil {
|
||||
l.Warnln("Resetting database:", err)
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
l.Infoln("Successfully reset database - it will be rebuilt after next start.")
|
||||
return
|
||||
@ -610,7 +610,7 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
|
||||
cfg, err := syncthing.LoadConfigAtStartup(locations.Get(locations.ConfigFile), cert, evLogger, runtimeOptions.allowNewerConfig, noDefaultFolder)
|
||||
if err != nil {
|
||||
l.Warnln("Failed to initialize config:", err)
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
// Candidate builds should auto upgrade. Make sure the option is set,
|
||||
@ -656,7 +656,7 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
|
||||
}
|
||||
} else {
|
||||
l.Infof("Upgraded to %q, exiting now.", release.Tag)
|
||||
os.Exit(util.ExitUpgrade.AsInt())
|
||||
os.Exit(svcutil.ExitUpgrade.AsInt())
|
||||
}
|
||||
}
|
||||
|
||||
@ -684,7 +684,7 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
|
||||
app, err := syncthing.New(cfg, ldb, evLogger, cert, appOpts)
|
||||
if err != nil {
|
||||
l.Warnln("Failed to start Syncthing:", err)
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
if autoUpgradePossible {
|
||||
@ -701,18 +701,18 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
|
||||
f, err := os.Create(fmt.Sprintf("cpu-%d.pprof", os.Getpid()))
|
||||
if err != nil {
|
||||
l.Warnln("Creating profile:", err)
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
l.Warnln("Starting profile:", err)
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
}
|
||||
|
||||
go standbyMonitor(app, cfg)
|
||||
|
||||
if err := app.Start(); err != nil {
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
cleanConfigDirectory()
|
||||
@ -725,7 +725,7 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
|
||||
|
||||
status := app.Wait()
|
||||
|
||||
if status == util.ExitError {
|
||||
if status == svcutil.ExitError {
|
||||
l.Warnln("Syncthing stopped with error:", app.Error())
|
||||
}
|
||||
|
||||
@ -744,7 +744,7 @@ func setupSignalHandling(app *syncthing.App) {
|
||||
signal.Notify(restartSign, sigHup)
|
||||
go func() {
|
||||
<-restartSign
|
||||
app.Stop(util.ExitRestart)
|
||||
app.Stop(svcutil.ExitRestart)
|
||||
}()
|
||||
|
||||
// Exit with "success" code (no restart) on INT/TERM
|
||||
@ -753,7 +753,7 @@ func setupSignalHandling(app *syncthing.App) {
|
||||
signal.Notify(stopSign, os.Interrupt, sigTerm)
|
||||
go func() {
|
||||
<-stopSign
|
||||
app.Stop(util.ExitSuccess)
|
||||
app.Stop(svcutil.ExitSuccess)
|
||||
}()
|
||||
}
|
||||
|
||||
@ -790,7 +790,7 @@ func auditWriter(auditFile string) io.Writer {
|
||||
fd, err = os.OpenFile(auditFile, auditFlags, 0600)
|
||||
if err != nil {
|
||||
l.Warnln("Audit:", err)
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
auditDest = auditFile
|
||||
}
|
||||
@ -840,7 +840,7 @@ func standbyMonitor(app *syncthing.App, cfg config.Wrapper) {
|
||||
// things a moment to stabilize.
|
||||
time.Sleep(restartDelay)
|
||||
|
||||
app.Stop(util.ExitRestart)
|
||||
app.Stop(svcutil.ExitRestart)
|
||||
return
|
||||
}
|
||||
now = time.Now()
|
||||
@ -910,7 +910,7 @@ func autoUpgrade(cfg config.Wrapper, app *syncthing.App, evLogger events.Logger)
|
||||
sub.Unsubscribe()
|
||||
l.Warnf("Automatically upgraded to version %q. Restarting in 1 minute.", rel.Tag)
|
||||
time.Sleep(time.Minute)
|
||||
app.Stop(util.ExitUpgrade)
|
||||
app.Stop(svcutil.ExitUpgrade)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -998,13 +998,13 @@ func setPauseState(cfg config.Wrapper, paused bool) {
|
||||
}
|
||||
if _, err := cfg.Replace(raw); err != nil {
|
||||
l.Warnln("Cannot adjust paused state:", err)
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
}
|
||||
|
||||
func exitCodeForUpgrade(err error) int {
|
||||
if _, ok := err.(*errNoUpgrade); ok {
|
||||
return util.ExitNoUpgradeAvailable.AsInt()
|
||||
return svcutil.ExitNoUpgradeAvailable.AsInt()
|
||||
}
|
||||
return util.ExitError.AsInt()
|
||||
return svcutil.ExitError.AsInt()
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/locations"
|
||||
"github.com/syncthing/syncthing/lib/osutil"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -99,7 +99,7 @@ func monitorMain(runtimeOptions RuntimeOptions) {
|
||||
|
||||
if t := time.Since(restarts[0]); t < loopThreshold {
|
||||
l.Warnf("%d restarts in %v; not retrying further", countRestarts, t)
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
copy(restarts[0:], restarts[1:])
|
||||
@ -169,7 +169,7 @@ func monitorMain(runtimeOptions RuntimeOptions) {
|
||||
|
||||
if err == nil {
|
||||
// Successful exit indicates an intentional shutdown
|
||||
os.Exit(util.ExitSuccess.AsInt())
|
||||
os.Exit(svcutil.ExitSuccess.AsInt())
|
||||
}
|
||||
|
||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
@ -177,7 +177,7 @@ func monitorMain(runtimeOptions RuntimeOptions) {
|
||||
if stopped || runtimeOptions.noRestart {
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
if exitCode == util.ExitUpgrade.AsInt() {
|
||||
if exitCode == svcutil.ExitUpgrade.AsInt() {
|
||||
// Restart the monitor process to release the .old
|
||||
// binary as part of the upgrade process.
|
||||
l.Infoln("Restarting monitor...")
|
||||
@ -189,7 +189,7 @@ func monitorMain(runtimeOptions RuntimeOptions) {
|
||||
}
|
||||
|
||||
if runtimeOptions.noRestart {
|
||||
os.Exit(util.ExitError.AsInt())
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
l.Infoln("Syncthing exited:", err)
|
||||
|
@ -49,11 +49,11 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/model"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/rand"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
"github.com/syncthing/syncthing/lib/tlsutil"
|
||||
"github.com/syncthing/syncthing/lib/upgrade"
|
||||
"github.com/syncthing/syncthing/lib/ur"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
)
|
||||
|
||||
// matches a bcrypt hash and not too much else
|
||||
@ -89,7 +89,7 @@ type service struct {
|
||||
startedOnce chan struct{} // the service has started successfully at least once
|
||||
startupErr error
|
||||
listenerAddr net.Addr
|
||||
exitChan chan *util.FatalErr
|
||||
exitChan chan *svcutil.FatalErr
|
||||
|
||||
guiErrors logger.Recorder
|
||||
systemLog logger.Recorder
|
||||
@ -123,7 +123,7 @@ func New(id protocol.DeviceID, cfg config.Wrapper, assetDir, tlsDefaultCommonNam
|
||||
tlsDefaultCommonName: tlsDefaultCommonName,
|
||||
configChanged: make(chan struct{}),
|
||||
startedOnce: make(chan struct{}),
|
||||
exitChan: make(chan *util.FatalErr, 1),
|
||||
exitChan: make(chan *svcutil.FatalErr, 1),
|
||||
}
|
||||
}
|
||||
|
||||
@ -474,7 +474,7 @@ func (s *service) CommitConfiguration(from, to config.Configuration) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *service) fatal(err *util.FatalErr) {
|
||||
func (s *service) fatal(err *svcutil.FatalErr) {
|
||||
// s.exitChan is 1-buffered and whoever is first gets handled.
|
||||
select {
|
||||
case s.exitChan <- err:
|
||||
@ -915,9 +915,9 @@ func (s *service) getDebugFile(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *service) postSystemRestart(w http.ResponseWriter, r *http.Request) {
|
||||
s.flushResponse(`{"ok": "restarting"}`, w)
|
||||
|
||||
s.fatal(&util.FatalErr{
|
||||
s.fatal(&svcutil.FatalErr{
|
||||
Err: errors.New("restart initiated by rest API"),
|
||||
Status: util.ExitRestart,
|
||||
Status: svcutil.ExitRestart,
|
||||
})
|
||||
}
|
||||
|
||||
@ -944,17 +944,17 @@ func (s *service) postSystemReset(w http.ResponseWriter, r *http.Request) {
|
||||
s.flushResponse(`{"ok": "resetting folder `+folder+`"}`, w)
|
||||
}
|
||||
|
||||
s.fatal(&util.FatalErr{
|
||||
s.fatal(&svcutil.FatalErr{
|
||||
Err: errors.New("restart after db reset initiated by rest API"),
|
||||
Status: util.ExitRestart,
|
||||
Status: svcutil.ExitRestart,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *service) postSystemShutdown(w http.ResponseWriter, r *http.Request) {
|
||||
s.flushResponse(`{"ok": "shutting down"}`, w)
|
||||
s.fatal(&util.FatalErr{
|
||||
s.fatal(&svcutil.FatalErr{
|
||||
Err: errors.New("shutdown initiated by rest API"),
|
||||
Status: util.ExitSuccess,
|
||||
Status: svcutil.ExitSuccess,
|
||||
})
|
||||
}
|
||||
|
||||
@ -1390,9 +1390,9 @@ func (s *service) postSystemUpgrade(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
s.flushResponse(`{"ok": "restarting"}`, w)
|
||||
s.fatal(&util.FatalErr{
|
||||
s.fatal(&svcutil.FatalErr{
|
||||
Err: errors.New("exit after upgrade initiated by rest API"),
|
||||
Status: util.ExitUpgrade,
|
||||
Status: svcutil.ExitUpgrade,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -32,10 +32,10 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/fs"
|
||||
"github.com/syncthing/syncthing/lib/locations"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
"github.com/syncthing/syncthing/lib/tlsutil"
|
||||
"github.com/syncthing/syncthing/lib/ur"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
"github.com/thejerf/suture/v4"
|
||||
)
|
||||
|
||||
@ -119,7 +119,7 @@ func TestStopAfterBrokenConfig(t *testing.T) {
|
||||
defer os.Remove(token)
|
||||
srv.started = make(chan string)
|
||||
|
||||
sup := suture.New("test", util.SpecWithDebugLogger(l))
|
||||
sup := suture.New("test", svcutil.SpecWithDebugLogger(l))
|
||||
sup.Add(srv)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
sup.ServeBackground(ctx)
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
|
||||
"github.com/thejerf/suture/v4"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
)
|
||||
|
||||
type recv struct {
|
||||
@ -33,8 +33,8 @@ type Interface interface {
|
||||
type cast struct {
|
||||
*suture.Supervisor
|
||||
name string
|
||||
reader util.ServiceWithError
|
||||
writer util.ServiceWithError
|
||||
reader svcutil.ServiceWithError
|
||||
writer svcutil.ServiceWithError
|
||||
outbox chan recv
|
||||
inbox chan []byte
|
||||
stopped chan struct{}
|
||||
@ -45,7 +45,7 @@ type cast struct {
|
||||
// methods to get a functional implementation of Interface.
|
||||
func newCast(name string) *cast {
|
||||
// Only log restarts in debug mode.
|
||||
spec := util.SpecWithDebugLogger(l)
|
||||
spec := svcutil.SpecWithDebugLogger(l)
|
||||
// Don't retry too frenetically: an error to open a socket or
|
||||
// whatever is usually something that is either permanent or takes
|
||||
// a while to get solved...
|
||||
@ -58,7 +58,7 @@ func newCast(name string) *cast {
|
||||
outbox: make(chan recv, 16),
|
||||
stopped: make(chan struct{}),
|
||||
}
|
||||
util.OnSupervisorDone(c.Supervisor, func() { close(c.stopped) })
|
||||
svcutil.OnSupervisorDone(c.Supervisor, func() { close(c.stopped) })
|
||||
return c
|
||||
}
|
||||
|
||||
@ -72,8 +72,8 @@ func (c *cast) addWriter(svc func(ctx context.Context) error) {
|
||||
c.Add(c.writer)
|
||||
}
|
||||
|
||||
func (c *cast) createService(svc func(context.Context) error, suffix string) util.ServiceWithError {
|
||||
return util.AsService(svc, fmt.Sprintf("%s/%s", c, suffix))
|
||||
func (c *cast) createService(svc func(context.Context) error, suffix string) svcutil.ServiceWithError {
|
||||
return svcutil.AsService(svc, fmt.Sprintf("%s/%s", c, suffix))
|
||||
}
|
||||
|
||||
func (c *cast) String() string {
|
||||
|
@ -24,7 +24,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/connections/registry"
|
||||
"github.com/syncthing/syncthing/lib/nat"
|
||||
"github.com/syncthing/syncthing/lib/stun"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -35,7 +35,7 @@ func init() {
|
||||
}
|
||||
|
||||
type quicListener struct {
|
||||
util.ServiceWithError
|
||||
svcutil.ServiceWithError
|
||||
nat atomic.Value
|
||||
|
||||
onAddressesChangedNotifier
|
||||
@ -205,7 +205,7 @@ func (f *quicListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.
|
||||
conns: conns,
|
||||
factory: f,
|
||||
}
|
||||
l.ServiceWithError = util.AsService(l.serve, l.String())
|
||||
l.ServiceWithError = svcutil.AsService(l.serve, l.String())
|
||||
l.nat.Store(stun.NATUnknown)
|
||||
return l
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/dialer"
|
||||
"github.com/syncthing/syncthing/lib/nat"
|
||||
"github.com/syncthing/syncthing/lib/relay/client"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -30,7 +30,7 @@ func init() {
|
||||
}
|
||||
|
||||
type relayListener struct {
|
||||
util.ServiceWithError
|
||||
svcutil.ServiceWithError
|
||||
onAddressesChangedNotifier
|
||||
|
||||
uri *url.URL
|
||||
@ -184,7 +184,7 @@ func (f *relayListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls
|
||||
conns: conns,
|
||||
factory: f,
|
||||
}
|
||||
t.ServiceWithError = util.AsService(t.serve, t.String())
|
||||
t.ServiceWithError = svcutil.AsService(t.serve, t.String())
|
||||
return t
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/nat"
|
||||
"github.com/syncthing/syncthing/lib/osutil"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
|
||||
@ -143,7 +144,7 @@ type service struct {
|
||||
}
|
||||
|
||||
func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *tls.Config, discoverer discover.Finder, bepProtocolName string, tlsDefaultCommonName string, evLogger events.Logger) Service {
|
||||
spec := util.SpecWithInfoLogger(l)
|
||||
spec := svcutil.SpecWithInfoLogger(l)
|
||||
service := &service{
|
||||
Supervisor: suture.New("connections.Service", spec),
|
||||
connectionStatusHandler: newConnectionStatusHandler(),
|
||||
@ -191,12 +192,12 @@ func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *t
|
||||
// the common handling regardless of whether the connection was
|
||||
// incoming or outgoing.
|
||||
|
||||
service.Add(util.AsService(service.connect, fmt.Sprintf("%s/connect", service)))
|
||||
service.Add(util.AsService(service.handle, fmt.Sprintf("%s/handle", service)))
|
||||
service.Add(svcutil.AsService(service.connect, fmt.Sprintf("%s/connect", service)))
|
||||
service.Add(svcutil.AsService(service.handle, fmt.Sprintf("%s/handle", service)))
|
||||
service.Add(service.listenerSupervisor)
|
||||
service.Add(service.natService)
|
||||
|
||||
util.OnSupervisorDone(service.Supervisor, func() {
|
||||
svcutil.OnSupervisorDone(service.Supervisor, func() {
|
||||
service.cfg.Unsubscribe(service.limiter)
|
||||
service.cfg.Unsubscribe(service)
|
||||
})
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/connections/registry"
|
||||
"github.com/syncthing/syncthing/lib/dialer"
|
||||
"github.com/syncthing/syncthing/lib/nat"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -29,7 +29,7 @@ func init() {
|
||||
}
|
||||
|
||||
type tcpListener struct {
|
||||
util.ServiceWithError
|
||||
svcutil.ServiceWithError
|
||||
onAddressesChangedNotifier
|
||||
|
||||
uri *url.URL
|
||||
@ -207,7 +207,7 @@ func (f *tcpListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.C
|
||||
natService: natService,
|
||||
factory: f,
|
||||
}
|
||||
l.ServiceWithError = util.AsService(l.serve, l.String())
|
||||
l.ServiceWithError = svcutil.AsService(l.serve, l.String())
|
||||
return l
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/rand"
|
||||
"github.com/syncthing/syncthing/lib/sha256"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
"github.com/thejerf/suture/v4"
|
||||
@ -73,7 +74,7 @@ type Lowlevel struct {
|
||||
|
||||
func NewLowlevel(backend backend.Backend, evLogger events.Logger, opts ...Option) (*Lowlevel, error) {
|
||||
// Only log restarts in debug mode.
|
||||
spec := util.SpecWithDebugLogger(l)
|
||||
spec := svcutil.SpecWithDebugLogger(l)
|
||||
db := &Lowlevel{
|
||||
Supervisor: suture.New("db.Lowlevel", spec),
|
||||
Backend: backend,
|
||||
@ -89,7 +90,7 @@ func NewLowlevel(backend backend.Backend, evLogger events.Logger, opts ...Option
|
||||
opt(db)
|
||||
}
|
||||
db.keyer = newDefaultKeyer(db.folderIdx, db.deviceIdx)
|
||||
db.Add(util.AsService(db.gcRunner, "db.Lowlevel/gcRunner"))
|
||||
db.Add(svcutil.AsService(db.gcRunner, "db.Lowlevel/gcRunner"))
|
||||
if path := db.needsRepairPath(); path != "" {
|
||||
if _, err := os.Lstat(path); err == nil {
|
||||
l.Infoln("Database was marked for repair - this may take a while")
|
||||
|
@ -24,7 +24,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/rand"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
"github.com/thejerf/suture/v4"
|
||||
)
|
||||
|
||||
@ -52,7 +52,7 @@ const (
|
||||
|
||||
func NewLocal(id protocol.DeviceID, addr string, addrList AddressLister, evLogger events.Logger) (FinderService, error) {
|
||||
c := &localClient{
|
||||
Supervisor: suture.New("local", util.SpecWithDebugLogger(l)),
|
||||
Supervisor: suture.New("local", svcutil.SpecWithDebugLogger(l)),
|
||||
myID: id,
|
||||
addrList: addrList,
|
||||
evLogger: evLogger,
|
||||
@ -81,9 +81,9 @@ func NewLocal(id protocol.DeviceID, addr string, addrList AddressLister, evLogge
|
||||
c.beacon = beacon.NewMulticast(addr)
|
||||
}
|
||||
c.Add(c.beacon)
|
||||
c.Add(util.AsService(c.recvAnnouncements, fmt.Sprintf("%s/recv", c)))
|
||||
c.Add(svcutil.AsService(c.recvAnnouncements, fmt.Sprintf("%s/recv", c)))
|
||||
|
||||
c.Add(util.AsService(c.sendLocalAnnouncements, fmt.Sprintf("%s/sendLocal", c)))
|
||||
c.Add(svcutil.AsService(c.sendLocalAnnouncements, fmt.Sprintf("%s/sendLocal", c)))
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
)
|
||||
@ -47,7 +48,7 @@ type manager struct {
|
||||
|
||||
func NewManager(myID protocol.DeviceID, cfg config.Wrapper, cert tls.Certificate, evLogger events.Logger, lister AddressLister) Manager {
|
||||
m := &manager{
|
||||
Supervisor: suture.New("discover.Manager", util.SpecWithDebugLogger(l)),
|
||||
Supervisor: suture.New("discover.Manager", svcutil.SpecWithDebugLogger(l)),
|
||||
myID: myID,
|
||||
cfg: cfg,
|
||||
cert: cert,
|
||||
@ -57,7 +58,7 @@ func NewManager(myID protocol.DeviceID, cfg config.Wrapper, cert tls.Certificate
|
||||
finders: make(map[string]cachedFinder),
|
||||
mut: sync.NewRWMutex(),
|
||||
}
|
||||
m.Add(util.AsService(m.serve, m.String()))
|
||||
m.Add(svcutil.AsService(m.serve, m.String()))
|
||||
return m
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,8 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/db"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
)
|
||||
|
||||
const maxDurationSinceLastEventReq = time.Minute
|
||||
@ -52,7 +52,7 @@ type folderSummaryService struct {
|
||||
|
||||
func NewFolderSummaryService(cfg config.Wrapper, m Model, id protocol.DeviceID, evLogger events.Logger) FolderSummaryService {
|
||||
service := &folderSummaryService{
|
||||
Supervisor: suture.New("folderSummaryService", util.SpecWithDebugLogger(l)),
|
||||
Supervisor: suture.New("folderSummaryService", svcutil.SpecWithDebugLogger(l)),
|
||||
cfg: cfg,
|
||||
model: m,
|
||||
id: id,
|
||||
@ -63,8 +63,8 @@ func NewFolderSummaryService(cfg config.Wrapper, m Model, id protocol.DeviceID,
|
||||
lastEventReqMut: sync.NewMutex(),
|
||||
}
|
||||
|
||||
service.Add(util.AsService(service.listenForUpdates, fmt.Sprintf("%s/listenForUpdates", service)))
|
||||
service.Add(util.AsService(service.calculateSummaries, fmt.Sprintf("%s/calculateSummaries", service)))
|
||||
service.Add(svcutil.AsService(service.listenForUpdates, fmt.Sprintf("%s/listenForUpdates", service)))
|
||||
service.Add(svcutil.AsService(service.calculateSummaries, fmt.Sprintf("%s/calculateSummaries", service)))
|
||||
|
||||
return service
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/db"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
)
|
||||
|
||||
type indexSender struct {
|
||||
@ -38,7 +38,7 @@ type indexSender struct {
|
||||
func (s *indexSender) Serve(ctx context.Context) (err error) {
|
||||
l.Debugf("Starting indexSender for %s to %s at %s (slv=%d)", s.folder, s.conn.ID(), s.conn, s.prevSequence)
|
||||
defer func() {
|
||||
err = util.NoRestartErr(err)
|
||||
err = svcutil.NoRestartErr(err)
|
||||
l.Debugf("Exiting indexSender for %s to %s at %s: %v", s.folder, s.conn.ID(), s.conn, err)
|
||||
}()
|
||||
|
||||
|
@ -33,9 +33,9 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/scanner"
|
||||
"github.com/syncthing/syncthing/lib/stats"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
"github.com/syncthing/syncthing/lib/ur/contract"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
"github.com/syncthing/syncthing/lib/versioner"
|
||||
)
|
||||
|
||||
@ -199,7 +199,7 @@ var (
|
||||
// where it sends index information to connected peers and responds to requests
|
||||
// for file data without altering the local folder in any way.
|
||||
func NewModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersion string, ldb *db.Lowlevel, protectedFiles []string, evLogger events.Logger) Model {
|
||||
spec := util.SpecWithDebugLogger(l)
|
||||
spec := svcutil.SpecWithDebugLogger(l)
|
||||
m := &model{
|
||||
Supervisor: suture.New("model", spec),
|
||||
|
||||
@ -249,7 +249,7 @@ func NewModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersio
|
||||
m.deviceStatRefs[devID] = stats.NewDeviceStatisticsReference(m.db, devID.String())
|
||||
}
|
||||
m.Add(m.progressEmitter)
|
||||
m.Add(util.AsService(m.serve, m.String()))
|
||||
m.Add(svcutil.AsService(m.serve, m.String()))
|
||||
|
||||
return m
|
||||
}
|
||||
@ -262,7 +262,7 @@ func (m *model) serve(ctx context.Context) error {
|
||||
|
||||
if err := m.initFolders(); err != nil {
|
||||
close(m.started)
|
||||
return util.AsFatalErr(err, util.ExitError)
|
||||
return svcutil.AsFatalErr(err, svcutil.ExitError)
|
||||
}
|
||||
|
||||
close(m.started)
|
||||
@ -271,7 +271,7 @@ func (m *model) serve(ctx context.Context) error {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case err := <-m.fatalChan:
|
||||
return util.AsFatalErr(err, util.ExitError)
|
||||
return svcutil.AsFatalErr(err, svcutil.ExitError)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/relay/protocol"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
|
||||
"github.com/thejerf/suture/v4"
|
||||
)
|
||||
@ -45,7 +45,7 @@ func NewClient(uri *url.URL, certs []tls.Certificate, invitations chan protocol.
|
||||
}
|
||||
|
||||
type commonClient struct {
|
||||
util.ServiceWithError
|
||||
svcutil.ServiceWithError
|
||||
|
||||
invitations chan protocol.SessionInvitation
|
||||
closeInvitationsOnFinish bool
|
||||
@ -61,7 +61,7 @@ func newCommonClient(invitations chan protocol.SessionInvitation, serve func(con
|
||||
defer c.cleanup()
|
||||
return serve(ctx)
|
||||
}
|
||||
c.ServiceWithError = util.AsService(newServe, creator)
|
||||
c.ServiceWithError = svcutil.AsService(newServe, creator)
|
||||
if c.invitations == nil {
|
||||
c.closeInvitationsOnFinish = true
|
||||
c.invitations = make(chan protocol.SessionInvitation)
|
||||
|
177
lib/svcutil/svcutil.go
Normal file
177
lib/svcutil/svcutil.go
Normal file
@ -0,0 +1,177 @@
|
||||
// Copyright (C) 2016 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package svcutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
|
||||
"github.com/thejerf/suture/v4"
|
||||
)
|
||||
|
||||
const ServiceTimeout = 10 * time.Second
|
||||
|
||||
type FatalErr struct {
|
||||
Err error
|
||||
Status ExitStatus
|
||||
}
|
||||
|
||||
// AsFatalErr wraps the given error creating a FatalErr. If the given error
|
||||
// already is of type FatalErr, it is not wrapped again.
|
||||
func AsFatalErr(err error, status ExitStatus) *FatalErr {
|
||||
var ferr *FatalErr
|
||||
if errors.As(err, &ferr) {
|
||||
return ferr
|
||||
}
|
||||
return &FatalErr{
|
||||
Err: err,
|
||||
Status: status,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *FatalErr) Error() string {
|
||||
return e.Err.Error()
|
||||
}
|
||||
|
||||
func (e *FatalErr) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
func (e *FatalErr) Is(target error) bool {
|
||||
return target == suture.ErrTerminateSupervisorTree
|
||||
}
|
||||
|
||||
// NoRestartErr wraps the given error err (which may be nil) to make sure that
|
||||
// `errors.Is(err, suture.ErrDoNotRestart) == true`.
|
||||
func NoRestartErr(err error) error {
|
||||
if err == nil {
|
||||
return suture.ErrDoNotRestart
|
||||
}
|
||||
return &noRestartErr{err}
|
||||
}
|
||||
|
||||
type noRestartErr struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *noRestartErr) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
func (e *noRestartErr) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
func (e *noRestartErr) Is(target error) bool {
|
||||
return target == suture.ErrDoNotRestart
|
||||
}
|
||||
|
||||
type ExitStatus int
|
||||
|
||||
const (
|
||||
ExitSuccess ExitStatus = 0
|
||||
ExitError ExitStatus = 1
|
||||
ExitNoUpgradeAvailable ExitStatus = 2
|
||||
ExitRestart ExitStatus = 3
|
||||
ExitUpgrade ExitStatus = 4
|
||||
)
|
||||
|
||||
func (s ExitStatus) AsInt() int {
|
||||
return int(s)
|
||||
}
|
||||
|
||||
type ServiceWithError interface {
|
||||
suture.Service
|
||||
fmt.Stringer
|
||||
Error() error
|
||||
SetError(error)
|
||||
}
|
||||
|
||||
// AsService wraps the given function to implement suture.Service. In addition
|
||||
// it keeps track of the returned error and allows querying and setting that error.
|
||||
func AsService(fn func(ctx context.Context) error, creator string) ServiceWithError {
|
||||
return &service{
|
||||
creator: creator,
|
||||
serve: fn,
|
||||
mut: sync.NewMutex(),
|
||||
}
|
||||
}
|
||||
|
||||
type service struct {
|
||||
creator string
|
||||
serve func(ctx context.Context) error
|
||||
err error
|
||||
mut sync.Mutex
|
||||
}
|
||||
|
||||
func (s *service) Serve(ctx context.Context) error {
|
||||
s.mut.Lock()
|
||||
s.err = nil
|
||||
s.mut.Unlock()
|
||||
|
||||
err := s.serve(ctx)
|
||||
|
||||
s.mut.Lock()
|
||||
s.err = err
|
||||
s.mut.Unlock()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *service) Error() error {
|
||||
s.mut.Lock()
|
||||
defer s.mut.Unlock()
|
||||
return s.err
|
||||
}
|
||||
|
||||
func (s *service) SetError(err error) {
|
||||
s.mut.Lock()
|
||||
s.err = err
|
||||
s.mut.Unlock()
|
||||
}
|
||||
|
||||
func (s *service) String() string {
|
||||
return fmt.Sprintf("Service@%p created by %v", s, s.creator)
|
||||
|
||||
}
|
||||
|
||||
type doneService struct {
|
||||
fn func()
|
||||
}
|
||||
|
||||
func (s *doneService) Serve(ctx context.Context) error {
|
||||
<-ctx.Done()
|
||||
s.fn()
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnSupervisorDone calls fn when sup is done.
|
||||
func OnSupervisorDone(sup *suture.Supervisor, fn func()) {
|
||||
sup.Add(&doneService{fn})
|
||||
}
|
||||
|
||||
func SpecWithDebugLogger(l logger.Logger) suture.Spec {
|
||||
return spec(func(e suture.Event) { l.Debugln(e) })
|
||||
}
|
||||
|
||||
func SpecWithInfoLogger(l logger.Logger) suture.Spec {
|
||||
return spec(func(e suture.Event) { l.Infoln(e) })
|
||||
}
|
||||
|
||||
func spec(eventHook suture.EventHook) suture.Spec {
|
||||
return suture.Spec{
|
||||
EventHook: eventHook,
|
||||
Timeout: ServiceTimeout,
|
||||
PassThroughPanics: true,
|
||||
DontPropagateTermination: false,
|
||||
}
|
||||
}
|
@ -37,10 +37,10 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/rand"
|
||||
"github.com/syncthing/syncthing/lib/sha256"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
"github.com/syncthing/syncthing/lib/tlsutil"
|
||||
"github.com/syncthing/syncthing/lib/upgrade"
|
||||
"github.com/syncthing/syncthing/lib/ur"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -73,7 +73,7 @@ type App struct {
|
||||
evLogger events.Logger
|
||||
cert tls.Certificate
|
||||
opts Options
|
||||
exitStatus util.ExitStatus
|
||||
exitStatus svcutil.ExitStatus
|
||||
err error
|
||||
stopOnce sync.Once
|
||||
mainServiceCancel context.CancelFunc
|
||||
@ -103,7 +103,7 @@ func New(cfg config.Wrapper, dbBackend backend.Backend, evLogger events.Logger,
|
||||
func (a *App) Start() error {
|
||||
// Create a main service manager. We'll add things to this as we go along.
|
||||
// We want any logging it does to go through our log system.
|
||||
spec := util.SpecWithDebugLogger(l)
|
||||
spec := svcutil.SpecWithDebugLogger(l)
|
||||
a.mainService = suture.New("main", spec)
|
||||
|
||||
// Start the supervisor and wait for it to stop to handle cleanup.
|
||||
@ -113,7 +113,7 @@ func (a *App) Start() error {
|
||||
go a.run(ctx)
|
||||
|
||||
if err := a.startup(); err != nil {
|
||||
a.stopWithErr(util.ExitError, err)
|
||||
a.stopWithErr(svcutil.ExitError, err)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -355,19 +355,19 @@ func (a *App) handleMainServiceError(err error) {
|
||||
if err == nil || errors.Is(err, context.Canceled) {
|
||||
return
|
||||
}
|
||||
var fatalErr *util.FatalErr
|
||||
var fatalErr *svcutil.FatalErr
|
||||
if errors.As(err, &fatalErr) {
|
||||
a.exitStatus = fatalErr.Status
|
||||
a.err = fatalErr.Err
|
||||
return
|
||||
}
|
||||
a.err = err
|
||||
a.exitStatus = util.ExitError
|
||||
a.exitStatus = svcutil.ExitError
|
||||
}
|
||||
|
||||
// Wait blocks until the app stops running. Also returns if the app hasn't been
|
||||
// started yet.
|
||||
func (a *App) Wait() util.ExitStatus {
|
||||
func (a *App) Wait() svcutil.ExitStatus {
|
||||
<-a.stopped
|
||||
return a.exitStatus
|
||||
}
|
||||
@ -385,11 +385,11 @@ func (a *App) Error() error {
|
||||
|
||||
// Stop stops the app and sets its exit status to given reason, unless the app
|
||||
// was already stopped before. In any case it returns the effective exit status.
|
||||
func (a *App) Stop(stopReason util.ExitStatus) util.ExitStatus {
|
||||
func (a *App) Stop(stopReason svcutil.ExitStatus) svcutil.ExitStatus {
|
||||
return a.stopWithErr(stopReason, nil)
|
||||
}
|
||||
|
||||
func (a *App) stopWithErr(stopReason util.ExitStatus, err error) util.ExitStatus {
|
||||
func (a *App) stopWithErr(stopReason svcutil.ExitStatus, err error) svcutil.ExitStatus {
|
||||
a.stopOnce.Do(func() {
|
||||
a.exitStatus = stopReason
|
||||
a.err = err
|
||||
|
@ -17,8 +17,8 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/db/backend"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
"github.com/syncthing/syncthing/lib/tlsutil"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
)
|
||||
|
||||
func tempCfgFilename(t *testing.T) string {
|
||||
@ -90,7 +90,7 @@ func TestStartupFail(t *testing.T) {
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
var waitE util.ExitStatus
|
||||
var waitE svcutil.ExitStatus
|
||||
go func() {
|
||||
waitE = app.Wait()
|
||||
close(done)
|
||||
@ -102,8 +102,8 @@ func TestStartupFail(t *testing.T) {
|
||||
case <-done:
|
||||
}
|
||||
|
||||
if waitE != util.ExitError {
|
||||
t.Errorf("Got exit status %v, expected %v", waitE, util.ExitError)
|
||||
if waitE != svcutil.ExitError {
|
||||
t.Errorf("Got exit status %v, expected %v", waitE, svcutil.ExitError)
|
||||
}
|
||||
|
||||
if err = app.Error(); err != startErr {
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/dialer"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
|
||||
"github.com/thejerf/suture/v4"
|
||||
)
|
||||
@ -28,6 +29,7 @@ var (
|
||||
minDelay = 10 * time.Second
|
||||
maxDelay = time.Minute
|
||||
sendTimeout = time.Minute
|
||||
finalSendTimeout = svcutil.ServiceTimeout / 2
|
||||
evChanClosed = "failure event channel closed"
|
||||
invalidEventDataType = "failure event data is not a string"
|
||||
)
|
||||
@ -116,11 +118,7 @@ outer:
|
||||
now := time.Now()
|
||||
for descr, stat := range h.buf {
|
||||
if now.Sub(stat.last) > minDelay || now.Sub(stat.first) > maxDelay {
|
||||
reports = append(reports, FailureReport{
|
||||
Description: descr,
|
||||
Count: stat.count,
|
||||
Version: build.LongVersion,
|
||||
})
|
||||
reports = append(reports, newFailureReport(descr, stat.count))
|
||||
delete(h.buf, descr)
|
||||
}
|
||||
}
|
||||
@ -145,6 +143,13 @@ outer:
|
||||
|
||||
if sub != nil {
|
||||
sub.Unsubscribe()
|
||||
reports := make([]FailureReport, 0, len(h.buf))
|
||||
for descr, stat := range h.buf {
|
||||
reports = append(reports, newFailureReport(descr, stat.count))
|
||||
}
|
||||
timeout, cancel := context.WithTimeout(context.Background(), finalSendTimeout)
|
||||
defer cancel()
|
||||
sendFailureReports(timeout, reports, url)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@ -207,3 +212,11 @@ func sendFailureReports(ctx context.Context, reports []FailureReport, url string
|
||||
resp.Body.Close()
|
||||
return
|
||||
}
|
||||
|
||||
func newFailureReport(descr string, count int) FailureReport {
|
||||
return FailureReport{
|
||||
Description: descr,
|
||||
Count: count,
|
||||
Version: build.LongVersion,
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
@ -17,9 +16,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
|
||||
"github.com/thejerf/suture/v4"
|
||||
)
|
||||
|
||||
@ -263,19 +259,6 @@ type FatalErr struct {
|
||||
Status ExitStatus
|
||||
}
|
||||
|
||||
// AsFatalErr wraps the given error creating a FatalErr. If the given error
|
||||
// already is of type FatalErr, it is not wrapped again.
|
||||
func AsFatalErr(err error, status ExitStatus) *FatalErr {
|
||||
var ferr *FatalErr
|
||||
if errors.As(err, &ferr) {
|
||||
return ferr
|
||||
}
|
||||
return &FatalErr{
|
||||
Err: err,
|
||||
Status: status,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *FatalErr) Error() string {
|
||||
return e.Err.Error()
|
||||
}
|
||||
@ -327,61 +310,6 @@ func (s ExitStatus) AsInt() int {
|
||||
return int(s)
|
||||
}
|
||||
|
||||
type ServiceWithError interface {
|
||||
suture.Service
|
||||
fmt.Stringer
|
||||
Error() error
|
||||
SetError(error)
|
||||
}
|
||||
|
||||
// AsService wraps the given function to implement suture.Service. In addition
|
||||
// it keeps track of the returned error and allows querying and setting that error.
|
||||
func AsService(fn func(ctx context.Context) error, creator string) ServiceWithError {
|
||||
return &service{
|
||||
creator: creator,
|
||||
serve: fn,
|
||||
mut: sync.NewMutex(),
|
||||
}
|
||||
}
|
||||
|
||||
type service struct {
|
||||
creator string
|
||||
serve func(ctx context.Context) error
|
||||
err error
|
||||
mut sync.Mutex
|
||||
}
|
||||
|
||||
func (s *service) Serve(ctx context.Context) error {
|
||||
s.mut.Lock()
|
||||
s.err = nil
|
||||
s.mut.Unlock()
|
||||
|
||||
err := s.serve(ctx)
|
||||
|
||||
s.mut.Lock()
|
||||
s.err = err
|
||||
s.mut.Unlock()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *service) Error() error {
|
||||
s.mut.Lock()
|
||||
defer s.mut.Unlock()
|
||||
return s.err
|
||||
}
|
||||
|
||||
func (s *service) SetError(err error) {
|
||||
s.mut.Lock()
|
||||
s.err = err
|
||||
s.mut.Unlock()
|
||||
}
|
||||
|
||||
func (s *service) String() string {
|
||||
return fmt.Sprintf("Service@%p created by %v", s, s.creator)
|
||||
|
||||
}
|
||||
|
||||
// OnDone calls fn when ctx is cancelled.
|
||||
func OnDone(ctx context.Context, fn func()) {
|
||||
go func() {
|
||||
@ -390,37 +318,6 @@ func OnDone(ctx context.Context, fn func()) {
|
||||
}()
|
||||
}
|
||||
|
||||
type doneService struct {
|
||||
fn func()
|
||||
}
|
||||
|
||||
func (s *doneService) Serve(ctx context.Context) error {
|
||||
<-ctx.Done()
|
||||
s.fn()
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnSupervisorDone calls fn when sup is done.
|
||||
func OnSupervisorDone(sup *suture.Supervisor, fn func()) {
|
||||
sup.Add(&doneService{fn})
|
||||
}
|
||||
|
||||
func SpecWithDebugLogger(l logger.Logger) suture.Spec {
|
||||
return spec(func(e suture.Event) { l.Debugln(e) })
|
||||
}
|
||||
|
||||
func SpecWithInfoLogger(l logger.Logger) suture.Spec {
|
||||
return spec(func(e suture.Event) { l.Infoln(e) })
|
||||
}
|
||||
|
||||
func spec(eventHook suture.EventHook) suture.Spec {
|
||||
return suture.Spec{
|
||||
EventHook: eventHook,
|
||||
PassThroughPanics: true,
|
||||
DontPropagateTermination: false,
|
||||
}
|
||||
}
|
||||
|
||||
func CallWithContext(ctx context.Context, fn func() error) error {
|
||||
var err error
|
||||
done := make(chan struct{})
|
||||
|
Loading…
Reference in New Issue
Block a user