Skip to content

Commit

Permalink
Break out usage reporting into a service
Browse files Browse the repository at this point in the history
  • Loading branch information
calmh committed May 13, 2015
1 parent 83ea8dc commit c6b2ca8
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 31 deletions.
8 changes: 1 addition & 7 deletions cmd/syncthing/gui.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,22 +485,16 @@ func (s *apiSvc) postSystemConfig(w http.ResponseWriter, r *http.Request) {
}
}

// Start or stop usage reporting as appropriate
// Fixup usage reporting settings

if curAcc := cfg.Options().URAccepted; newCfg.Options.URAccepted > curAcc {
// UR was enabled
newCfg.Options.URAccepted = usageReportVersion
newCfg.Options.URUniqueID = randomString(8)
err := sendUsageReport(s.model)
if err != nil {
l.Infoln("Usage report:", err)
}
go usageReportingLoop(s.model)
} else if newCfg.Options.URAccepted < curAcc {
// UR was disabled
newCfg.Options.URAccepted = -1
newCfg.Options.URUniqueID = ""
stopUsageReporting()
}

// Activate and save
Expand Down
13 changes: 5 additions & 8 deletions cmd/syncthing/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -677,16 +677,13 @@ func syncthingMain() {
cfg.SetOptions(opts)
cfg.Save()
}
go usageReportingLoop(m)
go func() {
time.Sleep(10 * time.Minute)
err := sendUsageReport(m)
if err != nil {
l.Infoln("Usage report:", err)
}
}()
}

// The usageReportingManager registers itself to listen to configuration
// changes, and there's nothing more we need to tell it from the outside.
// Hence we don't keep the returned pointer.
newUsageReportingManager(m, cfg)

if opts.RestartOnWakeup {
go standbyMonitor()
}
Expand Down
76 changes: 60 additions & 16 deletions cmd/syncthing/usage_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,55 @@ import (
"runtime"
"time"

"github.com/syncthing/syncthing/internal/config"
"github.com/syncthing/syncthing/internal/model"
"github.com/thejerf/suture"
)

// Current version number of the usage report, for acceptance purposes. If
// fields are added or changed this integer must be incremented so that users
// are prompted for acceptance of the new report.
const usageReportVersion = 1

var stopUsageReportingCh = make(chan struct{})
type usageReportingManager struct {
model *model.Model
sup *suture.Supervisor
}

func newUsageReportingManager(m *model.Model, cfg *config.Wrapper) *usageReportingManager {
mgr := &usageReportingManager{
model: m,
}

// Start UR if it's enabled.
mgr.Changed(cfg.Raw())

// Listen to future config changes so that we can start and stop as
// appropriate.
cfg.Subscribe(mgr)

return mgr
}

func (m *usageReportingManager) Changed(cfg config.Configuration) error {
if cfg.Options.URAccepted >= usageReportVersion && m.sup == nil {
// Usage reporting was turned on; lets start it.
svc := &usageReportingService{
model: m.model,
}
m.sup = suture.NewSimple("usageReporting")
m.sup.Add(svc)
m.sup.ServeBackground()
} else if cfg.Options.URAccepted < usageReportVersion && m.sup != nil {
// Usage reporting was turned off
m.sup.Stop()
m.sup = nil
}
return nil
}

// reportData returns the data to be sent in a usage report. It's used in
// various places, so not part of the usageReportingSvc object.
func reportData(m *model.Model) map[string]interface{} {
res := make(map[string]interface{})
res["uniqueID"] = cfg.Options().URUniqueID
Expand Down Expand Up @@ -75,8 +114,13 @@ func reportData(m *model.Model) map[string]interface{} {
return res
}

func sendUsageReport(m *model.Model) error {
d := reportData(m)
type usageReportingService struct {
model *model.Model
stop chan struct{}
}

func (s *usageReportingService) sendUsageReport() error {
d := reportData(s.model)
var b bytes.Buffer
json.NewEncoder(&b).Encode(d)

Expand All @@ -94,32 +138,32 @@ func sendUsageReport(m *model.Model) error {
return err
}

func usageReportingLoop(m *model.Model) {
func (s *usageReportingService) Serve() {
s.stop = make(chan struct{})

l.Infoln("Starting usage reporting")
t := time.NewTicker(86400 * time.Second)
loop:
defer l.Infoln("Stopping usage reporting")

t := time.NewTimer(10 * time.Minute) // time to initial report at start
for {
select {
case <-stopUsageReportingCh:
break loop
case <-s.stop:
return
case <-t.C:
err := sendUsageReport(m)
err := s.sendUsageReport()
if err != nil {
l.Infoln("Usage report:", err)
}
t.Reset(24 * time.Hour) // next report tomorrow
}
}
l.Infoln("Stopping usage reporting")
}

func stopUsageReporting() {
select {
case stopUsageReportingCh <- struct{}{}:
default:
}
func (s *usageReportingService) Stop() {
close(s.stop)
}

// Returns CPU performance as a measure of single threaded SHA-256 MiB/s
// cpuBench returns CPU performance as a measure of single threaded SHA-256 MiB/s
func cpuBench() float64 {
chunkSize := 100 * 1 << 10
h := sha256.New()
Expand Down

0 comments on commit c6b2ca8

Please sign in to comment.