mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-14 01:04:14 +00:00
174 lines
3.4 KiB
Go
174 lines
3.4 KiB
Go
// 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 IsFatal(err error) bool {
|
|
ferr := &FatalErr{}
|
|
return errors.As(err, &ferr)
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// AsService wraps the given function to implement suture.Service. In addition
|
|
// it keeps track of the returned error and allows querying 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) String() string {
|
|
return fmt.Sprintf("Service@%p created by %v", s, s.creator)
|
|
|
|
}
|
|
|
|
type doneService func()
|
|
|
|
func (fn doneService) Serve(ctx context.Context) error {
|
|
<-ctx.Done()
|
|
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,
|
|
}
|
|
}
|