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	"time"
9
10	"github.com/keybase/client/go/kbfs/idutil"
11	"github.com/keybase/client/go/kbfs/kbfscrypto"
12	"github.com/keybase/client/go/kbfs/kbfsmd"
13	"github.com/keybase/client/go/kbfs/tlf"
14	kbname "github.com/keybase/client/go/kbun"
15	"github.com/keybase/client/go/protocol/keybase1"
16	metrics "github.com/rcrowley/go-metrics"
17	"golang.org/x/net/context"
18)
19
20// KeybaseServiceMeasured delegates to another KeybaseService instance
21// but also keeps track of stats.
22type KeybaseServiceMeasured struct {
23	delegate                         KeybaseService
24	resolveTimer                     metrics.Timer
25	identifyTimer                    metrics.Timer
26	normalizeSocialAssertionTimer    metrics.Timer
27	resolveIdentifyImplicitTeamTimer metrics.Timer
28	resolveImplicitTeamByIDTimer     metrics.Timer
29	loadUserPlusKeysTimer            metrics.Timer
30	loadTeamPlusKeysTimer            metrics.Timer
31	createTeamTLFTimer               metrics.Timer
32	getTeamSettingsTimer             metrics.Timer
33	getCurrentMerkleRootTimer        metrics.Timer
34	verifyMerkleRootTimer            metrics.Timer
35	currentSessionTimer              metrics.Timer
36	favoriteAddTimer                 metrics.Timer
37	favoriteDeleteTimer              metrics.Timer
38	favoriteListTimer                metrics.Timer
39	encryptFavoritesTimer            metrics.Timer
40	decryptFavoritesTimer            metrics.Timer
41	notifyTimer                      metrics.Timer
42	notifyPathUpdatedTimer           metrics.Timer
43	putGitMetadataTimer              metrics.Timer
44	onPathChangeTimer                metrics.Timer
45	onChangeTimer                    metrics.Timer
46}
47
48var _ KeybaseService = KeybaseServiceMeasured{}
49
50// NewKeybaseServiceMeasured creates and returns a new KeybaseServiceMeasured
51// instance with the given delegate and registry.
52func NewKeybaseServiceMeasured(delegate KeybaseService, r metrics.Registry) KeybaseServiceMeasured {
53	resolveTimer := metrics.GetOrRegisterTimer("KeybaseService.Resolve", r)
54	identifyTimer := metrics.GetOrRegisterTimer("KeybaseService.Identify", r)
55	normalizeSocialAssertionTimer := metrics.GetOrRegisterTimer("KeybaseService.NormalizeSocialAssertion", r)
56	resolveIdentifyImplicitTeamTimer := metrics.GetOrRegisterTimer(
57		"KeybaseService.ResolveIdentifyImplicitTeam", r)
58	resolveImplicitTeamByIDTimer := metrics.GetOrRegisterTimer(
59		"KeybaseService.ResolveImplicitTeamByID", r)
60	loadUserPlusKeysTimer := metrics.GetOrRegisterTimer("KeybaseService.LoadUserPlusKeys", r)
61	loadTeamPlusKeysTimer := metrics.GetOrRegisterTimer("KeybaseService.LoadTeamPlusKeys", r)
62	createTeamTLFTimer := metrics.GetOrRegisterTimer("KeybaseService.CreateTeamTLF", r)
63	getTeamSettingsTimer := metrics.GetOrRegisterTimer("KeybaseService.GetTeamSettings", r)
64	getCurrentMerkleRootTimer := metrics.GetOrRegisterTimer("KeybaseService.GetCurrentMerkleRoot", r)
65	verifyMerkleRootTimer := metrics.GetOrRegisterTimer("KeybaseService.VerifyMerkleRoot", r)
66	currentSessionTimer := metrics.GetOrRegisterTimer("KeybaseService.CurrentSession", r)
67	favoriteAddTimer := metrics.GetOrRegisterTimer("KeybaseService.FavoriteAdd", r)
68	favoriteDeleteTimer := metrics.GetOrRegisterTimer("KeybaseService.FavoriteDelete", r)
69	favoriteListTimer := metrics.GetOrRegisterTimer("KeybaseService.FavoriteList", r)
70	encryptFavoritesTimer := metrics.GetOrRegisterTimer("KeybaseService."+
71		"EncryptFavorites", r)
72	decryptFavoritesTimer := metrics.GetOrRegisterTimer("KeybaseService."+
73		"DecryptFavorites", r)
74	notifyTimer := metrics.GetOrRegisterTimer("KeybaseService.Notify", r)
75	notifyPathUpdatedTimer := metrics.GetOrRegisterTimer("KeybaseService.NotifyPathUpdated", r)
76	putGitMetadataTimer := metrics.GetOrRegisterTimer(
77		"KeybaseService.PutGitMetadata", r)
78	onPathChangeTimer := metrics.GetOrRegisterTimer(
79		"KeybaseService.OnPathChangeTimer", r)
80	onChangeTimer := metrics.GetOrRegisterTimer(
81		"KeybaseService.OnChangeTimer", r)
82	return KeybaseServiceMeasured{
83		delegate:                         delegate,
84		resolveTimer:                     resolveTimer,
85		identifyTimer:                    identifyTimer,
86		normalizeSocialAssertionTimer:    normalizeSocialAssertionTimer,
87		resolveIdentifyImplicitTeamTimer: resolveIdentifyImplicitTeamTimer,
88		resolveImplicitTeamByIDTimer:     resolveImplicitTeamByIDTimer,
89		loadUserPlusKeysTimer:            loadUserPlusKeysTimer,
90		loadTeamPlusKeysTimer:            loadTeamPlusKeysTimer,
91		createTeamTLFTimer:               createTeamTLFTimer,
92		getTeamSettingsTimer:             getTeamSettingsTimer,
93		getCurrentMerkleRootTimer:        getCurrentMerkleRootTimer,
94		verifyMerkleRootTimer:            verifyMerkleRootTimer,
95		currentSessionTimer:              currentSessionTimer,
96		favoriteAddTimer:                 favoriteAddTimer,
97		favoriteDeleteTimer:              favoriteDeleteTimer,
98		favoriteListTimer:                favoriteListTimer,
99		encryptFavoritesTimer:            encryptFavoritesTimer,
100		decryptFavoritesTimer:            decryptFavoritesTimer,
101		notifyTimer:                      notifyTimer,
102		notifyPathUpdatedTimer:           notifyPathUpdatedTimer,
103		putGitMetadataTimer:              putGitMetadataTimer,
104		onPathChangeTimer:                onPathChangeTimer,
105		onChangeTimer:                    onChangeTimer,
106	}
107}
108
109// Resolve implements the KeybaseService interface for KeybaseServiceMeasured.
110func (k KeybaseServiceMeasured) Resolve(
111	ctx context.Context, assertion string,
112	offline keybase1.OfflineAvailability) (
113	name kbname.NormalizedUsername, uid keybase1.UserOrTeamID, err error) {
114	k.resolveTimer.Time(func() {
115		name, uid, err = k.delegate.Resolve(ctx, assertion, offline)
116	})
117	return name, uid, err
118}
119
120// Identify implements the KeybaseService interface for KeybaseServiceMeasured.
121func (k KeybaseServiceMeasured) Identify(
122	ctx context.Context, assertion, reason string,
123	offline keybase1.OfflineAvailability) (
124	name kbname.NormalizedUsername, id keybase1.UserOrTeamID, err error) {
125	k.identifyTimer.Time(func() {
126		name, id, err = k.delegate.Identify(ctx, assertion, reason, offline)
127	})
128	return name, id, err
129}
130
131// NormalizeSocialAssertion implements the KeybaseService interface for
132// KeybaseServiceMeasured.
133func (k KeybaseServiceMeasured) NormalizeSocialAssertion(
134	ctx context.Context, assertion string) (res keybase1.SocialAssertion, err error) {
135	k.normalizeSocialAssertionTimer.Time(func() {
136		res, err = k.delegate.NormalizeSocialAssertion(
137			ctx, assertion)
138	})
139	return res, err
140}
141
142// ResolveIdentifyImplicitTeam implements the KeybaseService interface
143// for KeybaseServiceMeasured.
144func (k KeybaseServiceMeasured) ResolveIdentifyImplicitTeam(
145	ctx context.Context, assertions, suffix string, tlfType tlf.Type,
146	doIdentifies bool, reason string, offline keybase1.OfflineAvailability) (
147	info idutil.ImplicitTeamInfo, err error) {
148	k.resolveIdentifyImplicitTeamTimer.Time(func() {
149		info, err = k.delegate.ResolveIdentifyImplicitTeam(
150			ctx, assertions, suffix, tlfType, doIdentifies, reason, offline)
151	})
152	return info, err
153}
154
155// ResolveImplicitTeamByID implements the KeybaseService interface for
156// KeybaseServiceMeasured.
157func (k KeybaseServiceMeasured) ResolveImplicitTeamByID(
158	ctx context.Context, teamID keybase1.TeamID) (name string, err error) {
159	k.resolveImplicitTeamByIDTimer.Time(func() {
160		name, err = k.delegate.ResolveImplicitTeamByID(ctx, teamID)
161	})
162	return name, err
163}
164
165// LoadUserPlusKeys implements the KeybaseService interface for KeybaseServiceMeasured.
166func (k KeybaseServiceMeasured) LoadUserPlusKeys(
167	ctx context.Context, uid keybase1.UID, pollForKID keybase1.KID,
168	offline keybase1.OfflineAvailability) (userInfo idutil.UserInfo, err error) {
169	k.loadUserPlusKeysTimer.Time(func() {
170		userInfo, err = k.delegate.LoadUserPlusKeys(
171			ctx, uid, pollForKID, offline)
172	})
173	return userInfo, err
174}
175
176// LoadTeamPlusKeys implements the KeybaseService interface for KeybaseServiceMeasured.
177func (k KeybaseServiceMeasured) LoadTeamPlusKeys(ctx context.Context,
178	tid keybase1.TeamID, tlfType tlf.Type, desiredKeyGen kbfsmd.KeyGen,
179	desiredUser keybase1.UserVersion, desiredKey kbfscrypto.VerifyingKey,
180	desiredRole keybase1.TeamRole, offline keybase1.OfflineAvailability) (
181	teamInfo idutil.TeamInfo, err error) {
182	k.loadTeamPlusKeysTimer.Time(func() {
183		teamInfo, err = k.delegate.LoadTeamPlusKeys(
184			ctx, tid, tlfType, desiredKeyGen, desiredUser, desiredKey,
185			desiredRole, offline)
186	})
187	return teamInfo, err
188}
189
190// CreateTeamTLF implements the KeybaseService interface for
191// KeybaseServiceMeasured.
192func (k KeybaseServiceMeasured) CreateTeamTLF(
193	ctx context.Context, teamID keybase1.TeamID, tlfID tlf.ID) (err error) {
194	k.createTeamTLFTimer.Time(func() {
195		err = k.delegate.CreateTeamTLF(ctx, teamID, tlfID)
196	})
197	return err
198}
199
200// GetTeamSettings implements the KeybaseService interface for
201// KeybaseServiceMeasured.
202func (k KeybaseServiceMeasured) GetTeamSettings(
203	ctx context.Context, teamID keybase1.TeamID,
204	offline keybase1.OfflineAvailability) (
205	settings keybase1.KBFSTeamSettings, err error) {
206	k.getTeamSettingsTimer.Time(func() {
207		settings, err = k.delegate.GetTeamSettings(ctx, teamID, offline)
208	})
209	return settings, err
210}
211
212// GetCurrentMerkleRoot implements the KeybaseService interface for
213// KeybaseServiceMeasured.
214func (k KeybaseServiceMeasured) GetCurrentMerkleRoot(ctx context.Context) (
215	root keybase1.MerkleRootV2, updateTime time.Time, err error) {
216	k.getCurrentMerkleRootTimer.Time(func() {
217		root, updateTime, err = k.delegate.GetCurrentMerkleRoot(ctx)
218	})
219	return root, updateTime, err
220}
221
222// VerifyMerkleRoot implements the KBPKI interface for
223// KeybaseServiceMeasured.
224func (k KeybaseServiceMeasured) VerifyMerkleRoot(
225	ctx context.Context, root keybase1.MerkleRootV2,
226	kbfsRoot keybase1.KBFSRoot) (err error) {
227	k.verifyMerkleRootTimer.Time(func() {
228		err = k.delegate.VerifyMerkleRoot(ctx, root, kbfsRoot)
229	})
230	return err
231}
232
233// CurrentSession implements the KeybaseService interface for
234// KeybaseServiceMeasured.
235func (k KeybaseServiceMeasured) CurrentSession(ctx context.Context, sessionID int) (
236	sessionInfo idutil.SessionInfo, err error) {
237	k.currentSessionTimer.Time(func() {
238		sessionInfo, err = k.delegate.CurrentSession(ctx, sessionID)
239	})
240	return sessionInfo, err
241}
242
243// FavoriteAdd implements the KeybaseService interface for
244// KeybaseServiceMeasured.
245func (k KeybaseServiceMeasured) FavoriteAdd(ctx context.Context, folder keybase1.FolderHandle) (err error) {
246	k.favoriteAddTimer.Time(func() {
247		err = k.delegate.FavoriteAdd(ctx, folder)
248	})
249	return err
250}
251
252// FavoriteDelete implements the KeybaseService interface for
253// KeybaseServiceMeasured.
254func (k KeybaseServiceMeasured) FavoriteDelete(ctx context.Context, folder keybase1.FolderHandle) (err error) {
255	k.favoriteDeleteTimer.Time(func() {
256		err = k.delegate.FavoriteDelete(ctx, folder)
257	})
258	return err
259}
260
261// FavoriteList implements the KeybaseService interface for
262// KeybaseServiceMeasured.
263func (k KeybaseServiceMeasured) FavoriteList(ctx context.Context, sessionID int) (
264	favorites keybase1.FavoritesResult, err error) {
265	k.favoriteListTimer.Time(func() {
266		favorites, err = k.delegate.FavoriteList(ctx, sessionID)
267	})
268	return favorites, err
269}
270
271// EncryptFavorites implements the KeybaseService interface for
272// KeybaseServiceMeasured.
273func (k KeybaseServiceMeasured) EncryptFavorites(ctx context.Context,
274	dataIn []byte) (dataOut []byte, err error) {
275	k.favoriteListTimer.Time(func() {
276		dataOut, err = k.delegate.EncryptFavorites(ctx, dataIn)
277	})
278	return dataOut, err
279}
280
281// DecryptFavorites implements the KeybaseService interface for
282// KeybaseServiceMeasured.
283func (k KeybaseServiceMeasured) DecryptFavorites(ctx context.Context,
284	dataIn []byte) (dataOut []byte, err error) {
285	k.favoriteListTimer.Time(func() {
286		dataOut, err = k.delegate.DecryptFavorites(ctx, dataIn)
287	})
288	return dataOut, err
289}
290
291// NotifyOnlineStatusChanged implements the KeybaseService interface for
292// KeybaseServiceMeasured.
293func (k KeybaseServiceMeasured) NotifyOnlineStatusChanged(
294	ctx context.Context, online bool) (err error) {
295	k.notifyTimer.Time(func() {
296		err = k.delegate.NotifyOnlineStatusChanged(ctx, online)
297	})
298	return err
299}
300
301// Notify implements the KeybaseService interface for KeybaseServiceMeasured.
302func (k KeybaseServiceMeasured) Notify(ctx context.Context, notification *keybase1.FSNotification) (err error) {
303	k.notifyTimer.Time(func() {
304		err = k.delegate.Notify(ctx, notification)
305	})
306	return err
307}
308
309// NotifyPathUpdated implements the KeybaseService interface for
310// KeybaseServiceMeasured.
311func (k KeybaseServiceMeasured) NotifyPathUpdated(
312	ctx context.Context, path string) (err error) {
313	k.notifyPathUpdatedTimer.Time(func() {
314		err = k.delegate.NotifyPathUpdated(ctx, path)
315	})
316	return err
317}
318
319// NotifySyncStatus implements the KeybaseService interface for
320// KeybaseServiceMeasured.
321func (k KeybaseServiceMeasured) NotifySyncStatus(ctx context.Context,
322	status *keybase1.FSPathSyncStatus) (err error) {
323	k.notifyTimer.Time(func() {
324		err = k.delegate.NotifySyncStatus(ctx, status)
325	})
326	return err
327}
328
329// NotifyOverallSyncStatus implements the KeybaseService interface for
330// KeybaseServiceMeasured.
331func (k KeybaseServiceMeasured) NotifyOverallSyncStatus(
332	ctx context.Context, status keybase1.FolderSyncStatus) (err error) {
333	k.notifyTimer.Time(func() {
334		err = k.delegate.NotifyOverallSyncStatus(ctx, status)
335	})
336	return err
337}
338
339// NotifyFavoritesChanged implements the KeybaseService interface for
340// KeybaseServiceMeasured.
341func (k KeybaseServiceMeasured) NotifyFavoritesChanged(
342	ctx context.Context) (err error) {
343	k.notifyTimer.Time(func() {
344		err = k.delegate.NotifyFavoritesChanged(ctx)
345	})
346	return err
347}
348
349// FlushUserFromLocalCache implements the KeybaseService interface for
350// KeybaseServiceMeasured.
351func (k KeybaseServiceMeasured) FlushUserFromLocalCache(
352	ctx context.Context, uid keybase1.UID) {
353	k.delegate.FlushUserFromLocalCache(ctx, uid)
354}
355
356// ClearCaches implements the KeybaseService interface for
357// KeybaseServiceMeasured.
358func (k KeybaseServiceMeasured) ClearCaches(ctx context.Context) {
359	k.delegate.ClearCaches(ctx)
360}
361
362// EstablishMountDir implements the KeybaseDaemon interface for KeybaseDaemonLocal.
363func (k KeybaseServiceMeasured) EstablishMountDir(ctx context.Context) (string, error) {
364	return k.delegate.EstablishMountDir(ctx)
365}
366
367// PutGitMetadata implements the KeybaseDaemon interface for
368// KeybaseServiceMeasured.
369func (k KeybaseServiceMeasured) PutGitMetadata(
370	ctx context.Context, folder keybase1.FolderHandle, repoID keybase1.RepoID,
371	metadata keybase1.GitLocalMetadata) (err error) {
372	k.putGitMetadataTimer.Time(func() {
373		err = k.delegate.PutGitMetadata(ctx, folder, repoID, metadata)
374	})
375	return err
376}
377
378// OnPathChange implements the SubscriptionNotifier interface.
379func (k KeybaseServiceMeasured) OnPathChange(clientID SubscriptionManagerClientID,
380	subscriptionIDs []SubscriptionID, path string, topics []keybase1.PathSubscriptionTopic) {
381	k.onPathChangeTimer.Time(func() {
382		k.delegate.OnPathChange(clientID, subscriptionIDs, path, topics)
383	})
384}
385
386// OnNonPathChange implements the SubscriptionNotifier interface.
387func (k KeybaseServiceMeasured) OnNonPathChange(
388	clientID SubscriptionManagerClientID,
389	subscriptionIDs []SubscriptionID, topic keybase1.SubscriptionTopic) {
390	k.onChangeTimer.Time(func() {
391		k.delegate.OnNonPathChange(clientID, subscriptionIDs, topic)
392	})
393}
394
395// GetKVStoreClient implements the KeybaseService interface.
396func (k KeybaseServiceMeasured) GetKVStoreClient() keybase1.KvstoreInterface {
397	return k.delegate.GetKVStoreClient()
398}
399
400// Shutdown implements the KeybaseService interface for
401// KeybaseServiceMeasured.
402func (k KeybaseServiceMeasured) Shutdown() {
403	k.delegate.Shutdown()
404}
405