github.com/hellofresh/janus@v0.0.0-20230925145208-ce8de8183c67/pkg/proxy/definition.go (about) 1 package proxy 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 "time" 8 9 "github.com/asaskevich/govalidator" 10 "go.mongodb.org/mongo-driver/bson" 11 "go.mongodb.org/mongo-driver/bson/bsontype" 12 13 "github.com/hellofresh/janus/pkg/proxy/balancer" 14 "github.com/hellofresh/janus/pkg/router" 15 ) 16 17 // Definition defines proxy rules for a route 18 type Definition struct { 19 PreserveHost bool `bson:"preserve_host" json:"preserve_host" mapstructure:"preserve_host"` 20 ListenPath string `bson:"listen_path" json:"listen_path" mapstructure:"listen_path" valid:"required~proxy.listen_path is required,urlpath"` 21 Upstreams *Upstreams `bson:"upstreams" json:"upstreams" mapstructure:"upstreams"` 22 InsecureSkipVerify bool `bson:"insecure_skip_verify" json:"insecure_skip_verify" mapstructure:"insecure_skip_verify"` 23 StripPath bool `bson:"strip_path" json:"strip_path" mapstructure:"strip_path"` 24 AppendPath bool `bson:"append_path" json:"append_path" mapstructure:"append_path"` 25 Methods []string `bson:"methods" json:"methods"` 26 Hosts []string `bson:"hosts" json:"hosts"` 27 ForwardingTimeouts ForwardingTimeouts `bson:"forwarding_timeouts" json:"forwarding_timeouts" mapstructure:"forwarding_timeouts"` 28 } 29 30 // RouterDefinition represents an API that you want to proxy with internal router routines 31 type RouterDefinition struct { 32 *Definition 33 middleware []router.Constructor 34 } 35 36 // Upstreams represents a collection of targets where the requests will go to 37 type Upstreams struct { 38 Balancing string `bson:"balancing" json:"balancing"` 39 Targets Targets `bson:"targets" json:"targets"` 40 } 41 42 // Target is an ip address/hostname with a port that identifies an instance of a backend service 43 type Target struct { 44 Target string `bson:"target" json:"target" valid:"url,required"` 45 Weight int `bson:"weight" json:"weight"` 46 } 47 48 // Targets is a set of target 49 type Targets []*Target 50 51 // Duration is the time.Duration that can be unmarshalled from JSON 52 type Duration time.Duration 53 54 // MarshalJSON implements marshalling from JSON 55 func (d *Duration) MarshalJSON() ([]byte, error) { 56 s := (*time.Duration)(d).String() 57 s = strconv.Quote(s) 58 59 return []byte(s), nil 60 } 61 62 // UnmarshalJSON implements unmarshalling from JSON 63 func (d *Duration) UnmarshalJSON(data []byte) (err error) { 64 s := string(data) 65 if s == "null" { 66 return 67 } 68 69 // if Unquote returns error - assume that string is not quoted at all 70 if sUnquoted, err := strconv.Unquote(s); err == nil { 71 s = sUnquoted 72 } 73 74 t, err := time.ParseDuration(s) 75 if err != nil { 76 return 77 } 78 79 *d = Duration(t) 80 return 81 } 82 83 // GetBSON implements marshalling to BSON 84 func (d Duration) GetBSON() (interface{}, error) { 85 return time.Duration(d).String(), nil 86 } 87 88 // SetBSON implements unmarshalling from BSON 89 func (d *Duration) SetBSON(raw bson.RawValue) error { 90 // took BSON string parsing logic from BSON decoder 91 if raw.Type != bsontype.String { 92 return fmt.Errorf("expected %q type, but got %q", bsontype.String.String(), raw.Type.String()) 93 } 94 95 // l := d.readInt32() 96 b := raw.Value[0:4] 97 l := int32((uint32(b[0]) << 0) | 98 (uint32(b[1]) << 8) | 99 (uint32(b[2]) << 16) | 100 (uint32(b[3]) << 24)) 101 102 // b := d.readBytes(l - 1) 103 b = raw.Value[4 : 4+l-1] 104 105 return d.UnmarshalJSON(b) 106 } 107 108 // ForwardingTimeouts contains timeout configurations for forwarding requests to the backend servers. 109 type ForwardingTimeouts struct { 110 DialTimeout Duration `bson:"dial_timeout" json:"dial_timeout"` 111 ResponseHeaderTimeout Duration `bson:"response_header_timeout" json:"response_header_timeout"` 112 } 113 114 // NewDefinition creates a new Proxy Definition with default values 115 func NewDefinition() *Definition { 116 return &Definition{ 117 Methods: []string{"GET"}, 118 Hosts: make([]string, 0), 119 Upstreams: &Upstreams{ 120 Targets: make([]*Target, 0), 121 }, 122 } 123 } 124 125 // NewRouterDefinition creates a new Proxy RouterDefinition from Proxy Definition 126 func NewRouterDefinition(def *Definition) *RouterDefinition { 127 return &RouterDefinition{Definition: def} 128 } 129 130 // Middleware returns s.middleware (useful for tests). 131 func (d *RouterDefinition) Middleware() []router.Constructor { 132 return d.middleware 133 } 134 135 // AddMiddleware adds a middleware to a site's middleware stack. 136 func (d *RouterDefinition) AddMiddleware(m router.Constructor) { 137 d.middleware = append(d.middleware, m) 138 } 139 140 // Validate validates proxy data 141 func (d *Definition) Validate() (bool, error) { 142 return govalidator.ValidateStruct(d) 143 } 144 145 // IsBalancerDefined checks if load balancer is defined 146 func (d *Definition) IsBalancerDefined() bool { 147 return d.Upstreams != nil && d.Upstreams.Targets != nil && len(d.Upstreams.Targets) > 0 148 } 149 150 // ToBalancerTargets returns the balancer expected type 151 func (t Targets) ToBalancerTargets() []*balancer.Target { 152 var balancerTargets []*balancer.Target 153 for _, t := range t { 154 balancerTargets = append(balancerTargets, &balancer.Target{ 155 Target: t.Target, 156 Weight: t.Weight, 157 }) 158 } 159 160 return balancerTargets 161 } 162 func init() { 163 // initializes custom validators 164 govalidator.CustomTypeTagMap.Set("urlpath", func(i interface{}, o interface{}) bool { 165 s, ok := i.(string) 166 if !ok { 167 return false 168 } 169 170 return strings.Index(s, "/") == 0 171 }) 172 }