github.com/cs3org/reva/v2@v2.27.7/pkg/app/registry/static/static.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 static 20 21 import ( 22 "container/heap" 23 "context" 24 "fmt" 25 "strconv" 26 "strings" 27 "sync" 28 29 registrypb "github.com/cs3org/go-cs3apis/cs3/app/registry/v1beta1" 30 "github.com/cs3org/reva/v2/pkg/app" 31 "github.com/cs3org/reva/v2/pkg/app/registry/registry" 32 "github.com/cs3org/reva/v2/pkg/errtypes" 33 "github.com/mitchellh/mapstructure" 34 "github.com/rs/zerolog/log" 35 orderedmap "github.com/wk8/go-ordered-map" 36 ) 37 38 func init() { 39 registry.Register("static", New) 40 } 41 42 const defaultPriority = 0 43 44 type mimeTypeConfig struct { 45 MimeType string `mapstructure:"mime_type"` 46 Extension string `mapstructure:"extension"` 47 Name string `mapstructure:"name"` 48 Description string `mapstructure:"description"` 49 Icon string `mapstructure:"icon"` 50 DefaultApp string `mapstructure:"default_app"` 51 AllowCreation bool `mapstructure:"allow_creation"` 52 apps providerHeap 53 } 54 55 type config struct { 56 Providers []*registrypb.ProviderInfo `mapstructure:"providers"` 57 MimeTypes []*mimeTypeConfig `mapstructure:"mime_types"` 58 } 59 60 func (c *config) init() { 61 if len(c.Providers) == 0 { 62 c.Providers = []*registrypb.ProviderInfo{} 63 } 64 } 65 66 func parseConfig(m map[string]interface{}) (*config, error) { 67 c := &config{} 68 if err := mapstructure.Decode(m, c); err != nil { 69 return nil, err 70 } 71 return c, nil 72 } 73 74 type manager struct { 75 providers map[string]*registrypb.ProviderInfo 76 mimetypes *orderedmap.OrderedMap // map[string]*mimeTypeConfig -> map the mime type to the addresses of the corresponding providers 77 sync.RWMutex 78 } 79 80 // New returns an implementation of the app.Registry interface. 81 func New(m map[string]interface{}) (app.Registry, error) { 82 c, err := parseConfig(m) 83 if err != nil { 84 return nil, err 85 } 86 c.init() 87 88 mimetypes := orderedmap.New() 89 90 for _, mime := range c.MimeTypes { 91 mimetypes.Set(mime.MimeType, mime) 92 } 93 94 providerMap := make(map[string]*registrypb.ProviderInfo) 95 for _, p := range c.Providers { 96 providerMap[p.Address] = p 97 } 98 99 // register providers configured manually from the config 100 // (different from the others that are registering themselves - 101 // dinamically added invoking the AddProvider function) 102 for _, p := range c.Providers { 103 if p != nil { 104 for _, m := range p.MimeTypes { 105 if v, ok := mimetypes.Get(m); ok { 106 mtc := v.(*mimeTypeConfig) 107 registerProvider(p, mtc) 108 } else { 109 return nil, errtypes.NotFound(fmt.Sprintf("mimetype %s not found in the configuration", m)) 110 } 111 } 112 } 113 } 114 115 newManager := manager{ 116 providers: providerMap, 117 mimetypes: mimetypes, 118 } 119 return &newManager, nil 120 } 121 122 // remove a provider from the provider list in a mime type 123 // it's a no-op if the provider is not in the list of providers in the mime type 124 func unregisterProvider(p *registrypb.ProviderInfo, mime *mimeTypeConfig) { 125 if index, in := getIndex(mime.apps, p); in { 126 // remove the provider from the list 127 heap.Remove(&mime.apps, index) 128 } 129 } 130 131 func registerProvider(p *registrypb.ProviderInfo, mime *mimeTypeConfig) { 132 // the app provider could be previously registered to the same mime type list 133 // so we will remove it 134 unregisterProvider(p, mime) 135 136 heap.Push(&mime.apps, providerWithPriority{ 137 provider: p, 138 priority: getPriority(p), 139 }) 140 } 141 142 func getPriority(p *registrypb.ProviderInfo) uint64 { 143 if p.Opaque != nil && len(p.Opaque.Map) != 0 { 144 if priority, ok := p.Opaque.Map["priority"]; ok { 145 if pr, err := strconv.ParseUint(string(priority.GetValue()), 10, 64); err == nil { 146 return pr 147 } 148 } 149 } 150 return defaultPriority 151 } 152 153 func (m *manager) FindProviders(ctx context.Context, mimeType string) ([]*registrypb.ProviderInfo, error) { 154 // find longest match 155 var match string 156 157 m.RLock() 158 defer m.RUnlock() 159 160 for pair := m.mimetypes.Oldest(); pair != nil; pair = pair.Next() { 161 prefix := pair.Key.(string) 162 if strings.HasPrefix(mimeType, prefix) && len(prefix) > len(match) { 163 match = prefix 164 } 165 } 166 167 if match == "" { 168 return nil, errtypes.NotFound("application provider not found for mime type " + mimeType) 169 } 170 171 mimeInterface, _ := m.mimetypes.Get(match) 172 mimeMatch := mimeInterface.(*mimeTypeConfig) 173 var providers = make([]*registrypb.ProviderInfo, 0, len(mimeMatch.apps)) 174 for _, p := range mimeMatch.apps { 175 providers = append(providers, m.providers[p.provider.Address]) 176 } 177 return providers, nil 178 } 179 180 func (m *manager) AddProvider(ctx context.Context, p *registrypb.ProviderInfo) error { 181 m.Lock() 182 defer m.Unlock() 183 184 // check if the provider was already registered 185 // if it's the case, we have to unregister it 186 // from all the old mime types 187 if oldP, ok := m.providers[p.Address]; ok { 188 oldMimeTypes := oldP.MimeTypes 189 for _, mimeName := range oldMimeTypes { 190 mimeIf, ok := m.mimetypes.Get(mimeName) 191 if !ok { 192 continue 193 } 194 mime := mimeIf.(*mimeTypeConfig) 195 unregisterProvider(p, mime) 196 } 197 } 198 199 m.providers[p.Address] = p 200 201 for _, mime := range p.MimeTypes { 202 if mimeTypeInterface, ok := m.mimetypes.Get(mime); ok { 203 mimeType := mimeTypeInterface.(*mimeTypeConfig) 204 registerProvider(p, mimeType) 205 } else { 206 // the mime type should be already registered as config in the AppRegistry 207 // we will create a new entry fot the mimetype, but leaving a warning for 208 // future log inspection for weird behaviour 209 // log.Warn().Msgf("config for mimetype '%s' not found while adding a new AppProvider", m) 210 m.mimetypes.Set(mime, dummyMimeType(mime, []*registrypb.ProviderInfo{p})) 211 } 212 } 213 return nil 214 } 215 216 func (m *manager) ListProviders(ctx context.Context) ([]*registrypb.ProviderInfo, error) { 217 m.RLock() 218 defer m.RUnlock() 219 220 providers := make([]*registrypb.ProviderInfo, 0, len(m.providers)) 221 for _, p := range m.providers { 222 providers = append(providers, p) 223 } 224 return providers, nil 225 } 226 227 func (m *manager) ListSupportedMimeTypes(ctx context.Context) ([]*registrypb.MimeTypeInfo, error) { 228 m.RLock() 229 defer m.RUnlock() 230 231 res := make([]*registrypb.MimeTypeInfo, 0, m.mimetypes.Len()) 232 233 for pair := m.mimetypes.Oldest(); pair != nil; pair = pair.Next() { 234 235 mime := pair.Value.(*mimeTypeConfig) 236 237 res = append(res, ®istrypb.MimeTypeInfo{ 238 MimeType: mime.MimeType, 239 Ext: mime.Extension, 240 Name: mime.Name, 241 Description: mime.Description, 242 Icon: mime.Icon, 243 AppProviders: mime.apps.getOrderedProviderByPriority(), 244 AllowCreation: mime.AllowCreation, 245 DefaultApplication: mime.DefaultApp, 246 }) 247 248 } 249 250 return res, nil 251 } 252 253 func (h providerHeap) getOrderedProviderByPriority() []*registrypb.ProviderInfo { 254 providers := make([]*registrypb.ProviderInfo, 0, h.Len()) 255 for _, pp := range h { 256 providers = append(providers, pp.provider) 257 } 258 return providers 259 } 260 261 func getIndex(h providerHeap, s *registrypb.ProviderInfo) (int, bool) { 262 for i, e := range h { 263 if equalsProviderInfo(e.provider, s) { 264 return i, true 265 } 266 } 267 return -1, false 268 } 269 270 func (m *manager) SetDefaultProviderForMimeType(ctx context.Context, mimeType string, p *registrypb.ProviderInfo) error { 271 m.Lock() 272 defer m.Unlock() 273 274 mimeInterface, ok := m.mimetypes.Get(mimeType) 275 if ok { 276 mime := mimeInterface.(*mimeTypeConfig) 277 mime.DefaultApp = p.Address 278 279 registerProvider(p, mime) 280 } else { 281 // the mime type should be already registered as config in the AppRegistry 282 // we will create a new entry fot the mimetype, but leaving a warning for 283 // future log inspection for weird behaviour 284 log.Warn().Msgf("config for mimetype '%s' not found while setting a new default AppProvider", mimeType) 285 m.mimetypes.Set(mimeType, dummyMimeType(mimeType, []*registrypb.ProviderInfo{p})) 286 } 287 return nil 288 } 289 290 func dummyMimeType(m string, apps []*registrypb.ProviderInfo) *mimeTypeConfig { 291 appsHeap := providerHeap{} 292 for _, p := range apps { 293 heap.Push(&appsHeap, providerWithPriority{ 294 provider: p, 295 priority: getPriority(p), 296 }) 297 } 298 299 return &mimeTypeConfig{ 300 MimeType: m, 301 apps: appsHeap, 302 //Extension: "", // there is no meaningful general extension, so omit it 303 //Name: "", // there is no meaningful general name, so omit it 304 //Description: "", // there is no meaningful general description, so omit it 305 } 306 } 307 308 func (m *manager) GetDefaultProviderForMimeType(ctx context.Context, mimeType string) (*registrypb.ProviderInfo, error) { 309 m.RLock() 310 defer m.RUnlock() 311 312 mimeInterface, ok := m.mimetypes.Get(mimeType) 313 if ok { 314 mime := mimeInterface.(*mimeTypeConfig) 315 // default by provider address 316 if p, ok := m.providers[mime.DefaultApp]; ok { 317 return p, nil 318 } 319 320 // default by provider name 321 for _, p := range m.providers { 322 if p.Name == mime.DefaultApp { 323 return p, nil 324 } 325 } 326 } 327 328 return nil, errtypes.NotFound("default application provider not set for mime type " + mimeType) 329 } 330 331 func equalsProviderInfo(p1, p2 *registrypb.ProviderInfo) bool { 332 return p1.Name == p2.Name 333 } 334 335 // check that all providers in the two lists are equals 336 func providersEquals(l1, l2 []*registrypb.ProviderInfo) bool { 337 if len(l1) != len(l2) { 338 return false 339 } 340 341 for i := 0; i < len(l1); i++ { 342 if !equalsProviderInfo(l1[i], l2[i]) { 343 return false 344 } 345 } 346 return true 347 } 348 349 type providerWithPriority struct { 350 provider *registrypb.ProviderInfo 351 priority uint64 352 } 353 354 type providerHeap []providerWithPriority 355 356 func (h providerHeap) Len() int { 357 return len(h) 358 } 359 360 func (h providerHeap) Less(i, j int) bool { 361 return h[i].priority > h[j].priority 362 } 363 364 func (h providerHeap) Swap(i, j int) { 365 h[i], h[j] = h[j], h[i] 366 } 367 368 func (h *providerHeap) Push(x interface{}) { 369 *h = append(*h, x.(providerWithPriority)) 370 } 371 372 func (h *providerHeap) Pop() interface{} { 373 last := len(*h) - 1 374 x := (*h)[last] 375 *h = (*h)[:last] 376 return x 377 }