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