Add settings value protobuf and store implementation
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
// Package store implements the go-micro store interface
|
||||
package store
|
||||
|
||||
import (
|
||||
"github.com/owncloud/ocis-settings/pkg/proto/v0"
|
||||
"google.golang.org/grpc/codes"
|
||||
gstatus "google.golang.org/grpc/status"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
)
|
||||
|
||||
// ListByExtension returns all bundles in the mountPath folder belonging to the given extension
|
||||
func (s Store) ListByExtension(extension string) ([]*proto.SettingsBundle, error) {
|
||||
bundlesFolder := s.buildFolderPathBundles()
|
||||
extensionFolders, err := ioutil.ReadDir(bundlesFolder)
|
||||
if err != nil {
|
||||
s.Logger.Err(err).Msgf("error reading %v", bundlesFolder)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.Logger.Info().Msgf("listing bundles by extension %v", extension)
|
||||
var records []*proto.SettingsBundle
|
||||
for _, extensionFolder := range extensionFolders {
|
||||
extensionPath := path.Join(bundlesFolder, extensionFolder.Name())
|
||||
bundleFiles, err := ioutil.ReadDir(extensionPath)
|
||||
if err == nil {
|
||||
for _, bundleFile := range bundleFiles {
|
||||
record := proto.SettingsBundle{}
|
||||
err = s.parseRecordFromFile(&record, path.Join(extensionPath, bundleFile.Name()))
|
||||
if err == nil && (len(extension) == 0 || extension == record.Extension) {
|
||||
records = append(records, &record)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s.Logger.Err(err).Msgf("error reading %v", extensionPath)
|
||||
}
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// Read tries to find a bundle by the given extension and key within the mountPath
|
||||
func (s Store) ReadBundle(extension string, bundleKey string) (*proto.SettingsBundle, error) {
|
||||
if len(extension) < 1 || len(bundleKey) < 1 {
|
||||
s.Logger.Error().Msg("extension and bundleKey cannot be empty")
|
||||
return nil, gstatus.Error(codes.InvalidArgument, "Missing a required identifier attribute")
|
||||
}
|
||||
|
||||
filePath := s.buildFilePathFromBundleArgs(extension, bundleKey)
|
||||
record := proto.SettingsBundle{}
|
||||
if err := s.parseRecordFromFile(&record, filePath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.Logger.Debug().Msgf("read contents from file: %v", filePath)
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// Write writes the given record into a file within the mountPath
|
||||
func (s Store) WriteBundle(record *proto.SettingsBundle) (*proto.SettingsBundle, error) {
|
||||
if len(record.Extension) < 1 || len(record.BundleKey) < 1 {
|
||||
s.Logger.Error().Msg("extension and bundleKey cannot be empty")
|
||||
return nil, gstatus.Error(codes.InvalidArgument, "Missing a required identifier attribute")
|
||||
}
|
||||
|
||||
filePath := s.buildFilePathFromBundle(record)
|
||||
if err := s.writeRecordToFile(record, filePath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.Logger.Debug().Msgf("request contents written to file: %v", filePath)
|
||||
return record, nil
|
||||
}
|
||||
@@ -7,32 +7,52 @@ import (
|
||||
)
|
||||
|
||||
const folderNameBundles = "bundles"
|
||||
const folderNameSettings = "settings"
|
||||
const folderNameValues = "values"
|
||||
|
||||
// Builds the folder path for storing settings bundles
|
||||
func buildFolderPathBundles(mountPath string) string {
|
||||
folderPath := path.Join(mountPath, folderNameBundles)
|
||||
ensureFolderExists(folderPath)
|
||||
func (s Store) buildFolderPathBundles() string {
|
||||
folderPath := path.Join(s.mountPath, folderNameBundles)
|
||||
s.ensureFolderExists(folderPath)
|
||||
return folderPath
|
||||
}
|
||||
|
||||
// Builds a unique file name from the given bundle
|
||||
func buildFilePathFromBundle(mountPath string, bundle *proto.SettingsBundle) string {
|
||||
return buildFilePathFromBundleArgs(mountPath, bundle.Extension, bundle.Key)
|
||||
// Builds a unique file name from the given settings bundle
|
||||
func (s Store) buildFilePathFromBundle(bundle *proto.SettingsBundle) string {
|
||||
return s.buildFilePathFromBundleArgs(bundle.Extension, bundle.BundleKey)
|
||||
}
|
||||
|
||||
// Builds a unique file name from the given params
|
||||
func buildFilePathFromBundleArgs(mountPath string, extension string, key string) string {
|
||||
extensionFolder := path.Join(mountPath, folderNameBundles, extension)
|
||||
if _, err := os.Stat(extensionFolder); os.IsNotExist(err) {
|
||||
_ = os.MkdirAll(extensionFolder, 0700)
|
||||
}
|
||||
return path.Join(extensionFolder, key + ".json")
|
||||
func (s Store) buildFilePathFromBundleArgs(extension string, bundleKey string) string {
|
||||
extensionFolder := path.Join(s.mountPath, folderNameBundles, extension)
|
||||
s.ensureFolderExists(extensionFolder)
|
||||
return path.Join(extensionFolder, bundleKey+".json")
|
||||
}
|
||||
|
||||
// Builds the folder path for storing settings values
|
||||
func (s Store) buildFolderPathValues() string {
|
||||
folderPath := path.Join(s.mountPath, folderNameValues)
|
||||
s.ensureFolderExists(folderPath)
|
||||
return folderPath
|
||||
}
|
||||
|
||||
// Builds a unique file name from the given settings value
|
||||
func (s Store) buildFilePathFromValue(value *proto.SettingsValue) string {
|
||||
return s.buildFilePathFromValueArgs(value.AccountUuid, value.Extension, value.BundleKey)
|
||||
}
|
||||
|
||||
// Builds a unique file name from the given params
|
||||
func (s Store) buildFilePathFromValueArgs(accountUuid string, extension string, bundleKey string) string {
|
||||
extensionFolder := path.Join(s.mountPath, folderNameValues, accountUuid, extension)
|
||||
s.ensureFolderExists(extensionFolder)
|
||||
return path.Join(extensionFolder, bundleKey+".json")
|
||||
}
|
||||
|
||||
// Checks if the given path is an existing folder and creates one if not existing
|
||||
func ensureFolderExists(path string) {
|
||||
func (s Store) ensureFolderExists(path string) {
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
_ = os.MkdirAll(path, 0700)
|
||||
err = os.MkdirAll(path, 0700)
|
||||
if err != nil {
|
||||
s.Logger.Err(err).Msgf("Error creating folder %v", path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,11 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
olog "github.com/owncloud/ocis-pkg/v2/log"
|
||||
"github.com/owncloud/ocis-settings/pkg/config"
|
||||
"github.com/owncloud/ocis-settings/pkg/proto/v0"
|
||||
"github.com/owncloud/ocis-settings/pkg/settings"
|
||||
)
|
||||
|
||||
@@ -17,7 +14,6 @@ var (
|
||||
// StoreName is the default name for the settings store
|
||||
StoreName = "ocis-settings-store"
|
||||
managerName = "filesystem"
|
||||
emptyKeyError = "key cannot be empty"
|
||||
)
|
||||
|
||||
// Store interacts with the filesystem to manage settings information
|
||||
@@ -43,69 +39,6 @@ func New(cfg *config.Config) settings.Manager {
|
||||
return &s
|
||||
}
|
||||
|
||||
// ListByExtension returns all bundles in the mountPath folder belonging to the given extension
|
||||
func (s Store) ListByExtension(extension string) ([]*proto.SettingsBundle, error) {
|
||||
bundlesFolder := buildFolderPathBundles(s.mountPath)
|
||||
extensionFolders, err := ioutil.ReadDir(bundlesFolder)
|
||||
if err != nil {
|
||||
s.Logger.Err(err).Msgf("error reading %v", bundlesFolder)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.Logger.Info().Msgf("listing bundles by extension %v", extension)
|
||||
var records []*proto.SettingsBundle
|
||||
for _, extensionFolder := range extensionFolders {
|
||||
extensionPath := path.Join(bundlesFolder, extensionFolder.Name())
|
||||
bundleFiles, err := ioutil.ReadDir(extensionPath)
|
||||
if err == nil {
|
||||
for _, bundleFile := range bundleFiles {
|
||||
record := proto.SettingsBundle{}
|
||||
err = s.parseRecordFromFile(&record, path.Join(extensionPath, bundleFile.Name()))
|
||||
if err == nil && (len(extension) == 0 || extension == record.Extension) {
|
||||
records = append(records, &record)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s.Logger.Err(err).Msgf("error reading %v", extensionPath)
|
||||
}
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// Read tries to find a bundle by the given extension and key within the mountPath
|
||||
func (s Store) Read(extension string, key string) (*proto.SettingsBundle, error) {
|
||||
if len(extension) < 1 || len(key) < 1 {
|
||||
s.Logger.Error().Msg("extension and key cannot be empty")
|
||||
return nil, fmt.Errorf(emptyKeyError)
|
||||
}
|
||||
|
||||
filePath := buildFilePathFromBundleArgs(s.mountPath, extension, key)
|
||||
record := proto.SettingsBundle{}
|
||||
if err := s.parseRecordFromFile(&record, filePath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.Logger.Debug().Msgf("read contents from file: %v", filePath)
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// Write writes the given record into a file within the mountPath
|
||||
func (s Store) Write(record *proto.SettingsBundle) (*proto.SettingsBundle, error) {
|
||||
if len(record.Extension) < 1 || len(record.Key) < 1 {
|
||||
s.Logger.Error().Msg("extension and key cannot be empty")
|
||||
return nil, fmt.Errorf(emptyKeyError)
|
||||
}
|
||||
|
||||
filePath := buildFilePathFromBundle(s.mountPath, record)
|
||||
if err := s.writeRecordToFile(record, filePath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.Logger.Debug().Msgf("request contents written to file: %v", filePath)
|
||||
return record, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
settings.Registry[managerName] = New
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// Package store implements the go-micro store interface
|
||||
package store
|
||||
|
||||
import (
|
||||
"github.com/owncloud/ocis-settings/pkg/proto/v0"
|
||||
"google.golang.org/grpc/codes"
|
||||
gstatus "google.golang.org/grpc/status"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Read tries to find a value by the given identifier attributes within the mountPath
|
||||
func (s Store) ReadValue(accountUuid string, extension string, bundleKey string, settingKey string) (*proto.SettingsValue, error) {
|
||||
if len(accountUuid) < 1 || len(extension) < 1 || len(bundleKey) < 1 || len(settingKey) < 1 {
|
||||
s.Logger.Error().Msg("account, extension, bundle and setting are required")
|
||||
return nil, gstatus.Errorf(codes.InvalidArgument, "Missing a required identifier attribute")
|
||||
}
|
||||
|
||||
filePath := s.buildFilePathFromValueArgs(accountUuid, extension, bundleKey)
|
||||
values, err := s.readValuesMapFromFile(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if value := values.Values[settingKey]; value != nil {
|
||||
return value, nil
|
||||
}
|
||||
// TODO: we want to return sensible defaults here, when the value was not found
|
||||
return nil, gstatus.Error(codes.NotFound, "SettingsValue not set")
|
||||
}
|
||||
|
||||
// Write writes the given SettingsValue into a file within the mountPath
|
||||
func (s Store) WriteValue(value *proto.SettingsValue) (*proto.SettingsValue, error) {
|
||||
if len(value.AccountUuid) < 1 || len(value.Extension) < 1 || len(value.BundleKey) < 1 || len(value.SettingKey) < 1 {
|
||||
s.Logger.Error().Msg("account, extension, bundle and setting are required")
|
||||
return nil, gstatus.Errorf(codes.InvalidArgument, "Missing a required identifier attribute")
|
||||
}
|
||||
|
||||
filePath := s.buildFilePathFromValue(value)
|
||||
values, err := s.readValuesMapFromFile(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
values.Values[value.SettingKey] = value
|
||||
if err := s.writeRecordToFile(values, filePath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (s Store) readValuesMapFromFile(filePath string) (*proto.SettingsValues, error) {
|
||||
values := &proto.SettingsValues{}
|
||||
err := s.parseRecordFromFile(values, filePath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
values.Values = map[string]*proto.SettingsValue{}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
Reference in New Issue
Block a user