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 := ®istrypb.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 }