mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
MustUse and MustUseFunc - registers middleware for all parties and subdomains - Subdomains don't care about registering order now
1st: MustUse and MustUseFunc - registers middleware for all parties and subdomains 2nd: Subdomains don't care about registering order now 3rd: iris control plugin realtime logger
This commit is contained in:
parent
dde7ce31d5
commit
f21faa7cfd
85
http.go
85
http.go
|
@ -1004,18 +1004,32 @@ type (
|
|||
// if no name given then it's the subdomain+path
|
||||
name string
|
||||
subdomain string
|
||||
method string
|
||||
method []byte
|
||||
methodStr string
|
||||
path string
|
||||
middleware Middleware
|
||||
formattedPath string
|
||||
formattedParts int
|
||||
}
|
||||
|
||||
bySubdomain []*route
|
||||
)
|
||||
|
||||
// Sorting happens when the mux's request handler initialized
|
||||
func (s bySubdomain) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
func (s bySubdomain) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
func (s bySubdomain) Less(i, j int) bool {
|
||||
return len(s[i].Subdomain()) > len(s[j].Subdomain())
|
||||
}
|
||||
|
||||
var _ Route = &route{}
|
||||
|
||||
func newRoute(method []byte, subdomain string, path string, middleware Middleware) *route {
|
||||
r := &route{name: path + subdomain, method: string(method), subdomain: subdomain, path: path, middleware: middleware}
|
||||
r := &route{name: path + subdomain, method: method, subdomain: subdomain, path: path, middleware: middleware}
|
||||
r.formatPath()
|
||||
return r
|
||||
}
|
||||
|
@ -1063,7 +1077,10 @@ func (r route) Subdomain() string {
|
|||
}
|
||||
|
||||
func (r route) Method() string {
|
||||
return r.method
|
||||
if r.methodStr == "" {
|
||||
r.methodStr = string(r.method)
|
||||
}
|
||||
return r.methodStr
|
||||
}
|
||||
|
||||
func (r route) Path() string {
|
||||
|
@ -1188,31 +1205,6 @@ func (mux *serveMux) register(method []byte, subdomain string, path string, midd
|
|||
if subdomain != "" {
|
||||
mux.hosts = true
|
||||
}
|
||||
// add to the registry tree
|
||||
tree := mux.getTree(method, subdomain)
|
||||
if tree == nil {
|
||||
//first time we register a route to this method with this domain
|
||||
tree = &muxTree{method: method, subdomain: subdomain, entry: &muxEntry{}, next: nil}
|
||||
if mux.tree == nil {
|
||||
// it's the first entry
|
||||
mux.tree = tree
|
||||
} else {
|
||||
// find the last tree and make the .next to the tree we created before
|
||||
lastTree := mux.tree
|
||||
for lastTree != nil {
|
||||
if lastTree.next == nil {
|
||||
lastTree.next = tree
|
||||
break
|
||||
}
|
||||
lastTree = lastTree.next
|
||||
}
|
||||
}
|
||||
}
|
||||
// I decide that it's better to explicit give subdomain and a path to it than registedPath(mysubdomain./something) now its: subdomain: mysubdomain., path: /something
|
||||
// we have different tree for each of subdomains, now you can use everyting you can use with the normal paths ( before you couldn't set /any/*path)
|
||||
if err := tree.entry.add(path, middleware); err != nil {
|
||||
mux.logger.Panic(err.Error())
|
||||
}
|
||||
|
||||
// add to the lookups, it's just a collection of routes information
|
||||
lookup := newRoute(method, subdomain, path, middleware)
|
||||
|
@ -1222,6 +1214,39 @@ func (mux *serveMux) register(method []byte, subdomain string, path string, midd
|
|||
|
||||
}
|
||||
|
||||
// build collects all routes info and adds them to the registry in order to be served from the request handler
|
||||
// this happens once when server is setting the mux's handler.
|
||||
func (mux *serveMux) build() {
|
||||
routes := bySubdomain(mux.lookups)
|
||||
for _, r := range routes {
|
||||
// add to the registry tree
|
||||
tree := mux.getTree(r.method, r.subdomain)
|
||||
if tree == nil {
|
||||
//first time we register a route to this method with this domain
|
||||
tree = &muxTree{method: r.method, subdomain: r.subdomain, entry: &muxEntry{}, next: nil}
|
||||
if mux.tree == nil {
|
||||
// it's the first entry
|
||||
mux.tree = tree
|
||||
} else {
|
||||
// find the last tree and make the .next to the tree we created before
|
||||
lastTree := mux.tree
|
||||
for lastTree != nil {
|
||||
if lastTree.next == nil {
|
||||
lastTree.next = tree
|
||||
break
|
||||
}
|
||||
lastTree = lastTree.next
|
||||
}
|
||||
}
|
||||
}
|
||||
// I decide that it's better to explicit give subdomain and a path to it than registedPath(mysubdomain./something) now its: subdomain: mysubdomain., path: /something
|
||||
// we have different tree for each of subdomains, now you can use everyting you can use with the normal paths ( before you couldn't set /any/*path)
|
||||
if err := tree.entry.add(r.path, r.middleware); err != nil {
|
||||
mux.logger.Panic(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (mux *serveMux) lookup(routeName string) *route {
|
||||
for i := range mux.lookups {
|
||||
if r := mux.lookups[i]; r.name == routeName {
|
||||
|
@ -1232,6 +1257,10 @@ func (mux *serveMux) lookup(routeName string) *route {
|
|||
}
|
||||
|
||||
func (mux *serveMux) ServeRequest() fasthttp.RequestHandler {
|
||||
|
||||
// initialize the router once
|
||||
mux.build()
|
||||
|
||||
// optimize this once once, we could do that: context.RequestPath(mux.escapePath), but we lose some nanoseconds on if :)
|
||||
getRequestPath := func(reqCtx *fasthttp.RequestCtx) string {
|
||||
return utils.BytesToString(reqCtx.Path())
|
||||
|
|
|
@ -125,7 +125,7 @@ func (s *Framework) initialize() {
|
|||
// listen to websocket connections
|
||||
websocket.RegisterServer(s, s.Websocket, s.Logger)
|
||||
|
||||
// prepare the mux
|
||||
// prepare the mux & the server
|
||||
s.mux.setCorrectPath(!s.Config.DisablePathCorrection)
|
||||
s.mux.setEscapePath(!s.Config.DisablePathEscape)
|
||||
s.mux.setHostname(s.HTTPServer.VirtualHostname())
|
||||
|
@ -134,9 +134,6 @@ func (s *Framework) initialize() {
|
|||
s.Handle(MethodGet, debugPath+"/*action", profileMiddleware(debugPath)...)
|
||||
}
|
||||
|
||||
// prepare the server
|
||||
s.HTTPServer.SetHandler(s.mux)
|
||||
|
||||
if s.Config.MaxRequestBodySize > 0 {
|
||||
s.HTTPServer.MaxRequestBodySize = int(s.Config.MaxRequestBodySize)
|
||||
}
|
||||
|
@ -171,6 +168,8 @@ func (s *Framework) prepareTemplates() {
|
|||
func (s *Framework) openServer() (err error) {
|
||||
s.initialize()
|
||||
s.Plugins.DoPreListen(s)
|
||||
// set the server's handler now, in order to give the chance to the plugins to add their own middlewares and routes to this station
|
||||
s.HTTPServer.SetHandler(s.mux)
|
||||
if err = s.HTTPServer.Open(); err == nil {
|
||||
// print the banner
|
||||
if !s.Config.DisableBanner {
|
||||
|
@ -191,3 +190,12 @@ func (s *Framework) closeServer() error {
|
|||
s.Plugins.DoPreClose(s)
|
||||
return s.HTTPServer.close()
|
||||
}
|
||||
|
||||
// justServe initializes the whole framework but server doesn't listens to a specific net.Listener
|
||||
func (s *Framework) justServe() *Server {
|
||||
s.initialize()
|
||||
s.Plugins.DoPreListen(s)
|
||||
s.HTTPServer.SetHandler(s.mux)
|
||||
s.Plugins.DoPostListen(s)
|
||||
return s.HTTPServer
|
||||
}
|
||||
|
|
55
iris.go
55
iris.go
|
@ -92,6 +92,9 @@ type (
|
|||
ListenUNIX(string, os.FileMode)
|
||||
NoListen() *Server
|
||||
Close()
|
||||
// global middleware prepending, registers to all subdomains, to all parties, you can call it at the last also
|
||||
MustUse(...Handler)
|
||||
MustUseFunc(...HandlerFunc)
|
||||
OnError(int, HandlerFunc)
|
||||
EmitError(int, *Context)
|
||||
Lookup(string) Route
|
||||
|
@ -107,10 +110,10 @@ type (
|
|||
// MuxAPI the visible api for the serveMux
|
||||
MuxAPI interface {
|
||||
Party(string, ...HandlerFunc) MuxAPI
|
||||
|
||||
// middleware
|
||||
// middleware serial, appending
|
||||
Use(...Handler)
|
||||
UseFunc(...HandlerFunc)
|
||||
|
||||
// main handlers
|
||||
Handle(string, string, ...Handler) RouteNameFunc
|
||||
HandleFunc(string, string, ...HandlerFunc) RouteNameFunc
|
||||
|
@ -292,11 +295,9 @@ func NoListen() *Server {
|
|||
}
|
||||
|
||||
// NoListen is useful only when you want to test Iris, it doesn't starts the server but it configures and returns it
|
||||
// initializes the whole framework but server doesn't listens to a specific net.Listener
|
||||
func (s *Framework) NoListen() *Server {
|
||||
s.initialize()
|
||||
s.Plugins.DoPreListen(s)
|
||||
s.Plugins.DoPostListen(s)
|
||||
return s.HTTPServer
|
||||
return s.justServe()
|
||||
}
|
||||
|
||||
// CloseWithErr terminates the server and returns an error if any
|
||||
|
@ -319,6 +320,40 @@ func (s *Framework) Close() {
|
|||
s.Must(s.CloseWithErr())
|
||||
}
|
||||
|
||||
// MustUse registers Handler middleware to the beggining, prepends them instead of append
|
||||
//
|
||||
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
|
||||
// It can be called after other, (but before .Listen of course)
|
||||
func MustUse(handlers ...Handler) {
|
||||
Default.MustUse(handlers...)
|
||||
}
|
||||
|
||||
// MustUseFunc registers HandlerFunc middleware to the beggining, prepends them instead of append
|
||||
//
|
||||
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
|
||||
// It can be called after other, (but before .Listen of course)
|
||||
func MustUseFunc(handlersFn ...HandlerFunc) {
|
||||
Default.MustUseFunc(handlersFn...)
|
||||
}
|
||||
|
||||
// MustUse registers Handler middleware to the beggining, prepends them instead of append
|
||||
//
|
||||
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
|
||||
// It can be called after other, (but before .Listen of course)
|
||||
func (s *Framework) MustUse(handlers ...Handler) {
|
||||
for _, r := range s.mux.lookups {
|
||||
r.middleware = append(handlers, r.middleware...)
|
||||
}
|
||||
}
|
||||
|
||||
// MustUseFunc registers HandlerFunc middleware to the beggining, prepends them instead of append
|
||||
//
|
||||
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
|
||||
// It can be called after other, (but before .Listen of course)
|
||||
func (s *Framework) MustUseFunc(handlersFn ...HandlerFunc) {
|
||||
s.MustUse(convertToHandlers(handlersFn)...)
|
||||
}
|
||||
|
||||
// OnError registers a custom http error handler
|
||||
func OnError(statusCode int, handlerFn HandlerFunc) {
|
||||
Default.OnError(statusCode, handlerFn)
|
||||
|
@ -576,22 +611,22 @@ func (api *muxAPI) Party(relativePath string, handlersFn ...HandlerFunc) MuxAPI
|
|||
return &muxAPI{relativePath: fullpath, mux: api.mux, middleware: middleware}
|
||||
}
|
||||
|
||||
// Use registers a Handler middleware
|
||||
// Use registers Handler middleware
|
||||
func Use(handlers ...Handler) {
|
||||
Default.Use(handlers...)
|
||||
}
|
||||
|
||||
// UseFunc registers a HandlerFunc middleware
|
||||
// UseFunc registers HandlerFunc middleware
|
||||
func UseFunc(handlersFn ...HandlerFunc) {
|
||||
Default.UseFunc(handlersFn...)
|
||||
}
|
||||
|
||||
// Use registers a Handler middleware
|
||||
// Use registers Handler middleware
|
||||
func (api *muxAPI) Use(handlers ...Handler) {
|
||||
api.middleware = append(api.middleware, handlers...)
|
||||
}
|
||||
|
||||
// UseFunc registers a HandlerFunc middleware
|
||||
// UseFunc registers HandlerFunc middleware
|
||||
func (api *muxAPI) UseFunc(handlersFn ...HandlerFunc) {
|
||||
api.Use(convertToHandlers(handlersFn)...)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/config"
|
||||
"github.com/kataras/iris/middleware/basicauth"
|
||||
"github.com/kataras/iris/websocket"
|
||||
)
|
||||
|
||||
type (
|
||||
|
@ -22,19 +23,70 @@ type (
|
|||
// the station which this plugins is registed to
|
||||
parent *iris.Framework
|
||||
parentLastOp time.Time
|
||||
|
||||
// websocket
|
||||
clients clients
|
||||
}
|
||||
|
||||
clients []websocket.Connection
|
||||
|
||||
pluginInfo struct {
|
||||
Name string
|
||||
Description string
|
||||
}
|
||||
|
||||
logInfo struct {
|
||||
Date string
|
||||
Status int
|
||||
Latency time.Duration
|
||||
IP string
|
||||
Method string
|
||||
Subdomain string
|
||||
Path string
|
||||
}
|
||||
)
|
||||
|
||||
func (c clients) indexOf(connectionID string) int {
|
||||
for i := range c {
|
||||
if c[i].ID() == connectionID {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
var _ IrisControl = &iriscontrol{}
|
||||
|
||||
func (i *iriscontrol) listen(f *iris.Framework) {
|
||||
// set the path logger to the parent which will send the log via websocket to the browser
|
||||
f.MustUseFunc(func(ctx *iris.Context) {
|
||||
status := ctx.Response.StatusCode()
|
||||
path := ctx.PathString()
|
||||
method := ctx.MethodString()
|
||||
subdomain := ctx.Subdomain()
|
||||
ip := ctx.RemoteAddr()
|
||||
startTime := time.Now()
|
||||
|
||||
ctx.Next()
|
||||
//no time.Since in order to format it well after
|
||||
endTime := time.Now()
|
||||
date := endTime.Format("01/02 - 15:04:05")
|
||||
latency := endTime.Sub(startTime)
|
||||
info := logInfo{
|
||||
Date: date,
|
||||
Status: status,
|
||||
Latency: latency,
|
||||
IP: ip,
|
||||
Method: method,
|
||||
Subdomain: subdomain,
|
||||
Path: path,
|
||||
}
|
||||
i.Emit("log", info) //send this text to the browser,
|
||||
})
|
||||
|
||||
i.parent = f
|
||||
i.parentLastOp = time.Now()
|
||||
|
||||
i.initializeChild()
|
||||
}
|
||||
|
||||
|
@ -42,21 +94,45 @@ func (i *iriscontrol) initializeChild() {
|
|||
i.child = iris.New()
|
||||
i.child.Config.DisableBanner = true
|
||||
i.child.Config.Render.Template.Directory = assetsPath + "templates"
|
||||
i.child.Config.Websocket.Endpoint = "/ws"
|
||||
|
||||
// set the assets
|
||||
i.child.Static("/public", assetsPath+"static", 1)
|
||||
|
||||
// set the authentication middleware
|
||||
i.child.Use(basicauth.New(config.BasicAuth{
|
||||
// set the authentication middleware to all except websocket
|
||||
auth := basicauth.New(config.BasicAuth{
|
||||
Users: i.users,
|
||||
ContextKey: "user",
|
||||
Realm: config.DefaultBasicAuthRealm,
|
||||
Expires: time.Duration(1) * time.Hour,
|
||||
}))
|
||||
})
|
||||
|
||||
i.child.UseFunc(func(ctx *iris.Context) {
|
||||
///TODO: Remove this and make client-side basic auth when websocket connection.
|
||||
if ctx.PathString() == i.child.Config.Websocket.Endpoint {
|
||||
ctx.Next()
|
||||
return
|
||||
}
|
||||
auth.Serve(ctx)
|
||||
})
|
||||
|
||||
i.child.Websocket.OnConnection(func(c websocket.Connection) {
|
||||
// add the client to the list
|
||||
i.clients = append(i.clients, c)
|
||||
c.OnDisconnect(func() {
|
||||
// remove the client from the list
|
||||
if idx := i.clients.indexOf(c.ID()); idx != -1 {
|
||||
i.clients[idx] = i.clients[len(i.clients)-1]
|
||||
i.clients = i.clients[:len(i.clients)-1]
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
i.child.Get("/", func(ctx *iris.Context) {
|
||||
ctx.MustRender("index.html", iris.Map{
|
||||
"ServerIsRunning": i.parentIsRunning(),
|
||||
"Host": i.child.Config.Server.ListeningAddr,
|
||||
"Routes": i.parentLookups(),
|
||||
"Plugins": i.infoPlugins(),
|
||||
"LastOperationDateStr": i.infoLastOp(),
|
||||
|
@ -72,6 +148,7 @@ func (i *iriscontrol) initializeChild() {
|
|||
i.parent.Logger.Warningf(err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
i.parentLastOp = time.Now()
|
||||
}
|
||||
})
|
||||
|
@ -123,3 +200,9 @@ func (i *iriscontrol) infoPlugins() (info []pluginInfo) {
|
|||
func (i *iriscontrol) infoLastOp() string {
|
||||
return i.parentLastOp.Format(config.TimeFormat)
|
||||
}
|
||||
|
||||
func (i *iriscontrol) Emit(event string, msg interface{}) {
|
||||
for j := range i.clients {
|
||||
i.clients[j].Emit(event, msg)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user