package api import ( "github.com/pkg/errors" "gitlab.com/elixxir/client/stoppable" "sync" "time" ) // a service process starts itself in a new thread, returning from the // originator a stopable to control it type Service func() (stoppable.Stoppable, error) type services struct { services []Service stoppable *stoppable.Multi state Status mux sync.Mutex } // newServiceProcessiesList creates a new services list which will add its // services to the passed mux func newServices() *services { return &services{ services: make([]Service, 0), stoppable: stoppable.NewMulti("services"), state: Stopped, } } // Add adds the service process to the list and adds it to the multi-stopable. // Start running it if services are running func (s *services) add(sp Service) error { s.mux.Lock() defer s.mux.Unlock() //append the process to the list s.services = append(s.services, sp) //if services are running, start the process if s.state == Running { stop, err := sp() if err != nil { return errors.WithMessage(err, "Failed to start added service") } s.stoppable.Add(stop) } return nil } // Runs all services. If they are in the process of stopping, // it will wait for the stop to complete or the timeout to ellapse // Will error if already running func (s *services) start(timeout time.Duration) error { s.mux.Lock() defer s.mux.Unlock() //handle various states switch s.state { case Stopped: break case Running: return errors.New("Cannot start services when already Running") case Stopping: err := stoppable.WaitForStopped(s.stoppable, timeout) if err != nil { return errors.Errorf("Procesies did not all stop within %s, "+ "unable to start services: %+v", timeout, err) } } //create a new stopable s.stoppable = stoppable.NewMulti(followerStoppableName) //start all services and register with the stoppable for _, sp := range s.services { stop, err := sp() if err != nil { return errors.WithMessage(err, "Failed to start added service") } s.stoppable.Add(stop) } s.state = Running return nil } // Stops all currently running services. Will return an // error if the state is not "running" func (s *services) stop() error { s.mux.Lock() defer s.mux.Unlock() if s.state != Running { return errors.Errorf("cannot stop services when they "+ "are not Running, services are: %s", s.state) } s.state = Stopping if err := s.stoppable.Close(); err != nil { return errors.WithMessage(err, "Failed to stop services") } s.state = Stopped return nil } // returns the current state of services func (s *services) status() Status { s.mux.Lock() defer s.mux.Unlock() return s.state }