[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
+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