Settings values protobuf and service

This commit is contained in:
Benedikt Kulmann
2020-04-29 09:51:22 +02:00
parent 2ea182243f
commit 8a6a06fcb8
17 changed files with 1050 additions and 514 deletions
+12 -8
View File
@@ -9,8 +9,8 @@ import (
"path"
)
// ListByExtension returns all bundles in the mountPath folder belonging to the given extension
func (s Store) ListByExtension(extension string) ([]*proto.SettingsBundle, error) {
// ListBundles returns all bundles in the mountPath folder belonging to the given extension
func (s Store) ListBundles(identifier *proto.Identifier) ([]*proto.SettingsBundle, error) {
bundlesFolder := s.buildFolderPathBundles()
extensionFolders, err := ioutil.ReadDir(bundlesFolder)
if err != nil {
@@ -18,7 +18,11 @@ func (s Store) ListByExtension(extension string) ([]*proto.SettingsBundle, error
return nil, err
}
s.Logger.Info().Msgf("listing bundles by extension %v", extension)
if len(identifier.Extension) < 1 {
s.Logger.Info().Msg("listing all bundles")
} else {
s.Logger.Info().Msgf("listing bundles by extension %v", identifier.Extension)
}
var records []*proto.SettingsBundle
for _, extensionFolder := range extensionFolders {
extensionPath := path.Join(bundlesFolder, extensionFolder.Name())
@@ -27,7 +31,7 @@ func (s Store) ListByExtension(extension string) ([]*proto.SettingsBundle, error
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) {
if err == nil && (len(identifier.Extension) == 0 || identifier.Extension == record.Identifier.Extension) {
records = append(records, &record)
}
}
@@ -40,13 +44,13 @@ func (s Store) ListByExtension(extension string) ([]*proto.SettingsBundle, error
}
// 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 {
func (s Store) ReadBundle(identifier *proto.Identifier) (*proto.SettingsBundle, error) {
if len(identifier.Extension) < 1 || len(identifier.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)
filePath := s.buildFilePathFromBundleArgs(identifier.Extension, identifier.BundleKey)
record := proto.SettingsBundle{}
if err := s.parseRecordFromFile(&record, filePath); err != nil {
return nil, err
@@ -58,7 +62,7 @@ func (s Store) ReadBundle(extension string, bundleKey string) (*proto.SettingsBu
// 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 {
if len(record.Identifier.Extension) < 1 || len(record.Identifier.BundleKey) < 1 {
s.Logger.Error().Msg("extension and bundleKey cannot be empty")
return nil, gstatus.Error(codes.InvalidArgument, "Missing a required identifier attribute")
}
+2 -2
View File
@@ -18,7 +18,7 @@ func (s Store) buildFolderPathBundles() string {
// 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)
return s.buildFilePathFromBundleArgs(bundle.Identifier.Extension, bundle.Identifier.BundleKey)
}
// Builds a unique file name from the given params
@@ -37,7 +37,7 @@ func (s Store) buildFolderPathValues() string {
// 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)
return s.buildFilePathFromValueArgs(value.Identifier.AccountUuid, value.Identifier.Extension, value.Identifier.BundleKey)
}
// Builds a unique file name from the given params
+71 -10
View File
@@ -6,31 +6,33 @@ import (
"google.golang.org/grpc/codes"
gstatus "google.golang.org/grpc/status"
"os"
"path"
"path/filepath"
)
// 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")
// Tries to find a value by the given identifier attributes within the mountPath
func (s Store) ReadValue(identifier *proto.Identifier) (*proto.SettingsValue, error) {
if len(identifier.AccountUuid) < 1 || len(identifier.Extension) < 1 || len(identifier.BundleKey) < 1 || len(identifier.SettingKey) < 1 {
s.Logger.Error().Msg("account-uuid, extension, bundle and setting are required")
return nil, gstatus.Errorf(codes.InvalidArgument, "Missing a required identifier attribute")
}
filePath := s.buildFilePathFromValueArgs(accountUuid, extension, bundleKey)
filePath := s.buildFilePathFromValueArgs(identifier.AccountUuid, identifier.Extension, identifier.BundleKey)
values, err := s.readValuesMapFromFile(filePath)
if err != nil {
return nil, err
}
if value := values.Values[settingKey]; value != nil {
if value := values.Values[identifier.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
// 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")
if len(value.Identifier.AccountUuid) < 1 || len(value.Identifier.Extension) < 1 || len(value.Identifier.BundleKey) < 1 || len(value.Identifier.SettingKey) < 1 {
s.Logger.Error().Msg("account-uuid, extension, bundle and setting are required")
return nil, gstatus.Errorf(codes.InvalidArgument, "Missing a required identifier attribute")
}
@@ -39,13 +41,72 @@ func (s Store) WriteValue(value *proto.SettingsValue) (*proto.SettingsValue, err
if err != nil {
return nil, err
}
values.Values[value.SettingKey] = value
values.Values[value.Identifier.SettingKey] = value
if err := s.writeRecordToFile(values, filePath); err != nil {
return nil, err
}
return value, nil
}
// Reads all values within the scope of the given identifier
func (s Store) ListValues(identifier *proto.Identifier) ([]*proto.SettingsValue, error) {
if len(identifier.AccountUuid) < 1 {
s.Logger.Error().Msg("account-uuid is required")
return nil, gstatus.Errorf(codes.InvalidArgument, "Missing a required identifier attribute")
}
accountFolderPath := path.Join(s.mountPath, folderNameValues, identifier.AccountUuid)
var values []*proto.SettingsValue
if _, err := os.Stat(accountFolderPath); err != nil {
return values, nil
}
// TODO: might be a good idea to do this non-hierarchical. i.e. allowing all fragments in the identifier being set or not.
// depending on the set values in the identifier arg, collect all SettingValues files for the account
var valueFilePaths []string
if len(identifier.Extension) < 1 {
if err := filepath.Walk(accountFolderPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
valueFilePaths = append(valueFilePaths, path)
return nil
}); err != nil {
s.Logger.Err(err).Msgf("error reading %v", accountFolderPath)
return nil, err
}
} else if len(identifier.BundleKey) < 1 {
extensionPath := path.Join(accountFolderPath, identifier.Extension)
if err := filepath.Walk(extensionPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
valueFilePaths = append(valueFilePaths, path)
return nil
}); err != nil {
s.Logger.Err(err).Msgf("error reading %v", extensionPath)
return nil, err
}
} else {
bundlePath := path.Join(accountFolderPath, identifier.Extension, identifier.BundleKey+".json")
valueFilePaths = append(valueFilePaths, bundlePath)
}
// parse the SettingValues from the collected files
for _, filePath := range valueFilePaths {
bundleValues, err := s.readValuesMapFromFile(filePath)
if err != nil {
s.Logger.Err(err).Msgf("error reading %v", filePath)
} else {
for _, value := range bundleValues.Values {
values = append(values, value)
}
}
}
return values, nil
}
// Reads SettingsValues as map from the given file or returns an empty map if the file doesn't exist.
func (s Store) readValuesMapFromFile(filePath string) (*proto.SettingsValues, error) {
values := &proto.SettingsValues{}
err := s.parseRecordFromFile(values, filePath)