-
Notifications
You must be signed in to change notification settings - Fork 7.3k
/
plugin_key_value_store.go
160 lines (131 loc) · 6.39 KB
/
plugin_key_value_store.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package app
import (
"crypto/sha256"
"encoding/base64"
"errors"
"net/http"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/shared/mlog"
"github.com/mattermost/mattermost-server/v5/store"
)
func getKeyHash(key string) string {
hash := sha256.New()
hash.Write([]byte(key))
return base64.StdEncoding.EncodeToString(hash.Sum(nil))
}
func (a *App) SetPluginKey(pluginID string, key string, value []byte) *model.AppError {
return a.SetPluginKeyWithExpiry(pluginID, key, value, 0)
}
func (a *App) SetPluginKeyWithExpiry(pluginID string, key string, value []byte, expireInSeconds int64) *model.AppError {
options := model.PluginKVSetOptions{
ExpireInSeconds: expireInSeconds,
}
_, err := a.SetPluginKeyWithOptions(pluginID, key, value, options)
return err
}
func (a *App) CompareAndSetPluginKey(pluginID string, key string, oldValue, newValue []byte) (bool, *model.AppError) {
options := model.PluginKVSetOptions{
Atomic: true,
OldValue: oldValue,
}
return a.SetPluginKeyWithOptions(pluginID, key, newValue, options)
}
func (a *App) SetPluginKeyWithOptions(pluginID string, key string, value []byte, options model.PluginKVSetOptions) (bool, *model.AppError) {
if err := options.IsValid(); err != nil {
mlog.Debug("Failed to set plugin key value with options", mlog.String("plugin_id", pluginID), mlog.String("key", key), mlog.Err(err))
return false, err
}
updated, err := a.Srv().Store.Plugin().SetWithOptions(pluginID, key, value, options)
if err != nil {
mlog.Error("Failed to set plugin key value with options", mlog.String("plugin_id", pluginID), mlog.String("key", key), mlog.Err(err))
var appErr *model.AppError
switch {
case errors.As(err, &appErr):
return false, appErr
default:
return false, model.NewAppError("SetPluginKeyWithOptions", "app.plugin_store.save.app_error", nil, err.Error(), http.StatusInternalServerError)
}
}
// Clean up a previous entry using the hashed key, if it exists.
if err := a.Srv().Store.Plugin().Delete(pluginID, getKeyHash(key)); err != nil {
mlog.Warn("Failed to clean up previously hashed plugin key value", mlog.String("plugin_id", pluginID), mlog.String("key", key), mlog.Err(err))
}
return updated, nil
}
func (a *App) CompareAndDeletePluginKey(pluginID string, key string, oldValue []byte) (bool, *model.AppError) {
kv := &model.PluginKeyValue{
PluginId: pluginID,
Key: key,
}
deleted, err := a.Srv().Store.Plugin().CompareAndDelete(kv, oldValue)
if err != nil {
mlog.Error("Failed to compare and delete plugin key value", mlog.String("plugin_id", pluginID), mlog.String("key", key), mlog.Err(err))
var appErr *model.AppError
switch {
case errors.As(err, &appErr):
return deleted, appErr
default:
return false, model.NewAppError("CompareAndDeletePluginKey", "app.plugin_store.delete.app_error", nil, err.Error(), http.StatusInternalServerError)
}
}
// Clean up a previous entry using the hashed key, if it exists.
if err := a.Srv().Store.Plugin().Delete(pluginID, getKeyHash(key)); err != nil {
mlog.Warn("Failed to clean up previously hashed plugin key value", mlog.String("plugin_id", pluginID), mlog.String("key", key), mlog.Err(err))
}
return deleted, nil
}
func (a *App) GetPluginKey(pluginID string, key string) ([]byte, *model.AppError) {
if kv, err := a.Srv().Store.Plugin().Get(pluginID, key); err == nil {
return kv.Value, nil
} else if nfErr := new(store.ErrNotFound); !errors.As(err, &nfErr) {
mlog.Error("Failed to query plugin key value", mlog.String("plugin_id", pluginID), mlog.String("key", key), mlog.Err(err))
return nil, model.NewAppError("GetPluginKey", "app.plugin_store.get.app_error", nil, err.Error(), http.StatusInternalServerError)
}
// Lookup using the hashed version of the key for keys written prior to v5.6.
if kv, err := a.Srv().Store.Plugin().Get(pluginID, getKeyHash(key)); err == nil {
return kv.Value, nil
} else if nfErr := new(store.ErrNotFound); !errors.As(err, &nfErr) {
mlog.Error("Failed to query plugin key value using hashed key", mlog.String("plugin_id", pluginID), mlog.String("key", key), mlog.Err(err))
return nil, model.NewAppError("GetPluginKey", "app.plugin_store.get.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil, nil
}
func (a *App) DeletePluginKey(pluginID string, key string) *model.AppError {
if err := a.Srv().Store.Plugin().Delete(pluginID, getKeyHash(key)); err != nil {
mlog.Error("Failed to delete plugin key value", mlog.String("plugin_id", pluginID), mlog.String("key", key), mlog.Err(err))
return model.NewAppError("DeletePluginKey", "app.plugin_store.delete.app_error", nil, err.Error(), http.StatusInternalServerError)
}
// Also delete the key without hashing
if err := a.Srv().Store.Plugin().Delete(pluginID, key); err != nil {
mlog.Error("Failed to delete plugin key value using hashed key", mlog.String("plugin_id", pluginID), mlog.String("key", key), mlog.Err(err))
return model.NewAppError("DeletePluginKey", "app.plugin_store.delete.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
}
func (a *App) DeleteAllKeysForPlugin(pluginID string) *model.AppError {
if err := a.Srv().Store.Plugin().DeleteAllForPlugin(pluginID); err != nil {
mlog.Error("Failed to delete all plugin key values", mlog.String("plugin_id", pluginID), mlog.Err(err))
return model.NewAppError("DeleteAllKeysForPlugin", "app.plugin_store.delete.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
}
func (a *App) DeleteAllExpiredPluginKeys() *model.AppError {
if a.Srv() == nil {
return nil
}
if err := a.Srv().Store.Plugin().DeleteAllExpired(); err != nil {
mlog.Error("Failed to delete all expired plugin key values", mlog.Err(err))
return model.NewAppError("DeleteAllExpiredPluginKeys", "app.plugin_store.delete.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
}
func (a *App) ListPluginKeys(pluginID string, page, perPage int) ([]string, *model.AppError) {
data, err := a.Srv().Store.Plugin().List(pluginID, page*perPage, perPage)
if err != nil {
mlog.Error("Failed to list plugin key values", mlog.Int("page", page), mlog.Int("perPage", perPage), mlog.Err(err))
return nil, model.NewAppError("ListPluginKeys", "app.plugin_store.list.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return data, nil
}