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, &registrypb.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  }