github.com/cs3org/reva/v2@v2.27.7/internal/grpc/services/appprovider/appprovider.go (about)

     1  // Copyright 2018-2021 CERN
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // In applying this license, CERN does not waive the privileges and immunities
    16  // granted to it by virtue of its status as an Intergovernmental Organization
    17  // or submit itself to any jurisdiction.
    18  
    19  package appprovider
    20  
    21  import (
    22  	"context"
    23  	"os"
    24  	"strconv"
    25  	"time"
    26  
    27  	providerpb "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
    28  	registrypb "github.com/cs3org/go-cs3apis/cs3/app/registry/v1beta1"
    29  	rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
    30  	types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
    31  	"github.com/cs3org/reva/v2/pkg/app"
    32  	"github.com/cs3org/reva/v2/pkg/app/provider/registry"
    33  	"github.com/cs3org/reva/v2/pkg/errtypes"
    34  	"github.com/cs3org/reva/v2/pkg/logger"
    35  	"github.com/cs3org/reva/v2/pkg/rgrpc"
    36  	"github.com/cs3org/reva/v2/pkg/rgrpc/status"
    37  	"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
    38  	"github.com/cs3org/reva/v2/pkg/sharedconf"
    39  	"github.com/cs3org/reva/v2/pkg/utils"
    40  	"github.com/juliangruber/go-intersect"
    41  	"github.com/mitchellh/mapstructure"
    42  	"github.com/rs/zerolog"
    43  	"google.golang.org/grpc"
    44  )
    45  
    46  func init() {
    47  	rgrpc.Register("appprovider", New)
    48  }
    49  
    50  type service struct {
    51  	provider   app.Provider
    52  	conf       *config
    53  	context    context.Context
    54  	cancelFunc context.CancelFunc
    55  }
    56  
    57  type config struct {
    58  	Driver         string                            `mapstructure:"driver"`
    59  	Drivers        map[string]map[string]interface{} `mapstructure:"drivers"`
    60  	AppProviderURL string                            `mapstructure:"app_provider_url"`
    61  	GatewaySvc     string                            `mapstructure:"gatewaysvc"`
    62  	MimeTypes      []string                          `mapstructure:"mime_types"`
    63  	Priority       uint64                            `mapstructure:"priority"`
    64  	RefreshTime    time.Duration                     `mapstructure:"refreshtime"`
    65  }
    66  
    67  func (c *config) init() {
    68  	if c.Driver == "" {
    69  		c.Driver = "demo"
    70  	}
    71  	if c.RefreshTime < 1 {
    72  		c.RefreshTime = time.Second * 20
    73  	}
    74  	c.AppProviderURL = sharedconf.GetGatewaySVC(c.AppProviderURL)
    75  	c.GatewaySvc = sharedconf.GetGatewaySVC(c.GatewaySvc)
    76  }
    77  
    78  func parseConfig(m map[string]interface{}) (*config, error) {
    79  	c := &config{}
    80  	if err := mapstructure.Decode(m, c); err != nil {
    81  		return nil, err
    82  	}
    83  	c.init()
    84  	return c, nil
    85  }
    86  
    87  // New creates a new AppProviderService
    88  func New(m map[string]interface{}, ss *grpc.Server, _ *zerolog.Logger) (rgrpc.Service, error) {
    89  	c, err := parseConfig(m)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	provider, err := getProvider(c)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  
    99  	ctx, cancelFunc := context.WithCancel(context.Background())
   100  
   101  	service := &service{
   102  		conf:       c,
   103  		provider:   provider,
   104  		context:    ctx,
   105  		cancelFunc: cancelFunc,
   106  	}
   107  
   108  	t := time.NewTicker(c.RefreshTime)
   109  
   110  	go func() {
   111  		for {
   112  			select {
   113  			case <-t.C:
   114  				service.registerProvider()
   115  			case <-service.context.Done():
   116  				t.Stop()
   117  			}
   118  		}
   119  	}()
   120  	return service, nil
   121  }
   122  
   123  func (s *service) registerProvider() {
   124  	// Give the appregistry service time to come up
   125  	time.Sleep(2 * time.Second)
   126  
   127  	ctx := context.Background()
   128  	log := logger.New().With().Int("pid", os.Getpid()).Logger()
   129  	pInfo, err := s.provider.GetAppProviderInfo(ctx)
   130  	if err != nil {
   131  		log.Error().Err(err).Msg("error registering app provider: could not get provider info")
   132  		return
   133  	}
   134  	pInfo.Address = s.conf.AppProviderURL
   135  
   136  	if len(s.conf.MimeTypes) != 0 {
   137  		mimeTypesIf := intersect.Simple(pInfo.MimeTypes, s.conf.MimeTypes)
   138  		var mimeTypes []string
   139  		for _, m := range mimeTypesIf {
   140  			mimeTypes = append(mimeTypes, m.(string))
   141  		}
   142  		pInfo.MimeTypes = mimeTypes
   143  	}
   144  
   145  	client, err := pool.GetGatewayServiceClient(s.conf.GatewaySvc)
   146  	if err != nil {
   147  		log.Error().Err(err).Msg("error registering app provider: could not get gateway client")
   148  		return
   149  	}
   150  	req := &registrypb.AddAppProviderRequest{Provider: pInfo}
   151  
   152  	if s.conf.Priority != 0 {
   153  		req.Opaque = &types.Opaque{
   154  			Map: map[string]*types.OpaqueEntry{
   155  				"priority": {
   156  					Decoder: "plain",
   157  					Value:   []byte(strconv.FormatUint(s.conf.Priority, 10)),
   158  				},
   159  			},
   160  		}
   161  	}
   162  
   163  	res, err := client.AddAppProvider(ctx, req)
   164  	if err != nil {
   165  		log.Error().Err(err).Msg("error registering app provider: error calling add app provider")
   166  		return
   167  	}
   168  	if res.Status.Code != rpc.Code_CODE_OK {
   169  		err = status.NewErrorFromCode(res.Status.Code, "appprovider")
   170  		log.Error().Err(err).Msg("error registering app provider: add app provider returned error")
   171  		return
   172  	}
   173  }
   174  
   175  func (s *service) Close() error {
   176  	return nil
   177  }
   178  
   179  func (s *service) UnprotectedEndpoints() []string {
   180  	return []string{}
   181  }
   182  
   183  func (s *service) Register(ss *grpc.Server) {
   184  	providerpb.RegisterProviderAPIServer(ss, s)
   185  }
   186  
   187  func getProvider(c *config) (app.Provider, error) {
   188  	if f, ok := registry.NewFuncs[c.Driver]; ok {
   189  		return f(c.Drivers[c.Driver])
   190  	}
   191  	return nil, errtypes.NotFound("driver not found: " + c.Driver)
   192  }
   193  
   194  func (s *service) OpenInApp(ctx context.Context, req *providerpb.OpenInAppRequest) (*providerpb.OpenInAppResponse, error) {
   195  	appURL, err := s.provider.GetAppURL(ctx, req.ResourceInfo, req.ViewMode, req.AccessToken, utils.ReadPlainFromOpaque(req.Opaque, "lang"))
   196  	if err != nil {
   197  		res := &providerpb.OpenInAppResponse{
   198  			Status: status.NewInternal(ctx, err.Error()),
   199  		}
   200  		return res, nil
   201  	}
   202  	res := &providerpb.OpenInAppResponse{
   203  		Status: status.NewOK(ctx),
   204  		AppUrl: appURL,
   205  	}
   206  	return res, nil
   207  
   208  }