diff --git a/changelog/unreleased/favorite-cbox-driver.md b/changelog/unreleased/favorite-cbox-driver.md new file mode 100644 index 0000000000..e30253ab7f --- /dev/null +++ b/changelog/unreleased/favorite-cbox-driver.md @@ -0,0 +1,3 @@ +Enhancement: Revamp the favorite manager and add the cbox sql driver + +https://github.com/cs3org/reva/pull/2271 \ No newline at end of file diff --git a/cmd/revad/runtime/loader.go b/cmd/revad/runtime/loader.go index ed50b3913e..93f5c68ace 100644 --- a/cmd/revad/runtime/loader.go +++ b/cmd/revad/runtime/loader.go @@ -42,6 +42,7 @@ import ( _ "github.com/cs3org/reva/pkg/rhttp/datatx/manager/loader" _ "github.com/cs3org/reva/pkg/share/cache/loader" _ "github.com/cs3org/reva/pkg/share/manager/loader" + _ "github.com/cs3org/reva/pkg/storage/favorite/loader" _ "github.com/cs3org/reva/pkg/storage/fs/loader" _ "github.com/cs3org/reva/pkg/storage/registry/loader" _ "github.com/cs3org/reva/pkg/token/manager/loader" diff --git a/internal/http/services/owncloud/ocdav/ocdav.go b/internal/http/services/owncloud/ocdav/ocdav.go index 3fa1eadb5d..27d11407b2 100644 --- a/internal/http/services/owncloud/ocdav/ocdav.go +++ b/internal/http/services/owncloud/ocdav/ocdav.go @@ -35,12 +35,14 @@ import ( provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" "github.com/cs3org/reva/pkg/appctx" ctxpkg "github.com/cs3org/reva/pkg/ctx" + "github.com/cs3org/reva/pkg/errtypes" "github.com/cs3org/reva/pkg/rgrpc/todo/pool" "github.com/cs3org/reva/pkg/rhttp" "github.com/cs3org/reva/pkg/rhttp/global" "github.com/cs3org/reva/pkg/rhttp/router" "github.com/cs3org/reva/pkg/sharedconf" "github.com/cs3org/reva/pkg/storage/favorite" + "github.com/cs3org/reva/pkg/storage/favorite/registry" "github.com/cs3org/reva/pkg/storage/utils/templates" "github.com/mitchellh/mapstructure" "github.com/pkg/errors" @@ -98,16 +100,22 @@ type Config struct { // Example: if WebdavNamespace is /users/{{substr 0 1 .Username}}/{{.Username}} // and received path is /docs the internal path will be: // /users///docs - WebdavNamespace string `mapstructure:"webdav_namespace"` - GatewaySvc string `mapstructure:"gatewaysvc"` - Timeout int64 `mapstructure:"timeout"` - Insecure bool `mapstructure:"insecure"` - PublicURL string `mapstructure:"public_url"` + WebdavNamespace string `mapstructure:"webdav_namespace"` + GatewaySvc string `mapstructure:"gatewaysvc"` + Timeout int64 `mapstructure:"timeout"` + Insecure bool `mapstructure:"insecure"` + PublicURL string `mapstructure:"public_url"` + FavoriteStorageDriver string `mapstructure:"favorite_storage_driver"` + FavoriteStorageDrivers map[string]map[string]interface{} `mapstructure:"favorite_storage_drivers"` } func (c *Config) init() { // note: default c.Prefix is an empty string c.GatewaySvc = sharedconf.GetGatewaySVC(c.GatewaySvc) + + if c.FavoriteStorageDriver == "" { + c.FavoriteStorageDriver = "memory" + } } type svc struct { @@ -118,6 +126,13 @@ type svc struct { client *http.Client } +func getFavoritesManager(c *Config) (favorite.Manager, error) { + if f, ok := registry.NewFuncs[c.FavoriteStorageDriver]; ok { + return f(c.FavoriteStorageDrivers[c.FavoriteStorageDriver]) + } + return nil, errtypes.NotFound("driver not found: " + c.FavoriteStorageDriver) +} + // New returns a new ocdav func New(m map[string]interface{}, log *zerolog.Logger) (global.Service, error) { conf := &Config{} @@ -127,6 +142,11 @@ func New(m map[string]interface{}, log *zerolog.Logger) (global.Service, error) conf.init() + fm, err := getFavoritesManager(conf) + if err != nil { + return nil, err + } + s := &svc{ c: conf, webDavHandler: new(WebDavHandler), @@ -135,7 +155,7 @@ func New(m map[string]interface{}, log *zerolog.Logger) (global.Service, error) rhttp.Timeout(time.Duration(conf.Timeout*int64(time.Second))), rhttp.Insecure(conf.Insecure), ), - favoritesManager: favorite.NewInMemoryManager(), + favoritesManager: fm, } // initialize handlers and set default configs if err := s.webDavHandler.init(conf.WebdavNamespace, true); err != nil { diff --git a/internal/http/services/owncloud/ocdav/proppatch.go b/internal/http/services/owncloud/ocdav/proppatch.go index d7d5ce4a42..77c39673f7 100644 --- a/internal/http/services/owncloud/ocdav/proppatch.go +++ b/internal/http/services/owncloud/ocdav/proppatch.go @@ -240,7 +240,7 @@ func (s *svc) handleProppatch(ctx context.Context, w http.ResponseWriter, r *htt return nil, nil, false } currentUser := ctxpkg.ContextMustGetUser(ctx) - err = s.favoritesManager.UnsetFavorite(ctx, currentUser.Id, statRes.Info.Id) + err = s.favoritesManager.UnsetFavorite(ctx, currentUser.Id, statRes.Info) if err != nil { w.WriteHeader(http.StatusInternalServerError) return nil, nil, false @@ -281,7 +281,7 @@ func (s *svc) handleProppatch(ctx context.Context, w http.ResponseWriter, r *htt return nil, nil, false } currentUser := ctxpkg.ContextMustGetUser(ctx) - err = s.favoritesManager.SetFavorite(ctx, currentUser.Id, statRes.Info.Id) + err = s.favoritesManager.SetFavorite(ctx, currentUser.Id, statRes.Info) if err != nil { w.WriteHeader(http.StatusInternalServerError) return nil, nil, false diff --git a/internal/http/services/owncloud/ocdav/report.go b/internal/http/services/owncloud/ocdav/report.go index 49df7b4f1d..39729be770 100644 --- a/internal/http/services/owncloud/ocdav/report.go +++ b/internal/http/services/owncloud/ocdav/report.go @@ -107,14 +107,17 @@ func (s *svc) doFilterFiles(w http.ResponseWriter, r *http.Request, ff *reportFi continue } - // The paths we receive have the format /user// - // We only want the `` part. Thus we remove the /user// part. - parts := strings.SplitN(statRes.Info.Path, "/", 4) - if len(parts) != 4 { - log.Error().Str("path", statRes.Info.Path).Msg("path doesn't have the expected format") - continue + // If global URLs are not supported, return only the file path + if s.c.WebdavNamespace != "" { + // The paths we receive have the format /user// + // We only want the `` part. Thus we remove the /user// part. + parts := strings.SplitN(statRes.Info.Path, "/", 4) + if len(parts) != 4 { + log.Error().Str("path", statRes.Info.Path).Msg("path doesn't have the expected format") + continue + } + statRes.Info.Path = parts[3] } - statRes.Info.Path = parts[3] infos = append(infos, statRes.Info) } diff --git a/pkg/cbox/favorite/sql/sql.go b/pkg/cbox/favorite/sql/sql.go new file mode 100644 index 0000000000..3a49b8c99c --- /dev/null +++ b/pkg/cbox/favorite/sql/sql.go @@ -0,0 +1,136 @@ +// Copyright 2018-2021 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package cbox + +import ( + "context" + "database/sql" + "fmt" + + user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + "github.com/cs3org/reva/pkg/cbox/utils" + ctxpkg "github.com/cs3org/reva/pkg/ctx" + "github.com/cs3org/reva/pkg/storage/favorite" + "github.com/cs3org/reva/pkg/storage/favorite/registry" + "github.com/mitchellh/mapstructure" +) + +func init() { + registry.Register("sql", New) +} + +type config struct { + DbUsername string `mapstructure:"db_username"` + DbPassword string `mapstructure:"db_password"` + DbHost string `mapstructure:"db_host"` + DbPort int `mapstructure:"db_port"` + DbName string `mapstructure:"db_name"` +} + +type mgr struct { + c *config + db *sql.DB +} + +// New returns an instance of the cbox sql favorites manager. +func New(m map[string]interface{}) (favorite.Manager, error) { + c := &config{} + if err := mapstructure.Decode(m, c); err != nil { + return nil, err + } + + db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", c.DbUsername, c.DbPassword, c.DbHost, c.DbPort, c.DbName)) + if err != nil { + return nil, err + } + + return &mgr{ + c: c, + db: db, + }, nil +} + +func (m *mgr) ListFavorites(ctx context.Context, userID *user.UserId) ([]*provider.ResourceId, error) { + user := ctxpkg.ContextMustGetUser(ctx) + infos := []*provider.ResourceId{} + query := `SELECT fileid_prefix, fileid FROM cbox_metadata WHERE uid=? AND tag_key="fav"` + rows, err := m.db.Query(query, user.Id.OpaqueId) + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var info provider.ResourceId + if err := rows.Scan(&info.StorageId, &info.OpaqueId); err != nil { + return nil, err + } + infos = append(infos, &info) + } + + if err = rows.Err(); err != nil { + return nil, err + } + return infos, nil +} + +func (m *mgr) SetFavorite(ctx context.Context, userID *user.UserId, resourceInfo *provider.ResourceInfo) error { + user := ctxpkg.ContextMustGetUser(ctx) + + // The primary key is just the ID in the table, it should ideally be (uid, fileid_prefix, fileid, tag_key) + // For the time being, just check if the favorite already exists. If it does, return early + var id int + query := `"SELECT id FROM cbox_metadata WHERE uid=? AND fileid_prefix=? AND fileid=? AND tag_key="fav"` + if err := m.db.QueryRow(query, user.Id.OpaqueId, resourceInfo.Id.StorageId, resourceInfo.Id.OpaqueId).Scan(&id); err == nil { + // Favorite is already set, return + return nil + } + + query = `INSERT INTO cbox_metadata SET item_type=?, uid=?, fileid_prefix=?, fileid=?, tag_key="fav"` + vals := []interface{}{utils.ResourceTypeToItemInt(resourceInfo.Type), user.Id.OpaqueId, resourceInfo.Id.StorageId, resourceInfo.Id.OpaqueId} + stmt, err := m.db.Prepare(query) + if err != nil { + return err + } + + if _, err = stmt.Exec(vals...); err != nil { + return err + } + return nil +} + +func (m *mgr) UnsetFavorite(ctx context.Context, userID *user.UserId, resourceInfo *provider.ResourceInfo) error { + user := ctxpkg.ContextMustGetUser(ctx) + stmt, err := m.db.Prepare(`DELETE FROM cbox_metadata WHERE uid=? AND fileid_prefix=? AND fileid=? AND tag_key="fav"`) + if err != nil { + return err + } + + res, err := stmt.Exec(user.Id.OpaqueId, resourceInfo.Id.StorageId, resourceInfo.Id.OpaqueId) + if err != nil { + return err + } + + _, err = res.RowsAffected() + if err != nil { + return err + } + return nil +} diff --git a/pkg/cbox/loader/loader.go b/pkg/cbox/loader/loader.go index a215a8aa03..0dd9d07c4b 100644 --- a/pkg/cbox/loader/loader.go +++ b/pkg/cbox/loader/loader.go @@ -20,6 +20,7 @@ package loader import ( // Load cbox specific drivers. + _ "github.com/cs3org/reva/pkg/cbox/favorite/sql" _ "github.com/cs3org/reva/pkg/cbox/group/rest" _ "github.com/cs3org/reva/pkg/cbox/publicshare/sql" _ "github.com/cs3org/reva/pkg/cbox/share/sql" diff --git a/pkg/cbox/utils/conversions.go b/pkg/cbox/utils/conversions.go index 2f73cc6ea5..20d2297b4f 100644 --- a/pkg/cbox/utils/conversions.go +++ b/pkg/cbox/utils/conversions.go @@ -83,7 +83,7 @@ func ExtractGrantee(t int, g string) *provider.Grantee { return &grantee } -// ResourceTypeToItem maps a resource type to an integer +// ResourceTypeToItem maps a resource type to a string func ResourceTypeToItem(r provider.ResourceType) string { switch r { case provider.ResourceType_RESOURCE_TYPE_FILE: @@ -99,6 +99,18 @@ func ResourceTypeToItem(r provider.ResourceType) string { } } +// ResourceTypeToItemInt maps a resource type to an integer +func ResourceTypeToItemInt(r provider.ResourceType) int { + switch r { + case provider.ResourceType_RESOURCE_TYPE_CONTAINER: + return 0 + case provider.ResourceType_RESOURCE_TYPE_FILE: + return 1 + default: + return -1 + } +} + // SharePermToInt maps read/write permissions to an integer func SharePermToInt(p *provider.ResourcePermissions) int { var perm int diff --git a/pkg/storage/favorite/favorite.go b/pkg/storage/favorite/favorite.go index 65847cb3ac..73a8bebd8a 100644 --- a/pkg/storage/favorite/favorite.go +++ b/pkg/storage/favorite/favorite.go @@ -20,7 +20,6 @@ package favorite import ( "context" - "sync" user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" @@ -31,49 +30,7 @@ type Manager interface { // ListFavorites returns all resources that were favorited by a user. ListFavorites(ctx context.Context, userID *user.UserId) ([]*provider.ResourceId, error) // SetFavorite marks a resource as favorited by a user. - SetFavorite(ctx context.Context, userID *user.UserId, resourceID *provider.ResourceId) error + SetFavorite(ctx context.Context, userID *user.UserId, resourceInfo *provider.ResourceInfo) error // UnsetFavorite unmarks a resource as favorited by a user. - UnsetFavorite(ctx context.Context, userID *user.UserId, resourceID *provider.ResourceId) error -} - -// NewInMemoryManager returns an instance of the in-memory favorites manager. -func NewInMemoryManager() *InMemoryManager { - return &InMemoryManager{favorites: make(map[string]map[string]*provider.ResourceId)} -} - -// InMemoryManager implements the Manager interface to manage favorites using an in-memory storage. -// This should not be used in production but can be used for tests. -type InMemoryManager struct { - sync.RWMutex - favorites map[string]map[string]*provider.ResourceId -} - -// ListFavorites returns all resources that were favorited by a user. -func (m *InMemoryManager) ListFavorites(ctx context.Context, userID *user.UserId) ([]*provider.ResourceId, error) { - m.RLock() - defer m.RUnlock() - favorites := make([]*provider.ResourceId, 0, len(m.favorites[userID.OpaqueId])) - for _, id := range m.favorites[userID.OpaqueId] { - favorites = append(favorites, id) - } - return favorites, nil -} - -// SetFavorite marks a resource as favorited by a user. -func (m *InMemoryManager) SetFavorite(_ context.Context, userID *user.UserId, resourceID *provider.ResourceId) error { - m.Lock() - defer m.Unlock() - if m.favorites[userID.OpaqueId] == nil { - m.favorites[userID.OpaqueId] = make(map[string]*provider.ResourceId) - } - m.favorites[userID.OpaqueId][resourceID.OpaqueId] = resourceID - return nil -} - -// UnsetFavorite unmarks a resource as favorited by a user. -func (m *InMemoryManager) UnsetFavorite(_ context.Context, userID *user.UserId, resourceID *provider.ResourceId) error { - m.Lock() - defer m.Unlock() - delete(m.favorites[userID.OpaqueId], resourceID.OpaqueId) - return nil + UnsetFavorite(ctx context.Context, userID *user.UserId, resourceInfo *provider.ResourceInfo) error } diff --git a/pkg/storage/favorite/loader/loader.go b/pkg/storage/favorite/loader/loader.go new file mode 100644 index 0000000000..de90e7223c --- /dev/null +++ b/pkg/storage/favorite/loader/loader.go @@ -0,0 +1,25 @@ +// Copyright 2018-2021 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package loader + +import ( + // Load share cache drivers. + _ "github.com/cs3org/reva/pkg/storage/favorite/memory" + // Add your own here +) diff --git a/pkg/storage/favorite/memory/memory.go b/pkg/storage/favorite/memory/memory.go new file mode 100644 index 0000000000..3126224432 --- /dev/null +++ b/pkg/storage/favorite/memory/memory.go @@ -0,0 +1,70 @@ +// Copyright 2018-2021 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package memory + +import ( + "context" + "sync" + + user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + "github.com/cs3org/reva/pkg/storage/favorite" + "github.com/cs3org/reva/pkg/storage/favorite/registry" +) + +func init() { + registry.Register("memory", New) +} + +type mgr struct { + sync.RWMutex + favorites map[string]map[string]*provider.ResourceId +} + +// New returns an instance of the in-memory favorites manager. +func New(m map[string]interface{}) (favorite.Manager, error) { + return &mgr{favorites: make(map[string]map[string]*provider.ResourceId)}, nil +} + +func (m *mgr) ListFavorites(_ context.Context, userID *user.UserId) ([]*provider.ResourceId, error) { + m.RLock() + defer m.RUnlock() + favorites := make([]*provider.ResourceId, 0, len(m.favorites[userID.OpaqueId])) + for _, id := range m.favorites[userID.OpaqueId] { + favorites = append(favorites, id) + } + return favorites, nil +} + +func (m *mgr) SetFavorite(_ context.Context, userID *user.UserId, resourceInfo *provider.ResourceInfo) error { + m.Lock() + defer m.Unlock() + if m.favorites[userID.OpaqueId] == nil { + m.favorites[userID.OpaqueId] = make(map[string]*provider.ResourceId) + } + m.favorites[userID.OpaqueId][resourceInfo.Id.OpaqueId] = resourceInfo.Id + return nil +} + +func (m *mgr) UnsetFavorite(_ context.Context, userID *user.UserId, resourceInfo *provider.ResourceInfo) error { + m.Lock() + defer m.Unlock() + delete(m.favorites[userID.OpaqueId], resourceInfo.Id.OpaqueId) + return nil +} diff --git a/pkg/storage/favorite/favorite_test.go b/pkg/storage/favorite/memory/memory_test.go similarity index 95% rename from pkg/storage/favorite/favorite_test.go rename to pkg/storage/favorite/memory/memory_test.go index 61da0cfe9f..263ed97ce6 100644 --- a/pkg/storage/favorite/favorite_test.go +++ b/pkg/storage/favorite/memory/memory_test.go @@ -16,7 +16,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -package favorite +package memory import ( "context" @@ -65,16 +65,16 @@ func createEnvironment() environment { func TestListFavorite(t *testing.T) { env := createEnvironment() - sut := NewInMemoryManager() + sut, _ := New(nil) favorites, _ := sut.ListFavorites(env.userOneCtx, env.userOne.Id) if len(favorites) != 0 { t.Error("ListFavorites should not return anything when a user hasn't set a favorite") } - _ = sut.SetFavorite(env.userOneCtx, env.userOne.Id, env.resourceInfoOne.Id) - _ = sut.SetFavorite(env.userTwoCtx, env.userTwo.Id, env.resourceInfoOne.Id) - _ = sut.SetFavorite(env.userTwoCtx, env.userTwo.Id, env.resourceInfoTwo.Id) + _ = sut.SetFavorite(env.userOneCtx, env.userOne.Id, env.resourceInfoOne) + _ = sut.SetFavorite(env.userTwoCtx, env.userTwo.Id, env.resourceInfoOne) + _ = sut.SetFavorite(env.userTwoCtx, env.userTwo.Id, env.resourceInfoTwo) favorites, _ = sut.ListFavorites(env.userOneCtx, env.userOne.Id) if len(favorites) != 1 { @@ -95,12 +95,12 @@ func TestListFavorite(t *testing.T) { func TestSetFavorite(t *testing.T) { env := createEnvironment() - sut := NewInMemoryManager() + sut, _ := New(nil) favorites, _ := sut.ListFavorites(env.userOneCtx, env.userOne.Id) lenBefore := len(favorites) - _ = sut.SetFavorite(env.userOneCtx, env.userOne.Id, env.resourceInfoOne.Id) + _ = sut.SetFavorite(env.userOneCtx, env.userOne.Id, env.resourceInfoOne) favorites, _ = sut.ListFavorites(env.userOneCtx, env.userOne.Id) lenAfter := len(favorites) @@ -113,13 +113,13 @@ func TestSetFavorite(t *testing.T) { func TestUnsetFavorite(t *testing.T) { env := createEnvironment() - sut := NewInMemoryManager() + sut, _ := New(nil) - _ = sut.SetFavorite(env.userOneCtx, env.userOne.Id, env.resourceInfoOne.Id) + _ = sut.SetFavorite(env.userOneCtx, env.userOne.Id, env.resourceInfoOne) favorites, _ := sut.ListFavorites(env.userOneCtx, env.userOne.Id) lenBefore := len(favorites) - _ = sut.UnsetFavorite(env.userOneCtx, env.userOne.Id, env.resourceInfoOne.Id) + _ = sut.UnsetFavorite(env.userOneCtx, env.userOne.Id, env.resourceInfoOne) favorites, _ = sut.ListFavorites(env.userOneCtx, env.userOne.Id) lenAfter := len(favorites) diff --git a/pkg/storage/favorite/registry/registry.go b/pkg/storage/favorite/registry/registry.go new file mode 100644 index 0000000000..c5e0befa24 --- /dev/null +++ b/pkg/storage/favorite/registry/registry.go @@ -0,0 +1,34 @@ +// Copyright 2018-2021 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package registry + +import "github.com/cs3org/reva/pkg/storage/favorite" + +// NewFunc is the function that favorite storage implementations +// should register at init time. +type NewFunc func(map[string]interface{}) (favorite.Manager, error) + +// NewFuncs is a map containing all the registered favorite storage implementations. +var NewFuncs = map[string]NewFunc{} + +// Register registers a new favorite storage function. +// Not safe for concurrent use. Safe for use from package init. +func Register(name string, f NewFunc) { + NewFuncs[name] = f +}