PLT-8131 (part2) Add plugin key value store support (#7902)
* Add plugin key value store support * Add localization strings * Updates per feedback
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
e85ec38301
Коммит
6176bcff69
@@ -79,6 +79,20 @@ type API interface {
|
||||
// GetPost gets a post.
|
||||
GetPost(postId string) (*model.Post, *model.AppError)
|
||||
|
||||
// Update post updates a post.
|
||||
// UpdatePost updates a post.
|
||||
UpdatePost(post *model.Post) (*model.Post, *model.AppError)
|
||||
|
||||
// KeyValueStore returns an object for accessing the persistent key value storage.
|
||||
KeyValueStore() KeyValueStore
|
||||
}
|
||||
|
||||
type KeyValueStore interface {
|
||||
// Set will store a key-value pair, unique per plugin.
|
||||
Set(key string, value []byte) *model.AppError
|
||||
|
||||
// Get will retrieve a value based on the key. Returns nil for non-existent keys.
|
||||
Get(key string) ([]byte, *model.AppError)
|
||||
|
||||
// Delete will remove a key-value pair. Returns nil for non-existent keys.
|
||||
Delete(key string) *model.AppError
|
||||
}
|
||||
|
||||
@@ -12,9 +12,15 @@ import (
|
||||
|
||||
type API struct {
|
||||
mock.Mock
|
||||
Store *KeyValueStore
|
||||
}
|
||||
|
||||
type KeyValueStore struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
var _ plugin.API = (*API)(nil)
|
||||
var _ plugin.KeyValueStore = (*KeyValueStore)(nil)
|
||||
|
||||
func (m *API) LoadPluginConfiguration(dest interface{}) error {
|
||||
return m.Called(dest).Error(0)
|
||||
@@ -235,3 +241,35 @@ func (m *API) UpdatePost(post *model.Post) (*model.Post, *model.AppError) {
|
||||
err, _ := ret.Get(1).(*model.AppError)
|
||||
return postOut, err
|
||||
}
|
||||
|
||||
func (m *API) KeyValueStore() plugin.KeyValueStore {
|
||||
return m.Store
|
||||
}
|
||||
|
||||
func (m *KeyValueStore) Set(key string, value []byte) *model.AppError {
|
||||
ret := m.Called(key, value)
|
||||
if f, ok := ret.Get(0).(func(string, []byte) *model.AppError); ok {
|
||||
return f(key, value)
|
||||
}
|
||||
err, _ := ret.Get(0).(*model.AppError)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *KeyValueStore) Get(key string) ([]byte, *model.AppError) {
|
||||
ret := m.Called(key)
|
||||
if f, ok := ret.Get(0).(func(string) ([]byte, *model.AppError)); ok {
|
||||
return f(key)
|
||||
}
|
||||
psv, _ := ret.Get(0).([]byte)
|
||||
err, _ := ret.Get(1).(*model.AppError)
|
||||
return psv, err
|
||||
}
|
||||
|
||||
func (m *KeyValueStore) Delete(key string) *model.AppError {
|
||||
ret := m.Called(key)
|
||||
if f, ok := ret.Get(0).(func(string) *model.AppError); ok {
|
||||
return f(key)
|
||||
}
|
||||
err, _ := ret.Get(0).(*model.AppError)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -259,6 +259,41 @@ func (api *LocalAPI) UpdatePost(args *model.Post, reply *APIPostReply) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type APIKeyValueStoreReply struct {
|
||||
Value []byte
|
||||
Error *model.AppError
|
||||
}
|
||||
|
||||
type APIKeyValueStoreSetArgs struct {
|
||||
Key string
|
||||
Value []byte
|
||||
}
|
||||
|
||||
func (api *LocalAPI) KeyValueStoreSet(args *APIKeyValueStoreSetArgs, reply *APIErrorReply) error {
|
||||
err := api.api.KeyValueStore().Set(args.Key, args.Value)
|
||||
*reply = APIErrorReply{
|
||||
Error: err,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (api *LocalAPI) KeyValueStoreGet(args string, reply *APIKeyValueStoreReply) error {
|
||||
v, err := api.api.KeyValueStore().Get(args)
|
||||
*reply = APIKeyValueStoreReply{
|
||||
Value: v,
|
||||
Error: err,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (api *LocalAPI) KeyValueStoreDelete(args string, reply *APIErrorReply) error {
|
||||
err := api.api.KeyValueStore().Delete(args)
|
||||
*reply = APIErrorReply{
|
||||
Error: err,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ServeAPI(api plugin.API, conn io.ReadWriteCloser, muxer *Muxer) {
|
||||
server := rpc.NewServer()
|
||||
server.Register(&LocalAPI{
|
||||
@@ -269,11 +304,17 @@ func ServeAPI(api plugin.API, conn io.ReadWriteCloser, muxer *Muxer) {
|
||||
}
|
||||
|
||||
type RemoteAPI struct {
|
||||
client *rpc.Client
|
||||
muxer *Muxer
|
||||
client *rpc.Client
|
||||
muxer *Muxer
|
||||
keyValueStore *RemoteKeyValueStore
|
||||
}
|
||||
|
||||
type RemoteKeyValueStore struct {
|
||||
api *RemoteAPI
|
||||
}
|
||||
|
||||
var _ plugin.API = (*RemoteAPI)(nil)
|
||||
var _ plugin.KeyValueStore = (*RemoteKeyValueStore)(nil)
|
||||
|
||||
func (api *RemoteAPI) LoadPluginConfiguration(dest interface{}) error {
|
||||
var config []byte
|
||||
@@ -467,13 +508,47 @@ func (api *RemoteAPI) UpdatePost(post *model.Post) (*model.Post, *model.AppError
|
||||
return reply.Post, reply.Error
|
||||
}
|
||||
|
||||
func (api *RemoteAPI) KeyValueStore() plugin.KeyValueStore {
|
||||
return api.keyValueStore
|
||||
}
|
||||
|
||||
func (s *RemoteKeyValueStore) Set(key string, value []byte) *model.AppError {
|
||||
var reply APIErrorReply
|
||||
if err := s.api.client.Call("LocalAPI.KeyValueStoreSet", &APIKeyValueStoreSetArgs{Key: key, Value: value}, &reply); err != nil {
|
||||
return model.NewAppError("RemoteAPI.KeyValueStoreSet", "plugin.rpcplugin.invocation.error", nil, "err="+err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
return reply.Error
|
||||
}
|
||||
|
||||
func (s *RemoteKeyValueStore) Get(key string) ([]byte, *model.AppError) {
|
||||
var reply APIKeyValueStoreReply
|
||||
if err := s.api.client.Call("LocalAPI.KeyValueStoreGet", key, &reply); err != nil {
|
||||
return nil, model.NewAppError("RemoteAPI.KeyValueStoreGet", "plugin.rpcplugin.invocation.error", nil, "err="+err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
return reply.Value, reply.Error
|
||||
}
|
||||
|
||||
func (s *RemoteKeyValueStore) Delete(key string) *model.AppError {
|
||||
var reply APIErrorReply
|
||||
if err := s.api.client.Call("LocalAPI.KeyValueStoreDelete", key, &reply); err != nil {
|
||||
return model.NewAppError("RemoteAPI.KeyValueStoreDelete", "plugin.rpcplugin.invocation.error", nil, "err="+err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
return reply.Error
|
||||
}
|
||||
|
||||
func (h *RemoteAPI) Close() error {
|
||||
return h.client.Close()
|
||||
}
|
||||
|
||||
func ConnectAPI(conn io.ReadWriteCloser, muxer *Muxer) *RemoteAPI {
|
||||
return &RemoteAPI{
|
||||
client: rpc.NewClient(conn),
|
||||
muxer: muxer,
|
||||
remoteKeyValueStore := &RemoteKeyValueStore{}
|
||||
remoteApi := &RemoteAPI{
|
||||
client: rpc.NewClient(conn),
|
||||
muxer: muxer,
|
||||
keyValueStore: remoteKeyValueStore,
|
||||
}
|
||||
|
||||
remoteKeyValueStore.api = remoteApi
|
||||
|
||||
return remoteApi
|
||||
}
|
||||
|
||||
@@ -34,7 +34,8 @@ func testAPIRPC(api plugin.API, f func(plugin.API)) {
|
||||
}
|
||||
|
||||
func TestAPI(t *testing.T) {
|
||||
var api plugintest.API
|
||||
keyValueStore := &plugintest.KeyValueStore{}
|
||||
api := plugintest.API{Store: keyValueStore}
|
||||
defer api.AssertExpectations(t)
|
||||
|
||||
type Config struct {
|
||||
@@ -199,5 +200,20 @@ func TestAPI(t *testing.T) {
|
||||
post, err = remote.UpdatePost(testPost)
|
||||
assert.Equal(t, testPost, post)
|
||||
assert.Nil(t, err)
|
||||
|
||||
api.KeyValueStore().(*plugintest.KeyValueStore).On("Set", "thekey", []byte("thevalue")).Return(nil).Once()
|
||||
err = remote.KeyValueStore().Set("thekey", []byte("thevalue"))
|
||||
assert.Nil(t, err)
|
||||
|
||||
api.KeyValueStore().(*plugintest.KeyValueStore).On("Get", "thekey").Return(func(key string) ([]byte, *model.AppError) {
|
||||
return []byte("thevalue"), nil
|
||||
}).Once()
|
||||
ret, err := remote.KeyValueStore().Get("thekey")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, []byte("thevalue"), ret)
|
||||
|
||||
api.KeyValueStore().(*plugintest.KeyValueStore).On("Delete", "thekey").Return(nil).Once()
|
||||
err = remote.KeyValueStore().Delete("thekey")
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user