mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-02-28 09:29:41 -06:00
graph: Make user and group lookup cache re-usable
drives.go implemented a local user/group cache (ttl based) to speed up repeated user and group lookups. This commit moves the implementation to the 'identity' module to make it usable outside of drives.go.
This commit is contained in:
committed by
Ralf Haferkamp
parent
f2599dfa76
commit
c9df9f5f31
139
services/graph/pkg/identity/cache.go
Normal file
139
services/graph/pkg/identity/cache.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package identity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
cs3Group "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
|
||||
cs3User "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
revautils "github.com/cs3org/reva/v2/pkg/utils"
|
||||
"github.com/jellydator/ttlcache/v3"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
"github.com/owncloud/ocis/v2/services/graph/pkg/service/v0/errorcode"
|
||||
)
|
||||
|
||||
// IdentityCache implements a simple ttl based cache for looking up users and groups by ID
|
||||
type IdentityCache struct {
|
||||
users *ttlcache.Cache[string, libregraph.User]
|
||||
groups *ttlcache.Cache[string, libregraph.Group]
|
||||
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
}
|
||||
|
||||
type identityCacheOptions struct {
|
||||
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
usersTTL time.Duration
|
||||
groupsTTL time.Duration
|
||||
}
|
||||
|
||||
// IdentityCacheOptiondefines a single option function.
|
||||
type IdentityCacheOption func(o *identityCacheOptions)
|
||||
|
||||
// IdentityCacheWithGatewaySelector set the gatewaySelector for the Identity Cache
|
||||
func IdentityCacheWithGatewaySelector(gatewaySelector pool.Selectable[gateway.GatewayAPIClient]) IdentityCacheOption {
|
||||
return func(o *identityCacheOptions) {
|
||||
o.gatewaySelector = gatewaySelector
|
||||
}
|
||||
}
|
||||
|
||||
// IdentityCacheWithUsersTTL sets the TTL for the users cache
|
||||
func IdentityCacheWithUsersTTL(ttl time.Duration) IdentityCacheOption {
|
||||
return func(o *identityCacheOptions) {
|
||||
o.usersTTL = ttl
|
||||
}
|
||||
}
|
||||
|
||||
// IdentityCacheWithGroupsTTL sets the TTL for the groups cache
|
||||
func IdentityCacheWithGroupsTTL(ttl time.Duration) IdentityCacheOption {
|
||||
return func(o *identityCacheOptions) {
|
||||
o.groupsTTL = ttl
|
||||
}
|
||||
}
|
||||
|
||||
func newOptions(opts ...IdentityCacheOption) identityCacheOptions {
|
||||
opt := identityCacheOptions{}
|
||||
for _, o := range opts {
|
||||
o(&opt)
|
||||
}
|
||||
return opt
|
||||
}
|
||||
|
||||
// NewIdentityCache instanciates a new IdentityCache and sets the supplied options
|
||||
func NewIdentityCache(opts ...IdentityCacheOption) IdentityCache {
|
||||
opt := newOptions(opts...)
|
||||
|
||||
var cache IdentityCache
|
||||
|
||||
cache.users = ttlcache.New(
|
||||
ttlcache.WithTTL[string, libregraph.User](opt.usersTTL),
|
||||
ttlcache.WithDisableTouchOnHit[string, libregraph.User](),
|
||||
)
|
||||
go cache.users.Start()
|
||||
|
||||
cache.groups = ttlcache.New(
|
||||
ttlcache.WithTTL[string, libregraph.Group](opt.groupsTTL),
|
||||
ttlcache.WithDisableTouchOnHit[string, libregraph.Group](),
|
||||
)
|
||||
go cache.groups.Start()
|
||||
|
||||
cache.gatewaySelector = opt.gatewaySelector
|
||||
|
||||
return cache
|
||||
}
|
||||
|
||||
// GetUser looks up a user by id, if the user is not cached yet it will do a lookup via the CS3 API
|
||||
func (cache IdentityCache) GetUser(ctx context.Context, userid string) (libregraph.User, error) {
|
||||
var user libregraph.User
|
||||
if item := cache.users.Get(userid); item == nil {
|
||||
gatewayClient, err := cache.gatewaySelector.Next()
|
||||
cs3UserID := &cs3User.UserId{
|
||||
OpaqueId: userid,
|
||||
}
|
||||
cs3User, err := revautils.GetUser(cs3UserID, gatewayClient)
|
||||
if err != nil {
|
||||
if revautils.IsErrNotFound(err) {
|
||||
return libregraph.User{}, ErrNotFound
|
||||
}
|
||||
return libregraph.User{}, errorcode.New(errorcode.GeneralException, err.Error())
|
||||
}
|
||||
user = *CreateUserModelFromCS3(cs3User)
|
||||
cache.users.Set(userid, user, ttlcache.DefaultTTL)
|
||||
|
||||
} else {
|
||||
user = item.Value()
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// GetUser looks up a group by id, if the group is not cached yet it will do a lookup via the CS3 API
|
||||
func (cache IdentityCache) GetGroup(ctx context.Context, groupid string) (libregraph.Group, error) {
|
||||
var group libregraph.Group
|
||||
if item := cache.groups.Get(groupid); item == nil {
|
||||
gatewayClient, err := cache.gatewaySelector.Next()
|
||||
cs3GroupID := &cs3Group.GroupId{
|
||||
OpaqueId: groupid,
|
||||
}
|
||||
req := cs3Group.GetGroupRequest{
|
||||
GroupId: cs3GroupID,
|
||||
}
|
||||
res, err := gatewayClient.GetGroup(ctx, &req)
|
||||
if err != nil {
|
||||
return group, errorcode.New(errorcode.GeneralException, err.Error())
|
||||
}
|
||||
switch res.Status.Code {
|
||||
case rpc.Code_CODE_OK:
|
||||
cs3Group := res.GetGroup()
|
||||
group = *CreateGroupModelFromCS3(cs3Group)
|
||||
cache.groups.Set(groupid, group, ttlcache.DefaultTTL)
|
||||
case rpc.Code_CODE_NOT_FOUND:
|
||||
return group, ErrNotFound
|
||||
default:
|
||||
return group, errorcode.New(errorcode.GeneralException, res.Status.Message)
|
||||
}
|
||||
} else {
|
||||
group = item.Value()
|
||||
}
|
||||
return group, nil
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"github.com/cs3org/reva/v2/pkg/storagespace"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/jellydator/ttlcache/v3"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/service/grpc"
|
||||
v0 "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
|
||||
@@ -780,28 +779,16 @@ func (g Graph) cs3PermissionsToLibreGraph(ctx context.Context, space *storagepro
|
||||
tmp := id
|
||||
var identitySet libregraph.IdentitySet
|
||||
if _, ok := groupsMap[id]; ok {
|
||||
var group libregraph.Group
|
||||
if item := g.groupsCache.Get(id); item == nil {
|
||||
if requestedGroup, err := g.identityBackend.GetGroup(ctx, id, url.Values{}); err == nil {
|
||||
group = *requestedGroup
|
||||
g.groupsCache.Set(id, group, ttlcache.DefaultTTL)
|
||||
}
|
||||
} else {
|
||||
group = item.Value()
|
||||
group, err := g.identityCache.GetGroup(ctx, tmp)
|
||||
if err != nil {
|
||||
g.logger.Warn().Str("groupid", tmp).Msg("Group not found by id")
|
||||
}
|
||||
|
||||
identitySet = libregraph.IdentitySet{Group: &libregraph.Identity{Id: &tmp, DisplayName: group.GetDisplayName()}}
|
||||
} else {
|
||||
var user libregraph.User
|
||||
if item := g.usersCache.Get(id); item == nil {
|
||||
if requestedUser, err := g.identityBackend.GetUser(ctx, id, &godata.GoDataRequest{}); err == nil {
|
||||
user = *requestedUser
|
||||
g.usersCache.Set(id, user, ttlcache.DefaultTTL)
|
||||
}
|
||||
} else {
|
||||
user = item.Value()
|
||||
user, err := g.identityCache.GetUser(ctx, tmp)
|
||||
if err != nil {
|
||||
g.logger.Warn().Str("userid", tmp).Msg("User not found by id")
|
||||
}
|
||||
|
||||
identitySet = libregraph.IdentitySet{User: &libregraph.Identity{Id: &tmp, DisplayName: user.GetDisplayName()}}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/cs3org/reva/v2/pkg/storagespace"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/jellydator/ttlcache/v3"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/keycloak"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/log"
|
||||
ehsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/eventhistory/v0"
|
||||
@@ -71,8 +70,7 @@ type Graph struct {
|
||||
roleService RoleService
|
||||
permissionsService Permissions
|
||||
specialDriveItemsCache *ttlcache.Cache[string, interface{}]
|
||||
usersCache *ttlcache.Cache[string, libregraph.User]
|
||||
groupsCache *ttlcache.Cache[string, libregraph.Group]
|
||||
identityCache identity.IdentityCache
|
||||
eventsPublisher events.Publisher
|
||||
searchService searchsvc.SearchProviderService
|
||||
keycloakClient keycloak.Client
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
ldapv3 "github.com/go-ldap/ldap/v3"
|
||||
"github.com/jellydator/ttlcache/v3"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
ocisldap "github.com/owncloud/ocis/v2/ocis-pkg/ldap"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/registry"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/roles"
|
||||
@@ -125,29 +124,18 @@ func NewService(opts ...Option) (Graph, error) {
|
||||
)
|
||||
go spacePropertiesCache.Start()
|
||||
|
||||
usersCache := ttlcache.New(
|
||||
ttlcache.WithTTL[string, libregraph.User](
|
||||
time.Duration(options.Config.Spaces.UsersCacheTTL),
|
||||
),
|
||||
ttlcache.WithDisableTouchOnHit[string, libregraph.User](),
|
||||
identityCache := identity.NewIdentityCache(
|
||||
identity.IdentityCacheWithGatewaySelector(options.GatewaySelector),
|
||||
identity.IdentityCacheWithUsersTTL(time.Duration(options.Config.Spaces.UsersCacheTTL)),
|
||||
identity.IdentityCacheWithGroupsTTL(time.Duration(options.Config.Spaces.GroupsCacheTTL)),
|
||||
)
|
||||
go usersCache.Start()
|
||||
|
||||
groupsCache := ttlcache.New(
|
||||
ttlcache.WithTTL[string, libregraph.Group](
|
||||
time.Duration(options.Config.Spaces.GroupsCacheTTL),
|
||||
),
|
||||
ttlcache.WithDisableTouchOnHit[string, libregraph.Group](),
|
||||
)
|
||||
go groupsCache.Start()
|
||||
|
||||
svc := Graph{
|
||||
config: options.Config,
|
||||
mux: m,
|
||||
logger: &options.Logger,
|
||||
specialDriveItemsCache: spacePropertiesCache,
|
||||
usersCache: usersCache,
|
||||
groupsCache: groupsCache,
|
||||
identityCache: identityCache,
|
||||
eventsPublisher: options.EventsPublisher,
|
||||
gatewaySelector: options.GatewaySelector,
|
||||
searchService: options.SearchService,
|
||||
|
||||
Reference in New Issue
Block a user