[full-ci] enhancement: use reva client pool selectors (#6452)
* enhancement: use reva client pool selectors register mock service to registry and pass tests * enhancement: bump reva * Fix a couple of linter issues --------- Co-authored-by: Ralf Haferkamp <rhaferkamp@owncloud.com>
This commit is contained in:
co-authored by
Ralf Haferkamp
parent
021c9fcdd9
commit
4f26424db6
+1
-1
@@ -19,8 +19,8 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"github.com/cs3org/reva/v2/pkg/registry"
|
||||
"github.com/rs/zerolog"
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
// Option defines a single option function.
|
||||
|
||||
+3
-15
@@ -30,12 +30,11 @@ import (
|
||||
|
||||
"github.com/cs3org/reva/v2/cmd/revad/internal/grace"
|
||||
"github.com/cs3org/reva/v2/pkg/logger"
|
||||
"github.com/cs3org/reva/v2/pkg/registry/memory"
|
||||
"github.com/cs3org/reva/v2/pkg/registry"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc"
|
||||
"github.com/cs3org/reva/v2/pkg/rhttp"
|
||||
"github.com/cs3org/reva/v2/pkg/sharedconf"
|
||||
rtrace "github.com/cs3org/reva/v2/pkg/trace"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog"
|
||||
@@ -55,19 +54,8 @@ func RunWithOptions(mainConf map[string]interface{}, pidFile string, opts ...Opt
|
||||
parseSharedConfOrDie(mainConf["shared"])
|
||||
coreConf := parseCoreConfOrDie(mainConf["core"])
|
||||
|
||||
// TODO: one can pass the options from the config file to registry.New() and initialize a registry based upon config files.
|
||||
if options.Registry != nil {
|
||||
utils.GlobalRegistry = options.Registry
|
||||
} else if _, ok := mainConf["registry"]; ok {
|
||||
for _, services := range mainConf["registry"].(map[string]interface{}) {
|
||||
for sName, nodes := range services.(map[string]interface{}) {
|
||||
for _, instance := range nodes.([]interface{}) {
|
||||
if err := utils.GlobalRegistry.Add(memory.NewService(sName, instance.(map[string]interface{})["nodes"].([]interface{}))); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := registry.Init(options.Registry); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
run(mainConf, coreConf, options.Logger, pidFile)
|
||||
|
||||
+1
@@ -44,6 +44,7 @@ func (s *svc) Authenticate(ctx context.Context, req *gateway.AuthenticateRequest
|
||||
// find auth provider
|
||||
c, err := s.findAuthProvider(ctx, req.Type)
|
||||
if err != nil {
|
||||
log.Err(err).Str("type", req.Type).Msg("error getting auth provider client")
|
||||
return &gateway.AuthenticateResponse{
|
||||
Status: status.NewInternal(ctx, "error getting auth provider client"),
|
||||
}, nil
|
||||
|
||||
Generated
Vendored
+75
-19
@@ -59,8 +59,8 @@ type config struct {
|
||||
}
|
||||
|
||||
type service struct {
|
||||
conf *config
|
||||
gateway gateway.GatewayAPIClient
|
||||
conf *config
|
||||
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
}
|
||||
|
||||
func (s *service) Close() error {
|
||||
@@ -91,14 +91,14 @@ func New(m map[string]interface{}, ss *grpc.Server) (rgrpc.Service, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gateway, err := pool.GetGatewayServiceClient(c.GatewayAddr)
|
||||
gatewaySelector, err := pool.GatewaySelector(c.GatewayAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
service := &service{
|
||||
conf: c,
|
||||
gateway: gateway,
|
||||
conf: c,
|
||||
gatewaySelector: gatewaySelector,
|
||||
}
|
||||
|
||||
return service, nil
|
||||
@@ -114,7 +114,11 @@ func (s *service) SetArbitraryMetadata(ctx context.Context, req *provider.SetArb
|
||||
Status: st,
|
||||
}, nil
|
||||
}
|
||||
return s.gateway.SetArbitraryMetadata(ctx, &provider.SetArbitraryMetadataRequest{Opaque: req.Opaque, Ref: ref, ArbitraryMetadata: req.ArbitraryMetadata})
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gatewayClient.SetArbitraryMetadata(ctx, &provider.SetArbitraryMetadataRequest{Opaque: req.Opaque, Ref: ref, ArbitraryMetadata: req.ArbitraryMetadata})
|
||||
}
|
||||
|
||||
func (s *service) UnsetArbitraryMetadata(ctx context.Context, req *provider.UnsetArbitraryMetadataRequest) (*provider.UnsetArbitraryMetadataResponse, error) {
|
||||
@@ -132,7 +136,11 @@ func (s *service) SetLock(ctx context.Context, req *provider.SetLockRequest) (*p
|
||||
Status: st,
|
||||
}, nil
|
||||
}
|
||||
return s.gateway.SetLock(ctx, &provider.SetLockRequest{Opaque: req.Opaque, Ref: ref, Lock: req.Lock})
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gatewayClient.SetLock(ctx, &provider.SetLockRequest{Opaque: req.Opaque, Ref: ref, Lock: req.Lock})
|
||||
}
|
||||
|
||||
// GetLock returns an existing lock on the given reference
|
||||
@@ -146,7 +154,11 @@ func (s *service) GetLock(ctx context.Context, req *provider.GetLockRequest) (*p
|
||||
Status: st,
|
||||
}, nil
|
||||
}
|
||||
return s.gateway.GetLock(ctx, &provider.GetLockRequest{Opaque: req.Opaque, Ref: ref})
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gatewayClient.GetLock(ctx, &provider.GetLockRequest{Opaque: req.Opaque, Ref: ref})
|
||||
}
|
||||
|
||||
// RefreshLock refreshes an existing lock on the given reference
|
||||
@@ -160,7 +172,11 @@ func (s *service) RefreshLock(ctx context.Context, req *provider.RefreshLockRequ
|
||||
Status: st,
|
||||
}, nil
|
||||
}
|
||||
return s.gateway.RefreshLock(ctx, &provider.RefreshLockRequest{Opaque: req.Opaque, Ref: ref, Lock: req.Lock})
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gatewayClient.RefreshLock(ctx, &provider.RefreshLockRequest{Opaque: req.Opaque, Ref: ref, Lock: req.Lock})
|
||||
}
|
||||
|
||||
// Unlock removes an existing lock from the given reference
|
||||
@@ -174,7 +190,11 @@ func (s *service) Unlock(ctx context.Context, req *provider.UnlockRequest) (*pro
|
||||
Status: st,
|
||||
}, nil
|
||||
}
|
||||
return s.gateway.Unlock(ctx, &provider.UnlockRequest{Opaque: req.Opaque, Ref: ref, Lock: req.Lock})
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gatewayClient.Unlock(ctx, &provider.UnlockRequest{Opaque: req.Opaque, Ref: ref, Lock: req.Lock})
|
||||
}
|
||||
|
||||
func (s *service) InitiateFileDownload(ctx context.Context, req *provider.InitiateFileDownloadRequest) (*provider.InitiateFileDownloadResponse, error) {
|
||||
@@ -265,7 +285,11 @@ func (s *service) initiateFileDownload(ctx context.Context, req *provider.Initia
|
||||
Ref: cs3Ref,
|
||||
}
|
||||
|
||||
dRes, err := s.gateway.InitiateFileDownload(ctx, dReq)
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dRes, err := gatewayClient.InitiateFileDownload(ctx, dReq)
|
||||
if err != nil {
|
||||
return &provider.InitiateFileDownloadResponse{
|
||||
Status: status.NewInternal(ctx, "initiateFileDownload: error calling InitiateFileDownload"),
|
||||
@@ -319,7 +343,11 @@ func (s *service) InitiateFileUpload(ctx context.Context, req *provider.Initiate
|
||||
Opaque: req.Opaque,
|
||||
}
|
||||
|
||||
uRes, err := s.gateway.InitiateFileUpload(ctx, uReq)
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uRes, err := gatewayClient.InitiateFileUpload(ctx, uReq)
|
||||
if err != nil {
|
||||
return &provider.InitiateFileUploadResponse{
|
||||
Status: status.NewInternal(ctx, "InitiateFileUpload: error calling InitiateFileUpload"),
|
||||
@@ -543,7 +571,11 @@ func (s *service) CreateContainer(ctx context.Context, req *provider.CreateConta
|
||||
|
||||
var res *provider.CreateContainerResponse
|
||||
// the call has to be made to the gateway instead of the storage.
|
||||
res, err = s.gateway.CreateContainer(ctx, &provider.CreateContainerRequest{
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err = gatewayClient.CreateContainer(ctx, &provider.CreateContainerRequest{
|
||||
Ref: cs3Ref,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -568,7 +600,11 @@ func (s *service) TouchFile(ctx context.Context, req *provider.TouchFileRequest)
|
||||
Status: st,
|
||||
}, nil
|
||||
}
|
||||
return s.gateway.TouchFile(ctx, &provider.TouchFileRequest{Opaque: req.Opaque, Ref: ref})
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gatewayClient.TouchFile(ctx, &provider.TouchFileRequest{Opaque: req.Opaque, Ref: ref})
|
||||
}
|
||||
|
||||
func (s *service) Delete(ctx context.Context, req *provider.DeleteRequest) (*provider.DeleteResponse, error) {
|
||||
@@ -596,7 +632,11 @@ func (s *service) Delete(ctx context.Context, req *provider.DeleteRequest) (*pro
|
||||
|
||||
var res *provider.DeleteResponse
|
||||
// the call has to be made to the gateway instead of the storage.
|
||||
res, err = s.gateway.Delete(ctx, &provider.DeleteRequest{
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err = gatewayClient.Delete(ctx, &provider.DeleteRequest{
|
||||
Ref: cs3Ref,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -658,7 +698,11 @@ func (s *service) Move(ctx context.Context, req *provider.MoveRequest) (*provide
|
||||
|
||||
var res *provider.MoveResponse
|
||||
// the call has to be made to the gateway instead of the storage.
|
||||
res, err = s.gateway.Move(ctx, &provider.MoveRequest{
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err = gatewayClient.Move(ctx, &provider.MoveRequest{
|
||||
Source: cs3RefSource,
|
||||
Destination: cs3RefDestination,
|
||||
})
|
||||
@@ -721,7 +765,11 @@ func (s *service) Stat(ctx context.Context, req *provider.StatRequest) (*provide
|
||||
Path: utils.MakeRelativePath(req.Ref.Path),
|
||||
}
|
||||
|
||||
statResponse, err := s.gateway.Stat(ctx, &provider.StatRequest{Ref: ref})
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
statResponse, err := gatewayClient.Stat(ctx, &provider.StatRequest{Ref: ref})
|
||||
if err != nil {
|
||||
return &provider.StatResponse{
|
||||
Status: status.NewInternal(ctx, "Stat: error calling Stat for ref:"+req.Ref.String()),
|
||||
@@ -796,7 +844,11 @@ func (s *service) ListContainer(ctx context.Context, req *provider.ListContainer
|
||||
}, nil
|
||||
}
|
||||
|
||||
listContainerR, err := s.gateway.ListContainer(
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
listContainerR, err := gatewayClient.ListContainer(
|
||||
ctx,
|
||||
&provider.ListContainerRequest{
|
||||
Ref: &provider.Reference{
|
||||
@@ -926,7 +978,11 @@ func (s *service) resolveToken(ctx context.Context, token string) (*link.PublicS
|
||||
return nil, nil, publicShareResponse.Status, nil
|
||||
}
|
||||
|
||||
sRes, err := s.gateway.Stat(ctx, &provider.StatRequest{
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
sRes, err := gatewayClient.Stat(ctx, &provider.StatRequest{
|
||||
Ref: &provider.Reference{
|
||||
ResourceId: publicShareResponse.GetShare().GetResourceId(),
|
||||
},
|
||||
|
||||
Generated
Vendored
+118
-27
@@ -62,8 +62,8 @@ type config struct {
|
||||
}
|
||||
|
||||
type service struct {
|
||||
gateway gateway.GatewayAPIClient
|
||||
sharesProviderClient collaboration.CollaborationAPIClient
|
||||
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
sharingCollaborationSelector pool.Selectable[collaboration.CollaborationAPIClient]
|
||||
}
|
||||
|
||||
func (s *service) Close() error {
|
||||
@@ -86,24 +86,24 @@ func NewDefault(m map[string]interface{}, _ *grpc.Server) (rgrpc.Service, error)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gateway, err := pool.GetGatewayServiceClient(sharedconf.GetGatewaySVC(c.GatewayAddr))
|
||||
gatewaySelector, err := pool.GatewaySelector(sharedconf.GetGatewaySVC(c.GatewayAddr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client, err := pool.GetUserShareProviderClient(sharedconf.GetGatewaySVC(c.UserShareProviderEndpoint))
|
||||
sharingCollaborationSelector, err := pool.SharingCollaborationSelector(sharedconf.GetGatewaySVC(c.UserShareProviderEndpoint))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "sharesstorageprovider: error getting UserShareProvider client")
|
||||
}
|
||||
|
||||
return New(gateway, client)
|
||||
return New(gatewaySelector, sharingCollaborationSelector)
|
||||
}
|
||||
|
||||
// New returns a new instance of the SharesStorageProvider service
|
||||
func New(gateway gateway.GatewayAPIClient, c collaboration.CollaborationAPIClient) (rgrpc.Service, error) {
|
||||
func New(gatewaySelector pool.Selectable[gateway.GatewayAPIClient], sharingCollaborationSelector pool.Selectable[collaboration.CollaborationAPIClient]) (rgrpc.Service, error) {
|
||||
s := &service{
|
||||
gateway: gateway,
|
||||
sharesProviderClient: c,
|
||||
gatewaySelector: gatewaySelector,
|
||||
sharingCollaborationSelector: sharingCollaborationSelector,
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
@@ -123,7 +123,12 @@ func (s *service) SetArbitraryMetadata(ctx context.Context, req *provider.SetArb
|
||||
}, nil
|
||||
}
|
||||
|
||||
return s.gateway.SetArbitraryMetadata(ctx, &provider.SetArbitraryMetadataRequest{
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gatewayClient.SetArbitraryMetadata(ctx, &provider.SetArbitraryMetadataRequest{
|
||||
Opaque: req.Opaque,
|
||||
Ref: buildReferenceInShare(req.Ref, receivedShare),
|
||||
ArbitraryMetadata: req.ArbitraryMetadata,
|
||||
@@ -145,7 +150,12 @@ func (s *service) UnsetArbitraryMetadata(ctx context.Context, req *provider.Unse
|
||||
}, nil
|
||||
}
|
||||
|
||||
return s.gateway.UnsetArbitraryMetadata(ctx, &provider.UnsetArbitraryMetadataRequest{
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gatewayClient.UnsetArbitraryMetadata(ctx, &provider.UnsetArbitraryMetadataRequest{
|
||||
Opaque: req.Opaque,
|
||||
Ref: buildReferenceInShare(req.Ref, receivedShare),
|
||||
ArbitraryMetadataKeys: req.ArbitraryMetadataKeys,
|
||||
@@ -167,7 +177,12 @@ func (s *service) InitiateFileDownload(ctx context.Context, req *provider.Initia
|
||||
}, nil
|
||||
}
|
||||
|
||||
gwres, err := s.gateway.InitiateFileDownload(ctx, &provider.InitiateFileDownloadRequest{
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gwres, err := gatewayClient.InitiateFileDownload(ctx, &provider.InitiateFileDownloadRequest{
|
||||
Opaque: req.Opaque,
|
||||
Ref: buildReferenceInShare(req.Ref, receivedShare),
|
||||
LockId: req.LockId,
|
||||
@@ -229,7 +244,13 @@ func (s *service) InitiateFileUpload(ctx context.Context, req *provider.Initiate
|
||||
Status: status.NewPermissionDenied(ctx, nil, "share does not grant InitiateFileDownload permission"),
|
||||
}, nil
|
||||
}
|
||||
gwres, err := s.gateway.InitiateFileUpload(ctx, &provider.InitiateFileUploadRequest{
|
||||
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gwres, err := gatewayClient.InitiateFileUpload(ctx, &provider.InitiateFileUploadRequest{
|
||||
Opaque: req.Opaque,
|
||||
Ref: buildReferenceInShare(req.Ref, receivedShare),
|
||||
LockId: req.LockId,
|
||||
@@ -513,7 +534,12 @@ func (s *service) CreateContainer(ctx context.Context, req *provider.CreateConta
|
||||
}, nil
|
||||
}
|
||||
|
||||
return s.gateway.CreateContainer(ctx, &provider.CreateContainerRequest{
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gatewayClient.CreateContainer(ctx, &provider.CreateContainerRequest{
|
||||
Opaque: req.Opaque,
|
||||
Ref: buildReferenceInShare(req.Ref, receivedShare),
|
||||
})
|
||||
@@ -548,7 +574,12 @@ func (s *service) Delete(ctx context.Context, req *provider.DeleteRequest) (*pro
|
||||
}, nil
|
||||
}
|
||||
|
||||
return s.gateway.Delete(ctx, &provider.DeleteRequest{
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gatewayClient.Delete(ctx, &provider.DeleteRequest{
|
||||
Opaque: req.Opaque,
|
||||
Ref: buildReferenceInShare(req.Ref, receivedShare),
|
||||
})
|
||||
@@ -584,7 +615,12 @@ func (s *service) Move(ctx context.Context, req *provider.MoveRequest) (*provide
|
||||
Path: filepath.Base(req.Destination.Path),
|
||||
}
|
||||
|
||||
_, err = s.sharesProviderClient.UpdateReceivedShare(ctx, &collaboration.UpdateReceivedShareRequest{
|
||||
sharingCollaborationClient, err := s.sharingCollaborationSelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = sharingCollaborationClient.UpdateReceivedShare(ctx, &collaboration.UpdateReceivedShareRequest{
|
||||
Share: srcReceivedShare,
|
||||
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"state", "mount_point"}},
|
||||
})
|
||||
@@ -613,7 +649,12 @@ func (s *service) Move(ctx context.Context, req *provider.MoveRequest) (*provide
|
||||
}, nil
|
||||
}
|
||||
|
||||
return s.gateway.Move(ctx, &provider.MoveRequest{
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gatewayClient.Move(ctx, &provider.MoveRequest{
|
||||
Opaque: req.Opaque,
|
||||
Source: buildReferenceInShare(req.Source, srcReceivedShare),
|
||||
Destination: buildReferenceInShare(req.Destination, dstReceivedShare),
|
||||
@@ -712,8 +753,13 @@ func (s *service) Stat(ctx context.Context, req *provider.StatRequest) (*provide
|
||||
}, nil
|
||||
}
|
||||
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO return reference?
|
||||
return s.gateway.Stat(ctx, &provider.StatRequest{
|
||||
return gatewayClient.Stat(ctx, &provider.StatRequest{
|
||||
Opaque: req.Opaque,
|
||||
Ref: buildReferenceInShare(req.Ref, receivedShare),
|
||||
ArbitraryMetadataKeys: req.ArbitraryMetadataKeys,
|
||||
@@ -742,13 +788,18 @@ func (s *service) ListContainer(ctx context.Context, req *provider.ListContainer
|
||||
return nil, errors.Wrap(err, "sharesstorageprovider: error calling ListReceivedSharesRequest")
|
||||
}
|
||||
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
infos := []*provider.ResourceInfo{}
|
||||
for _, share := range receivedShares {
|
||||
if share.GetState() != collaboration.ShareState_SHARE_STATE_ACCEPTED {
|
||||
continue
|
||||
}
|
||||
|
||||
statRes, err := s.gateway.Stat(ctx, &provider.StatRequest{
|
||||
statRes, err := gatewayClient.Stat(ctx, &provider.StatRequest{
|
||||
Opaque: req.Opaque,
|
||||
Ref: &provider.Reference{
|
||||
ResourceId: share.Share.ResourceId,
|
||||
@@ -802,7 +853,12 @@ func (s *service) ListContainer(ctx context.Context, req *provider.ListContainer
|
||||
}, nil
|
||||
}
|
||||
|
||||
return s.gateway.ListContainer(ctx, &provider.ListContainerRequest{
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gatewayClient.ListContainer(ctx, &provider.ListContainerRequest{
|
||||
Opaque: req.Opaque,
|
||||
Ref: buildReferenceInShare(req.Ref, receivedShare),
|
||||
ArbitraryMetadataKeys: req.ArbitraryMetadataKeys,
|
||||
@@ -824,7 +880,12 @@ func (s *service) ListFileVersions(ctx context.Context, req *provider.ListFileVe
|
||||
}, nil
|
||||
}
|
||||
|
||||
return s.gateway.ListFileVersions(ctx, &provider.ListFileVersionsRequest{
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gatewayClient.ListFileVersions(ctx, &provider.ListFileVersionsRequest{
|
||||
Opaque: req.Opaque,
|
||||
Ref: buildReferenceInShare(req.Ref, receivedShare),
|
||||
})
|
||||
@@ -846,7 +907,12 @@ func (s *service) RestoreFileVersion(ctx context.Context, req *provider.RestoreF
|
||||
}, nil
|
||||
}
|
||||
|
||||
return s.gateway.RestoreFileVersion(ctx, &provider.RestoreFileVersionRequest{
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gatewayClient.RestoreFileVersion(ctx, &provider.RestoreFileVersionRequest{
|
||||
Opaque: req.Opaque,
|
||||
Ref: buildReferenceInShare(req.Ref, receivedShare),
|
||||
})
|
||||
@@ -911,7 +977,12 @@ func (s *service) TouchFile(ctx context.Context, req *provider.TouchFileRequest)
|
||||
}, nil
|
||||
}
|
||||
|
||||
return s.gateway.TouchFile(ctx, &provider.TouchFileRequest{
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gatewayClient.TouchFile(ctx, &provider.TouchFileRequest{
|
||||
Opaque: req.Opaque,
|
||||
Ref: buildReferenceInShare(req.Ref, receivedShare),
|
||||
})
|
||||
@@ -938,10 +1009,15 @@ func (s *service) resolveAcceptedShare(ctx context.Context, ref *provider.Refere
|
||||
return nil, status.NewNotFound(ctx, "sharesstorageprovider: not found "+ref.String()), nil
|
||||
}
|
||||
|
||||
sharingCollaborationClient, err := s.sharingCollaborationSelector.Next()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// we can get the share if the reference carries a share id
|
||||
if ref.ResourceId.OpaqueId != utils.ShareStorageProviderID {
|
||||
// look up share for this resourceid
|
||||
lsRes, err := s.sharesProviderClient.GetReceivedShare(ctx, &collaboration.GetReceivedShareRequest{
|
||||
lsRes, err := sharingCollaborationClient.GetReceivedShare(ctx, &collaboration.GetReceivedShareRequest{
|
||||
Ref: &collaboration.ShareReference{
|
||||
Spec: &collaboration.ShareReference_Id{
|
||||
Id: &collaboration.ShareId{
|
||||
@@ -968,7 +1044,7 @@ func (s *service) resolveAcceptedShare(ctx context.Context, ref *provider.Refere
|
||||
// we need to list accepted shares and match the path
|
||||
|
||||
// look up share for this resourceid
|
||||
lsRes, err := s.sharesProviderClient.ListReceivedShares(ctx, &collaboration.ListReceivedSharesRequest{
|
||||
lsRes, err := sharingCollaborationClient.ListReceivedShares(ctx, &collaboration.ListReceivedSharesRequest{
|
||||
Filters: []*collaboration.Filter{
|
||||
// FIXME filter by accepted ... and by mountpoint?
|
||||
},
|
||||
@@ -997,7 +1073,12 @@ func (s *service) rejectReceivedShare(ctx context.Context, receivedShare *collab
|
||||
receivedShare.State = collaboration.ShareState_SHARE_STATE_REJECTED
|
||||
receivedShare.MountPoint = nil
|
||||
|
||||
res, err := s.sharesProviderClient.UpdateReceivedShare(ctx, &collaboration.UpdateReceivedShareRequest{
|
||||
sharingCollaborationClient, err := s.sharingCollaborationSelector.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := sharingCollaborationClient.UpdateReceivedShare(ctx, &collaboration.UpdateReceivedShareRequest{
|
||||
Share: receivedShare,
|
||||
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"state", "mount_point"}},
|
||||
})
|
||||
@@ -1009,7 +1090,12 @@ func (s *service) rejectReceivedShare(ctx context.Context, receivedShare *collab
|
||||
}
|
||||
|
||||
func (s *service) fetchShares(ctx context.Context) ([]*collaboration.ReceivedShare, map[string]*provider.ResourceInfo, error) {
|
||||
lsRes, err := s.sharesProviderClient.ListReceivedShares(ctx, &collaboration.ListReceivedSharesRequest{
|
||||
sharingCollaborationClient, err := s.sharingCollaborationSelector.Next()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
lsRes, err := sharingCollaborationClient.ListReceivedShares(ctx, &collaboration.ListReceivedSharesRequest{
|
||||
// FIXME filter by received shares for resource id - listing all shares is tooo expensive!
|
||||
})
|
||||
if err != nil {
|
||||
@@ -1019,6 +1105,11 @@ func (s *service) fetchShares(ctx context.Context) ([]*collaboration.ReceivedSha
|
||||
return nil, nil, fmt.Errorf("sharesstorageprovider: error calling ListReceivedSharesRequest")
|
||||
}
|
||||
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
shareMetaData := make(map[string]*provider.ResourceInfo, len(lsRes.Shares))
|
||||
for _, rs := range lsRes.Shares {
|
||||
// only stat accepted shares
|
||||
@@ -1029,7 +1120,7 @@ func (s *service) fetchShares(ctx context.Context) ([]*collaboration.ReceivedSha
|
||||
// convert backwards compatible share id
|
||||
rs.Share.ResourceId.StorageId, rs.Share.ResourceId.SpaceId = storagespace.SplitStorageID(rs.Share.ResourceId.StorageId)
|
||||
}
|
||||
sRes, err := s.gateway.Stat(ctx, &provider.StatRequest{Ref: &provider.Reference{ResourceId: rs.Share.ResourceId}})
|
||||
sRes, err := gatewayClient.Stat(ctx, &provider.StatRequest{Ref: &provider.Reference{ResourceId: rs.Share.ResourceId}})
|
||||
if err != nil {
|
||||
appctx.GetLogger(ctx).Error().
|
||||
Err(err).
|
||||
|
||||
+17
-13
@@ -47,11 +47,11 @@ import (
|
||||
)
|
||||
|
||||
type svc struct {
|
||||
config *Config
|
||||
gtwClient gateway.GatewayAPIClient
|
||||
log *zerolog.Logger
|
||||
walker walker.Walker
|
||||
downloader downloader.Downloader
|
||||
config *Config
|
||||
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
log *zerolog.Logger
|
||||
walker walker.Walker
|
||||
downloader downloader.Downloader
|
||||
|
||||
allowedFolders []*regexp.Regexp
|
||||
}
|
||||
@@ -82,7 +82,7 @@ func New(conf map[string]interface{}, log *zerolog.Logger) (global.Service, erro
|
||||
|
||||
c.init()
|
||||
|
||||
gtw, err := pool.GetGatewayServiceClient(c.GatewaySvc)
|
||||
gatewaySelector, err := pool.GatewaySelector(c.GatewaySvc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -98,12 +98,12 @@ func New(conf map[string]interface{}, log *zerolog.Logger) (global.Service, erro
|
||||
}
|
||||
|
||||
return &svc{
|
||||
config: c,
|
||||
gtwClient: gtw,
|
||||
downloader: downloader.NewDownloader(gtw, rhttp.Insecure(c.Insecure), rhttp.Timeout(time.Duration(c.Timeout*int64(time.Second)))),
|
||||
walker: walker.NewWalker(gtw),
|
||||
log: log,
|
||||
allowedFolders: allowedFolderRegex,
|
||||
config: c,
|
||||
gatewaySelector: gatewaySelector,
|
||||
downloader: downloader.NewDownloader(gatewaySelector, rhttp.Insecure(c.Insecure), rhttp.Timeout(time.Duration(c.Timeout*int64(time.Second)))),
|
||||
walker: walker.NewWalker(gatewaySelector),
|
||||
log: log,
|
||||
allowedFolders: allowedFolderRegex,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -138,10 +138,14 @@ func (s *svc) getResources(ctx context.Context, paths, ids []string) ([]*provide
|
||||
|
||||
}
|
||||
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, p := range paths {
|
||||
// id is base64 encoded and after decoding has the form <storage_id>:<resource_id>
|
||||
|
||||
resp, err := s.gtwClient.Stat(ctx, &provider.StatRequest{
|
||||
resp, err := gatewayClient.Stat(ctx, &provider.StatRequest{
|
||||
Ref: &provider.Reference{
|
||||
Path: p,
|
||||
},
|
||||
|
||||
+31
-13
@@ -36,6 +36,7 @@ import (
|
||||
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/spacelookup"
|
||||
"github.com/cs3org/reva/v2/pkg/appctx"
|
||||
"github.com/cs3org/reva/v2/pkg/errtypes"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/cs3org/reva/v2/pkg/rhttp"
|
||||
"github.com/cs3org/reva/v2/pkg/rhttp/router"
|
||||
"github.com/cs3org/reva/v2/pkg/storagespace"
|
||||
@@ -105,7 +106,7 @@ func (s *svc) handlePathCopy(w http.ResponseWriter, r *http.Request, ns string)
|
||||
|
||||
sublog := appctx.GetLogger(ctx).With().Str("src", src).Str("dst", dst).Logger()
|
||||
|
||||
srcSpace, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gwClient, src)
|
||||
srcSpace, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gatewaySelector, src)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Str("path", src).Msg("failed to look up storage space")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -115,7 +116,7 @@ func (s *svc) handlePathCopy(w http.ResponseWriter, r *http.Request, ns string)
|
||||
errors.HandleErrorStatus(&sublog, w, status)
|
||||
return
|
||||
}
|
||||
dstSpace, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gwClient, dst)
|
||||
dstSpace, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gatewaySelector, dst)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Str("path", dst).Msg("failed to look up storage space")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -131,17 +132,22 @@ func (s *svc) handlePathCopy(w http.ResponseWriter, r *http.Request, ns string)
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.executePathCopy(ctx, s.gwClient, w, r, cp); err != nil {
|
||||
if err := s.executePathCopy(ctx, s.gatewaySelector, w, r, cp); err != nil {
|
||||
sublog.Error().Err(err).Str("depth", cp.depth.String()).Msg("error executing path copy")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
w.WriteHeader(cp.successCode)
|
||||
}
|
||||
|
||||
func (s *svc) executePathCopy(ctx context.Context, client gateway.GatewayAPIClient, w http.ResponseWriter, r *http.Request, cp *copy) error {
|
||||
func (s *svc) executePathCopy(ctx context.Context, selector pool.Selectable[gateway.GatewayAPIClient], w http.ResponseWriter, r *http.Request, cp *copy) error {
|
||||
log := appctx.GetLogger(ctx)
|
||||
log.Debug().Str("src", cp.sourceInfo.Path).Str("dst", cp.destination.Path).Msg("descending")
|
||||
|
||||
client, err := selector.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var fileid string
|
||||
if cp.sourceInfo.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER {
|
||||
// create dir
|
||||
@@ -192,7 +198,7 @@ func (s *svc) executePathCopy(ctx context.Context, client gateway.GatewayAPIClie
|
||||
ResourceId: cp.destination.ResourceId,
|
||||
Path: utils.MakeRelativePath(filepath.Join(cp.destination.Path, child)),
|
||||
}
|
||||
err := s.executePathCopy(ctx, client, w, r, ©{source: src, sourceInfo: res.Infos[i], destination: childDst, depth: cp.depth, successCode: cp.successCode})
|
||||
err := s.executePathCopy(ctx, selector, w, r, ©{source: src, sourceInfo: res.Infos[i], destination: childDst, depth: cp.depth, successCode: cp.successCode})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -354,7 +360,7 @@ func (s *svc) handleSpacesCopy(w http.ResponseWriter, r *http.Request, spaceID s
|
||||
return
|
||||
}
|
||||
|
||||
err = s.executeSpacesCopy(ctx, w, s.gwClient, cp)
|
||||
err = s.executeSpacesCopy(ctx, w, s.gatewaySelector, cp)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Str("depth", cp.depth.String()).Msg("error descending directory")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -362,10 +368,15 @@ func (s *svc) handleSpacesCopy(w http.ResponseWriter, r *http.Request, spaceID s
|
||||
w.WriteHeader(cp.successCode)
|
||||
}
|
||||
|
||||
func (s *svc) executeSpacesCopy(ctx context.Context, w http.ResponseWriter, client gateway.GatewayAPIClient, cp *copy) error {
|
||||
func (s *svc) executeSpacesCopy(ctx context.Context, w http.ResponseWriter, selector pool.Selectable[gateway.GatewayAPIClient], cp *copy) error {
|
||||
log := appctx.GetLogger(ctx)
|
||||
log.Debug().Interface("src", cp.sourceInfo).Interface("dst", cp.destination).Msg("descending")
|
||||
|
||||
client, err := selector.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var fileid string
|
||||
if cp.sourceInfo.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER {
|
||||
// create dir
|
||||
@@ -410,7 +421,7 @@ func (s *svc) executeSpacesCopy(ctx context.Context, w http.ResponseWriter, clie
|
||||
ResourceId: cp.destination.ResourceId,
|
||||
Path: utils.MakeRelativePath(path.Join(cp.destination.Path, res.Infos[i].Path)),
|
||||
}
|
||||
err := s.executeSpacesCopy(ctx, w, client, ©{sourceInfo: res.Infos[i], destination: childRef, depth: cp.depth, successCode: cp.successCode})
|
||||
err := s.executeSpacesCopy(ctx, w, selector, ©{sourceInfo: res.Infos[i], destination: childRef, depth: cp.depth, successCode: cp.successCode})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -528,7 +539,7 @@ func (s *svc) executeSpacesCopy(ctx context.Context, w http.ResponseWriter, clie
|
||||
}
|
||||
|
||||
func (s *svc) prepareCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, srcRef, dstRef *provider.Reference, log *zerolog.Logger) *copy {
|
||||
isChild, err := s.referenceIsChildOf(ctx, s.gwClient, dstRef, srcRef)
|
||||
isChild, err := s.referenceIsChildOf(ctx, s.gatewaySelector, dstRef, srcRef)
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case errtypes.IsNotSupported:
|
||||
@@ -573,8 +584,15 @@ func (s *svc) prepareCopy(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
|
||||
log.Debug().Bool("overwrite", overwrite).Str("depth", depth.String()).Msg("copy")
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error selecting next client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return nil
|
||||
}
|
||||
|
||||
srcStatReq := &provider.StatRequest{Ref: srcRef}
|
||||
srcStatRes, err := s.gwClient.Stat(ctx, srcStatReq)
|
||||
srcStatRes, err := client.Stat(ctx, srcStatReq)
|
||||
switch {
|
||||
case err != nil:
|
||||
log.Error().Err(err).Msg("error sending grpc stat request")
|
||||
@@ -592,7 +610,7 @@ func (s *svc) prepareCopy(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
|
||||
dstStatReq := &provider.StatRequest{Ref: dstRef}
|
||||
dstStatRes, err := s.gwClient.Stat(ctx, dstStatReq)
|
||||
dstStatRes, err := client.Stat(ctx, dstStatReq)
|
||||
switch {
|
||||
case err != nil:
|
||||
log.Error().Err(err).Msg("error sending grpc stat request")
|
||||
@@ -621,7 +639,7 @@ func (s *svc) prepareCopy(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
(dstStatRes.Info.Type == provider.ResourceType_RESOURCE_TYPE_FILE &&
|
||||
srcStatRes.Info.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER) {
|
||||
delReq := &provider.DeleteRequest{Ref: dstRef}
|
||||
delRes, err := s.gwClient.Delete(ctx, delReq)
|
||||
delRes, err := client.Delete(ctx, delReq)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error sending grpc delete request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -640,7 +658,7 @@ func (s *svc) prepareCopy(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
Path: utils.MakeRelativePath(p),
|
||||
}
|
||||
intStatReq := &provider.StatRequest{Ref: pRef}
|
||||
intStatRes, err := s.gwClient.Stat(ctx, intStatReq)
|
||||
intStatRes, err := client.Stat(ctx, intStatReq)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error sending grpc stat request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
+20
-6
@@ -32,6 +32,7 @@ import (
|
||||
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/net"
|
||||
"github.com/cs3org/reva/v2/pkg/appctx"
|
||||
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/cs3org/reva/v2/pkg/rhttp/router"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"google.golang.org/grpc/metadata"
|
||||
@@ -188,7 +189,7 @@ func (h *DavHandler) Handler(s *svc) http.Handler {
|
||||
var pass string
|
||||
var err error
|
||||
if _, pass, hasValidBasicAuthHeader = r.BasicAuth(); hasValidBasicAuthHeader {
|
||||
res, err = handleBasicAuth(r.Context(), s.gwClient, token, pass)
|
||||
res, err = handleBasicAuth(r.Context(), s.gatewaySelector, token, pass)
|
||||
} else {
|
||||
q := r.URL.Query()
|
||||
sig := q.Get("signature")
|
||||
@@ -198,7 +199,7 @@ func (h *DavHandler) Handler(s *svc) http.Handler {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
res, err = handleSignatureAuth(r.Context(), s.gwClient, token, sig, expiration)
|
||||
res, err = handleSignatureAuth(r.Context(), s.gatewaySelector, token, sig, expiration)
|
||||
}
|
||||
|
||||
switch {
|
||||
@@ -232,7 +233,7 @@ func (h *DavHandler) Handler(s *svc) http.Handler {
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
// the public share manager knew the token, but does the referenced target still exist?
|
||||
sRes, err := getTokenStatInfo(ctx, s.gwClient, token)
|
||||
sRes, err := getTokenStatInfo(ctx, s.gatewaySelector, token)
|
||||
switch {
|
||||
case err != nil:
|
||||
log.Error().Err(err).Msg("error sending grpc stat request")
|
||||
@@ -271,7 +272,12 @@ func (h *DavHandler) Handler(s *svc) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
func getTokenStatInfo(ctx context.Context, client gatewayv1beta1.GatewayAPIClient, token string) (*provider.StatResponse, error) {
|
||||
func getTokenStatInfo(ctx context.Context, selector pool.Selectable[gatewayv1beta1.GatewayAPIClient], token string) (*provider.StatResponse, error) {
|
||||
client, err := selector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client.Stat(ctx, &provider.StatRequest{Ref: &provider.Reference{
|
||||
ResourceId: &provider.ResourceId{
|
||||
StorageId: utils.PublicStorageProviderID,
|
||||
@@ -281,7 +287,11 @@ func getTokenStatInfo(ctx context.Context, client gatewayv1beta1.GatewayAPIClien
|
||||
}})
|
||||
}
|
||||
|
||||
func handleBasicAuth(ctx context.Context, c gatewayv1beta1.GatewayAPIClient, token, pw string) (*gatewayv1beta1.AuthenticateResponse, error) {
|
||||
func handleBasicAuth(ctx context.Context, selector pool.Selectable[gatewayv1beta1.GatewayAPIClient], token, pw string) (*gatewayv1beta1.AuthenticateResponse, error) {
|
||||
c, err := selector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authenticateRequest := gatewayv1beta1.AuthenticateRequest{
|
||||
Type: "publicshares",
|
||||
ClientId: token,
|
||||
@@ -291,7 +301,11 @@ func handleBasicAuth(ctx context.Context, c gatewayv1beta1.GatewayAPIClient, tok
|
||||
return c.Authenticate(ctx, &authenticateRequest)
|
||||
}
|
||||
|
||||
func handleSignatureAuth(ctx context.Context, c gatewayv1beta1.GatewayAPIClient, token, sig, expiration string) (*gatewayv1beta1.AuthenticateResponse, error) {
|
||||
func handleSignatureAuth(ctx context.Context, selector pool.Selectable[gatewayv1beta1.GatewayAPIClient], token, sig, expiration string) (*gatewayv1beta1.AuthenticateResponse, error) {
|
||||
c, err := selector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authenticateRequest := gatewayv1beta1.AuthenticateRequest{
|
||||
Type: "publicshares",
|
||||
ClientId: token,
|
||||
|
||||
+8
-3
@@ -45,7 +45,7 @@ func (s *svc) handlePathDelete(w http.ResponseWriter, r *http.Request, ns string
|
||||
|
||||
fn := path.Join(ns, r.URL.Path)
|
||||
|
||||
space, rpcStatus, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gwClient, fn)
|
||||
space, rpcStatus, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gatewaySelector, fn)
|
||||
switch {
|
||||
case err != nil:
|
||||
span.RecordError(err)
|
||||
@@ -73,7 +73,12 @@ func (s *svc) handleDelete(ctx context.Context, w http.ResponseWriter, r *http.R
|
||||
return http.StatusBadRequest, errtypes.BadRequest("invalid if header")
|
||||
}
|
||||
|
||||
res, err := s.gwClient.Delete(ctx, req)
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, errtypes.InternalError(err.Error())
|
||||
}
|
||||
|
||||
res, err := client.Delete(ctx, req)
|
||||
switch {
|
||||
case err != nil:
|
||||
span.RecordError(err)
|
||||
@@ -92,7 +97,7 @@ func (s *svc) handleDelete(ctx context.Context, w http.ResponseWriter, r *http.R
|
||||
status = http.StatusLocked
|
||||
}
|
||||
// check if user has access to resource
|
||||
sRes, err := s.gwClient.Stat(ctx, &provider.StatRequest{Ref: ref})
|
||||
sRes, err := client.Stat(ctx, &provider.StatRequest{Ref: ref})
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
return http.StatusInternalServerError, err
|
||||
|
||||
+9
-3
@@ -45,7 +45,7 @@ func (s *svc) handlePathGet(w http.ResponseWriter, r *http.Request, ns string) {
|
||||
|
||||
sublog := appctx.GetLogger(ctx).With().Str("path", fn).Str("svc", "ocdav").Str("handler", "get").Logger()
|
||||
|
||||
space, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gwClient, fn)
|
||||
space, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gatewaySelector, fn)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Str("path", fn).Msg("failed to look up storage space")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -60,10 +60,16 @@ func (s *svc) handlePathGet(w http.ResponseWriter, r *http.Request, ns string) {
|
||||
}
|
||||
|
||||
func (s *svc) handleGet(ctx context.Context, w http.ResponseWriter, r *http.Request, ref *provider.Reference, dlProtocol string, log zerolog.Logger) {
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error selecting next client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
sReq := &provider.StatRequest{
|
||||
Ref: ref,
|
||||
}
|
||||
sRes, err := s.gwClient.Stat(ctx, sReq)
|
||||
sRes, err := client.Stat(ctx, sReq)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error stat resource")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -85,7 +91,7 @@ func (s *svc) handleGet(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
|
||||
dReq := &provider.InitiateFileDownloadRequest{Ref: ref}
|
||||
dRes, err := s.gwClient.InitiateFileDownload(ctx, dReq)
|
||||
dRes, err := client.InitiateFileDownload(ctx, dReq)
|
||||
switch {
|
||||
case err != nil:
|
||||
log.Error().Err(err).Msg("error initiating file download")
|
||||
|
||||
+8
-3
@@ -48,7 +48,7 @@ func (s *svc) handlePathHead(w http.ResponseWriter, r *http.Request, ns string)
|
||||
|
||||
sublog := appctx.GetLogger(ctx).With().Str("path", fn).Logger()
|
||||
|
||||
space, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gwClient, fn)
|
||||
space, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gatewaySelector, fn)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Str("path", fn).Msg("failed to look up storage space")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -63,9 +63,14 @@ func (s *svc) handlePathHead(w http.ResponseWriter, r *http.Request, ns string)
|
||||
}
|
||||
|
||||
func (s *svc) handleHead(ctx context.Context, w http.ResponseWriter, r *http.Request, ref *provider.Reference, log zerolog.Logger) {
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error selecting next client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
req := &provider.StatRequest{Ref: ref}
|
||||
res, err := s.gwClient.Stat(ctx, req)
|
||||
res, err := client.Stat(ctx, req)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error sending grpc stat request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
+21
-7
@@ -41,6 +41,7 @@ import (
|
||||
"github.com/cs3org/reva/v2/pkg/appctx"
|
||||
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
"github.com/cs3org/reva/v2/pkg/errtypes"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/google/uuid"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
)
|
||||
@@ -159,14 +160,14 @@ type LockSystem interface {
|
||||
}
|
||||
|
||||
// NewCS3LS returns a new CS3 based LockSystem.
|
||||
func NewCS3LS(c gateway.GatewayAPIClient) LockSystem {
|
||||
func NewCS3LS(s pool.Selectable[gateway.GatewayAPIClient]) LockSystem {
|
||||
return &cs3LS{
|
||||
client: c,
|
||||
selector: s,
|
||||
}
|
||||
}
|
||||
|
||||
type cs3LS struct {
|
||||
client gateway.GatewayAPIClient
|
||||
selector pool.Selectable[gateway.GatewayAPIClient]
|
||||
}
|
||||
|
||||
func (cls *cs3LS) Confirm(ctx context.Context, now time.Time, name0, name1 string, conditions ...Condition) (func(), error) {
|
||||
@@ -205,7 +206,13 @@ func (cls *cs3LS) Create(ctx context.Context, now time.Time, details LockDetails
|
||||
Nanos: uint32(expiration.Nanosecond()),
|
||||
}
|
||||
}
|
||||
res, err := cls.client.SetLock(ctx, r)
|
||||
|
||||
client, err := cls.selector.Next()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
res, err := client.SetLock(ctx, r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -233,10 +240,17 @@ func (cls *cs3LS) Unlock(ctx context.Context, now time.Time, ref *provider.Refer
|
||||
User: u.Id,
|
||||
},
|
||||
}
|
||||
res, err := cls.client.Unlock(ctx, r)
|
||||
|
||||
client, err := cls.selector.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := client.Unlock(ctx, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch res.Status.Code {
|
||||
case rpc.Code_CODE_OK:
|
||||
return nil
|
||||
@@ -388,7 +402,7 @@ func (s *svc) handleLock(w http.ResponseWriter, r *http.Request, ns string) (ret
|
||||
fn := path.Join(ns, r.URL.Path) // TODO do we still need to jail if we query the registry about the spaces?
|
||||
|
||||
// TODO instead of using a string namespace ns pass in the space with the request?
|
||||
ref, cs3Status, err := spacelookup.LookupReferenceForPath(ctx, s.gwClient, fn)
|
||||
ref, cs3Status, err := spacelookup.LookupReferenceForPath(ctx, s.gatewaySelector, fn)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
@@ -566,7 +580,7 @@ func (s *svc) handleUnlock(w http.ResponseWriter, r *http.Request, ns string) (s
|
||||
fn := path.Join(ns, r.URL.Path) // TODO do we still need to jail if we query the registry about the spaces?
|
||||
|
||||
// TODO instead of using a string namespace ns pass in the space with the request?
|
||||
ref, cs3Status, err := spacelookup.LookupReferenceForPath(ctx, s.gwClient, fn)
|
||||
ref, cs3Status, err := spacelookup.LookupReferenceForPath(ctx, s.gatewaySelector, fn)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
+7
-2
@@ -119,9 +119,14 @@ func (h *MetaHandler) handlePathForUser(w http.ResponseWriter, r *http.Request,
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error selecting next client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
pathReq := &provider.GetPathRequest{ResourceId: rid}
|
||||
pathRes, err := s.gwClient.GetPath(ctx, pathReq)
|
||||
pathRes, err := client.GetPath(ctx, pathReq)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("could not send GetPath grpc request: transport error")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
+13
-4
@@ -45,9 +45,14 @@ func (s *svc) handlePathMkcol(w http.ResponseWriter, r *http.Request, ns string)
|
||||
}
|
||||
sublog := appctx.GetLogger(ctx).With().Str("path", fn).Logger()
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, errtypes.InternalError(err.Error())
|
||||
}
|
||||
|
||||
// stat requested path to make sure it isn't existing yet
|
||||
// NOTE: It could be on another storage provider than the 'parent' of it
|
||||
sr, err := s.gwClient.Stat(ctx, &provider.StatRequest{
|
||||
sr, err := client.Stat(ctx, &provider.StatRequest{
|
||||
Ref: &provider.Reference{
|
||||
Path: fn,
|
||||
},
|
||||
@@ -67,7 +72,7 @@ func (s *svc) handlePathMkcol(w http.ResponseWriter, r *http.Request, ns string)
|
||||
|
||||
parentPath := path.Dir(fn)
|
||||
|
||||
space, rpcStatus, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gwClient, parentPath)
|
||||
space, rpcStatus, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gatewaySelector, parentPath)
|
||||
switch {
|
||||
case err != nil:
|
||||
return http.StatusInternalServerError, err
|
||||
@@ -108,8 +113,12 @@ func (s *svc) handleMkcol(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
return http.StatusUnsupportedMediaType, fmt.Errorf("extended-mkcol not supported")
|
||||
}
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, errtypes.InternalError(err.Error())
|
||||
}
|
||||
req := &provider.CreateContainerRequest{Ref: childRef}
|
||||
res, err := s.gwClient.CreateContainer(ctx, req)
|
||||
res, err := client.CreateContainer(ctx, req)
|
||||
switch {
|
||||
case err != nil:
|
||||
return http.StatusInternalServerError, err
|
||||
@@ -123,7 +132,7 @@ func (s *svc) handleMkcol(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
return http.StatusNotFound, errors.New("Resource not found")
|
||||
case res.Status.Code == rpc.Code_CODE_PERMISSION_DENIED:
|
||||
// check if user has access to parent
|
||||
sRes, err := s.gwClient.Stat(ctx, &provider.StatRequest{Ref: &provider.Reference{
|
||||
sRes, err := client.Stat(ctx, &provider.StatRequest{Ref: &provider.Reference{
|
||||
ResourceId: childRef.GetResourceId(),
|
||||
Path: utils.MakeRelativePath(path.Dir(childRef.Path)),
|
||||
}})
|
||||
|
||||
+16
-9
@@ -78,7 +78,7 @@ func (s *svc) handlePathMove(w http.ResponseWriter, r *http.Request, ns string)
|
||||
|
||||
sublog := appctx.GetLogger(ctx).With().Str("src", srcPath).Str("dst", dstPath).Logger()
|
||||
|
||||
srcSpace, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gwClient, srcPath)
|
||||
srcSpace, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gatewaySelector, srcPath)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Str("path", srcPath).Msg("failed to look up source storage space")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -88,7 +88,7 @@ func (s *svc) handlePathMove(w http.ResponseWriter, r *http.Request, ns string)
|
||||
errors.HandleErrorStatus(&sublog, w, status)
|
||||
return
|
||||
}
|
||||
dstSpace, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gwClient, dstPath)
|
||||
dstSpace, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gatewaySelector, dstPath)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Str("path", dstPath).Msg("failed to look up destination storage space")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -141,7 +141,7 @@ func (s *svc) handleSpacesMove(w http.ResponseWriter, r *http.Request, srcSpaceI
|
||||
}
|
||||
|
||||
func (s *svc) handleMove(ctx context.Context, w http.ResponseWriter, r *http.Request, src, dst *provider.Reference, log zerolog.Logger) {
|
||||
isChild, err := s.referenceIsChildOf(ctx, s.gwClient, dst, src)
|
||||
isChild, err := s.referenceIsChildOf(ctx, s.gatewaySelector, dst, src)
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case errtypes.IsNotSupported:
|
||||
@@ -169,9 +169,16 @@ func (s *svc) handleMove(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
return
|
||||
}
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error selecting next client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// check src exists
|
||||
srcStatReq := &provider.StatRequest{Ref: src}
|
||||
srcStatRes, err := s.gwClient.Stat(ctx, srcStatReq)
|
||||
srcStatRes, err := client.Stat(ctx, srcStatReq)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error sending grpc stat request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -190,7 +197,7 @@ func (s *svc) handleMove(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
|
||||
// check dst exists
|
||||
dstStatReq := &provider.StatRequest{Ref: dst}
|
||||
dstStatRes, err := s.gwClient.Stat(ctx, dstStatReq)
|
||||
dstStatRes, err := client.Stat(ctx, dstStatReq)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error sending grpc stat request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -213,7 +220,7 @@ func (s *svc) handleMove(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
|
||||
// delete existing tree
|
||||
delReq := &provider.DeleteRequest{Ref: dst}
|
||||
delRes, err := s.gwClient.Delete(ctx, delReq)
|
||||
delRes, err := client.Delete(ctx, delReq)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error sending grpc delete request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -230,7 +237,7 @@ func (s *svc) handleMove(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
ResourceId: dst.ResourceId,
|
||||
Path: utils.MakeRelativePath(path.Dir(dst.Path)),
|
||||
}}
|
||||
intStatRes, err := s.gwClient.Stat(ctx, intStatReq)
|
||||
intStatRes, err := client.Stat(ctx, intStatReq)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error sending grpc stat request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -250,7 +257,7 @@ func (s *svc) handleMove(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
}
|
||||
|
||||
mReq := &provider.MoveRequest{Source: src, Destination: dst}
|
||||
mRes, err := s.gwClient.Move(ctx, mReq)
|
||||
mRes, err := client.Move(ctx, mReq)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error sending move grpc request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -279,7 +286,7 @@ func (s *svc) handleMove(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
return
|
||||
}
|
||||
|
||||
dstStatRes, err = s.gwClient.Stat(ctx, dstStatReq)
|
||||
dstStatRes, err = client.Stat(ctx, dstStatReq)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error sending grpc stat request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
+26
-12
@@ -144,7 +144,7 @@ type svc struct {
|
||||
davHandler *DavHandler
|
||||
favoritesManager favorite.Manager
|
||||
client *http.Client
|
||||
gwClient gateway.GatewayAPIClient
|
||||
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
// LockSystem is the lock management system.
|
||||
LockSystem LockSystem
|
||||
userIdentifierCache *ttlcache.Cache
|
||||
@@ -163,11 +163,11 @@ func getFavoritesManager(c *Config) (favorite.Manager, error) {
|
||||
}
|
||||
func getLockSystem(c *Config) (LockSystem, error) {
|
||||
// TODO in memory implementation
|
||||
client, err := pool.GetGatewayServiceClient(c.GatewaySvc)
|
||||
selector, err := pool.GatewaySelector(c.GatewaySvc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewCS3LS(client), nil
|
||||
return NewCS3LS(selector), nil
|
||||
}
|
||||
|
||||
// New returns a new ocdav service
|
||||
@@ -192,7 +192,7 @@ func New(m map[string]interface{}, log *zerolog.Logger) (global.Service, error)
|
||||
}
|
||||
|
||||
// NewWith returns a new ocdav service
|
||||
func NewWith(conf *Config, fm favorite.Manager, ls LockSystem, _ *zerolog.Logger, gwc gateway.GatewayAPIClient) (global.Service, error) {
|
||||
func NewWith(conf *Config, fm favorite.Manager, ls LockSystem, _ *zerolog.Logger, selector pool.Selectable[gateway.GatewayAPIClient]) (global.Service, error) {
|
||||
// be safe - init the conf again
|
||||
conf.init()
|
||||
|
||||
@@ -204,7 +204,7 @@ func NewWith(conf *Config, fm favorite.Manager, ls LockSystem, _ *zerolog.Logger
|
||||
rhttp.Timeout(time.Duration(conf.Timeout*int64(time.Second))),
|
||||
rhttp.Insecure(conf.Insecure),
|
||||
),
|
||||
gwClient: gwc,
|
||||
gatewaySelector: selector,
|
||||
favoritesManager: fm,
|
||||
LockSystem: ls,
|
||||
userIdentifierCache: ttlcache.NewCache(),
|
||||
@@ -219,9 +219,9 @@ func NewWith(conf *Config, fm favorite.Manager, ls LockSystem, _ *zerolog.Logger
|
||||
if err := s.davHandler.init(conf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if gwc == nil {
|
||||
if selector == nil {
|
||||
var err error
|
||||
s.gwClient, err = pool.GetGatewayServiceClient(s.c.GatewaySvc)
|
||||
s.gatewaySelector, err = pool.GatewaySelector(s.c.GatewaySvc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -326,7 +326,12 @@ func (s *svc) ApplyLayout(ctx context.Context, ns string, useLoggedInUserNS bool
|
||||
requestUsernameOrID, requestPath = router.ShiftPath(requestPath)
|
||||
|
||||
// Check if this is a Userid
|
||||
userRes, err := s.gwClient.GetUser(ctx, &userpb.GetUserRequest{
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
userRes, err := client.GetUser(ctx, &userpb.GetUserRequest{
|
||||
UserId: &userpb.UserId{OpaqueId: requestUsernameOrID},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -335,7 +340,7 @@ func (s *svc) ApplyLayout(ctx context.Context, ns string, useLoggedInUserNS bool
|
||||
|
||||
// If it's not a userid try if it is a user name
|
||||
if userRes.Status.Code != rpc.Code_CODE_OK {
|
||||
res, err := s.gwClient.GetUserByClaim(ctx, &userpb.GetUserByClaimRequest{
|
||||
res, err := client.GetUserByClaim(ctx, &userpb.GetUserByClaimRequest{
|
||||
Claim: "username",
|
||||
Value: requestUsernameOrID,
|
||||
})
|
||||
@@ -406,7 +411,11 @@ func authContextForUser(client gateway.GatewayAPIClient, userID *userpb.UserId,
|
||||
return granteeCtx, nil
|
||||
}
|
||||
|
||||
func (s *svc) sspReferenceIsChildOf(ctx context.Context, client gateway.GatewayAPIClient, child, parent *provider.Reference) (bool, error) {
|
||||
func (s *svc) sspReferenceIsChildOf(ctx context.Context, selector pool.Selectable[gateway.GatewayAPIClient], child, parent *provider.Reference) (bool, error) {
|
||||
client, err := selector.Next()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
parentStatRes, err := client.Stat(ctx, &provider.StatRequest{Ref: parent})
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -448,7 +457,7 @@ func (s *svc) sspReferenceIsChildOf(ctx context.Context, client gateway.GatewayA
|
||||
return strings.HasPrefix(cp, pp), nil
|
||||
}
|
||||
|
||||
func (s *svc) referenceIsChildOf(ctx context.Context, client gateway.GatewayAPIClient, child, parent *provider.Reference) (bool, error) {
|
||||
func (s *svc) referenceIsChildOf(ctx context.Context, selector pool.Selectable[gateway.GatewayAPIClient], child, parent *provider.Reference) (bool, error) {
|
||||
if child.ResourceId.SpaceId != parent.ResourceId.SpaceId {
|
||||
return false, nil // Not on the same storage -> not a child
|
||||
}
|
||||
@@ -459,7 +468,12 @@ func (s *svc) referenceIsChildOf(ctx context.Context, client gateway.GatewayAPIC
|
||||
|
||||
if child.ResourceId.SpaceId == utils.ShareStorageSpaceID || parent.ResourceId.SpaceId == utils.ShareStorageSpaceID {
|
||||
// the sharesstorageprovider needs some special handling
|
||||
return s.sspReferenceIsChildOf(ctx, client, child, parent)
|
||||
return s.sspReferenceIsChildOf(ctx, selector, child, parent)
|
||||
}
|
||||
|
||||
client, err := selector.Next()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// the references are on the same storage but relative to different resources
|
||||
|
||||
Generated
Vendored
+9
-11
@@ -47,6 +47,7 @@ import (
|
||||
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
"github.com/cs3org/reva/v2/pkg/publicshare"
|
||||
rstatus "github.com/cs3org/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/cs3org/reva/v2/pkg/rhttp/router"
|
||||
"github.com/cs3org/reva/v2/pkg/storagespace"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
@@ -163,20 +164,17 @@ func NewMultiStatusResponseXML() *MultiStatusResponseXML {
|
||||
}
|
||||
}
|
||||
|
||||
// GetGatewayServiceClientFunc is a callback used to pass in a StorageProviderClient during testing
|
||||
type GetGatewayServiceClientFunc func() (gateway.GatewayAPIClient, error)
|
||||
|
||||
// Handler handles propfind requests
|
||||
type Handler struct {
|
||||
PublicURL string
|
||||
getClient GetGatewayServiceClientFunc
|
||||
selector pool.Selectable[gateway.GatewayAPIClient]
|
||||
}
|
||||
|
||||
// NewHandler returns a new PropfindHandler instance
|
||||
func NewHandler(publicURL string, getClientFunc GetGatewayServiceClientFunc) *Handler {
|
||||
func NewHandler(publicURL string, selector pool.Selectable[gateway.GatewayAPIClient]) *Handler {
|
||||
return &Handler{
|
||||
PublicURL: publicURL,
|
||||
getClient: getClientFunc,
|
||||
selector: selector,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +195,7 @@ func (p *Handler) HandlePathPropfind(w http.ResponseWriter, r *http.Request, ns
|
||||
}
|
||||
|
||||
// retrieve a specific storage space
|
||||
client, err := p.getClient()
|
||||
client, err := p.selector.Next()
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error retrieving a gateway service client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -263,7 +261,7 @@ func (p *Handler) HandleSpacesPropfind(w http.ResponseWriter, r *http.Request, s
|
||||
return
|
||||
}
|
||||
|
||||
client, err := p.getClient()
|
||||
client, err := p.selector.Next()
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error getting grpc client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -386,7 +384,7 @@ func (p *Handler) propfindResponse(ctx context.Context, w http.ResponseWriter, r
|
||||
// same as user / group shares for share indicators
|
||||
filters = append(filters, publicshare.ResourceIDFilter(resourceInfos[i].Id))
|
||||
}
|
||||
client, err := p.getClient()
|
||||
client, err := p.selector.Next()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error getting grpc client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -465,7 +463,7 @@ func (p *Handler) getResourceInfos(ctx context.Context, w http.ResponseWriter, r
|
||||
}
|
||||
span.SetAttributes(attribute.KeyValue{Key: "depth", Value: attribute.StringValue(depth.String())})
|
||||
|
||||
client, err := p.getClient()
|
||||
client, err := p.selector.Next()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error getting grpc client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -675,7 +673,7 @@ func (p *Handler) getSpaceResourceInfos(ctx context.Context, w http.ResponseWrit
|
||||
span.SetAttributes(attribute.KeyValue{Key: "depth", Value: attribute.StringValue(depth.String())})
|
||||
defer span.End()
|
||||
|
||||
client, err := p.getClient()
|
||||
client, err := p.selector.Next()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error getting grpc client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
Generated
Vendored
+19
-8
@@ -55,7 +55,7 @@ func (s *svc) handlePathProppatch(w http.ResponseWriter, r *http.Request, ns str
|
||||
return status, err
|
||||
}
|
||||
|
||||
space, rpcStatus, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gwClient, fn)
|
||||
space, rpcStatus, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gatewaySelector, fn)
|
||||
switch {
|
||||
case err != nil:
|
||||
return http.StatusInternalServerError, err
|
||||
@@ -64,9 +64,14 @@ func (s *svc) handlePathProppatch(w http.ResponseWriter, r *http.Request, ns str
|
||||
case rpcStatus.Code != rpc.Code_CODE_OK:
|
||||
return rstatus.HTTPStatusFromCode(rpcStatus.Code), errtypes.NewErrtypeFromStatus(rpcStatus)
|
||||
}
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, errtypes.InternalError(err.Error())
|
||||
}
|
||||
// check if resource exists
|
||||
statReq := &provider.StatRequest{Ref: spacelookup.MakeRelativeReference(space, fn, false)}
|
||||
statRes, err := s.gwClient.Stat(ctx, statReq)
|
||||
statRes, err := client.Stat(ctx, statReq)
|
||||
switch {
|
||||
case err != nil:
|
||||
return http.StatusInternalServerError, err
|
||||
@@ -137,6 +142,12 @@ func (s *svc) handleProppatch(ctx context.Context, w http.ResponseWriter, r *htt
|
||||
acceptedProps := []xml.Name{}
|
||||
removedProps := []xml.Name{}
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error selecting next gateway client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return nil, nil, false
|
||||
}
|
||||
for i := range patches {
|
||||
if len(patches[i].Props) < 1 {
|
||||
continue
|
||||
@@ -161,7 +172,7 @@ func (s *svc) handleProppatch(ctx context.Context, w http.ResponseWriter, r *htt
|
||||
// FIXME: batch this somehow
|
||||
if remove {
|
||||
rreq.ArbitraryMetadataKeys[0] = key
|
||||
res, err := s.gwClient.UnsetArbitraryMetadata(ctx, rreq)
|
||||
res, err := client.UnsetArbitraryMetadata(ctx, rreq)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error sending a grpc UnsetArbitraryMetadata request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -178,7 +189,7 @@ func (s *svc) handleProppatch(ctx context.Context, w http.ResponseWriter, r *htt
|
||||
m := res.Status.Message
|
||||
if res.Status.Code == rpc.Code_CODE_PERMISSION_DENIED {
|
||||
// check if user has access to resource
|
||||
sRes, err := s.gwClient.Stat(ctx, &provider.StatRequest{Ref: ref})
|
||||
sRes, err := client.Stat(ctx, &provider.StatRequest{Ref: ref})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error performing stat grpc request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -200,7 +211,7 @@ func (s *svc) handleProppatch(ctx context.Context, w http.ResponseWriter, r *htt
|
||||
return nil, nil, false
|
||||
}
|
||||
if key == "http://owncloud.org/ns/favorite" {
|
||||
statRes, err := s.gwClient.Stat(ctx, &provider.StatRequest{Ref: ref})
|
||||
statRes, err := client.Stat(ctx, &provider.StatRequest{Ref: ref})
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return nil, nil, false
|
||||
@@ -215,7 +226,7 @@ func (s *svc) handleProppatch(ctx context.Context, w http.ResponseWriter, r *htt
|
||||
removedProps = append(removedProps, propNameXML)
|
||||
} else {
|
||||
sreq.ArbitraryMetadata.Metadata[key] = value
|
||||
res, err := s.gwClient.SetArbitraryMetadata(ctx, sreq)
|
||||
res, err := client.SetArbitraryMetadata(ctx, sreq)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("key", key).Str("value", value).Msg("error sending a grpc SetArbitraryMetadata request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -232,7 +243,7 @@ func (s *svc) handleProppatch(ctx context.Context, w http.ResponseWriter, r *htt
|
||||
m := res.Status.Message
|
||||
if res.Status.Code == rpc.Code_CODE_PERMISSION_DENIED {
|
||||
// check if user has access to resource
|
||||
sRes, err := s.gwClient.Stat(ctx, &provider.StatRequest{Ref: ref})
|
||||
sRes, err := client.Stat(ctx, &provider.StatRequest{Ref: ref})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error performing stat grpc request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -258,7 +269,7 @@ func (s *svc) handleProppatch(ctx context.Context, w http.ResponseWriter, r *htt
|
||||
delete(sreq.ArbitraryMetadata.Metadata, key)
|
||||
|
||||
if key == "http://owncloud.org/ns/favorite" {
|
||||
statRes, err := s.gwClient.Stat(ctx, &provider.StatRequest{Ref: ref})
|
||||
statRes, err := client.Stat(ctx, &provider.StatRequest{Ref: ref})
|
||||
if err != nil || statRes.Info == nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return nil, nil, false
|
||||
|
||||
+11
-5
@@ -114,7 +114,7 @@ func (s *svc) handlePathPut(w http.ResponseWriter, r *http.Request, ns string) {
|
||||
fn := path.Join(ns, r.URL.Path)
|
||||
|
||||
sublog := appctx.GetLogger(ctx).With().Str("path", fn).Logger()
|
||||
space, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gwClient, fn)
|
||||
space, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gatewaySelector, fn)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Str("path", fn).Msg("failed to look up storage space")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -148,8 +148,14 @@ func (s *svc) handlePut(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
return
|
||||
}
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error selecting next gateway client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if length == 0 {
|
||||
tfRes, err := s.gwClient.TouchFile(ctx, &provider.TouchFileRequest{
|
||||
tfRes, err := client.TouchFile(ctx, &provider.TouchFileRequest{
|
||||
Ref: ref,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -162,7 +168,7 @@ func (s *svc) handlePut(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
sRes, err := s.gwClient.Stat(ctx, &provider.StatRequest{
|
||||
sRes, err := client.Stat(ctx, &provider.StatRequest{
|
||||
Ref: ref,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -241,7 +247,7 @@ func (s *svc) handlePut(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
|
||||
// where to upload the file?
|
||||
uRes, err := s.gwClient.InitiateFileUpload(ctx, uReq)
|
||||
uRes, err := client.InitiateFileUpload(ctx, uReq)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error initiating file upload")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -258,7 +264,7 @@ func (s *svc) handlePut(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
status := http.StatusForbidden
|
||||
m := uRes.Status.Message
|
||||
// check if user has access to parent
|
||||
sRes, err := s.gwClient.Stat(ctx, &provider.StatRequest{Ref: &provider.Reference{
|
||||
sRes, err := client.Stat(ctx, &provider.StatRequest{Ref: &provider.Reference{
|
||||
ResourceId: ref.ResourceId,
|
||||
Path: utils.MakeRelativePath(path.Dir(ref.Path)),
|
||||
}})
|
||||
|
||||
+7
-1
@@ -81,9 +81,15 @@ func (s *svc) doFilterFiles(w http.ResponseWriter, r *http.Request, ff *reportFi
|
||||
return
|
||||
}
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error selecting next gateway client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
infos := make([]*provider.ResourceInfo, 0, len(favorites))
|
||||
for i := range favorites {
|
||||
statRes, err := s.gwClient.Stat(ctx, &providerv1beta1.StatRequest{Ref: &providerv1beta1.Reference{ResourceId: favorites[i]}})
|
||||
statRes, err := client.Stat(ctx, &providerv1beta1.StatRequest{Ref: &providerv1beta1.Reference{ResourceId: favorites[i]}})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error getting resource info")
|
||||
continue
|
||||
|
||||
Generated
Vendored
+9
-3
@@ -29,6 +29,7 @@ import (
|
||||
storageProvider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/cs3org/reva/v2/pkg/storagespace"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"google.golang.org/protobuf/types/known/fieldmaskpb"
|
||||
@@ -37,8 +38,8 @@ import (
|
||||
// LookupReferenceForPath returns:
|
||||
// a reference with root and relative path
|
||||
// the status and error for the lookup
|
||||
func LookupReferenceForPath(ctx context.Context, client gateway.GatewayAPIClient, path string) (*storageProvider.Reference, *rpc.Status, error) {
|
||||
space, cs3Status, err := LookUpStorageSpaceForPath(ctx, client, path)
|
||||
func LookupReferenceForPath(ctx context.Context, selector pool.Selectable[gateway.GatewayAPIClient], path string) (*storageProvider.Reference, *rpc.Status, error) {
|
||||
space, cs3Status, err := LookUpStorageSpaceForPath(ctx, selector, path)
|
||||
if err != nil || cs3Status.Code != rpc.Code_CODE_OK {
|
||||
return nil, cs3Status, err
|
||||
}
|
||||
@@ -52,7 +53,7 @@ func LookupReferenceForPath(ctx context.Context, client gateway.GatewayAPIClient
|
||||
// LookUpStorageSpaceForPath returns:
|
||||
// the storage spaces responsible for a path
|
||||
// the status and error for the lookup
|
||||
func LookUpStorageSpaceForPath(ctx context.Context, client gateway.GatewayAPIClient, path string) (*storageProvider.StorageSpace, *rpc.Status, error) {
|
||||
func LookUpStorageSpaceForPath(ctx context.Context, selector pool.Selectable[gateway.GatewayAPIClient], path string) (*storageProvider.StorageSpace, *rpc.Status, error) {
|
||||
// TODO add filter to only fetch spaces changed in the last 30 sec?
|
||||
// TODO cache space information, invalidate after ... 5min? so we do not need to fetch all spaces?
|
||||
// TODO use ListContainerStream to listen for changes
|
||||
@@ -72,6 +73,11 @@ func LookUpStorageSpaceForPath(ctx context.Context, client gateway.GatewayAPICli
|
||||
},
|
||||
}
|
||||
|
||||
client, err := selector.Next()
|
||||
if err != nil {
|
||||
return nil, status.NewInternal(ctx, "could not select next client"), err
|
||||
}
|
||||
|
||||
lSSRes, err := client.ListStorageSpaces(ctx, lSSReq)
|
||||
if err != nil || lSSRes.Status.Code != rpc.Code_CODE_OK {
|
||||
status := status.NewStatusFromErrType(ctx, "failed to lookup storage spaces", err)
|
||||
|
||||
+1
-4
@@ -22,7 +22,6 @@ import (
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/errors"
|
||||
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/net"
|
||||
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind"
|
||||
@@ -79,9 +78,7 @@ func (h *SpacesHandler) Handler(s *svc, trashbinHandler *TrashbinHandler) http.H
|
||||
var err error
|
||||
switch r.Method {
|
||||
case MethodPropfind:
|
||||
p := propfind.NewHandler(config.PublicURL, func() (gateway.GatewayAPIClient, error) {
|
||||
return s.gwClient, nil
|
||||
})
|
||||
p := propfind.NewHandler(config.PublicURL, s.gatewaySelector)
|
||||
p.HandleSpacesPropfind(w, r, spaceID)
|
||||
case MethodProppatch:
|
||||
status, err = s.handleSpacesProppatch(w, r, spaceID)
|
||||
|
||||
+31
-6
@@ -37,6 +37,7 @@ import (
|
||||
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/net"
|
||||
"github.com/cs3org/reva/v2/pkg/appctx"
|
||||
"github.com/cs3org/reva/v2/pkg/errtypes"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/cs3org/reva/v2/pkg/rhttp"
|
||||
)
|
||||
|
||||
@@ -134,10 +135,16 @@ func (s *svc) handleTPCPull(ctx context.Context, w http.ResponseWriter, r *http.
|
||||
}
|
||||
sublog.Debug().Bool("overwrite", overwrite).Msg("TPC Pull")
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error selecting next gateway client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
// check if destination exists
|
||||
ref := &provider.Reference{Path: dst}
|
||||
dstStatReq := &provider.StatRequest{Ref: ref}
|
||||
dstStatRes, err := s.gwClient.Stat(ctx, dstStatReq)
|
||||
dstStatRes, err := client.Stat(ctx, dstStatReq)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error sending grpc stat request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -153,7 +160,7 @@ func (s *svc) handleTPCPull(ctx context.Context, w http.ResponseWriter, r *http.
|
||||
return
|
||||
}
|
||||
|
||||
err = s.performHTTPPull(ctx, s.gwClient, r, w, ns)
|
||||
err = s.performHTTPPull(ctx, s.gatewaySelector, r, w, ns)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error performing TPC Pull")
|
||||
return
|
||||
@@ -161,7 +168,7 @@ func (s *svc) handleTPCPull(ctx context.Context, w http.ResponseWriter, r *http.
|
||||
fmt.Fprintf(w, "success: Created")
|
||||
}
|
||||
|
||||
func (s *svc) performHTTPPull(ctx context.Context, client gateway.GatewayAPIClient, r *http.Request, w http.ResponseWriter, ns string) error {
|
||||
func (s *svc) performHTTPPull(ctx context.Context, selector pool.Selectable[gateway.GatewayAPIClient], r *http.Request, w http.ResponseWriter, ns string) error {
|
||||
src := r.Header.Get("Source")
|
||||
dst := path.Join(ns, r.URL.Path)
|
||||
sublog := appctx.GetLogger(ctx)
|
||||
@@ -197,6 +204,12 @@ func (s *svc) performHTTPPull(ctx context.Context, client gateway.GatewayAPIClie
|
||||
return errtypes.InternalError(fmt.Sprintf("Remote GET returned status code %d", httpDownloadRes.StatusCode))
|
||||
}
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error selecting next gateway client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return errtypes.InternalError(err.Error())
|
||||
}
|
||||
// get upload url
|
||||
uReq := &provider.InitiateFileUploadRequest{
|
||||
Ref: &provider.Reference{Path: dst},
|
||||
@@ -287,9 +300,15 @@ func (s *svc) handleTPCPush(ctx context.Context, w http.ResponseWriter, r *http.
|
||||
|
||||
sublog.Debug().Bool("overwrite", overwrite).Msg("TPC Push")
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error selecting next gateway client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
ref := &provider.Reference{Path: src}
|
||||
srcStatReq := &provider.StatRequest{Ref: ref}
|
||||
srcStatRes, err := s.gwClient.Stat(ctx, srcStatReq)
|
||||
srcStatRes, err := client.Stat(ctx, srcStatReq)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error sending grpc stat request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -305,7 +324,7 @@ func (s *svc) handleTPCPush(ctx context.Context, w http.ResponseWriter, r *http.
|
||||
return
|
||||
}
|
||||
|
||||
err = s.performHTTPPush(ctx, s.gwClient, r, w, srcStatRes.Info, ns)
|
||||
err = s.performHTTPPush(ctx, r, w, srcStatRes.Info, ns)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error performing TPC Push")
|
||||
return
|
||||
@@ -313,7 +332,7 @@ func (s *svc) handleTPCPush(ctx context.Context, w http.ResponseWriter, r *http.
|
||||
fmt.Fprintf(w, "success: Created")
|
||||
}
|
||||
|
||||
func (s *svc) performHTTPPush(ctx context.Context, client gateway.GatewayAPIClient, r *http.Request, w http.ResponseWriter, srcInfo *provider.ResourceInfo, ns string) error {
|
||||
func (s *svc) performHTTPPush(ctx context.Context, r *http.Request, w http.ResponseWriter, srcInfo *provider.ResourceInfo, ns string) error {
|
||||
src := path.Join(ns, r.URL.Path)
|
||||
dst := r.Header.Get("Destination")
|
||||
|
||||
@@ -325,6 +344,12 @@ func (s *svc) performHTTPPush(ctx context.Context, client gateway.GatewayAPIClie
|
||||
Ref: &provider.Reference{Path: src},
|
||||
}
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error selecting next gateway client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return err
|
||||
}
|
||||
dRes, err := client.InitiateFileDownload(ctx, dReq)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
Generated
Vendored
+28
-10
@@ -111,7 +111,7 @@ func (h *TrashbinHandler) Handler(s *svc) http.Handler {
|
||||
r.URL.Path = newPath
|
||||
|
||||
basePath := path.Join(ns, newPath)
|
||||
space, rpcstatus, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gwClient, basePath)
|
||||
space, rpcstatus, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gatewaySelector, basePath)
|
||||
switch {
|
||||
case err != nil:
|
||||
log.Error().Err(err).Str("path", basePath).Msg("failed to look up storage space")
|
||||
@@ -151,7 +151,7 @@ func (h *TrashbinHandler) Handler(s *svc) http.Handler {
|
||||
|
||||
p := path.Join(ns, dst)
|
||||
// The destination can be in another space. E.g. the 'Shares Jail'.
|
||||
space, rpcstatus, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gwClient, p)
|
||||
space, rpcstatus, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gatewaySelector, p)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("path", p).Msg("failed to look up destination storage space")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -216,8 +216,14 @@ func (h *TrashbinHandler) listTrashbin(w http.ResponseWriter, r *http.Request, s
|
||||
return
|
||||
}
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error selecting next gateway client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
// ask gateway for recycle items
|
||||
getRecycleRes, err := s.gwClient.ListRecycle(ctx, &provider.ListRecycleRequest{Ref: ref, Key: path.Join(key, itemPath)})
|
||||
getRecycleRes, err := client.ListRecycle(ctx, &provider.ListRecycleRequest{Ref: ref, Key: path.Join(key, itemPath)})
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error calling ListRecycle")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -247,7 +253,7 @@ func (h *TrashbinHandler) listTrashbin(w http.ResponseWriter, r *http.Request, s
|
||||
|
||||
for len(stack) > 0 {
|
||||
key := stack[len(stack)-1]
|
||||
getRecycleRes, err := s.gwClient.ListRecycle(ctx, &provider.ListRecycleRequest{Ref: ref, Key: key})
|
||||
getRecycleRes, err := client.ListRecycle(ctx, &provider.ListRecycleRequest{Ref: ref, Key: key})
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error calling ListRecycle")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -465,8 +471,14 @@ func (h *TrashbinHandler) restore(w http.ResponseWriter, r *http.Request, s *svc
|
||||
return
|
||||
}
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error selecting next gateway client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
dstStatReq := &provider.StatRequest{Ref: dst}
|
||||
dstStatRes, err := s.gwClient.Stat(ctx, dstStatReq)
|
||||
dstStatRes, err := client.Stat(ctx, dstStatReq)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error sending grpc stat request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -484,7 +496,7 @@ func (h *TrashbinHandler) restore(w http.ResponseWriter, r *http.Request, s *svc
|
||||
parentRef := &provider.Reference{ResourceId: dst.ResourceId, Path: utils.MakeRelativePath(path.Dir(dst.Path))}
|
||||
parentStatReq := &provider.StatRequest{Ref: parentRef}
|
||||
|
||||
parentStatResponse, err := s.gwClient.Stat(ctx, parentStatReq)
|
||||
parentStatResponse, err := client.Stat(ctx, parentStatReq)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error sending grpc stat request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -515,7 +527,7 @@ func (h *TrashbinHandler) restore(w http.ResponseWriter, r *http.Request, s *svc
|
||||
}
|
||||
// delete existing tree
|
||||
delReq := &provider.DeleteRequest{Ref: dst}
|
||||
delRes, err := s.gwClient.Delete(ctx, delReq)
|
||||
delRes, err := client.Delete(ctx, delReq)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error sending grpc delete request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -534,7 +546,7 @@ func (h *TrashbinHandler) restore(w http.ResponseWriter, r *http.Request, s *svc
|
||||
RestoreRef: dst,
|
||||
}
|
||||
|
||||
res, err := s.gwClient.RestoreRecycleItem(ctx, req)
|
||||
res, err := client.RestoreRecycleItem(ctx, req)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error sending a grpc restore recycle item request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -551,7 +563,7 @@ func (h *TrashbinHandler) restore(w http.ResponseWriter, r *http.Request, s *svc
|
||||
return
|
||||
}
|
||||
|
||||
dstStatRes, err = s.gwClient.Stat(ctx, dstStatReq)
|
||||
dstStatRes, err = client.Stat(ctx, dstStatReq)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error sending grpc stat request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -584,7 +596,13 @@ func (h *TrashbinHandler) delete(w http.ResponseWriter, r *http.Request, s *svc,
|
||||
Key: trashPath,
|
||||
}
|
||||
|
||||
res, err := s.gwClient.PurgeRecycle(ctx, req)
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error selecting next gateway client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
res, err := client.PurgeRecycle(ctx, req)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error sending a grpc restore recycle item request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
+9
-4
@@ -114,10 +114,15 @@ func (s *svc) handleTusPost(ctx context.Context, w http.ResponseWriter, r *http.
|
||||
|
||||
// TODO check Expect: 100-continue
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
sReq := &provider.StatRequest{
|
||||
Ref: ref,
|
||||
}
|
||||
sRes, err := s.gwClient.Stat(ctx, sReq)
|
||||
sRes, err := client.Stat(ctx, sReq)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error sending grpc stat request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -155,7 +160,7 @@ func (s *svc) handleTusPost(ctx context.Context, w http.ResponseWriter, r *http.
|
||||
return
|
||||
}
|
||||
if uploadLength == 0 {
|
||||
tfRes, err := s.gwClient.TouchFile(ctx, &provider.TouchFileRequest{
|
||||
tfRes, err := client.TouchFile(ctx, &provider.TouchFileRequest{
|
||||
Ref: ref,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -193,7 +198,7 @@ func (s *svc) handleTusPost(ctx context.Context, w http.ResponseWriter, r *http.
|
||||
},
|
||||
}
|
||||
|
||||
uRes, err := s.gwClient.InitiateFileUpload(ctx, uReq)
|
||||
uRes, err := client.InitiateFileUpload(ctx, uReq)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error initiating file upload")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -284,7 +289,7 @@ func (s *svc) handleTusPost(ctx context.Context, w http.ResponseWriter, r *http.
|
||||
}
|
||||
}
|
||||
|
||||
sRes, err := s.gwClient.Stat(ctx, sReq)
|
||||
sRes, err := client.Stat(ctx, sReq)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error sending grpc stat request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
Generated
Vendored
+15
-3
@@ -122,8 +122,14 @@ func (h *VersionsHandler) doListVersions(w http.ResponseWriter, r *http.Request,
|
||||
return
|
||||
}
|
||||
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error selecting next gateway client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
ref := &provider.Reference{ResourceId: rid}
|
||||
res, err := s.gwClient.Stat(ctx, &provider.StatRequest{Ref: ref})
|
||||
res, err := client.Stat(ctx, &provider.StatRequest{Ref: ref})
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error sending a grpc stat request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -142,7 +148,7 @@ func (h *VersionsHandler) doListVersions(w http.ResponseWriter, r *http.Request,
|
||||
|
||||
info := res.Info
|
||||
|
||||
lvRes, err := s.gwClient.ListFileVersions(ctx, &provider.ListFileVersionsRequest{Ref: ref})
|
||||
lvRes, err := client.ListFileVersions(ctx, &provider.ListFileVersionsRequest{Ref: ref})
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error sending list container grpc request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -225,7 +231,13 @@ func (h *VersionsHandler) doRestore(w http.ResponseWriter, r *http.Request, s *s
|
||||
Key: key,
|
||||
}
|
||||
|
||||
res, err := s.gwClient.RestoreFileVersion(ctx, req)
|
||||
client, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error selecting next gateway client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
res, err := client.RestoreFileVersion(ctx, req)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Msg("error sending a grpc restore version request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
+1
-4
@@ -23,7 +23,6 @@ import (
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/errors"
|
||||
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind"
|
||||
"github.com/cs3org/reva/v2/pkg/appctx"
|
||||
@@ -73,9 +72,7 @@ func (h *WebDavHandler) Handler(s *svc) http.Handler {
|
||||
var status int // status 0 means the handler already sent the response
|
||||
switch r.Method {
|
||||
case MethodPropfind:
|
||||
p := propfind.NewHandler(config.PublicURL, func() (gateway.GatewayAPIClient, error) {
|
||||
return s.gwClient, nil
|
||||
})
|
||||
p := propfind.NewHandler(config.PublicURL, s.gatewaySelector)
|
||||
p.HandlePathPropfind(w, r, ns)
|
||||
case MethodLock:
|
||||
status, err = s.handleLock(w, r, ns)
|
||||
|
||||
Generated
Vendored
+1
-1
@@ -345,7 +345,7 @@ func ParseTimestamp(timestampString string) (*types.Timestamp, error) {
|
||||
parsedTime, err = time.Parse("2006-01-02", timestampString)
|
||||
if err == nil {
|
||||
// the link needs to be valid for the whole day
|
||||
parsedTime.Add(23*time.Hour + 59*time.Minute + 59*time.Second)
|
||||
parsedTime = parsedTime.Add(23*time.Hour + 59*time.Minute + 59*time.Second)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
+6
@@ -379,6 +379,9 @@ func (c *EOSHTTPClient) PUTFile(ctx context.Context, remoteuser string, auth eos
|
||||
// Execute the request. I don't like that there is no explicit timeout or buffer control on the input stream
|
||||
log.Debug().Str("func", "PUTFile").Msg("sending req")
|
||||
resp, err := c.cl.Do(req)
|
||||
if resp != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
// Let's support redirections... and if we retry we retry at the same FST
|
||||
if resp != nil && resp.StatusCode == 307 {
|
||||
@@ -471,6 +474,9 @@ func (c *EOSHTTPClient) Head(ctx context.Context, remoteuser string, auth eoscli
|
||||
}
|
||||
// Execute the request. I don't like that there is no explicit timeout or buffer control on the input stream
|
||||
resp, err := c.cl.Do(req)
|
||||
if resp != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
// And get an error code (if error) that is worth propagating
|
||||
e := c.getRespError(resp, err)
|
||||
|
||||
+5
-4
@@ -24,6 +24,7 @@ import (
|
||||
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/favorite"
|
||||
"github.com/rs/zerolog"
|
||||
"go-micro.dev/v4/broker"
|
||||
@@ -45,7 +46,7 @@ type Options struct {
|
||||
JWTSecret string
|
||||
|
||||
FavoriteManager favorite.Manager
|
||||
GatewayClient gateway.GatewayAPIClient
|
||||
GatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
|
||||
TracingEnabled bool
|
||||
TracingInsecure bool
|
||||
@@ -196,10 +197,10 @@ func FavoriteManager(val favorite.Manager) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// GatewayClient provides a function to set the GatewayClient option.
|
||||
func GatewayClient(val gateway.GatewayAPIClient) Option {
|
||||
// GatewaySelector provides a function to set the GatewaySelector option.
|
||||
func GatewaySelector(val pool.Selectable[gateway.GatewayAPIClient]) Option {
|
||||
return func(o *Options) {
|
||||
o.GatewayClient = val
|
||||
o.GatewaySelector = val
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -35,6 +35,7 @@ import (
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
httpServer "github.com/go-micro/plugins/v4/server/http"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/registry"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"go-micro.dev/v4"
|
||||
@@ -68,7 +69,7 @@ func Service(opts ...Option) (micro.Service, error) {
|
||||
server.Version(sopts.config.VersionString),
|
||||
)
|
||||
|
||||
revaService, err := ocdav.NewWith(&sopts.config, sopts.FavoriteManager, sopts.lockSystem, &sopts.Logger, sopts.GatewayClient)
|
||||
revaService, err := ocdav.NewWith(&sopts.config, sopts.FavoriteManager, sopts.lockSystem, &sopts.Logger, sopts.GatewaySelector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -137,11 +138,11 @@ func setDefaults(sopts *Options) error {
|
||||
sopts.Name = ServerName
|
||||
}
|
||||
if sopts.lockSystem == nil {
|
||||
client, err := pool.GetGatewayServiceClient(sopts.config.GatewaySvc)
|
||||
selector, err := pool.GatewaySelector(sopts.config.GatewaySvc)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "error getting gateway selector")
|
||||
}
|
||||
sopts.lockSystem = ocdav.NewCS3LS(client)
|
||||
sopts.lockSystem = ocdav.NewCS3LS(selector)
|
||||
}
|
||||
if sopts.FavoriteManager == nil {
|
||||
sopts.FavoriteManager, _ = memory.New(map[string]interface{}{})
|
||||
|
||||
-1
@@ -58,7 +58,6 @@ func randSeq(n int) string {
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
registry.Register("nextcloud", New)
|
||||
}
|
||||
|
||||
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
// 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/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
// Config configures a registry
|
||||
type Config struct {
|
||||
Services map[string]map[string]*service `mapstructure:"services"`
|
||||
}
|
||||
|
||||
// service implements the Service interface. Attributes are exported so that mapstructure can unmarshal values onto them.
|
||||
type service struct {
|
||||
Name string `mapstructure:"name"`
|
||||
Nodes []node `mapstructure:"nodes"`
|
||||
}
|
||||
|
||||
type node struct {
|
||||
Address string `mapstructure:"address"`
|
||||
Metadata map[string]string `mapstructure:"metadata"`
|
||||
}
|
||||
|
||||
// ParseConfig translates Config file values into a Config struct for consumers.
|
||||
func ParseConfig(m map[string]interface{}) (*Config, error) {
|
||||
c := &Config{}
|
||||
if err := mapstructure.Decode(m, c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(c.Services) == 0 {
|
||||
c.Services = make(map[string]map[string]*service)
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
-81
@@ -1,81 +0,0 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/cs3org/reva/v2/pkg/registry"
|
||||
)
|
||||
|
||||
// Registry implements the Registry interface.
|
||||
type Registry struct {
|
||||
// m protects async access to the services map.
|
||||
sync.Mutex
|
||||
// services map a service name with a set of nodes.
|
||||
services map[string]registry.Service
|
||||
}
|
||||
|
||||
// Add implements the Registry interface. If the service is already known in this registry it will only update the nodes.
|
||||
func (r *Registry) Add(svc registry.Service) error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
// append the nodes if the service is already registered.
|
||||
if _, ok := r.services[svc.Name()]; ok {
|
||||
s := service{
|
||||
name: svc.Name(),
|
||||
nodes: make([]node, 0),
|
||||
}
|
||||
|
||||
s.mergeNodes(svc.Nodes(), r.services[svc.Name()].Nodes())
|
||||
|
||||
r.services[svc.Name()] = s
|
||||
return nil
|
||||
}
|
||||
|
||||
r.services[svc.Name()] = svc
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetService implements the Registry interface. There is currently no load balance being done, but it should not be
|
||||
// hard to add.
|
||||
func (r *Registry) GetService(name string) (registry.Service, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
if service, ok := r.services[name]; ok {
|
||||
return service, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("service %v not found", name)
|
||||
}
|
||||
|
||||
// New returns an implementation of the Registry interface.
|
||||
func New(m map[string]interface{}) registry.Registry {
|
||||
// c, err := registry.ParseConfig(m)
|
||||
// if err != nil {
|
||||
// return nil
|
||||
// }
|
||||
|
||||
return &Registry{
|
||||
services: map[string]registry.Service{},
|
||||
}
|
||||
}
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
// 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 "fmt"
|
||||
|
||||
// node implements the registry.Node interface.
|
||||
type node struct {
|
||||
id string
|
||||
address string
|
||||
metadata map[string]string
|
||||
}
|
||||
|
||||
func (n node) Address() string {
|
||||
return n.address
|
||||
}
|
||||
|
||||
func (n node) Metadata() map[string]string {
|
||||
return n.metadata
|
||||
}
|
||||
|
||||
func (n node) String() string {
|
||||
return fmt.Sprintf("%v-%v", n.id, n.address)
|
||||
}
|
||||
|
||||
func (n node) ID() string {
|
||||
return n.id
|
||||
}
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
// 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 "github.com/cs3org/reva/v2/pkg/registry"
|
||||
|
||||
// NewService creates a new memory registry.Service.
|
||||
func NewService(name string, nodes []interface{}) registry.Service {
|
||||
n := make([]node, 0)
|
||||
for i := 0; i < len(nodes); i++ {
|
||||
n = append(n, node{
|
||||
// explicit type conversions because types are not exported to prevent from circular dependencies until released.
|
||||
id: nodes[i].(map[string]interface{})["id"].(string),
|
||||
address: nodes[i].(map[string]interface{})["address"].(string),
|
||||
//metadata: nodes[i].(map[string]interface{})["metadata"].(map[string]string),
|
||||
})
|
||||
}
|
||||
|
||||
return service{
|
||||
name: name,
|
||||
nodes: n,
|
||||
}
|
||||
}
|
||||
|
||||
// service implements the Service interface
|
||||
type service struct {
|
||||
name string
|
||||
nodes []node
|
||||
}
|
||||
|
||||
// Name implements the service interface.
|
||||
func (s service) Name() string {
|
||||
return s.name
|
||||
}
|
||||
|
||||
// Nodes implements the service interface.
|
||||
func (s service) Nodes() []registry.Node {
|
||||
ret := make([]registry.Node, 0)
|
||||
for i := range s.nodes {
|
||||
ret = append(ret, s.nodes[i])
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (s *service) mergeNodes(n1, n2 []registry.Node) {
|
||||
n1 = append(n1, n2...)
|
||||
for _, n := range n1 {
|
||||
s.nodes = append(s.nodes, node{
|
||||
id: n.ID(),
|
||||
address: n.Address(),
|
||||
metadata: n.Metadata(),
|
||||
})
|
||||
}
|
||||
}
|
||||
+29
-23
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018-2021 CERN
|
||||
// Copyright 2018-2023 CERN
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -18,32 +18,38 @@
|
||||
|
||||
package registry
|
||||
|
||||
// Registry provides with means for dynamically registering services.
|
||||
type Registry interface {
|
||||
// Add registers a Service on the memoryRegistry. Repeated names is allowed, services are distinguished by their metadata.
|
||||
Add(Service) error
|
||||
import (
|
||||
mRegistry "go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/selector"
|
||||
)
|
||||
|
||||
// GetService retrieves a Service and all of its nodes by Service name. It returns []*Service because we can have
|
||||
// multiple versions of the same Service running alongside each others.
|
||||
GetService(string) (Service, error)
|
||||
var (
|
||||
// fixme: get rid of global registry
|
||||
gRegistry mRegistry.Registry
|
||||
)
|
||||
|
||||
// Init prepares the service registry
|
||||
func Init(nRegistry mRegistry.Registry) error {
|
||||
// first come first serves, the first service defines the registry type.
|
||||
if gRegistry == nil && nRegistry != nil {
|
||||
gRegistry = nRegistry
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Service defines a service.
|
||||
type Service interface {
|
||||
Name() string
|
||||
Nodes() []Node
|
||||
// GetRegistry exposes the registry
|
||||
func GetRegistry() mRegistry.Registry {
|
||||
return gRegistry
|
||||
}
|
||||
|
||||
// Node defines nodes on a service.
|
||||
type Node interface {
|
||||
// Address where the given node is running.
|
||||
Address() string
|
||||
// GetNodeAddress returns a random address from the service nodes
|
||||
func GetNodeAddress(services []*mRegistry.Service) (string, error) {
|
||||
next := selector.Random(services)
|
||||
node, err := next()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// metadata is used in order to differentiate services implementations. For instance an AuthProvider Service could
|
||||
// have multiple implementations, basic, bearer ..., metadata would be used to select the Service type depending on
|
||||
// its implementation.
|
||||
Metadata() map[string]string
|
||||
|
||||
// ID returns the node ID.
|
||||
ID() string
|
||||
return node.Address, nil
|
||||
}
|
||||
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
// 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 pool
|
||||
|
||||
import (
|
||||
appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
|
||||
appregistry "github.com/cs3org/go-cs3apis/cs3/app/registry/v1beta1"
|
||||
applicationauth "github.com/cs3org/go-cs3apis/cs3/auth/applications/v1beta1"
|
||||
authprovider "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
|
||||
authregistry "github.com/cs3org/go-cs3apis/cs3/auth/registry/v1beta1"
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
group "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
|
||||
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
ocmcore "github.com/cs3org/go-cs3apis/cs3/ocm/core/v1beta1"
|
||||
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
|
||||
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
|
||||
permissions "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1"
|
||||
preferences "github.com/cs3org/go-cs3apis/cs3/preferences/v1beta1"
|
||||
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
|
||||
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
|
||||
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
|
||||
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
storageregistry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
|
||||
datatx "github.com/cs3org/go-cs3apis/cs3/tx/v1beta1"
|
||||
)
|
||||
|
||||
// GetGatewayServiceClient returns a GatewayServiceClient.
|
||||
func GetGatewayServiceClient(id string, opts ...Option) (gateway.GatewayAPIClient, error) {
|
||||
selector, _ := GatewaySelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetUserProviderServiceClient returns a UserProviderServiceClient.
|
||||
func GetUserProviderServiceClient(id string, opts ...Option) (user.UserAPIClient, error) {
|
||||
selector, _ := IdentityUserSelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetGroupProviderServiceClient returns a GroupProviderServiceClient.
|
||||
func GetGroupProviderServiceClient(id string, opts ...Option) (group.GroupAPIClient, error) {
|
||||
selector, _ := IdentityGroupSelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetStorageProviderServiceClient returns a StorageProviderServiceClient.
|
||||
func GetStorageProviderServiceClient(id string, opts ...Option) (storageprovider.ProviderAPIClient, error) {
|
||||
selector, _ := StorageProviderSelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetAuthRegistryServiceClient returns a new AuthRegistryServiceClient.
|
||||
func GetAuthRegistryServiceClient(id string, opts ...Option) (authregistry.RegistryAPIClient, error) {
|
||||
selector, _ := AuthRegistrySelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetAuthProviderServiceClient returns a new AuthProviderServiceClient.
|
||||
func GetAuthProviderServiceClient(id string, opts ...Option) (authprovider.ProviderAPIClient, error) {
|
||||
selector, _ := AuthProviderSelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetAppAuthProviderServiceClient returns a new AppAuthProviderServiceClient.
|
||||
func GetAppAuthProviderServiceClient(id string, opts ...Option) (applicationauth.ApplicationsAPIClient, error) {
|
||||
selector, _ := AuthApplicationSelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetUserShareProviderClient returns a new UserShareProviderClient.
|
||||
func GetUserShareProviderClient(id string, opts ...Option) (collaboration.CollaborationAPIClient, error) {
|
||||
selector, _ := SharingCollaborationSelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetOCMShareProviderClient returns a new OCMShareProviderClient.
|
||||
func GetOCMShareProviderClient(id string, opts ...Option) (ocm.OcmAPIClient, error) {
|
||||
selector, _ := SharingOCMSelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetOCMInviteManagerClient returns a new OCMInviteManagerClient.
|
||||
func GetOCMInviteManagerClient(id string, opts ...Option) (invitepb.InviteAPIClient, error) {
|
||||
selector, _ := OCMInviteSelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetPublicShareProviderClient returns a new PublicShareProviderClient.
|
||||
func GetPublicShareProviderClient(id string, opts ...Option) (link.LinkAPIClient, error) {
|
||||
selector, _ := SharingLinkSelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetPreferencesClient returns a new PreferencesClient.
|
||||
func GetPreferencesClient(id string, opts ...Option) (preferences.PreferencesAPIClient, error) {
|
||||
selector, _ := PreferencesSelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetPermissionsClient returns a new PermissionsClient.
|
||||
func GetPermissionsClient(id string, opts ...Option) (permissions.PermissionsAPIClient, error) {
|
||||
selector, _ := PermissionsSelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetAppRegistryClient returns a new AppRegistryClient.
|
||||
func GetAppRegistryClient(id string, opts ...Option) (appregistry.RegistryAPIClient, error) {
|
||||
selector, _ := AppRegistrySelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetAppProviderClient returns a new AppRegistryClient.
|
||||
func GetAppProviderClient(id string, opts ...Option) (appprovider.ProviderAPIClient, error) {
|
||||
selector, _ := AppProviderSelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetStorageRegistryClient returns a new StorageRegistryClient.
|
||||
func GetStorageRegistryClient(id string, opts ...Option) (storageregistry.RegistryAPIClient, error) {
|
||||
selector, _ := StorageRegistrySelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetOCMProviderAuthorizerClient returns a new OCMProviderAuthorizerClient.
|
||||
func GetOCMProviderAuthorizerClient(id string, opts ...Option) (ocmprovider.ProviderAPIClient, error) {
|
||||
selector, _ := OCMProviderSelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetOCMCoreClient returns a new OCMCoreClient.
|
||||
func GetOCMCoreClient(id string, opts ...Option) (ocmcore.OcmCoreAPIClient, error) {
|
||||
selector, _ := OCMCoreSelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
|
||||
// GetDataTxClient returns a new DataTxClient.
|
||||
func GetDataTxClient(id string, opts ...Option) (datatx.TxAPIClient, error) {
|
||||
selector, _ := TXSelector(id, opts...)
|
||||
return selector.Next()
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
// 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 pool
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
|
||||
rtrace "github.com/cs3org/reva/v2/pkg/trace"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
var (
|
||||
maxCallRecvMsgSize = 10240000
|
||||
)
|
||||
|
||||
// NewConn creates a new connection to a grpc server
|
||||
// with open census tracing support.
|
||||
// TODO(labkode): make grpc tls configurable.
|
||||
// TODO make maxCallRecvMsgSize configurable, raised from the default 4MB to be able to list 10k files
|
||||
func NewConn(address string, opts ...Option) (*grpc.ClientConn, error) {
|
||||
|
||||
options := ClientOptions{}
|
||||
if err := options.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// then overwrite with supplied options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
var cred credentials.TransportCredentials
|
||||
switch options.tlsMode {
|
||||
case TLSOff:
|
||||
cred = insecure.NewCredentials()
|
||||
case TLSInsecure:
|
||||
tlsConfig := tls.Config{
|
||||
InsecureSkipVerify: true, //nolint:gosec
|
||||
}
|
||||
cred = credentials.NewTLS(&tlsConfig)
|
||||
case TLSOn:
|
||||
if options.caCert != "" {
|
||||
var err error
|
||||
if cred, err = credentials.NewClientTLSFromFile(options.caCert, ""); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// Use system's cert pool
|
||||
cred = credentials.NewTLS(&tls.Config{})
|
||||
}
|
||||
}
|
||||
|
||||
conn, err := grpc.Dial(
|
||||
address,
|
||||
grpc.WithTransportCredentials(cred),
|
||||
grpc.WithDefaultCallOptions(
|
||||
grpc.MaxCallRecvMsgSize(maxCallRecvMsgSize),
|
||||
),
|
||||
grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor(
|
||||
otelgrpc.WithTracerProvider(
|
||||
options.tracerProvider,
|
||||
),
|
||||
otelgrpc.WithPropagators(
|
||||
rtrace.Propagator,
|
||||
),
|
||||
)),
|
||||
grpc.WithUnaryInterceptor(
|
||||
otelgrpc.UnaryClientInterceptor(
|
||||
otelgrpc.WithTracerProvider(
|
||||
options.tracerProvider,
|
||||
),
|
||||
otelgrpc.WithPropagators(
|
||||
rtrace.Propagator,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
// 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 pool
|
||||
|
||||
import (
|
||||
"github.com/cs3org/reva/v2/pkg/sharedconf"
|
||||
rtrace "github.com/cs3org/reva/v2/pkg/trace"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// Option is used to pass client options
|
||||
type Option func(opts *ClientOptions)
|
||||
|
||||
// ClientOptions represent additional options (e.g. tls settings) for the grpc clients
|
||||
type ClientOptions struct {
|
||||
tlsMode TLSMode
|
||||
caCert string
|
||||
tracerProvider trace.TracerProvider
|
||||
registry registry.Registry
|
||||
}
|
||||
|
||||
func (o *ClientOptions) init() error {
|
||||
// default to shared settings
|
||||
sharedOpt := sharedconf.GRPCClientOptions()
|
||||
var err error
|
||||
|
||||
if o.tlsMode, err = StringToTLSMode(sharedOpt.TLSMode); err != nil {
|
||||
return err
|
||||
}
|
||||
o.caCert = sharedOpt.CACertFile
|
||||
o.tracerProvider = rtrace.DefaultProvider()
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithTLSMode allows to set the TLSMode option for grpc clients
|
||||
func WithTLSMode(v TLSMode) Option {
|
||||
return func(o *ClientOptions) {
|
||||
o.tlsMode = v
|
||||
}
|
||||
}
|
||||
|
||||
// WithTLSCACert allows to set the CA Certificate for grpc clients
|
||||
func WithTLSCACert(v string) Option {
|
||||
return func(o *ClientOptions) {
|
||||
o.caCert = v
|
||||
}
|
||||
}
|
||||
|
||||
// WithTracerProvider allows to set the opentelemetry tracer provider for grpc clients
|
||||
func WithTracerProvider(v trace.TracerProvider) Option {
|
||||
return func(o *ClientOptions) {
|
||||
o.tracerProvider = v
|
||||
}
|
||||
}
|
||||
|
||||
// WithRegistry allows to set the registry for service lookup
|
||||
func WithRegistry(v registry.Registry) Option {
|
||||
return func(o *ClientOptions) {
|
||||
o.registry = v
|
||||
}
|
||||
}
|
||||
-560
@@ -19,50 +19,9 @@
|
||||
package pool
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
|
||||
appregistry "github.com/cs3org/go-cs3apis/cs3/app/registry/v1beta1"
|
||||
applicationauth "github.com/cs3org/go-cs3apis/cs3/auth/applications/v1beta1"
|
||||
authprovider "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
|
||||
authregistry "github.com/cs3org/go-cs3apis/cs3/auth/registry/v1beta1"
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
group "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
|
||||
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
ocmcore "github.com/cs3org/go-cs3apis/cs3/ocm/core/v1beta1"
|
||||
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
|
||||
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
|
||||
permissions "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1"
|
||||
preferences "github.com/cs3org/go-cs3apis/cs3/preferences/v1beta1"
|
||||
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
|
||||
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
|
||||
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
|
||||
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
storageregistry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
|
||||
datatx "github.com/cs3org/go-cs3apis/cs3/tx/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/sharedconf"
|
||||
rtrace "github.com/cs3org/reva/v2/pkg/trace"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
type provider struct {
|
||||
m sync.Mutex
|
||||
conn map[string]interface{}
|
||||
}
|
||||
|
||||
func newProvider() provider {
|
||||
return provider{
|
||||
sync.Mutex{},
|
||||
make(map[string]interface{}),
|
||||
}
|
||||
}
|
||||
|
||||
// TLSMode represents TLS mode for the clients
|
||||
type TLSMode int
|
||||
|
||||
@@ -76,41 +35,6 @@ const (
|
||||
TLSInsecure
|
||||
)
|
||||
|
||||
// ClientOptions represent additional options (e.g. tls settings) for the grpc clients
|
||||
type ClientOptions struct {
|
||||
tlsMode TLSMode
|
||||
caCert string
|
||||
tracerProvider trace.TracerProvider
|
||||
}
|
||||
|
||||
// Option is used to pass client options
|
||||
type Option func(opts *ClientOptions)
|
||||
|
||||
// TODO(labkode): is concurrent access to the maps safe?
|
||||
// var storageProviders = map[string]storageprovider.ProviderAPIClient{}
|
||||
var (
|
||||
storageProviders = newProvider()
|
||||
authProviders = newProvider()
|
||||
appAuthProviders = newProvider()
|
||||
authRegistries = newProvider()
|
||||
userShareProviders = newProvider()
|
||||
ocmShareProviders = newProvider()
|
||||
ocmInviteManagers = newProvider()
|
||||
ocmProviderAuthorizers = newProvider()
|
||||
ocmCores = newProvider()
|
||||
publicShareProviders = newProvider()
|
||||
preferencesProviders = newProvider()
|
||||
permissionsProviders = newProvider()
|
||||
appRegistries = newProvider()
|
||||
appProviders = newProvider()
|
||||
storageRegistries = newProvider()
|
||||
gatewayProviders = newProvider()
|
||||
userProviders = newProvider()
|
||||
groupProviders = newProvider()
|
||||
dataTxs = newProvider()
|
||||
maxCallRecvMsgSize = 10240000
|
||||
)
|
||||
|
||||
// StringToTLSMode converts the supply string into the equivalent TLSMode constant
|
||||
func StringToTLSMode(m string) (TLSMode, error) {
|
||||
switch m {
|
||||
@@ -124,487 +48,3 @@ func StringToTLSMode(m string) (TLSMode, error) {
|
||||
return TLSOff, fmt.Errorf("unknown TLS mode: '%s'. Valid values are 'on', 'off' and 'insecure'", m)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *ClientOptions) init() error {
|
||||
// default to shared settings
|
||||
sharedOpt := sharedconf.GRPCClientOptions()
|
||||
var err error
|
||||
|
||||
if o.tlsMode, err = StringToTLSMode(sharedOpt.TLSMode); err != nil {
|
||||
return err
|
||||
}
|
||||
o.caCert = sharedOpt.CACertFile
|
||||
o.tracerProvider = rtrace.DefaultProvider()
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithTLSMode allows to set the TLSMode option for grpc clients
|
||||
func WithTLSMode(v TLSMode) Option {
|
||||
return func(o *ClientOptions) {
|
||||
o.tlsMode = v
|
||||
}
|
||||
}
|
||||
|
||||
// WithTLSCACert allows to set the CA Certificate for grpc clients
|
||||
func WithTLSCACert(v string) Option {
|
||||
return func(o *ClientOptions) {
|
||||
o.caCert = v
|
||||
}
|
||||
}
|
||||
|
||||
// WithTracerProvider allows to set the opentelemetry tracer provider for grpc clients
|
||||
func WithTracerProvider(v trace.TracerProvider) Option {
|
||||
return func(o *ClientOptions) {
|
||||
o.tracerProvider = v
|
||||
}
|
||||
}
|
||||
|
||||
// NewConn creates a new connection to a grpc server
|
||||
// with open census tracing support.
|
||||
// TODO(labkode): make grpc tls configurable.
|
||||
// TODO make maxCallRecvMsgSize configurable, raised from the default 4MB to be able to list 10k files
|
||||
func NewConn(endpoint string, opts ...Option) (*grpc.ClientConn, error) {
|
||||
|
||||
options := ClientOptions{}
|
||||
if err := options.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// then overwrite with supplied options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
var cred credentials.TransportCredentials
|
||||
switch options.tlsMode {
|
||||
case TLSOff:
|
||||
cred = insecure.NewCredentials()
|
||||
case TLSInsecure:
|
||||
tlsConfig := tls.Config{
|
||||
InsecureSkipVerify: true, //nolint:gosec
|
||||
}
|
||||
cred = credentials.NewTLS(&tlsConfig)
|
||||
case TLSOn:
|
||||
if options.caCert != "" {
|
||||
var err error
|
||||
if cred, err = credentials.NewClientTLSFromFile(options.caCert, ""); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// Use system's cert pool
|
||||
cred = credentials.NewTLS(&tls.Config{})
|
||||
}
|
||||
}
|
||||
|
||||
conn, err := grpc.Dial(
|
||||
endpoint,
|
||||
grpc.WithTransportCredentials(cred),
|
||||
grpc.WithDefaultCallOptions(
|
||||
grpc.MaxCallRecvMsgSize(maxCallRecvMsgSize),
|
||||
),
|
||||
grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor(
|
||||
otelgrpc.WithTracerProvider(
|
||||
options.tracerProvider,
|
||||
),
|
||||
otelgrpc.WithPropagators(
|
||||
rtrace.Propagator,
|
||||
),
|
||||
)),
|
||||
grpc.WithUnaryInterceptor(
|
||||
otelgrpc.UnaryClientInterceptor(
|
||||
otelgrpc.WithTracerProvider(
|
||||
options.tracerProvider,
|
||||
),
|
||||
otelgrpc.WithPropagators(
|
||||
rtrace.Propagator,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// GetGatewayServiceClient returns a GatewayServiceClient.
|
||||
func GetGatewayServiceClient(endpoint string, opts ...Option) (gateway.GatewayAPIClient, error) {
|
||||
gatewayProviders.m.Lock()
|
||||
defer gatewayProviders.m.Unlock()
|
||||
|
||||
if val, ok := gatewayProviders.conn[endpoint]; ok {
|
||||
return val.(gateway.GatewayAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := gateway.NewGatewayAPIClient(conn)
|
||||
gatewayProviders.conn[endpoint] = v
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetUserProviderServiceClient returns a UserProviderServiceClient.
|
||||
func GetUserProviderServiceClient(endpoint string, opts ...Option) (user.UserAPIClient, error) {
|
||||
userProviders.m.Lock()
|
||||
defer userProviders.m.Unlock()
|
||||
|
||||
if val, ok := userProviders.conn[endpoint]; ok {
|
||||
return val.(user.UserAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := user.NewUserAPIClient(conn)
|
||||
userProviders.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetGroupProviderServiceClient returns a GroupProviderServiceClient.
|
||||
func GetGroupProviderServiceClient(endpoint string, opts ...Option) (group.GroupAPIClient, error) {
|
||||
groupProviders.m.Lock()
|
||||
defer groupProviders.m.Unlock()
|
||||
|
||||
if val, ok := groupProviders.conn[endpoint]; ok {
|
||||
return val.(group.GroupAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := group.NewGroupAPIClient(conn)
|
||||
groupProviders.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetStorageProviderServiceClient returns a StorageProviderServiceClient.
|
||||
func GetStorageProviderServiceClient(endpoint string, opts ...Option) (storageprovider.ProviderAPIClient, error) {
|
||||
storageProviders.m.Lock()
|
||||
defer storageProviders.m.Unlock()
|
||||
|
||||
if c, ok := storageProviders.conn[endpoint]; ok {
|
||||
return c.(storageprovider.ProviderAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := storageprovider.NewProviderAPIClient(conn)
|
||||
storageProviders.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetAuthRegistryServiceClient returns a new AuthRegistryServiceClient.
|
||||
func GetAuthRegistryServiceClient(endpoint string, opts ...Option) (authregistry.RegistryAPIClient, error) {
|
||||
authRegistries.m.Lock()
|
||||
defer authRegistries.m.Unlock()
|
||||
|
||||
// if there is already a connection to this node, use it.
|
||||
if c, ok := authRegistries.conn[endpoint]; ok {
|
||||
return c.(authregistry.RegistryAPIClient), nil
|
||||
}
|
||||
|
||||
// if not, create a new connection
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// and memoize it
|
||||
v := authregistry.NewRegistryAPIClient(conn)
|
||||
authRegistries.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetAuthProviderServiceClient returns a new AuthProviderServiceClient.
|
||||
func GetAuthProviderServiceClient(endpoint string, opts ...Option) (authprovider.ProviderAPIClient, error) {
|
||||
authProviders.m.Lock()
|
||||
defer authProviders.m.Unlock()
|
||||
|
||||
if c, ok := authProviders.conn[endpoint]; ok {
|
||||
return c.(authprovider.ProviderAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := authprovider.NewProviderAPIClient(conn)
|
||||
authProviders.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetAppAuthProviderServiceClient returns a new AppAuthProviderServiceClient.
|
||||
func GetAppAuthProviderServiceClient(endpoint string, opts ...Option) (applicationauth.ApplicationsAPIClient, error) {
|
||||
appAuthProviders.m.Lock()
|
||||
defer appAuthProviders.m.Unlock()
|
||||
|
||||
if c, ok := appAuthProviders.conn[endpoint]; ok {
|
||||
return c.(applicationauth.ApplicationsAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := applicationauth.NewApplicationsAPIClient(conn)
|
||||
appAuthProviders.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetUserShareProviderClient returns a new UserShareProviderClient.
|
||||
func GetUserShareProviderClient(endpoint string, opts ...Option) (collaboration.CollaborationAPIClient, error) {
|
||||
userShareProviders.m.Lock()
|
||||
defer userShareProviders.m.Unlock()
|
||||
|
||||
if c, ok := userShareProviders.conn[endpoint]; ok {
|
||||
return c.(collaboration.CollaborationAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := collaboration.NewCollaborationAPIClient(conn)
|
||||
userShareProviders.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetOCMShareProviderClient returns a new OCMShareProviderClient.
|
||||
func GetOCMShareProviderClient(endpoint string, opts ...Option) (ocm.OcmAPIClient, error) {
|
||||
ocmShareProviders.m.Lock()
|
||||
defer ocmShareProviders.m.Unlock()
|
||||
|
||||
if c, ok := ocmShareProviders.conn[endpoint]; ok {
|
||||
return c.(ocm.OcmAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := ocm.NewOcmAPIClient(conn)
|
||||
ocmShareProviders.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetOCMInviteManagerClient returns a new OCMInviteManagerClient.
|
||||
func GetOCMInviteManagerClient(endpoint string, opts ...Option) (invitepb.InviteAPIClient, error) {
|
||||
ocmInviteManagers.m.Lock()
|
||||
defer ocmInviteManagers.m.Unlock()
|
||||
|
||||
if c, ok := ocmInviteManagers.conn[endpoint]; ok {
|
||||
return c.(invitepb.InviteAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := invitepb.NewInviteAPIClient(conn)
|
||||
ocmInviteManagers.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetPublicShareProviderClient returns a new PublicShareProviderClient.
|
||||
func GetPublicShareProviderClient(endpoint string, opts ...Option) (link.LinkAPIClient, error) {
|
||||
publicShareProviders.m.Lock()
|
||||
defer publicShareProviders.m.Unlock()
|
||||
|
||||
if c, ok := publicShareProviders.conn[endpoint]; ok {
|
||||
return c.(link.LinkAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := link.NewLinkAPIClient(conn)
|
||||
publicShareProviders.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetPreferencesClient returns a new PreferencesClient.
|
||||
func GetPreferencesClient(endpoint string, opts ...Option) (preferences.PreferencesAPIClient, error) {
|
||||
preferencesProviders.m.Lock()
|
||||
defer preferencesProviders.m.Unlock()
|
||||
|
||||
if c, ok := preferencesProviders.conn[endpoint]; ok {
|
||||
return c.(preferences.PreferencesAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := preferences.NewPreferencesAPIClient(conn)
|
||||
preferencesProviders.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetPermissionsClient returns a new PermissionsClient.
|
||||
func GetPermissionsClient(endpoint string, opts ...Option) (permissions.PermissionsAPIClient, error) {
|
||||
permissionsProviders.m.Lock()
|
||||
defer permissionsProviders.m.Unlock()
|
||||
|
||||
if c, ok := permissionsProviders.conn[endpoint]; ok {
|
||||
return c.(permissions.PermissionsAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := permissions.NewPermissionsAPIClient(conn)
|
||||
permissionsProviders.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetAppRegistryClient returns a new AppRegistryClient.
|
||||
func GetAppRegistryClient(endpoint string, opts ...Option) (appregistry.RegistryAPIClient, error) {
|
||||
appRegistries.m.Lock()
|
||||
defer appRegistries.m.Unlock()
|
||||
|
||||
if c, ok := appRegistries.conn[endpoint]; ok {
|
||||
return c.(appregistry.RegistryAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := appregistry.NewRegistryAPIClient(conn)
|
||||
appRegistries.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetAppProviderClient returns a new AppRegistryClient.
|
||||
func GetAppProviderClient(endpoint string, opts ...Option) (appprovider.ProviderAPIClient, error) {
|
||||
appProviders.m.Lock()
|
||||
defer appProviders.m.Unlock()
|
||||
|
||||
if c, ok := appProviders.conn[endpoint]; ok {
|
||||
return c.(appprovider.ProviderAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := appprovider.NewProviderAPIClient(conn)
|
||||
appProviders.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetStorageRegistryClient returns a new StorageRegistryClient.
|
||||
func GetStorageRegistryClient(endpoint string, opts ...Option) (storageregistry.RegistryAPIClient, error) {
|
||||
storageRegistries.m.Lock()
|
||||
defer storageRegistries.m.Unlock()
|
||||
|
||||
if c, ok := storageRegistries.conn[endpoint]; ok {
|
||||
return c.(storageregistry.RegistryAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := storageregistry.NewRegistryAPIClient(conn)
|
||||
storageRegistries.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetOCMProviderAuthorizerClient returns a new OCMProviderAuthorizerClient.
|
||||
func GetOCMProviderAuthorizerClient(endpoint string, opts ...Option) (ocmprovider.ProviderAPIClient, error) {
|
||||
ocmProviderAuthorizers.m.Lock()
|
||||
defer ocmProviderAuthorizers.m.Unlock()
|
||||
|
||||
if c, ok := ocmProviderAuthorizers.conn[endpoint]; ok {
|
||||
return c.(ocmprovider.ProviderAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := ocmprovider.NewProviderAPIClient(conn)
|
||||
ocmProviderAuthorizers.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetOCMCoreClient returns a new OCMCoreClient.
|
||||
func GetOCMCoreClient(endpoint string, opts ...Option) (ocmcore.OcmCoreAPIClient, error) {
|
||||
ocmCores.m.Lock()
|
||||
defer ocmCores.m.Unlock()
|
||||
|
||||
if c, ok := ocmCores.conn[endpoint]; ok {
|
||||
return c.(ocmcore.OcmCoreAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := ocmcore.NewOcmCoreAPIClient(conn)
|
||||
ocmCores.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetDataTxClient returns a new DataTxClient.
|
||||
func GetDataTxClient(endpoint string, opts ...Option) (datatx.TxAPIClient, error) {
|
||||
dataTxs.m.Lock()
|
||||
defer dataTxs.m.Unlock()
|
||||
|
||||
if c, ok := dataTxs.conn[endpoint]; ok {
|
||||
return c.(datatx.TxAPIClient), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := datatx.NewTxAPIClient(conn)
|
||||
dataTxs.conn[endpoint] = v
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// getEndpointByName resolve service names to ip addresses present on the registry.
|
||||
// func getEndpointByName(name string) (string, error) {
|
||||
// if services, err := utils.GlobalRegistry.GetService(name); err == nil {
|
||||
// if len(services) > 0 {
|
||||
// for i := range services {
|
||||
// for j := range services[i].Nodes() {
|
||||
// // return the first one. This MUST be improved upon with selectors.
|
||||
// return services[i].Nodes()[j].Address(), nil
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return "", fmt.Errorf("could not get service by name: %v", name)
|
||||
// }
|
||||
|
||||
+315
@@ -0,0 +1,315 @@
|
||||
// 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 pool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
appProvider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
|
||||
appRegistry "github.com/cs3org/go-cs3apis/cs3/app/registry/v1beta1"
|
||||
authApplication "github.com/cs3org/go-cs3apis/cs3/auth/applications/v1beta1"
|
||||
authProvider "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
|
||||
authRegistry "github.com/cs3org/go-cs3apis/cs3/auth/registry/v1beta1"
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
identityGroup "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
|
||||
identityUser "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
ocmCore "github.com/cs3org/go-cs3apis/cs3/ocm/core/v1beta1"
|
||||
ocmInvite "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
|
||||
ocmProvider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
|
||||
permissions "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1"
|
||||
preferences "github.com/cs3org/go-cs3apis/cs3/preferences/v1beta1"
|
||||
sharingCollaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
|
||||
sharingLink "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
|
||||
sharingOCM "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
|
||||
storageProvider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
storageRegistry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
|
||||
tx "github.com/cs3org/go-cs3apis/cs3/tx/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/registry"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type Selectable[T any] interface {
|
||||
Next(opts ...Option) (T, error)
|
||||
}
|
||||
|
||||
var selectors sync.Map
|
||||
|
||||
// RemoveSelector removes given id from the selectors map.
|
||||
func RemoveSelector(id string) {
|
||||
selectors.Delete(id)
|
||||
}
|
||||
|
||||
func GetSelector[T any](k string, id string, f func(cc *grpc.ClientConn) T, options ...Option) *Selector[T] {
|
||||
existingSelector, ok := selectors.Load(k + id)
|
||||
if ok {
|
||||
return existingSelector.(*Selector[T])
|
||||
}
|
||||
|
||||
newSelector := &Selector[T]{
|
||||
id: id,
|
||||
clientFactory: f,
|
||||
options: options,
|
||||
}
|
||||
|
||||
selectors.Store(k+id, newSelector)
|
||||
|
||||
return newSelector
|
||||
}
|
||||
|
||||
type Selector[T any] struct {
|
||||
id string
|
||||
clientFactory func(cc *grpc.ClientConn) T
|
||||
clientMap sync.Map
|
||||
options []Option
|
||||
}
|
||||
|
||||
func (s *Selector[T]) Next(opts ...Option) (T, error) {
|
||||
options := ClientOptions{
|
||||
registry: registry.GetRegistry(),
|
||||
}
|
||||
|
||||
allOpts := append([]Option{}, s.options...)
|
||||
allOpts = append(allOpts, opts...)
|
||||
|
||||
for _, opt := range allOpts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
address := s.id
|
||||
if options.registry != nil {
|
||||
services, err := options.registry.GetService(s.id)
|
||||
if err != nil {
|
||||
return *new(T), fmt.Errorf("%s: %w", s.id, err)
|
||||
}
|
||||
|
||||
nodeAddress, err := registry.GetNodeAddress(services)
|
||||
if err != nil {
|
||||
return *new(T), fmt.Errorf("%s: %w", s.id, err)
|
||||
}
|
||||
|
||||
address = nodeAddress
|
||||
}
|
||||
|
||||
existingClient, ok := s.clientMap.Load(address)
|
||||
if ok {
|
||||
return existingClient.(T), nil
|
||||
}
|
||||
|
||||
conn, err := NewConn(address, allOpts...)
|
||||
if err != nil {
|
||||
return *new(T), errors.Wrap(err, fmt.Sprintf("could not create connection for %s to %s", s.id, address))
|
||||
}
|
||||
|
||||
newClient := s.clientFactory(conn)
|
||||
s.clientMap.Store(address, newClient)
|
||||
|
||||
return newClient, nil
|
||||
}
|
||||
|
||||
// GatewaySelector returns a Selector[gateway.GatewayAPIClient].
|
||||
func GatewaySelector(id string, options ...Option) (*Selector[gateway.GatewayAPIClient], error) {
|
||||
return GetSelector[gateway.GatewayAPIClient](
|
||||
"GatewaySelector",
|
||||
id,
|
||||
gateway.NewGatewayAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// IdentityUserSelector returns a Selector[identityUser.UserAPIClient].
|
||||
func IdentityUserSelector(id string, options ...Option) (*Selector[identityUser.UserAPIClient], error) {
|
||||
return GetSelector[identityUser.UserAPIClient](
|
||||
"IdentityUserSelector",
|
||||
id,
|
||||
identityUser.NewUserAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// IdentityGroupSelector returns a Selector[identityGroup.GroupAPIClient].
|
||||
func IdentityGroupSelector(id string, options ...Option) (*Selector[identityGroup.GroupAPIClient], error) {
|
||||
return GetSelector[identityGroup.GroupAPIClient](
|
||||
"IdentityGroupSelector",
|
||||
id,
|
||||
identityGroup.NewGroupAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// StorageProviderSelector returns a Selector[storageProvider.ProviderAPIClient].
|
||||
func StorageProviderSelector(id string, options ...Option) (*Selector[storageProvider.ProviderAPIClient], error) {
|
||||
return GetSelector[storageProvider.ProviderAPIClient](
|
||||
"StorageProviderSelector",
|
||||
id,
|
||||
storageProvider.NewProviderAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// AuthRegistrySelector returns a Selector[authRegistry.RegistryAPIClient].
|
||||
func AuthRegistrySelector(id string, options ...Option) (*Selector[authRegistry.RegistryAPIClient], error) {
|
||||
return GetSelector[authRegistry.RegistryAPIClient](
|
||||
"AuthRegistrySelector",
|
||||
id,
|
||||
authRegistry.NewRegistryAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// AuthProviderSelector returns a Selector[authProvider.RegistryAPIClient].
|
||||
func AuthProviderSelector(id string, options ...Option) (*Selector[authProvider.ProviderAPIClient], error) {
|
||||
return GetSelector[authProvider.ProviderAPIClient](
|
||||
"AuthProviderSelector",
|
||||
id,
|
||||
authProvider.NewProviderAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// AuthApplicationSelector returns a Selector[authApplication.ApplicationsAPIClient].
|
||||
func AuthApplicationSelector(id string, options ...Option) (*Selector[authApplication.ApplicationsAPIClient], error) {
|
||||
return GetSelector[authApplication.ApplicationsAPIClient](
|
||||
"AuthApplicationSelector",
|
||||
id,
|
||||
authApplication.NewApplicationsAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// SharingCollaborationSelector returns a Selector[sharingCollaboration.ApplicationsAPIClient].
|
||||
func SharingCollaborationSelector(id string, options ...Option) (*Selector[sharingCollaboration.CollaborationAPIClient], error) {
|
||||
return GetSelector[sharingCollaboration.CollaborationAPIClient](
|
||||
"SharingCollaborationSelector",
|
||||
id,
|
||||
sharingCollaboration.NewCollaborationAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// SharingOCMSelector returns a Selector[sharingOCM.OcmAPIClient].
|
||||
func SharingOCMSelector(id string, options ...Option) (*Selector[sharingOCM.OcmAPIClient], error) {
|
||||
return GetSelector[sharingOCM.OcmAPIClient](
|
||||
"SharingOCMSelector",
|
||||
id,
|
||||
sharingOCM.NewOcmAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// SharingLinkSelector returns a Selector[sharingLink.LinkAPIClient].
|
||||
func SharingLinkSelector(id string, options ...Option) (*Selector[sharingLink.LinkAPIClient], error) {
|
||||
return GetSelector[sharingLink.LinkAPIClient](
|
||||
"SharingLinkSelector",
|
||||
id,
|
||||
sharingLink.NewLinkAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// PreferencesSelector returns a Selector[preferences.PreferencesAPIClient].
|
||||
func PreferencesSelector(id string, options ...Option) (*Selector[preferences.PreferencesAPIClient], error) {
|
||||
return GetSelector[preferences.PreferencesAPIClient](
|
||||
"PreferencesSelector",
|
||||
id,
|
||||
preferences.NewPreferencesAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// PermissionsSelector returns a Selector[permissions.PermissionsAPIClient].
|
||||
func PermissionsSelector(id string, options ...Option) (*Selector[permissions.PermissionsAPIClient], error) {
|
||||
return GetSelector[permissions.PermissionsAPIClient](
|
||||
"PermissionsSelector",
|
||||
id,
|
||||
permissions.NewPermissionsAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// AppRegistrySelector returns a Selector[appRegistry.RegistryAPIClient].
|
||||
func AppRegistrySelector(id string, options ...Option) (*Selector[appRegistry.RegistryAPIClient], error) {
|
||||
return GetSelector[appRegistry.RegistryAPIClient](
|
||||
"AppRegistrySelector",
|
||||
id,
|
||||
appRegistry.NewRegistryAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// AppProviderSelector returns a Selector[appProvider.ProviderAPIClient].
|
||||
func AppProviderSelector(id string, options ...Option) (*Selector[appProvider.ProviderAPIClient], error) {
|
||||
return GetSelector[appProvider.ProviderAPIClient](
|
||||
"AppProviderSelector",
|
||||
id,
|
||||
appProvider.NewProviderAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// StorageRegistrySelector returns a Selector[storageRegistry.RegistryAPIClient].
|
||||
func StorageRegistrySelector(id string, options ...Option) (*Selector[storageRegistry.RegistryAPIClient], error) {
|
||||
return GetSelector[storageRegistry.RegistryAPIClient](
|
||||
"StorageRegistrySelector",
|
||||
id,
|
||||
storageRegistry.NewRegistryAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// OCMProviderSelector returns a Selector[storageRegistry.RegistryAPIClient].
|
||||
func OCMProviderSelector(id string, options ...Option) (*Selector[ocmProvider.ProviderAPIClient], error) {
|
||||
return GetSelector[ocmProvider.ProviderAPIClient](
|
||||
"OCMProviderSelector",
|
||||
id,
|
||||
ocmProvider.NewProviderAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// OCMCoreSelector returns a Selector[ocmCore.OcmCoreAPIClient].
|
||||
func OCMCoreSelector(id string, options ...Option) (*Selector[ocmCore.OcmCoreAPIClient], error) {
|
||||
return GetSelector[ocmCore.OcmCoreAPIClient](
|
||||
"OCMCoreSelector",
|
||||
id,
|
||||
ocmCore.NewOcmCoreAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// OCMInviteSelector returns a Selector[ocmInvite.InviteAPIClient].
|
||||
func OCMInviteSelector(id string, options ...Option) (*Selector[ocmInvite.InviteAPIClient], error) {
|
||||
return GetSelector[ocmInvite.InviteAPIClient](
|
||||
"OCMInviteSelector",
|
||||
id,
|
||||
ocmInvite.NewInviteAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
|
||||
// TXSelector returns a Selector[tx.TxAPIClient].
|
||||
func TXSelector(id string, options ...Option) (*Selector[tx.TxAPIClient], error) {
|
||||
return GetSelector[tx.TxAPIClient](
|
||||
"TXSelector",
|
||||
id,
|
||||
tx.NewTxAPIClient,
|
||||
options...,
|
||||
), nil
|
||||
}
|
||||
+133
-40
@@ -33,6 +33,7 @@ import (
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/genproto/protobuf/field_mask"
|
||||
|
||||
gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
@@ -109,12 +110,16 @@ import (
|
||||
- if the mtime changed we download the file to update the local cache
|
||||
*/
|
||||
|
||||
// name is the Tracer name used to identify this instrumentation library.
|
||||
const tracerName = "jsoncs3"
|
||||
|
||||
func init() {
|
||||
registry.Register("jsoncs3", NewDefault)
|
||||
}
|
||||
|
||||
type config struct {
|
||||
GatewayAddr string `mapstructure:"gateway_addr"`
|
||||
MaxConcurrency int `mapstructure:"max_concurrency"`
|
||||
ProviderAddr string `mapstructure:"provider_addr"`
|
||||
ServiceUserID string `mapstructure:"service_user_id"`
|
||||
ServiceUserIdp string `mapstructure:"service_user_idp"`
|
||||
@@ -145,6 +150,8 @@ type Manager struct {
|
||||
|
||||
initialized bool
|
||||
|
||||
MaxConcurrency int
|
||||
|
||||
gateway gatewayv1beta1.GatewayAPIClient
|
||||
eventStream events.Stream
|
||||
}
|
||||
@@ -205,11 +212,11 @@ func NewDefault(m map[string]interface{}) (share.Manager, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return New(s, gc, c.CacheTTL, es)
|
||||
return New(s, gc, c.CacheTTL, es, c.MaxConcurrency)
|
||||
}
|
||||
|
||||
// New returns a new manager instance.
|
||||
func New(s metadata.Storage, gc gatewayv1beta1.GatewayAPIClient, ttlSeconds int, es events.Stream) (*Manager, error) {
|
||||
func New(s metadata.Storage, gc gatewayv1beta1.GatewayAPIClient, ttlSeconds int, es events.Stream, maxconcurrency int) (*Manager, error) {
|
||||
ttl := time.Duration(ttlSeconds) * time.Second
|
||||
return &Manager{
|
||||
Cache: providercache.New(s, ttl),
|
||||
@@ -219,6 +226,7 @@ func New(s metadata.Storage, gc gatewayv1beta1.GatewayAPIClient, ttlSeconds int,
|
||||
storage: s,
|
||||
gateway: gc,
|
||||
eventStream: es,
|
||||
MaxConcurrency: maxconcurrency,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -259,6 +267,8 @@ func (m *Manager) initialize() error {
|
||||
|
||||
// Share creates a new share
|
||||
func (m *Manager) Share(ctx context.Context, md *provider.ResourceInfo, g *collaboration.ShareGrant) (*collaboration.Share, error) {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Share")
|
||||
defer span.End()
|
||||
if err := m.initialize(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -413,6 +423,8 @@ func (m *Manager) get(ctx context.Context, ref *collaboration.ShareReference) (s
|
||||
|
||||
// GetShare gets the information for a share by the given ref.
|
||||
func (m *Manager) GetShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.Share, error) {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "GetShare")
|
||||
defer span.End()
|
||||
if err := m.initialize(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -463,6 +475,9 @@ func (m *Manager) GetShare(ctx context.Context, ref *collaboration.ShareReferenc
|
||||
|
||||
// Unshare deletes a share
|
||||
func (m *Manager) Unshare(ctx context.Context, ref *collaboration.ShareReference) error {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Unshare")
|
||||
defer span.End()
|
||||
|
||||
if err := m.initialize(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -486,6 +501,9 @@ func (m *Manager) Unshare(ctx context.Context, ref *collaboration.ShareReference
|
||||
|
||||
// UpdateShare updates the mode of the given share.
|
||||
func (m *Manager) UpdateShare(ctx context.Context, ref *collaboration.ShareReference, p *collaboration.SharePermissions, updated *collaboration.Share, fieldMask *field_mask.FieldMask) (*collaboration.Share, error) {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "UpdateShare")
|
||||
defer span.End()
|
||||
|
||||
if err := m.initialize(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -565,6 +583,9 @@ func (m *Manager) UpdateShare(ctx context.Context, ref *collaboration.ShareRefer
|
||||
|
||||
// ListShares returns the shares created by the user
|
||||
func (m *Manager) ListShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.Share, error) {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "ListShares")
|
||||
defer span.End()
|
||||
|
||||
if err := m.initialize(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -582,6 +603,9 @@ func (m *Manager) ListShares(ctx context.Context, filters []*collaboration.Filte
|
||||
}
|
||||
|
||||
func (m *Manager) listSharesByIDs(ctx context.Context, user *userv1beta1.User, filters []*collaboration.Filter) ([]*collaboration.Share, error) {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "listSharesByIDs")
|
||||
defer span.End()
|
||||
|
||||
providerSpaces := make(map[string]map[string]struct{})
|
||||
for _, f := range share.FilterFiltersByType(filters, collaboration.Filter_TYPE_RESOURCE_ID) {
|
||||
storageID := f.GetResourceId().GetStorageId()
|
||||
@@ -649,6 +673,9 @@ func (m *Manager) listSharesByIDs(ctx context.Context, user *userv1beta1.User, f
|
||||
}
|
||||
|
||||
func (m *Manager) listCreatedShares(ctx context.Context, user *userv1beta1.User, filters []*collaboration.Filter) ([]*collaboration.Share, error) {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "listCreatedShares")
|
||||
defer span.End()
|
||||
|
||||
var ss []*collaboration.Share
|
||||
|
||||
if err := m.CreatedCache.Sync(ctx, user.Id.OpaqueId); err != nil {
|
||||
@@ -696,6 +723,9 @@ func (m *Manager) listCreatedShares(ctx context.Context, user *userv1beta1.User,
|
||||
|
||||
// ListReceivedShares returns the list of shares the user has access to.
|
||||
func (m *Manager) ListReceivedShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.ReceivedShare, error) {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "ListReceivedShares")
|
||||
defer span.End()
|
||||
|
||||
if err := m.initialize(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -703,7 +733,6 @@ func (m *Manager) ListReceivedShares(ctx context.Context, filters []*collaborati
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
var rss []*collaboration.ReceivedShare
|
||||
user := ctxpkg.ContextMustGetUser(ctx)
|
||||
|
||||
ssids := map[string]*receivedsharecache.Space{}
|
||||
@@ -750,46 +779,98 @@ func (m *Manager) ListReceivedShares(ctx context.Context, filters []*collaborati
|
||||
}
|
||||
}
|
||||
|
||||
for ssid, rspace := range ssids {
|
||||
storageID, spaceID, _ := shareid.Decode(ssid)
|
||||
err := m.Cache.Sync(ctx, storageID, spaceID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for shareID, state := range rspace.States {
|
||||
s := m.Cache.Get(storageID, spaceID, shareID)
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
if share.IsExpired(s) {
|
||||
if err := m.removeShare(ctx, s); err != nil {
|
||||
log.Error().Err(err).
|
||||
Msg("failed to unshare expired share")
|
||||
}
|
||||
if err := events.Publish(m.eventStream, events.ShareExpired{
|
||||
ShareOwner: s.GetOwner(),
|
||||
ItemID: s.GetResourceId(),
|
||||
ExpiredAt: time.Unix(int64(s.GetExpiration().GetSeconds()), int64(s.GetExpiration().GetNanos())),
|
||||
GranteeUserID: s.GetGrantee().GetUserId(),
|
||||
GranteeGroupID: s.GetGrantee().GetGroupId(),
|
||||
}); err != nil {
|
||||
log.Error().Err(err).
|
||||
Msg("failed to publish share expired event")
|
||||
}
|
||||
continue
|
||||
}
|
||||
numWorkers := m.MaxConcurrency
|
||||
if numWorkers == 0 || len(ssids) < numWorkers {
|
||||
numWorkers = len(ssids)
|
||||
}
|
||||
|
||||
if share.IsGrantedToUser(s, user) {
|
||||
if share.MatchesFiltersWithState(s, state.State, filters) {
|
||||
rs := &collaboration.ReceivedShare{
|
||||
Share: s,
|
||||
State: state.State,
|
||||
MountPoint: state.MountPoint,
|
||||
}
|
||||
rss = append(rss, rs)
|
||||
}
|
||||
type w struct {
|
||||
ssid string
|
||||
rspace *receivedsharecache.Space
|
||||
}
|
||||
work := make(chan w)
|
||||
results := make(chan *collaboration.ReceivedShare)
|
||||
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
// Distribute work
|
||||
g.Go(func() error {
|
||||
defer close(work)
|
||||
for ssid, rspace := range ssids {
|
||||
select {
|
||||
case work <- w{ssid, rspace}:
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Spawn workers that'll concurrently work the queue
|
||||
for i := 0; i < numWorkers; i++ {
|
||||
g.Go(func() error {
|
||||
for w := range work {
|
||||
storageID, spaceID, _ := shareid.Decode(w.ssid)
|
||||
err := m.Cache.Sync(ctx, storageID, spaceID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for shareID, state := range w.rspace.States {
|
||||
s := m.Cache.Get(storageID, spaceID, shareID)
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
if share.IsExpired(s) {
|
||||
if err := m.removeShare(ctx, s); err != nil {
|
||||
log.Error().Err(err).
|
||||
Msg("failed to unshare expired share")
|
||||
}
|
||||
if err := events.Publish(m.eventStream, events.ShareExpired{
|
||||
ShareOwner: s.GetOwner(),
|
||||
ItemID: s.GetResourceId(),
|
||||
ExpiredAt: time.Unix(int64(s.GetExpiration().GetSeconds()), int64(s.GetExpiration().GetNanos())),
|
||||
GranteeUserID: s.GetGrantee().GetUserId(),
|
||||
GranteeGroupID: s.GetGrantee().GetGroupId(),
|
||||
}); err != nil {
|
||||
log.Error().Err(err).
|
||||
Msg("failed to publish share expired event")
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if share.IsGrantedToUser(s, user) {
|
||||
if share.MatchesFiltersWithState(s, state.State, filters) {
|
||||
rs := &collaboration.ReceivedShare{
|
||||
Share: s,
|
||||
State: state.State,
|
||||
MountPoint: state.MountPoint,
|
||||
}
|
||||
select {
|
||||
case results <- rs:
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Wait for things to settle down, then close results chan
|
||||
go func() {
|
||||
_ = g.Wait() // error is checked later
|
||||
close(results)
|
||||
}()
|
||||
|
||||
rss := []*collaboration.ReceivedShare{}
|
||||
for n := range results {
|
||||
rss = append(rss, n)
|
||||
}
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rss, nil
|
||||
@@ -797,6 +878,9 @@ func (m *Manager) ListReceivedShares(ctx context.Context, filters []*collaborati
|
||||
|
||||
// convert must be called in a lock-controlled block.
|
||||
func (m *Manager) convert(ctx context.Context, userID string, s *collaboration.Share) *collaboration.ReceivedShare {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "convert")
|
||||
defer span.End()
|
||||
|
||||
rs := &collaboration.ReceivedShare{
|
||||
Share: s,
|
||||
State: collaboration.ShareState_SHARE_STATE_PENDING,
|
||||
@@ -823,6 +907,9 @@ func (m *Manager) GetReceivedShare(ctx context.Context, ref *collaboration.Share
|
||||
}
|
||||
|
||||
func (m *Manager) getReceived(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.ReceivedShare, error) {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "getReceived")
|
||||
defer span.End()
|
||||
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
s, err := m.get(ctx, ref)
|
||||
@@ -854,6 +941,9 @@ func (m *Manager) getReceived(ctx context.Context, ref *collaboration.ShareRefer
|
||||
|
||||
// UpdateReceivedShare updates the received share with share state.
|
||||
func (m *Manager) UpdateReceivedShare(ctx context.Context, receivedShare *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask) (*collaboration.ReceivedShare, error) {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "UpdateReceivedShare")
|
||||
defer span.End()
|
||||
|
||||
if err := m.initialize(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -964,6 +1054,9 @@ func (m *Manager) Load(ctx context.Context, shareChan <-chan *collaboration.Shar
|
||||
}
|
||||
|
||||
func (m *Manager) removeShare(ctx context.Context, s *collaboration.Share) error {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "removeShare")
|
||||
defer span.End()
|
||||
|
||||
storageID, spaceID, _ := shareid.Decode(s.Id.OpaqueId)
|
||||
err := m.Cache.Remove(ctx, storageID, spaceID, s.Id.OpaqueId)
|
||||
if _, ok := err.(errtypes.IsPreconditionFailed); ok {
|
||||
|
||||
Generated
Vendored
+33
-6
@@ -33,8 +33,13 @@ import (
|
||||
"github.com/cs3org/reva/v2/pkg/errtypes"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/metadata"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
)
|
||||
|
||||
// name is the Tracer name used to identify this instrumentation library.
|
||||
const tracerName = "providercache"
|
||||
|
||||
// Cache holds share information structured by provider and space
|
||||
type Cache struct {
|
||||
Providers map[string]*Spaces
|
||||
@@ -106,6 +111,10 @@ func New(s metadata.Storage, ttl time.Duration) Cache {
|
||||
|
||||
// Add adds a share to the cache
|
||||
func (c *Cache) Add(ctx context.Context, storageID, spaceID, shareID string, share *collaboration.Share) error {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Add")
|
||||
defer span.End()
|
||||
span.SetAttributes(attribute.String("cs3.storageid", storageID), attribute.String("cs3.spaceid", spaceID), attribute.String("cs3.shareid", shareID))
|
||||
|
||||
switch {
|
||||
case storageID == "":
|
||||
return fmt.Errorf("missing storage id")
|
||||
@@ -122,6 +131,10 @@ func (c *Cache) Add(ctx context.Context, storageID, spaceID, shareID string, sha
|
||||
|
||||
// Remove removes a share from the cache
|
||||
func (c *Cache) Remove(ctx context.Context, storageID, spaceID, shareID string) error {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Remove")
|
||||
defer span.End()
|
||||
span.SetAttributes(attribute.String("cs3.storageid", storageID), attribute.String("cs3.spaceid", spaceID), attribute.String("cs3.shareid", shareID))
|
||||
|
||||
if c.Providers[storageID] == nil ||
|
||||
c.Providers[storageID].Spaces[spaceID] == nil {
|
||||
return nil
|
||||
@@ -150,6 +163,10 @@ func (c *Cache) ListSpace(storageID, spaceID string) *Shares {
|
||||
|
||||
// PersistWithTime persists the data of one space if it has not been modified since the given mtime
|
||||
func (c *Cache) PersistWithTime(ctx context.Context, storageID, spaceID string, mtime time.Time) error {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "PersistWithTime")
|
||||
defer span.End()
|
||||
span.SetAttributes(attribute.String("cs3.storageid", storageID), attribute.String("cs3.spaceid", spaceID))
|
||||
|
||||
if c.Providers[storageID] == nil || c.Providers[storageID].Spaces[spaceID] == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -187,15 +204,20 @@ func (c *Cache) Persist(ctx context.Context, storageID, spaceID string) error {
|
||||
|
||||
// Sync updates the in-memory data with the data from the storage if it is outdated
|
||||
func (c *Cache) Sync(ctx context.Context, storageID, spaceID string) error {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Sync")
|
||||
defer span.End()
|
||||
|
||||
span.SetAttributes(attribute.String("cs3.storageid", storageID), attribute.String("cs3.spaceid", spaceID))
|
||||
|
||||
log := appctx.GetLogger(ctx).With().Str("storageID", storageID).Str("spaceID", spaceID).Logger()
|
||||
log.Debug().Msg("Syncing provider cache...")
|
||||
|
||||
var mtime time.Time
|
||||
if c.Providers[storageID] != nil && c.Providers[storageID].Spaces[spaceID] != nil {
|
||||
mtime = c.Providers[storageID].Spaces[spaceID].Mtime
|
||||
|
||||
if time.Now().Before(c.Providers[storageID].Spaces[spaceID].nextSync) {
|
||||
log.Debug().Msg("Skipping provider cache sync, it was just recently synced...")
|
||||
span.AddEvent("skip sync")
|
||||
span.SetStatus(codes.Ok, "")
|
||||
return nil
|
||||
}
|
||||
c.Providers[storageID].Spaces[spaceID].nextSync = time.Now().Add(c.ttl)
|
||||
@@ -207,28 +229,33 @@ func (c *Cache) Sync(ctx context.Context, storageID, spaceID string) error {
|
||||
info, err := c.storage.Stat(ctx, jsonPath)
|
||||
if err != nil {
|
||||
if _, ok := err.(errtypes.NotFound); ok {
|
||||
log.Debug().Msg("no json file, nothing to sync")
|
||||
span.AddEvent("no file")
|
||||
span.SetStatus(codes.Ok, "")
|
||||
return nil // Nothing to sync against
|
||||
}
|
||||
if _, ok := err.(*os.PathError); ok {
|
||||
log.Debug().Msg("no storage dir, nothing to sync")
|
||||
span.AddEvent("no dir")
|
||||
span.SetStatus(codes.Ok, "")
|
||||
return nil // Nothing to sync against
|
||||
}
|
||||
span.SetStatus(codes.Error, fmt.Sprintf("Failed to stat the provider cache: %s", err.Error()))
|
||||
log.Error().Err(err).Msg("Failed to stat the provider cache")
|
||||
return err
|
||||
}
|
||||
// check mtime of /users/{userid}/created.json
|
||||
if utils.TSToTime(info.Mtime).After(mtime) {
|
||||
log.Debug().Msg("Updating provider cache...")
|
||||
span.AddEvent("updating cache")
|
||||
// - update cached list of created shares for the user in memory if changed
|
||||
createdBlob, err := c.storage.SimpleDownload(ctx, jsonPath)
|
||||
if err != nil {
|
||||
span.SetStatus(codes.Error, fmt.Sprintf("Failed to download the provider cache: %s", err.Error()))
|
||||
log.Error().Err(err).Msg("Failed to download the provider cache")
|
||||
return err
|
||||
}
|
||||
newShares := &Shares{}
|
||||
err = json.Unmarshal(createdBlob, newShares)
|
||||
if err != nil {
|
||||
span.SetStatus(codes.Error, fmt.Sprintf("Failed to unmarshal the provider cache: %s", err.Error()))
|
||||
log.Error().Err(err).Msg("Failed to unmarshal the provider cache")
|
||||
return err
|
||||
}
|
||||
@@ -236,7 +263,7 @@ func (c *Cache) Sync(ctx context.Context, storageID, spaceID string) error {
|
||||
c.initializeIfNeeded(storageID, spaceID)
|
||||
c.Providers[storageID].Spaces[spaceID] = newShares
|
||||
}
|
||||
log.Debug().Msg("Provider cache is up to date")
|
||||
span.SetStatus(codes.Ok, "")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Generated
Vendored
+28
-5
@@ -21,6 +21,7 @@ package receivedsharecache
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"time"
|
||||
@@ -31,8 +32,13 @@ import (
|
||||
"github.com/cs3org/reva/v2/pkg/errtypes"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/metadata"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
)
|
||||
|
||||
// name is the Tracer name used to identify this instrumentation library.
|
||||
const tracerName = "receivedsharecache"
|
||||
|
||||
// Cache stores the list of received shares and their states
|
||||
// It functions as an in-memory cache with a persistence layer
|
||||
// The storage is sharded by user
|
||||
@@ -74,6 +80,10 @@ func New(s metadata.Storage, ttl time.Duration) Cache {
|
||||
|
||||
// Add adds a new entry to the cache
|
||||
func (c *Cache) Add(ctx context.Context, userID, spaceID string, rs *collaboration.ReceivedShare) error {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Add")
|
||||
defer span.End()
|
||||
span.SetAttributes(attribute.String("cs3.userid", userID), attribute.String("cs3.spaceid", spaceID))
|
||||
|
||||
if c.ReceivedSpaces[userID] == nil {
|
||||
c.ReceivedSpaces[userID] = &Spaces{
|
||||
Spaces: map[string]*Space{},
|
||||
@@ -106,13 +116,17 @@ func (c *Cache) Get(userID, spaceID, shareID string) *State {
|
||||
|
||||
// Sync updates the in-memory data with the data from the storage if it is outdated
|
||||
func (c *Cache) Sync(ctx context.Context, userID string) error {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Sync")
|
||||
defer span.End()
|
||||
span.SetAttributes(attribute.String("cs3.userid", userID))
|
||||
|
||||
log := appctx.GetLogger(ctx).With().Str("userID", userID).Logger()
|
||||
log.Debug().Msg("Syncing received share cache...")
|
||||
|
||||
var mtime time.Time
|
||||
if c.ReceivedSpaces[userID] != nil {
|
||||
if time.Now().Before(c.ReceivedSpaces[userID].nextSync) {
|
||||
log.Debug().Msg("Skipping received share cache sync, it was just recently synced...")
|
||||
span.AddEvent("skip sync")
|
||||
span.SetStatus(codes.Ok, "")
|
||||
return nil
|
||||
}
|
||||
c.ReceivedSpaces[userID].nextSync = time.Now().Add(c.ttl)
|
||||
@@ -123,38 +137,47 @@ func (c *Cache) Sync(ctx context.Context, userID string) error {
|
||||
}
|
||||
|
||||
jsonPath := userJSONPath(userID)
|
||||
info, err := c.storage.Stat(ctx, jsonPath)
|
||||
info, err := c.storage.Stat(ctx, jsonPath) // TODO we only need the mtime ... use fieldmask to make the request cheaper
|
||||
if err != nil {
|
||||
if _, ok := err.(errtypes.NotFound); ok {
|
||||
span.AddEvent("no file")
|
||||
span.SetStatus(codes.Ok, "")
|
||||
return nil // Nothing to sync against
|
||||
}
|
||||
span.SetStatus(codes.Error, fmt.Sprintf("Failed to stat the received share: %s", err.Error()))
|
||||
log.Error().Err(err).Msg("Failed to stat the received share")
|
||||
return err
|
||||
}
|
||||
// check mtime of /users/{userid}/created.json
|
||||
if utils.TSToTime(info.Mtime).After(mtime) {
|
||||
log.Debug().Msg("Updating received share cache...")
|
||||
span.AddEvent("updating cache")
|
||||
// - update cached list of created shares for the user in memory if changed
|
||||
createdBlob, err := c.storage.SimpleDownload(ctx, jsonPath)
|
||||
if err != nil {
|
||||
span.SetStatus(codes.Error, fmt.Sprintf("Failed to download the received share: %s", err.Error()))
|
||||
log.Error().Err(err).Msg("Failed to download the received share")
|
||||
return err
|
||||
}
|
||||
newSpaces := &Spaces{}
|
||||
err = json.Unmarshal(createdBlob, newSpaces)
|
||||
if err != nil {
|
||||
span.SetStatus(codes.Error, fmt.Sprintf("Failed to unmarshal the received share: %s", err.Error()))
|
||||
log.Error().Err(err).Msg("Failed to unmarshal the received share")
|
||||
return err
|
||||
}
|
||||
newSpaces.Mtime = utils.TSToTime(info.Mtime)
|
||||
c.ReceivedSpaces[userID] = newSpaces
|
||||
}
|
||||
log.Debug().Msg("Received share cache is up to date")
|
||||
span.SetStatus(codes.Ok, "")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Persist persists the data for one user to the storage
|
||||
func (c *Cache) Persist(ctx context.Context, userID string) error {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Persist")
|
||||
defer span.End()
|
||||
span.SetAttributes(attribute.String("cs3.userid", userID))
|
||||
|
||||
if c.ReceivedSpaces[userID] == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
Generated
Vendored
+31
-4
@@ -21,6 +21,7 @@ package sharecache
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"time"
|
||||
@@ -30,8 +31,13 @@ import (
|
||||
"github.com/cs3org/reva/v2/pkg/share/manager/jsoncs3/shareid"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/metadata"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
)
|
||||
|
||||
// name is the Tracer name used to identify this instrumentation library.
|
||||
const tracerName = "sharecache"
|
||||
|
||||
// Cache caches the list of share ids for users/groups
|
||||
// It functions as an in-memory cache with a persistence layer
|
||||
// The storage is sharded by user/group
|
||||
@@ -71,6 +77,10 @@ func New(s metadata.Storage, namespace, filename string, ttl time.Duration) Cach
|
||||
|
||||
// Add adds a share to the cache
|
||||
func (c *Cache) Add(ctx context.Context, userid, shareID string) error {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Add")
|
||||
defer span.End()
|
||||
span.SetAttributes(attribute.String("cs3.userid", userid), attribute.String("cs3.shareid", shareID))
|
||||
|
||||
storageid, spaceid, _ := shareid.Decode(shareID)
|
||||
ssid := storageid + shareid.IDDelimiter + spaceid
|
||||
|
||||
@@ -94,6 +104,10 @@ func (c *Cache) Add(ctx context.Context, userid, shareID string) error {
|
||||
|
||||
// Remove removes a share for the given user
|
||||
func (c *Cache) Remove(ctx context.Context, userid, shareID string) error {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Remove")
|
||||
defer span.End()
|
||||
span.SetAttributes(attribute.String("cs3.userid", userid), attribute.String("cs3.shareid", shareID))
|
||||
|
||||
storageid, spaceid, _ := shareid.Decode(shareID)
|
||||
ssid := storageid + shareid.IDDelimiter + spaceid
|
||||
|
||||
@@ -133,14 +147,18 @@ func (c *Cache) List(userid string) map[string]SpaceShareIDs {
|
||||
|
||||
// Sync updates the in-memory data with the data from the storage if it is outdated
|
||||
func (c *Cache) Sync(ctx context.Context, userID string) error {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Sync")
|
||||
defer span.End()
|
||||
span.SetAttributes(attribute.String("cs3.userid", userID))
|
||||
|
||||
log := appctx.GetLogger(ctx).With().Str("userID", userID).Logger()
|
||||
log.Debug().Msg("Syncing share cache...")
|
||||
|
||||
var mtime time.Time
|
||||
// - do we have a cached list of created shares for the user in memory?
|
||||
if usc := c.UserShares[userID]; usc != nil {
|
||||
if time.Now().Before(c.UserShares[userID].nextSync) {
|
||||
log.Debug().Msg("Skipping share cache sync, it was just recently synced...")
|
||||
span.AddEvent("skip sync")
|
||||
span.SetStatus(codes.Ok, "")
|
||||
return nil
|
||||
}
|
||||
c.UserShares[userID].nextSync = time.Now().Add(c.ttl)
|
||||
@@ -155,35 +173,44 @@ func (c *Cache) Sync(ctx context.Context, userID string) error {
|
||||
info, err := c.storage.Stat(ctx, userCreatedPath)
|
||||
if err != nil {
|
||||
if _, ok := err.(errtypes.NotFound); ok {
|
||||
span.AddEvent("no file")
|
||||
span.SetStatus(codes.Ok, "")
|
||||
return nil // Nothing to sync against
|
||||
}
|
||||
span.SetStatus(codes.Error, fmt.Sprintf("Failed to stat the share cache: %s", err.Error()))
|
||||
log.Error().Err(err).Msg("Failed to stat the share cache")
|
||||
return err
|
||||
}
|
||||
// check mtime of /users/{userid}/created.json
|
||||
if utils.TSToTime(info.Mtime).After(mtime) {
|
||||
log.Debug().Msg("Updating share cache...")
|
||||
span.AddEvent("updating cache")
|
||||
// - update cached list of created shares for the user in memory if changed
|
||||
createdBlob, err := c.storage.SimpleDownload(ctx, userCreatedPath)
|
||||
if err != nil {
|
||||
span.SetStatus(codes.Error, fmt.Sprintf("Failed to download the share cache: %s", err.Error()))
|
||||
log.Error().Err(err).Msg("Failed to download the share cache")
|
||||
return err
|
||||
}
|
||||
newShareCache := &UserShareCache{}
|
||||
err = json.Unmarshal(createdBlob, newShareCache)
|
||||
if err != nil {
|
||||
span.SetStatus(codes.Error, fmt.Sprintf("Failed to unmarshal the share cache: %s", err.Error()))
|
||||
log.Error().Err(err).Msg("Failed to unmarshal the share cache")
|
||||
return err
|
||||
}
|
||||
newShareCache.Mtime = utils.TSToTime(info.Mtime)
|
||||
c.UserShares[userID] = newShareCache
|
||||
}
|
||||
log.Debug().Msg("Share cache is up to date")
|
||||
span.SetStatus(codes.Ok, "")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Persist persists the data for one user/group to the storage
|
||||
func (c *Cache) Persist(ctx context.Context, userid string) error {
|
||||
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Persist")
|
||||
defer span.End()
|
||||
span.SetAttributes(attribute.String("cs3.userid", userid))
|
||||
|
||||
oldMtime := c.UserShares[userid].Mtime
|
||||
c.UserShares[userid].Mtime = time.Now()
|
||||
|
||||
|
||||
+1
-1
@@ -39,5 +39,5 @@ func NewFileMetadataCache(store string, nodes []string, database, table string,
|
||||
|
||||
// RemoveMetadata removes a reference from the metadata cache
|
||||
func (c *fileMetadataCache) RemoveMetadata(path string) error {
|
||||
return c.s.Delete(path)
|
||||
return c.Delete(path)
|
||||
}
|
||||
|
||||
+3
-2
@@ -127,12 +127,13 @@ func NewDefault(m map[string]interface{}, bs tree.Blobstore, es events.Stream) (
|
||||
microstore.Database(o.IDCache.Database),
|
||||
microstore.Table(o.IDCache.Table),
|
||||
))
|
||||
permissionsClient, err := pool.GetPermissionsClient(o.PermissionsSVC, pool.WithTLSMode(o.PermTLSMode))
|
||||
|
||||
permissionsSelector, err := pool.PermissionsSelector(o.PermissionsSVC, pool.WithTLSMode(o.PermTLSMode))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
permissions := NewPermissions(node.NewPermissions(lu), permissionsClient)
|
||||
permissions := NewPermissions(node.NewPermissions(lu), permissionsSelector)
|
||||
|
||||
return New(o, lu, permissions, tp, es)
|
||||
}
|
||||
|
||||
-1
@@ -1039,7 +1039,6 @@ func (n *Node) ReadUserPermissions(ctx context.Context, u *userpb.User) (ap prov
|
||||
}
|
||||
AddPermissions(&ap, g.GetPermissions())
|
||||
case metadata.IsAttrUnset(err):
|
||||
err = nil
|
||||
appctx.GetLogger(ctx).Error().Interface("node", n).Str("grant", grantees[i]).Interface("grantees", grantees).Msg("grant vanished from node after listing")
|
||||
// continue with next segment
|
||||
default:
|
||||
|
||||
Generated
Vendored
+11
-5
@@ -8,6 +8,7 @@ import (
|
||||
v1beta11 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"google.golang.org/grpc"
|
||||
@@ -25,13 +26,13 @@ type CS3PermissionsClient interface {
|
||||
|
||||
// Permissions manages permissions
|
||||
type Permissions struct {
|
||||
item PermissionsChecker // handles item permissions
|
||||
space CS3PermissionsClient // handlers space permissions
|
||||
item PermissionsChecker // handles item permissions
|
||||
permissionsSelector pool.Selectable[cs3permissions.PermissionsAPIClient] // handlers space permissions
|
||||
}
|
||||
|
||||
// NewPermissions returns a new Permissions instance
|
||||
func NewPermissions(item PermissionsChecker, space CS3PermissionsClient) Permissions {
|
||||
return Permissions{item: item, space: space}
|
||||
func NewPermissions(item PermissionsChecker, permissionsSelector pool.Selectable[cs3permissions.PermissionsAPIClient]) Permissions {
|
||||
return Permissions{item: item, permissionsSelector: permissionsSelector}
|
||||
}
|
||||
|
||||
// AssemblePermissions is used to assemble file permissions
|
||||
@@ -96,8 +97,13 @@ func (p Permissions) DeleteAllHomeSpaces(ctx context.Context) bool {
|
||||
|
||||
// checkPermission is used to check a users space permissions
|
||||
func (p Permissions) checkPermission(ctx context.Context, perm string, ref *provider.Reference) bool {
|
||||
permissionsClient, err := p.permissionsSelector.Next()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
user := ctxpkg.ContextMustGetUser(ctx)
|
||||
checkRes, err := p.space.CheckPermission(ctx, &cs3permissions.CheckPermissionRequest{
|
||||
checkRes, err := permissionsClient.CheckPermission(ctx, &cs3permissions.CheckPermissionRequest{
|
||||
Permission: perm,
|
||||
SubjectRef: &cs3permissions.SubjectReference{
|
||||
Spec: &cs3permissions.SubjectReference_UserId{
|
||||
|
||||
+11
-6
@@ -29,6 +29,7 @@ import (
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/cs3org/reva/v2/internal/http/services/datagateway"
|
||||
"github.com/cs3org/reva/v2/pkg/errtypes"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/cs3org/reva/v2/pkg/rhttp"
|
||||
)
|
||||
|
||||
@@ -39,15 +40,15 @@ type Downloader interface {
|
||||
}
|
||||
|
||||
type revaDownloader struct {
|
||||
gtw gateway.GatewayAPIClient
|
||||
httpClient *http.Client
|
||||
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
// NewDownloader creates a Downloader from the reva gateway
|
||||
func NewDownloader(gtw gateway.GatewayAPIClient, options ...rhttp.Option) Downloader {
|
||||
func NewDownloader(gatewaySelector pool.Selectable[gateway.GatewayAPIClient], options ...rhttp.Option) Downloader {
|
||||
return &revaDownloader{
|
||||
gtw: gtw,
|
||||
httpClient: rhttp.GetHTTPClient(options...),
|
||||
gatewaySelector: gatewaySelector,
|
||||
httpClient: rhttp.GetHTTPClient(options...),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +63,11 @@ func getDownloadProtocol(protocols []*gateway.FileDownloadProtocol, prot string)
|
||||
|
||||
// Download downloads a resource given the path to the dst Writer
|
||||
func (r *revaDownloader) Download(ctx context.Context, id *provider.ResourceId, dst io.Writer) error {
|
||||
downResp, err := r.gtw.InitiateFileDownload(ctx, &provider.InitiateFileDownloadRequest{
|
||||
gatewayClient, err := r.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
downResp, err := gatewayClient.InitiateFileDownload(ctx, &provider.InitiateFileDownloadRequest{
|
||||
Ref: &provider.Reference{
|
||||
ResourceId: id,
|
||||
Path: ".",
|
||||
|
||||
+47
-1
@@ -37,9 +37,17 @@ import (
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
var tracer trace.Tracer
|
||||
|
||||
func init() {
|
||||
tracer = otel.Tracer("github.com/cs3org/reva/pkg/storage/utils/metadata")
|
||||
}
|
||||
|
||||
// CS3 represents a metadata storage with a cs3 storage backend
|
||||
type CS3 struct {
|
||||
providerAddr string
|
||||
@@ -75,6 +83,9 @@ func (cs3 *CS3) Backend() string {
|
||||
|
||||
// Init creates the metadata space
|
||||
func (cs3 *CS3) Init(ctx context.Context, spaceid string) (err error) {
|
||||
ctx, span := tracer.Start(ctx, "Init")
|
||||
defer span.End()
|
||||
|
||||
client, err := cs3.providerClient()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -114,6 +125,9 @@ func (cs3 *CS3) Init(ctx context.Context, spaceid string) (err error) {
|
||||
|
||||
// SimpleUpload uploads a file to the metadata storage
|
||||
func (cs3 *CS3) SimpleUpload(ctx context.Context, uploadpath string, content []byte) error {
|
||||
ctx, span := tracer.Start(ctx, "SimpleUpload")
|
||||
defer span.End()
|
||||
|
||||
return cs3.Upload(ctx, UploadRequest{
|
||||
Path: uploadpath,
|
||||
Content: content,
|
||||
@@ -122,6 +136,9 @@ func (cs3 *CS3) SimpleUpload(ctx context.Context, uploadpath string, content []b
|
||||
|
||||
// Upload uploads a file to the metadata storage
|
||||
func (cs3 *CS3) Upload(ctx context.Context, req UploadRequest) error {
|
||||
ctx, span := tracer.Start(ctx, "Upload")
|
||||
defer span.End()
|
||||
|
||||
client, err := cs3.providerClient()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -185,6 +202,9 @@ func (cs3 *CS3) Upload(ctx context.Context, req UploadRequest) error {
|
||||
|
||||
// Stat returns the metadata for the given path
|
||||
func (cs3 *CS3) Stat(ctx context.Context, path string) (*provider.ResourceInfo, error) {
|
||||
ctx, span := tracer.Start(ctx, "Stat")
|
||||
defer span.End()
|
||||
|
||||
client, err := cs3.providerClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -214,6 +234,9 @@ func (cs3 *CS3) Stat(ctx context.Context, path string) (*provider.ResourceInfo,
|
||||
|
||||
// SimpleDownload reads a file from the metadata storage
|
||||
func (cs3 *CS3) SimpleDownload(ctx context.Context, downloadpath string) (content []byte, err error) {
|
||||
ctx, span := tracer.Start(ctx, "SimpleDownload")
|
||||
defer span.End()
|
||||
|
||||
client, err := cs3.providerClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -277,6 +300,9 @@ func (cs3 *CS3) SimpleDownload(ctx context.Context, downloadpath string) (conten
|
||||
|
||||
// Delete deletes a path
|
||||
func (cs3 *CS3) Delete(ctx context.Context, path string) error {
|
||||
ctx, span := tracer.Start(ctx, "Delete")
|
||||
defer span.End()
|
||||
|
||||
client, err := cs3.providerClient()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -304,6 +330,9 @@ func (cs3 *CS3) Delete(ctx context.Context, path string) error {
|
||||
|
||||
// ReadDir returns the entries in a given directory
|
||||
func (cs3 *CS3) ReadDir(ctx context.Context, path string) ([]string, error) {
|
||||
ctx, span := tracer.Start(ctx, "ReadDir")
|
||||
defer span.End()
|
||||
|
||||
infos, err := cs3.ListDir(ctx, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -318,6 +347,9 @@ func (cs3 *CS3) ReadDir(ctx context.Context, path string) ([]string, error) {
|
||||
|
||||
// ListDir returns a list of ResourceInfos for the entries in a given directory
|
||||
func (cs3 *CS3) ListDir(ctx context.Context, path string) ([]*provider.ResourceInfo, error) {
|
||||
ctx, span := tracer.Start(ctx, "ListDir")
|
||||
defer span.End()
|
||||
|
||||
client, err := cs3.providerClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -347,6 +379,9 @@ func (cs3 *CS3) ListDir(ctx context.Context, path string) ([]*provider.ResourceI
|
||||
|
||||
// MakeDirIfNotExist will create a root node in the metadata storage. Requires an authenticated context.
|
||||
func (cs3 *CS3) MakeDirIfNotExist(ctx context.Context, folder string) error {
|
||||
ctx, span := tracer.Start(ctx, "MakeDirIfNotExist")
|
||||
defer span.End()
|
||||
|
||||
client, err := cs3.providerClient()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -395,6 +430,9 @@ func (cs3 *CS3) MakeDirIfNotExist(ctx context.Context, folder string) error {
|
||||
|
||||
// CreateSymlink creates a symlink
|
||||
func (cs3 *CS3) CreateSymlink(ctx context.Context, oldname, newname string) error {
|
||||
ctx, span := tracer.Start(ctx, "CreateSymlink")
|
||||
defer span.End()
|
||||
|
||||
if _, err := cs3.ResolveSymlink(ctx, newname); err == nil {
|
||||
return os.ErrExist
|
||||
}
|
||||
@@ -404,6 +442,9 @@ func (cs3 *CS3) CreateSymlink(ctx context.Context, oldname, newname string) erro
|
||||
|
||||
// ResolveSymlink resolves a symlink
|
||||
func (cs3 *CS3) ResolveSymlink(ctx context.Context, name string) (string, error) {
|
||||
ctx, span := tracer.Start(ctx, "ResolveSymlink")
|
||||
defer span.End()
|
||||
|
||||
b, err := cs3.SimpleDownload(ctx, name)
|
||||
if err != nil {
|
||||
if errors.Is(err, errtypes.NotFound("")) {
|
||||
@@ -420,12 +461,17 @@ func (cs3 *CS3) providerClient() (provider.ProviderAPIClient, error) {
|
||||
}
|
||||
|
||||
func (cs3 *CS3) getAuthContext(ctx context.Context) (context.Context, error) {
|
||||
// we need to start a new context to get rid of an existing x-access-token in the outgoing context
|
||||
authCtx := context.Background()
|
||||
authCtx, span := tracer.Start(authCtx, "getAuthContext", trace.WithLinks(trace.LinkFromContext(ctx)))
|
||||
defer span.End()
|
||||
|
||||
client, err := pool.GetGatewayServiceClient(cs3.gatewayAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
authCtx := ctxpkg.ContextSetUser(context.Background(), cs3.serviceUser)
|
||||
authCtx = ctxpkg.ContextSetUser(authCtx, cs3.serviceUser)
|
||||
authRes, err := client.Authenticate(authCtx, &gateway.AuthenticateRequest{
|
||||
Type: "machine",
|
||||
ClientId: "userid:" + cs3.serviceUser.Id.OpaqueId,
|
||||
|
||||
+14
-5
@@ -27,6 +27,7 @@ import (
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/errtypes"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
)
|
||||
|
||||
// WalkFunc is the type of function called by Walk to visit each file or directory
|
||||
@@ -46,12 +47,12 @@ type Walker interface {
|
||||
}
|
||||
|
||||
type revaWalker struct {
|
||||
gtw gateway.GatewayAPIClient
|
||||
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
}
|
||||
|
||||
// NewWalker creates a Walker object that uses the reva gateway
|
||||
func NewWalker(gtw gateway.GatewayAPIClient) Walker {
|
||||
return &revaWalker{gtw: gtw}
|
||||
func NewWalker(gatewaySelector pool.Selectable[gateway.GatewayAPIClient]) Walker {
|
||||
return &revaWalker{gatewaySelector: gatewaySelector}
|
||||
}
|
||||
|
||||
// Walk walks the file tree rooted at root, calling fn for each file or folder in the tree, including the root.
|
||||
@@ -95,7 +96,11 @@ func (r *revaWalker) walkRecursively(ctx context.Context, wd string, info *provi
|
||||
}
|
||||
|
||||
func (r *revaWalker) readDir(ctx context.Context, id *provider.ResourceId) ([]*provider.ResourceInfo, error) {
|
||||
resp, err := r.gtw.ListContainer(ctx, &provider.ListContainerRequest{Ref: &provider.Reference{ResourceId: id, Path: "."}})
|
||||
gatewayClient, err := r.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := gatewayClient.ListContainer(ctx, &provider.ListContainerRequest{Ref: &provider.Reference{ResourceId: id, Path: "."}})
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
@@ -108,7 +113,11 @@ func (r *revaWalker) readDir(ctx context.Context, id *provider.ResourceId) ([]*p
|
||||
}
|
||||
|
||||
func (r *revaWalker) stat(ctx context.Context, id *provider.ResourceId) (*provider.ResourceInfo, error) {
|
||||
resp, err := r.gtw.Stat(ctx, &provider.StatRequest{Ref: &provider.Reference{ResourceId: id, Path: "."}})
|
||||
gatewayClient, err := r.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := gatewayClient.Stat(ctx, &provider.StatRequest{Ref: &provider.Reference{ResourceId: id, Path: "."}})
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
|
||||
-5
@@ -39,8 +39,6 @@ import (
|
||||
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/registry"
|
||||
"github.com/cs3org/reva/v2/pkg/registry/memory"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
)
|
||||
@@ -49,9 +47,6 @@ var (
|
||||
matchFirstCap = regexp.MustCompile("(.)([A-Z][a-z]+)")
|
||||
matchAllCap = regexp.MustCompile("([a-z0-9])([A-Z])")
|
||||
matchEmail = regexp.MustCompile(`^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$`)
|
||||
// GlobalRegistry configures a service registry globally accessible. It defaults to a memory registry. The usage of
|
||||
// globals is not encouraged, and this is a workaround until the PR is out of a draft state.
|
||||
GlobalRegistry registry.Registry = memory.New(map[string]interface{}{})
|
||||
|
||||
// ShareStorageProviderID is the provider id used by the sharestorageprovider
|
||||
ShareStorageProviderID = "a0ca6a90-a365-4782-871e-d44447bbc668"
|
||||
|
||||
Reference in New Issue
Block a user