Skip to content
Snippets Groups Projects
Select Git revision
  • f78427b990a185d852a7fbd9446f8784109b09d9
  • release default
  • master protected
  • hotfix/gtnNoToken
  • XX-4441
  • Jakub/rootless-CI
  • jonah/refactorProviders
  • Ace/Huawei
  • AceVentura/AccountBackup
  • hotfix/delete-error
  • waitingRoundsRewrite
  • dev
  • quantumSecure
  • hotfix/ratelimit
  • fullRateLimit
  • XX-3564/TlsCipherSuite
  • hotfix/notifications-db
  • hotfix/groupNotification
  • Project/LastMile
  • notls
  • url-repo-rename
  • v2.3.0
  • v2.2.0
  • v2.1.0
  • v2.0.0
  • v1.0.0
26 results

go.mod

Blame
  • This project manages its dependencies using Go Modules. Learn more
    single.go 3.32 KiB
    ///////////////////////////////////////////////////////////////////////////////
    // Copyright © 2020 xx network SEZC                                          //
    //                                                                           //
    // Use of this source code is governed by a license that can be found in the //
    // LICENSE file                                                              //
    ///////////////////////////////////////////////////////////////////////////////
    
    package stoppable
    
    import (
    	"github.com/pkg/errors"
    	jww "github.com/spf13/jwalterweatherman"
    	"sync"
    	"sync/atomic"
    )
    
    // Error message.
    const toStoppingErr = "failed to set the status of single stoppable %q to " +
    	"stopped when status is %s instead of %s"
    
    // Single allows stopping a single goroutine using a channel. It adheres to the
    // Stoppable interface.
    type Single struct {
    	name   string
    	quit   chan struct{}
    	status Status
    	once   sync.Once
    }
    
    // NewSingle returns a new single Stoppable.
    func NewSingle(name string) *Single {
    	return &Single{
    		name:   name,
    		quit:   make(chan struct{}, 1),
    		status: Running,
    	}
    }
    
    // Name returns the name of the Single Stoppable.
    func (s *Single) Name() string {
    	return s.name
    }
    
    // GetStatus returns the status of the Stoppable.
    func (s *Single) GetStatus() Status {
    	return Status(atomic.LoadUint32((*uint32)(&s.status)))
    }
    
    // IsRunning returns true if Stoppable is marked as running.
    func (s *Single) IsRunning() bool {
    	return s.GetStatus() == Running
    }
    
    // IsStopping returns true if Stoppable is marked as stopping.
    func (s *Single) IsStopping() bool {
    	return s.GetStatus() == Stopping
    }
    
    // IsStopped returns true if Stoppable is marked as stopped.
    func (s *Single) IsStopped() bool {
    	return s.GetStatus() == Stopped
    }
    
    // toStopping changes the status from running to stopping. An error is returned
    // if the status is not already set to running.
    func (s *Single) toStopping() error {
    	if !atomic.CompareAndSwapUint32((*uint32)(&s.status), uint32(Running), uint32(Stopping)) {
    		return errors.Errorf(toStoppingErr, s.Name(), s.GetStatus(), Running)
    	}
    
    	jww.TRACE.Printf("Switched status of single stoppable %q from %s to %s.",
    		s.Name(), Running, Stopping)
    
    	return nil
    }
    
    // ToStopped changes the status from stopping to stopped. Panics if the status
    // is not already set to stopping.
    func (s *Single) ToStopped() {
    	if !atomic.CompareAndSwapUint32((*uint32)(&s.status), uint32(Stopping), uint32(Stopped)) {
    		jww.FATAL.Panicf("Failed to set the status of single stoppable %q to "+
    			"stopped when status is %s instead of %s.",
    			s.Name(), s.GetStatus(), Stopping)
    	}
    
    	jww.TRACE.Printf("Switched status of single stoppable %q from %s to %s.",
    		s.Name(), Stopping, Stopped)
    }
    
    // Quit returns a receive-only channel that will be triggered when the Stoppable
    // quits.
    func (s *Single) Quit() <-chan struct{} {
    	return s.quit
    }
    
    // Close signals the Single to close via the quit channel. Returns an error if
    // the status of the Single is not Running.
    func (s *Single) Close() error {
    	var err error
    
    	s.once.Do(func() {
    		// Attempt to set status to stopping or return an error if unable
    		err = s.toStopping()
    		if err != nil {
    			return
    		}
    
    		jww.TRACE.Printf("Sending on quit channel to single stoppable %q.",
    			s.Name())
    
    		// Send on quit channel
    		s.quit <- struct{}{}
    	})
    
    	if err != nil {
    		jww.ERROR.Print(err.Error())
    	}
    
    	return err
    }