github.com/willyham/dosa@v2.3.1-0.20171024181418-1e446d37ee71+incompatible/connectors/routing/config.go (about)

     1  // Copyright (c) 2017 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package routing
    22  
    23  import (
    24  	"fmt"
    25  	"sort"
    26  
    27  	"github.com/pkg/errors"
    28  )
    29  
    30  // DefaultScope represents the default scope
    31  const DefaultScope = "default"
    32  
    33  // Routers represents a list of routing config
    34  type Routers []*Rule
    35  
    36  func (r Routers) Len() int {
    37  	return len(r)
    38  }
    39  func (r Routers) Swap(i, j int) {
    40  	r[i], r[j] = r[j], r[i]
    41  }
    42  func (r Routers) Less(i, j int) bool {
    43  	if r[i].Scope == r[j].Scope {
    44  		return r[i].NamePrefix > r[j].NamePrefix
    45  	}
    46  
    47  	return r[i].Scope > r[j].Scope
    48  }
    49  
    50  // UnmarshalYAML unmarshals the config into gocql cluster config
    51  func (r *Routers) UnmarshalYAML(unmarshal func(interface{}) error) error {
    52  	routers := make(Routers, 0)
    53  	scopes := make([]map[string]interface{}, 0)
    54  	if err := unmarshal(&scopes); err != nil {
    55  		return err
    56  	}
    57  	defaultRouterExist := false
    58  	for _, scopeMap := range scopes {
    59  		for scope, namePrefixes := range scopeMap {
    60  			namePrefixesMap, ok := namePrefixes.(map[interface{}]interface{})
    61  			if !ok {
    62  				return fmt.Errorf("failed to parse the config: %v", namePrefixes)
    63  			}
    64  
    65  			for namePrefix, connector := range namePrefixesMap {
    66  				namePrefixStr := namePrefix.(string)
    67  				connectorName, ok := connector.(string)
    68  				if !ok {
    69  					return fmt.Errorf("failed to parse the config: %v", namePrefixesMap)
    70  				}
    71  				router, err := NewRule(scope, namePrefixStr, connectorName)
    72  				if err != nil {
    73  					return errors.Wrap(err, "failed to parse routing config")
    74  				}
    75  				routers = append(routers, router)
    76  				if scope == DefaultScope {
    77  					defaultRouterExist = true
    78  				}
    79  			}
    80  		}
    81  	}
    82  
    83  	if !defaultRouterExist {
    84  		return errors.New("there should be a default scope defined in routing config yaml file")
    85  	}
    86  
    87  	sort.Sort(routers)
    88  	*r = routers
    89  	return nil
    90  }
    91  
    92  // Config is a struct contains fields from yaml
    93  // scope should be an exact string in any case,
    94  // namePrefix could be in 3 different format:
    95  // 1. exact string like "service" that matches namePrefix that is exactly "service"
    96  // 2. partial glob match like "service.*" that matches all namePrefix that has a prefix of "service."
    97  // 3. full glob match like "*" that matches all namePrefix
    98  type Config struct {
    99  	Routers Routers `yaml:"routers"`
   100  }
   101  
   102  // FindRouter finds the router information based on scope and namePrefix.
   103  func (c *Config) FindRouter(scope, namePrefix string) (*Rule) {
   104  	for _, router := range c.Routers {
   105  		if router.RouteTo(scope, namePrefix) {
   106  			return router
   107  		}
   108  	}
   109  
   110  	return c.findDefaultRouter()
   111  }
   112  
   113  // findDefaultRouter finds the default router information.
   114  func (c *Config) findDefaultRouter() (*Rule) {
   115  	for _, router := range c.Routers {
   116  		if router.Scope == DefaultScope {
   117  			return router
   118  		}
   119  	}
   120  	return nil
   121  }