github.com/mutagen-io/mutagen@v0.18.0-rc1/pkg/service/daemon/server.go (about)

     1  package daemon
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	"github.com/mutagen-io/mutagen/pkg/housekeeping"
     8  	"github.com/mutagen-io/mutagen/pkg/mutagen"
     9  )
    10  
    11  const (
    12  	// housekeepingInterval is the interval at which housekeeping will be
    13  	// invoked by the daemon.
    14  	housekeepingInterval = 24 * time.Hour
    15  )
    16  
    17  // Server provides an implementation of the Daemon service.
    18  type Server struct {
    19  	// UnimplementedDaemonServer is the required base implementation.
    20  	UnimplementedDaemonServer
    21  	// Termination is populated with requests from clients invoking the shutdown
    22  	// method over RPC. It can be ignored by daemon host processes wishing to
    23  	// ignore temination requests originating from clients. The channel is
    24  	// buffered and non-blocking, so it doesn't need to be serviced by the
    25  	// daemon host-process at all - additional incoming shutdown requests will
    26  	// just bounce off once the channel is populated. We do this, instead of
    27  	// closing the channel, because we can't close the channel multiple times.
    28  	Termination chan struct{}
    29  	// workerCtx is the context regulating the server's internal operations.
    30  	workerCtx context.Context
    31  	// shutdown is the context cancellation function for the server's internal
    32  	// operation context.
    33  	shutdown context.CancelFunc
    34  }
    35  
    36  // NewServer creates a new daemon server.
    37  func NewServer() *Server {
    38  	// Create a cancellable context for daemon background operations.
    39  	workerCtx, shutdown := context.WithCancel(context.Background())
    40  
    41  	// Create the server.
    42  	server := &Server{
    43  		Termination: make(chan struct{}, 1),
    44  		workerCtx:   workerCtx,
    45  		shutdown:    shutdown,
    46  	}
    47  
    48  	// Start the housekeeping Goroutine.
    49  	go server.housekeep()
    50  
    51  	// Done.
    52  	return server
    53  }
    54  
    55  // housekeep provides regular housekeeping facilities for the daemon.
    56  func (s *Server) housekeep() {
    57  	// Perform an initial housekeeping operation since the ticker won't fire
    58  	// straight away.
    59  	housekeeping.Housekeep()
    60  
    61  	// Create a ticker to regulate housekeeping and defer its shutdown.
    62  	ticker := time.NewTicker(housekeepingInterval)
    63  	defer ticker.Stop()
    64  
    65  	// Loop and wait for the ticker or cancellation.
    66  	for {
    67  		select {
    68  		case <-s.workerCtx.Done():
    69  			return
    70  		case <-ticker.C:
    71  			housekeeping.Housekeep()
    72  		}
    73  	}
    74  }
    75  
    76  // Shutdown gracefully shuts down server resources.
    77  func (s *Server) Shutdown() {
    78  	// Cancel all internal operations.
    79  	s.shutdown()
    80  }
    81  
    82  // Version provides version information.
    83  func (s *Server) Version(_ context.Context, _ *VersionRequest) (*VersionResponse, error) {
    84  	return &VersionResponse{
    85  		Major: mutagen.VersionMajor,
    86  		Minor: mutagen.VersionMinor,
    87  		Patch: mutagen.VersionPatch,
    88  		Tag:   mutagen.VersionTag,
    89  	}, nil
    90  }
    91  
    92  // Terminate requests daemon termination.
    93  func (s *Server) Terminate(_ context.Context, _ *TerminateRequest) (*TerminateResponse, error) {
    94  	// Send the termination request in a non-blocking manner.
    95  	select {
    96  	case s.Termination <- struct{}{}:
    97  	default:
    98  	}
    99  
   100  	// Success.
   101  	return &TerminateResponse{}, nil
   102  }