1// Copyright 2016 Keybase Inc. All rights reserved.
2// Use of this source code is governed by a BSD
3// license that can be found in the LICENSE file.
4
5package libkbfs
6
7import (
8	"runtime"
9	"sync"
10
11	"golang.org/x/net/context"
12
13	"github.com/keybase/client/go/kbfs/tlf"
14	"github.com/keybase/client/go/protocol/keybase1"
15)
16
17// ReporterSimple remembers the last maxErrors errors, or all errors
18// if maxErrors < 1.
19type ReporterSimple struct {
20	clock          Clock
21	maxErrors      int
22	currErrorIndex int
23	filledOnce     bool
24	// errors is a circular buffer when maxErrors >= 1
25	errors []ReportedError
26	lock   sync.RWMutex // protects everything
27}
28
29// NewReporterSimple creates a new ReporterSimple.
30func NewReporterSimple(clock Clock, maxErrors int) *ReporterSimple {
31	rs := &ReporterSimple{
32		clock:          clock,
33		maxErrors:      maxErrors,
34		currErrorIndex: -1,
35	}
36
37	if maxErrors >= 1 {
38		rs.errors = make([]ReportedError, maxErrors)
39	}
40
41	return rs
42}
43
44// ReportErr implements the Reporter interface for ReporterSimple.
45func (r *ReporterSimple) ReportErr(ctx context.Context,
46	_ tlf.CanonicalName, _ tlf.Type, _ ErrorModeType, err error) {
47	r.lock.Lock()
48	defer r.lock.Unlock()
49
50	stack := make([]uintptr, 20)
51	n := runtime.Callers(2, stack)
52	re := ReportedError{
53		Time:  r.clock.Now(),
54		Error: err,
55		Stack: stack[:n],
56	}
57	r.currErrorIndex++
58	if r.maxErrors < 1 {
59		r.errors = append(r.errors, re)
60	} else {
61		if r.currErrorIndex == r.maxErrors {
62			r.currErrorIndex = 0
63			r.filledOnce = true
64		}
65		r.errors[r.currErrorIndex] = re
66	}
67
68}
69
70// AllKnownErrors implements the Reporter interface for ReporterSimple.
71func (r *ReporterSimple) AllKnownErrors() []ReportedError {
72	r.lock.RLock()
73	defer r.lock.RUnlock()
74
75	if !r.filledOnce {
76		// deep copy since r.errors shouldn't be read without the lock.
77		errors := make([]ReportedError, r.currErrorIndex+1)
78		copy(errors, r.errors[:r.currErrorIndex+1])
79		return errors
80	}
81
82	errors := make([]ReportedError, r.maxErrors)
83	s := r.currErrorIndex + 1
84	t := r.maxErrors - s
85	copy(errors[:t], r.errors[s:])
86	copy(errors[t:], r.errors[:s])
87	return errors
88}
89
90// OnlineStatusChanged implements the Reporter interface for ReporterSimple.
91func (r *ReporterSimple) OnlineStatusChanged(_ context.Context, online bool) {
92	// ignore notifications
93}
94
95// Notify implements the Reporter interface for ReporterSimple.
96func (r *ReporterSimple) Notify(_ context.Context, _ *keybase1.FSNotification) {
97	// ignore notifications
98}
99
100// NotifyPathUpdated implements the Reporter interface for ReporterSimple.
101func (r *ReporterSimple) NotifyPathUpdated(_ context.Context, _ string) {
102	// ignore notifications
103}
104
105// NotifySyncStatus implements the Reporter interface for ReporterSimple.
106func (r *ReporterSimple) NotifySyncStatus(_ context.Context,
107	_ *keybase1.FSPathSyncStatus) {
108	// ignore notifications
109}
110
111// NotifyFavoritesChanged implements the Reporter interface for
112// ReporterSimple.
113func (r *ReporterSimple) NotifyFavoritesChanged(_ context.Context) {
114	// ignore notifications
115}
116
117// NotifyOverallSyncStatus implements the Reporter interface for
118// ReporterSimple.
119func (r *ReporterSimple) NotifyOverallSyncStatus(
120	_ context.Context, _ keybase1.FolderSyncStatus) {
121	// ignore notifications
122}
123
124// Shutdown implements the Reporter interface for ReporterSimple.
125func (r *ReporterSimple) Shutdown() {
126
127}
128