forked from kataras/iris
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathswitch.go
159 lines (137 loc) · 4.12 KB
/
switch.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package apps
import (
"strings"
"github.com/kataras/iris/v12"
)
// Switch returns a new Application
// with the sole purpose of routing the
// matched Applications through the "provided cases".
//
// The cases are filtered in order of their registration.
//
// Example Code:
//
// switcher := Switch(Hosts{
// "mydomain.com": app,
// "test.mydomain.com": testSubdomainApp,
// "otherdomain.com": "appName",
// })
// switcher.Listen(":80")
//
// Note that this is NOT an alternative for a load balancer.
// The filters are executed by registration order and a matched Application
// handles the request, that's all it does.
//
// The returned Switch Iris Application can register routes that will run
// when neither of the registered Applications is responsible
// to handle the incoming request against the provided filters.
// The returned Switch Iris Application can also register custom error code handlers,
// e.g. to inject the 404 on not responsible Application was found.
// It can also be wrapped with its `WrapRouter` method,
// which is really useful for logging and statistics.
//
// Wrap with the `Join` slice to pass
// more than one provider at the same time.
func Switch(provider SwitchProvider, options ...SwitchOption) *iris.Application {
cases := provider.GetSwitchCases()
if len(cases) == 0 {
panic("iris: switch: empty cases")
}
var friendlyAddrs []string
if fp, ok := provider.(FriendlyNameProvider); ok {
if friendlyName := fp.GetFriendlyName(); friendlyName != "" {
friendlyAddrs = append(friendlyAddrs, friendlyName)
}
}
opts := DefaultSwitchOptions()
for _, opt := range options {
if opt == nil {
continue
}
opt.Apply(&opts)
}
app := iris.New()
// Try to build the cases apps on app.Build/Listen/Run so
// end-developers don't worry about it.
app.OnBuild = func() error {
for _, c := range cases {
if err := c.App.Build(); err != nil {
return err
}
}
return nil
}
// If we have a request to support
// middlewares in that switcher app then
// we can use app.Get("{p:path}"...) instead.
app.UseRouter(func(ctx iris.Context) {
for _, c := range cases {
if c.Filter(ctx) {
w := ctx.ResponseWriter()
r := ctx.Request()
for _, reqMod := range opts.RequestModifiers {
reqMod(r)
}
c.App.ServeHTTP(w, r)
// if c.App.Downgraded() {
// c.App.ServeHTTP(w, r)
// } else {
// Note(@kataras): don't ever try something like that;
// the context pool is the switcher's one.
// ctx.SetApplication(c.App)
// c.App.ServeHTTPC(ctx)
// ctx.SetApplication(app)
// }
return
}
}
// let the "switch app" handle it or fire a custom 404 error page,
// next is the switch app's router.
ctx.Next()
})
// Configure the switcher's supervisor.
app.ConfigureHost(func(su *iris.Supervisor) {
if len(friendlyAddrs) > 0 {
su.FriendlyAddr = strings.Join(friendlyAddrs, ", ")
}
})
return app
}
type (
// SwitchCase contains the filter
// and the matched Application instance.
SwitchCase struct {
Filter iris.Filter // Filter runs against the Switcher.
App *iris.Application // App is the main target application responsible to handle the request.
}
// A SwitchProvider should return the switch cases.
// It's an interface instead of a direct slice because
// we want to make available different type of structures
// without wrapping.
SwitchProvider interface {
GetSwitchCases() []SwitchCase
}
// FriendlyNameProvider can be optionally implemented by providers
// to customize the Switcher's Supervisor.FriendlyAddr field (Startup log).
FriendlyNameProvider interface {
GetFriendlyName() string
}
// Join returns a new slice which joins different type of switch cases.
Join []SwitchProvider
)
var _ SwitchProvider = SwitchCase{}
// GetSwitchCases completes the SwitchProvider, it returns itself.
func (sc SwitchCase) GetSwitchCases() []SwitchCase {
return []SwitchCase{sc}
}
var _ SwitchProvider = Join{}
// GetSwitchCases completes the switch provider.
func (j Join) GetSwitchCases() (cases []SwitchCase) {
for _, p := range j {
if p == nil {
continue
}
cases = append(cases, p.GetSwitchCases()...)
}
return
}