mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
One of the best requests https://github.com/kataras/iris/issues/165
This commit is contained in:
parent
7f56cdea8c
commit
9e03a529d6
|
@ -116,7 +116,7 @@ Iris suggests you to use [this](https://github.com/gavv/httpexpect) new suite t
|
|||
Versioning
|
||||
------------
|
||||
|
||||
Current: **v3.0.0-beta**
|
||||
Current: **v3.0.0-beta.1**
|
||||
> Iris is an active project
|
||||
|
||||
|
||||
|
@ -134,7 +134,7 @@ Todo
|
|||
- [x] Create server & client side (js) library for .on('event', func action(...)) / .emit('event')... (like socket.io but supports only websocket).
|
||||
- [x] Find and provide support for the most stable template engine and be able to change it via the configuration, keep html/templates support.
|
||||
- [x] Extend, test and publish to the public the [Iris' cmd](https://github.com/kataras/iris/tree/master/iris).
|
||||
|
||||
- [x] Route naming and html url func, requested [here](https://github.com/kataras/iris/issues/165).
|
||||
|
||||
If you're willing to donate click [here](DONATIONS.md)
|
||||
|
||||
|
|
|
@ -124,8 +124,13 @@ type (
|
|||
Left string
|
||||
// Right delimeter, default is }}
|
||||
Right string
|
||||
// Funcs for HTMLTemplate html/template
|
||||
// Funcs like html/template
|
||||
Funcs template.FuncMap
|
||||
// Funcs like html/template
|
||||
// the difference from Funcs is that these funcs
|
||||
// can be used inside a layout and can override the predefined (yield,partial...) or add more custom funcs
|
||||
// these can override the Funcs inside no-layout templates also, use it when you know what you're doing
|
||||
LayoutFuncs template.FuncMap
|
||||
}
|
||||
// Pongo the configs for PongoEngine
|
||||
Pongo struct {
|
||||
|
@ -202,7 +207,7 @@ func DefaultTemplate() Template {
|
|||
ContentType: "text/html",
|
||||
Charset: "UTF-8",
|
||||
Layout: "", // currently this is the only config which not working for pongo2 yet but I will find a way
|
||||
HTMLTemplate: HTMLTemplate{Left: "{{", Right: "}}", Funcs: template.FuncMap{}},
|
||||
HTMLTemplate: HTMLTemplate{Left: "{{", Right: "}}", Funcs: template.FuncMap{}, LayoutFuncs: template.FuncMap{}},
|
||||
Pongo: Pongo{Filters: make(map[string]pongo2.FilterFunction, 0), Globals: make(map[string]interface{}, 0)},
|
||||
Markdown: Markdown{Sanitize: false},
|
||||
Amber: Amber{Funcs: template.FuncMap{}},
|
||||
|
|
|
@ -12,8 +12,11 @@ var (
|
|||
ErrHandleAnnotated = errors.New("HandleAnnotated parse: %s")
|
||||
// ErrControllerContextNotFound returns an error with message: 'Context *iris.Context could not be found, the Controller won't be registed.'
|
||||
ErrControllerContextNotFound = errors.New("Context *iris.Context could not be found, the Controller won't be registed.")
|
||||
// ErrDirectoryFileNotFound returns an errir with message: 'Directory or file %s couldn't found. Trace: +error trace'
|
||||
// ErrDirectoryFileNotFound returns an error with message: 'Directory or file %s couldn't found. Trace: +error trace'
|
||||
ErrDirectoryFileNotFound = errors.New("Directory or file %s couldn't found. Trace: %s")
|
||||
// ErrRenderRouteNotFound returns an error with message 'Route with name +route_name not found', used inside 'url' template func
|
||||
ErrRenderRouteNotFound = errors.New("Route with name %s not found")
|
||||
|
||||
// Plugin
|
||||
|
||||
// ErrPluginAlreadyExists returns an error with message: 'Cannot activate the same plugin again, plugin '+plugin name[+plugin description]' is already exists'
|
||||
|
|
42
iris.go
42
iris.go
|
@ -1,4 +1,4 @@
|
|||
// Package iris v3.0.0-beta
|
||||
// Package iris v3.0.0-beta.1
|
||||
//
|
||||
// Note: When 'Station', we mean the Iris type.
|
||||
package iris
|
||||
|
@ -31,14 +31,13 @@ import (
|
|||
|
||||
const (
|
||||
// Version of the iris
|
||||
Version = "v3.0.0-beta"
|
||||
Version = "v3.0.0-beta.1"
|
||||
banner = ` _____ _
|
||||
|_ _| (_)
|
||||
| | ____ _ ___
|
||||
| | | __|| |/ __|
|
||||
_| |_| | | |\__ \
|
||||
|_____|_| |_||___/
|
||||
|
||||
|_____|_| |_||___/ ` + Version + `
|
||||
`
|
||||
)
|
||||
|
||||
|
@ -118,7 +117,39 @@ func (s *Iris) newContextPool() sync.Pool {
|
|||
func (s *Iris) initTemplates() {
|
||||
if s.templates == nil { // because if .Templates() called before server's listen, s.templates != nil when PreListen
|
||||
// init the templates
|
||||
|
||||
// set the custom iris-direct-integration functions, layout and no-layout if HTMLEngine is used
|
||||
if s.config.Render.Template.Engine == config.HTMLEngine {
|
||||
funcs := map[string]interface{}{
|
||||
"url": func(routeName string, args ...interface{}) (string, error) {
|
||||
r := s.RouteByName(routeName)
|
||||
// check if not found
|
||||
if r.GetPath() == "" {
|
||||
return "", ErrRenderRouteNotFound.Format(routeName)
|
||||
}
|
||||
|
||||
if result, ok := r.parse(args...); ok {
|
||||
return result, nil
|
||||
}
|
||||
return "", nil
|
||||
},
|
||||
}
|
||||
for k, v := range funcs {
|
||||
// we don't want to override the user's LayoutFuncs, user should be able to override anything.
|
||||
if s.config.Render.Template.HTMLTemplate.LayoutFuncs[k] == nil {
|
||||
s.config.Render.Template.HTMLTemplate.LayoutFuncs[k] = v
|
||||
}
|
||||
|
||||
if s.config.Render.Template.HTMLTemplate.Funcs[k] == nil {
|
||||
s.config.Render.Template.HTMLTemplate.Funcs[k] = v
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
s.templates = template.New(s.config.Render.Template)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -153,7 +184,6 @@ func (s *Iris) printBanner() {
|
|||
|
||||
c.Add(color.FgGreen)
|
||||
stationsRunning++
|
||||
|
||||
c.Println()
|
||||
if stationsRunning > 1 {
|
||||
c.Println("Server[" + strconv.Itoa(stationsRunning) + "]")
|
||||
|
@ -163,7 +193,7 @@ func (s *Iris) printBanner() {
|
|||
}
|
||||
})
|
||||
|
||||
printTicker.Start(time.Duration(2) * time.Millisecond)
|
||||
printTicker.Start(time.Duration(1) * time.Millisecond)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -72,31 +72,24 @@ func Party(path string, handlersFn ...HandlerFunc) IParty {
|
|||
|
||||
// Handle registers a route to the server's router
|
||||
// if empty method is passed then registers handler(s) for all methods, same as .Any
|
||||
func Handle(method string, registedPath string, handlers ...Handler) {
|
||||
DefaultIris.Handle(method, registedPath, handlers...)
|
||||
func Handle(method string, registedPath string, handlers ...Handler) IRoute {
|
||||
return DefaultIris.Handle(method, registedPath, handlers...)
|
||||
}
|
||||
|
||||
// HandleFunc registers a route with a method, path string, and a handler
|
||||
func HandleFunc(method string, path string, handlersFn ...HandlerFunc) {
|
||||
DefaultIris.HandleFunc(method, path, handlersFn...)
|
||||
}
|
||||
|
||||
// HandleAnnotated registers a route handler using a Struct implements iris.Handler (as anonymous property)
|
||||
// which it's metadata has the form of
|
||||
// `method:"path"` and returns the route and an error if any occurs
|
||||
// handler is passed by func(urstruct MyStruct) Serve(ctx *Context) {}
|
||||
//
|
||||
// HandleAnnotated will be deprecated until the final v3 !
|
||||
func HandleAnnotated(irisHandler Handler) error {
|
||||
return DefaultIris.HandleAnnotated(irisHandler)
|
||||
func HandleFunc(method string, path string, handlersFn ...HandlerFunc) IRoute {
|
||||
return DefaultIris.HandleFunc(method, path, handlersFn...)
|
||||
}
|
||||
|
||||
// API converts & registers a custom struct to the router
|
||||
// receives three parameters
|
||||
// receives two parameters
|
||||
// first is the request path (string)
|
||||
// second is the custom struct (interface{}) which can be anything that has a *iris.Context as field
|
||||
// second is the custom struct (interface{}) which can be anything that has a *iris.Context as field.
|
||||
// third are the common middlewares, is optional parameter
|
||||
//
|
||||
// Note that API's routes have their default-name to the full registed path,
|
||||
// no need to give a special name for it, because it's not supposed to be used inside your templates.
|
||||
//
|
||||
// Recommend to use when you retrieve data from an external database,
|
||||
// and the router-performance is not the (only) thing which slows the server's overall performance.
|
||||
//
|
||||
|
@ -173,53 +166,59 @@ func UseFunc(handlersFn ...HandlerFunc) {
|
|||
}
|
||||
|
||||
// Get registers a route for the Get http method
|
||||
func Get(path string, handlersFn ...HandlerFunc) {
|
||||
DefaultIris.Get(path, handlersFn...)
|
||||
func Get(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return DefaultIris.Get(path, handlersFn...)
|
||||
}
|
||||
|
||||
// Post registers a route for the Post http method
|
||||
func Post(path string, handlersFn ...HandlerFunc) {
|
||||
DefaultIris.Post(path, handlersFn...)
|
||||
func Post(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return DefaultIris.Post(path, handlersFn...)
|
||||
}
|
||||
|
||||
// Put registers a route for the Put http method
|
||||
func Put(path string, handlersFn ...HandlerFunc) {
|
||||
DefaultIris.Put(path, handlersFn...)
|
||||
func Put(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return DefaultIris.Put(path, handlersFn...)
|
||||
}
|
||||
|
||||
// Delete registers a route for the Delete http method
|
||||
func Delete(path string, handlersFn ...HandlerFunc) {
|
||||
DefaultIris.Delete(path, handlersFn...)
|
||||
func Delete(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return DefaultIris.Delete(path, handlersFn...)
|
||||
}
|
||||
|
||||
// Connect registers a route for the Connect http method
|
||||
func Connect(path string, handlersFn ...HandlerFunc) {
|
||||
DefaultIris.Connect(path, handlersFn...)
|
||||
func Connect(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return DefaultIris.Connect(path, handlersFn...)
|
||||
}
|
||||
|
||||
// Head registers a route for the Head http method
|
||||
func Head(path string, handlersFn ...HandlerFunc) {
|
||||
DefaultIris.Head(path, handlersFn...)
|
||||
func Head(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return DefaultIris.Head(path, handlersFn...)
|
||||
}
|
||||
|
||||
// Options registers a route for the Options http method
|
||||
func Options(path string, handlersFn ...HandlerFunc) {
|
||||
DefaultIris.Options(path, handlersFn...)
|
||||
func Options(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return DefaultIris.Options(path, handlersFn...)
|
||||
}
|
||||
|
||||
// Patch registers a route for the Patch http method
|
||||
func Patch(path string, handlersFn ...HandlerFunc) {
|
||||
DefaultIris.Patch(path, handlersFn...)
|
||||
func Patch(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return DefaultIris.Patch(path, handlersFn...)
|
||||
}
|
||||
|
||||
// Trace registers a route for the Trace http methodd
|
||||
func Trace(path string, handlersFn ...HandlerFunc) {
|
||||
DefaultIris.Trace(path, handlersFn...)
|
||||
func Trace(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return DefaultIris.Trace(path, handlersFn...)
|
||||
}
|
||||
|
||||
// Any registers a route for ALL of the http methods (Get,Post,Put,Head,Patch,Options,Connect,Delete)
|
||||
func Any(path string, handlersFn ...HandlerFunc) {
|
||||
DefaultIris.Any(path, handlersFn...)
|
||||
func Any(path string, handlersFn ...HandlerFunc) []IRoute {
|
||||
return DefaultIris.Any(path, handlersFn...)
|
||||
}
|
||||
|
||||
// RouteByName returns a route by its name,if not found then returns a route with empty path
|
||||
// Note that the searching is case-sensitive
|
||||
func RouteByName(lookUpName string) IRoute {
|
||||
return DefaultIris.RouteByName(lookUpName)
|
||||
}
|
||||
|
||||
// StaticHandlerFunc returns a HandlerFunc to serve static system directory
|
||||
|
|
140
party.go
140
party.go
|
@ -19,20 +19,19 @@ import (
|
|||
type (
|
||||
// IParty is the interface which implements the whole Party of routes
|
||||
IParty interface {
|
||||
Handle(string, string, ...Handler)
|
||||
HandleFunc(string, string, ...HandlerFunc)
|
||||
HandleAnnotated(Handler) error
|
||||
Handle(string, string, ...Handler) IRoute
|
||||
HandleFunc(string, string, ...HandlerFunc) IRoute
|
||||
API(path string, controller HandlerAPI, middlewares ...HandlerFunc) error
|
||||
Get(string, ...HandlerFunc)
|
||||
Post(string, ...HandlerFunc)
|
||||
Put(string, ...HandlerFunc)
|
||||
Delete(string, ...HandlerFunc)
|
||||
Connect(string, ...HandlerFunc)
|
||||
Head(string, ...HandlerFunc)
|
||||
Options(string, ...HandlerFunc)
|
||||
Patch(string, ...HandlerFunc)
|
||||
Trace(string, ...HandlerFunc)
|
||||
Any(string, ...HandlerFunc)
|
||||
Get(string, ...HandlerFunc) RouteNameFunc
|
||||
Post(string, ...HandlerFunc) RouteNameFunc
|
||||
Put(string, ...HandlerFunc) RouteNameFunc
|
||||
Delete(string, ...HandlerFunc) RouteNameFunc
|
||||
Connect(string, ...HandlerFunc) RouteNameFunc
|
||||
Head(string, ...HandlerFunc) RouteNameFunc
|
||||
Options(string, ...HandlerFunc) RouteNameFunc
|
||||
Patch(string, ...HandlerFunc) RouteNameFunc
|
||||
Trace(string, ...HandlerFunc) RouteNameFunc
|
||||
Any(string, ...HandlerFunc) []IRoute
|
||||
Use(...Handler)
|
||||
UseFunc(...HandlerFunc)
|
||||
StaticHandlerFunc(systemPath string, stripSlashes int, compress bool, generateIndexPages bool, indexNames []string) HandlerFunc
|
||||
|
@ -61,13 +60,13 @@ func (p *GardenParty) IsRoot() bool {
|
|||
}
|
||||
|
||||
// Handle registers a route to the server's router
|
||||
// if empty method is passed then registers handler(s) for all methods, same as .Any
|
||||
func (p *GardenParty) Handle(method string, registedPath string, handlers ...Handler) {
|
||||
// if empty method is passed then registers handler(s) for all methods, same as .Any, but returns nil as result
|
||||
func (p *GardenParty) Handle(method string, registedPath string, handlers ...Handler) IRoute {
|
||||
if method == "" { // then use like it was .Any
|
||||
for _, k := range AllMethods {
|
||||
p.Handle(k, registedPath, handlers...)
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
path := fixPath(p.relativePath + registedPath) // keep the last "/" as default ex: "/xyz/"
|
||||
if !p.station.config.DisablePathCorrection {
|
||||
|
@ -79,69 +78,14 @@ func (p *GardenParty) Handle(method string, registedPath string, handlers ...Han
|
|||
p.station.plugins.DoPreHandle(route)
|
||||
p.station.addRoute(route)
|
||||
p.station.plugins.DoPostHandle(route)
|
||||
return route
|
||||
}
|
||||
|
||||
// HandleFunc registers and returns a route with a method string, path string and a handler
|
||||
// registedPath is the relative url path
|
||||
// handler is the iris.Handler which you can pass anything you want via iris.ToHandlerFunc(func(res,req){})... or just use func(c *iris.Context)
|
||||
func (p *GardenParty) HandleFunc(method string, registedPath string, handlersFn ...HandlerFunc) {
|
||||
p.Handle(method, registedPath, ConvertToHandlers(handlersFn)...)
|
||||
}
|
||||
|
||||
// HandleAnnotated registers a route handler using a Struct implements iris.Handler (as anonymous property)
|
||||
// which it's metadata has the form of
|
||||
// `method:"path"` and returns the route and an error if any occurs
|
||||
// handler is passed by func(urstruct MyStruct) Serve(ctx *Context) {}
|
||||
func (p *GardenParty) HandleAnnotated(irisHandler Handler) error {
|
||||
var method string
|
||||
var path string
|
||||
var errMessage = ""
|
||||
val := reflect.ValueOf(irisHandler).Elem()
|
||||
|
||||
for i := 0; i < val.NumField(); i++ {
|
||||
typeField := val.Type().Field(i)
|
||||
|
||||
if typeField.Anonymous && typeField.Name == "Handler" {
|
||||
tags := strings.Split(strings.TrimSpace(string(typeField.Tag)), " ")
|
||||
firstTag := tags[0]
|
||||
|
||||
idx := strings.Index(string(firstTag), ":")
|
||||
|
||||
tagName := strings.ToUpper(string(firstTag[:idx]))
|
||||
tagValue, unqerr := strconv.Unquote(string(firstTag[idx+1:]))
|
||||
|
||||
if unqerr != nil {
|
||||
errMessage = errMessage + "\non getting path: " + unqerr.Error()
|
||||
continue
|
||||
}
|
||||
|
||||
path = tagValue
|
||||
avalaibleMethodsStr := strings.Join(AllMethods[0:], ",")
|
||||
|
||||
if !strings.Contains(avalaibleMethodsStr, tagName) {
|
||||
//wrong method passed
|
||||
errMessage = errMessage + "\nWrong method passed to the anonymous property iris.Handler -> " + tagName
|
||||
continue
|
||||
}
|
||||
|
||||
method = tagName
|
||||
|
||||
} else {
|
||||
errMessage = "\nStruct passed but it doesn't have an anonymous property of type iris.Hanndler, please refer to docs\n"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if errMessage == "" {
|
||||
p.Handle(method, path, irisHandler)
|
||||
}
|
||||
|
||||
var err error
|
||||
if errMessage != "" {
|
||||
err = ErrHandleAnnotated.Format(errMessage)
|
||||
}
|
||||
|
||||
return err
|
||||
func (p *GardenParty) HandleFunc(method string, registedPath string, handlersFn ...HandlerFunc) IRoute {
|
||||
return p.Handle(method, registedPath, ConvertToHandlers(handlersFn)...)
|
||||
}
|
||||
|
||||
// API converts & registers a custom struct to the router
|
||||
|
@ -150,6 +94,9 @@ func (p *GardenParty) HandleAnnotated(irisHandler Handler) error {
|
|||
// second is the custom struct (interface{}) which can be anything that has a *iris.Context as field.
|
||||
// third are the common middlewares, is optional parameter
|
||||
//
|
||||
// Note that API's routes have their default-name to the full registed path,
|
||||
// no need to give a special name for it, because it's not supposed to be used inside your templates.
|
||||
//
|
||||
// Recommend to use when you retrieve data from an external database,
|
||||
// and the router-performance is not the (only) thing which slows the server's overall performance.
|
||||
//
|
||||
|
@ -300,56 +247,59 @@ func (p *GardenParty) API(path string, controller HandlerAPI, middlewares ...Han
|
|||
}
|
||||
|
||||
// Get registers a route for the Get http method
|
||||
func (p *GardenParty) Get(path string, handlersFn ...HandlerFunc) {
|
||||
p.HandleFunc(MethodGet, path, handlersFn...)
|
||||
func (p *GardenParty) Get(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return p.HandleFunc(MethodGet, path, handlersFn...).Name
|
||||
}
|
||||
|
||||
// Post registers a route for the Post http method
|
||||
func (p *GardenParty) Post(path string, handlersFn ...HandlerFunc) {
|
||||
p.HandleFunc(MethodPost, path, handlersFn...)
|
||||
func (p *GardenParty) Post(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return p.HandleFunc(MethodPost, path, handlersFn...).Name
|
||||
}
|
||||
|
||||
// Put registers a route for the Put http method
|
||||
func (p *GardenParty) Put(path string, handlersFn ...HandlerFunc) {
|
||||
p.HandleFunc(MethodPut, path, handlersFn...)
|
||||
func (p *GardenParty) Put(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return p.HandleFunc(MethodPut, path, handlersFn...).Name
|
||||
}
|
||||
|
||||
// Delete registers a route for the Delete http method
|
||||
func (p *GardenParty) Delete(path string, handlersFn ...HandlerFunc) {
|
||||
p.HandleFunc(MethodDelete, path, handlersFn...)
|
||||
func (p *GardenParty) Delete(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return p.HandleFunc(MethodDelete, path, handlersFn...).Name
|
||||
}
|
||||
|
||||
// Connect registers a route for the Connect http method
|
||||
func (p *GardenParty) Connect(path string, handlersFn ...HandlerFunc) {
|
||||
p.HandleFunc(MethodConnect, path, handlersFn...)
|
||||
func (p *GardenParty) Connect(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return p.HandleFunc(MethodConnect, path, handlersFn...).Name
|
||||
}
|
||||
|
||||
// Head registers a route for the Head http method
|
||||
func (p *GardenParty) Head(path string, handlersFn ...HandlerFunc) {
|
||||
p.HandleFunc(MethodHead, path, handlersFn...)
|
||||
func (p *GardenParty) Head(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return p.HandleFunc(MethodHead, path, handlersFn...).Name
|
||||
}
|
||||
|
||||
// Options registers a route for the Options http method
|
||||
func (p *GardenParty) Options(path string, handlersFn ...HandlerFunc) {
|
||||
p.HandleFunc(MethodOptions, path, handlersFn...)
|
||||
func (p *GardenParty) Options(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return p.HandleFunc(MethodOptions, path, handlersFn...).Name
|
||||
}
|
||||
|
||||
// Patch registers a route for the Patch http method
|
||||
func (p *GardenParty) Patch(path string, handlersFn ...HandlerFunc) {
|
||||
p.HandleFunc(MethodPatch, path, handlersFn...)
|
||||
func (p *GardenParty) Patch(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return p.HandleFunc(MethodPatch, path, handlersFn...).Name
|
||||
}
|
||||
|
||||
// Trace registers a route for the Trace http method
|
||||
func (p *GardenParty) Trace(path string, handlersFn ...HandlerFunc) {
|
||||
p.HandleFunc(MethodTrace, path, handlersFn...)
|
||||
func (p *GardenParty) Trace(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return p.HandleFunc(MethodTrace, path, handlersFn...).Name
|
||||
}
|
||||
|
||||
// Any registers a route for ALL of the http methods (Get,Post,Put,Head,Patch,Options,Connect,Delete)
|
||||
func (p *GardenParty) Any(registedPath string, handlersFn ...HandlerFunc) {
|
||||
for _, k := range AllMethods {
|
||||
p.HandleFunc(k, registedPath, handlersFn...)
|
||||
func (p *GardenParty) Any(registedPath string, handlersFn ...HandlerFunc) []IRoute {
|
||||
theRoutes := make([]IRoute, len(AllMethods), len(AllMethods))
|
||||
for idx, k := range AllMethods {
|
||||
r := p.HandleFunc(k, registedPath, handlersFn...)
|
||||
theRoutes[idx] = r
|
||||
}
|
||||
|
||||
return theRoutes
|
||||
}
|
||||
|
||||
// H_ is used to convert a context.IContext handler func to iris.HandlerFunc, is used only inside iris internal package to avoid import cycles
|
||||
|
|
|
@ -17,6 +17,9 @@ type (
|
|||
Engine struct {
|
||||
Config *config.Template
|
||||
Templates *template.Template
|
||||
// emptyFuncs returns empty functions, contains empty result for custom LayoutFuncs
|
||||
|
||||
emptyFuncs template.FuncMap
|
||||
// Middleware
|
||||
// Note:
|
||||
// I see that many template engines returns html/template as result
|
||||
|
@ -26,7 +29,10 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
var emptyFuncs = template.FuncMap{
|
||||
// New creates and returns the HTMLTemplate template engine
|
||||
func New(c config.Template) *Engine {
|
||||
s := &Engine{Config: &c}
|
||||
funcs := template.FuncMap{
|
||||
"yield": func() (string, error) {
|
||||
return "", fmt.Errorf("yield was called, yet no layout defined")
|
||||
},
|
||||
|
@ -38,15 +44,11 @@ var emptyFuncs = template.FuncMap{
|
|||
}, "render": func() (string, error) {
|
||||
return "", nil
|
||||
},
|
||||
// just for test with jade
|
||||
/*"bold": func() (string, error) {
|
||||
return "", nil
|
||||
},*/
|
||||
}
|
||||
|
||||
// New creates and returns the HTMLTemplate template engine
|
||||
func New(c config.Template) *Engine {
|
||||
return &Engine{Config: &c}
|
||||
s.emptyFuncs = funcs
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// BuildTemplates builds the templates
|
||||
|
@ -123,7 +125,7 @@ func (s *Engine) buildFromDir() error {
|
|||
tmpl.Funcs(s.Config.HTMLTemplate.Funcs)
|
||||
}
|
||||
|
||||
tmpl.Funcs(emptyFuncs).Parse(contents)
|
||||
tmpl.Funcs(s.emptyFuncs).Parse(contents)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +172,7 @@ func (s *Engine) buildFromAsset() error {
|
|||
tmpl.Funcs(s.Config.HTMLTemplate.Funcs)
|
||||
}
|
||||
|
||||
tmpl.Funcs(emptyFuncs).Parse(string(buf))
|
||||
tmpl.Funcs(s.emptyFuncs).Parse(string(buf))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -207,12 +209,13 @@ func (s *Engine) layoutFuncsFor(name string, binding interface{}) {
|
|||
buf, err := s.executeTemplateBuf(fullPartialName, binding)
|
||||
// Return safe HTML here since we are rendering our own template.
|
||||
return template.HTML(buf.String()), err
|
||||
|
||||
},
|
||||
// just for test with jade
|
||||
/*"bold": func(content string) (template.HTML, error) {
|
||||
return template.HTML("<b>" + content + "</b>"), nil
|
||||
},*/
|
||||
}
|
||||
_userLayoutFuncs := s.Config.HTMLTemplate.LayoutFuncs
|
||||
if _userLayoutFuncs != nil && len(_userLayoutFuncs) > 0 {
|
||||
for k, v := range _userLayoutFuncs {
|
||||
funcs[k] = v
|
||||
}
|
||||
}
|
||||
if tpl := s.Templates.Lookup(name); tpl != nil {
|
||||
tpl.Funcs(funcs)
|
||||
|
|
109
route.go
109
route.go
|
@ -1,6 +1,8 @@
|
|||
package iris
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -11,17 +13,33 @@ type (
|
|||
GetMethod() string
|
||||
GetDomain() string
|
||||
GetPath() string
|
||||
GetName() string
|
||||
// Name sets the name of the route
|
||||
Name(string) IRoute
|
||||
GetMiddleware() Middleware
|
||||
HasCors() bool
|
||||
// used internaly to check arguments with the route's named parameters
|
||||
parse(...interface{}) (string, bool)
|
||||
}
|
||||
|
||||
// RouteNameFunc is returned to from route handle
|
||||
RouteNameFunc func(string) IRoute
|
||||
|
||||
// Route contains basic and temporary info about the route in order to be stored to the tree
|
||||
// It's struct because we pass it ( as IRoute) to the plugins
|
||||
Route struct {
|
||||
method string
|
||||
domain string
|
||||
fullpath string
|
||||
// the name of the route, the default name is just the registed path.
|
||||
name string
|
||||
middleware Middleware
|
||||
|
||||
// this is used to convert /mypath/:aparam/:something to -> /mypath/%v/%v and /mypath/* -> mypath/%v
|
||||
// we use %v to escape from the conversions between strings,booleans and integers.
|
||||
// used inside custom html template func 'url'
|
||||
formattedPath string
|
||||
// formattedParts is just the formattedPath count, used to see if we have one path parameter then the url's function arguments will be passed as one string to the %v
|
||||
formattedParts int
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -57,11 +75,43 @@ func NewRoute(method string, registedPath string, middleware Middleware) *Route
|
|||
}
|
||||
|
||||
}
|
||||
r := &Route{method: method, domain: domain, fullpath: registedPath, middleware: middleware}
|
||||
|
||||
r := &Route{method: method, domain: domain, fullpath: registedPath, middleware: middleware, name: registedPath, formattedPath: registedPath}
|
||||
r.formatPath()
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Route) formatPath() {
|
||||
// we don't care about performance here, no runtime func.
|
||||
|
||||
n1Len := strings.Count(r.fullpath, ":")
|
||||
isMatchEverything := r.fullpath[len(r.fullpath)-1] == MatchEverythingByte
|
||||
if n1Len == 0 && !isMatchEverything {
|
||||
// its a static
|
||||
return
|
||||
}
|
||||
if n1Len == 0 && isMatchEverything {
|
||||
//if we have something like: /mypath/anything/* -> /mypatch/anything/%v
|
||||
r.formattedPath = r.fullpath[0:len(r.fullpath)-2] + "%v"
|
||||
r.formattedParts++
|
||||
return
|
||||
}
|
||||
|
||||
tempPath := r.fullpath
|
||||
|
||||
splittedN1 := strings.Split(r.fullpath, "/")
|
||||
|
||||
for _, v := range splittedN1 {
|
||||
if len(v) > 0 {
|
||||
if v[0] == ':' || v[0] == MatchEverythingByte {
|
||||
r.formattedParts++
|
||||
tempPath = strings.Replace(tempPath, v, "%v", -1) // n1Len, but let it we don't care about performance here.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
r.formattedPath = tempPath
|
||||
}
|
||||
|
||||
// GetMethod returns the http method
|
||||
func (r Route) GetMethod() string {
|
||||
return r.method
|
||||
|
@ -77,6 +127,17 @@ func (r Route) GetPath() string {
|
|||
return r.fullpath
|
||||
}
|
||||
|
||||
// GetName returns the name of the route
|
||||
func (r Route) GetName() string {
|
||||
return r.name
|
||||
}
|
||||
|
||||
// Name sets the route's name
|
||||
func (r *Route) Name(newName string) IRoute {
|
||||
r.name = newName
|
||||
return r
|
||||
}
|
||||
|
||||
// GetMiddleware returns the chain of the []HandlerFunc registed to this Route
|
||||
func (r Route) GetMiddleware() Middleware {
|
||||
return r.middleware
|
||||
|
@ -87,6 +148,48 @@ func (r *Route) HasCors() bool {
|
|||
return RouteConflicts(r, "httpmethod")
|
||||
}
|
||||
|
||||
// used internaly to check arguments with the route's named parameters (iris.initTemplates for funcs)
|
||||
func (r *Route) parse(args ...interface{}) (string, bool) {
|
||||
// check if arguments are not equal to the named parameters ( : = 1, * = all named parameters split to / ), if this happens then send not found err
|
||||
///TODO: I'm thinking of making an option to disable these checks and just return a result, because they have cost when rendering an html/template, not too big compared to the render action but... we will see
|
||||
// can also do a check if this url can be realy served (_tree.rootBranch.GetBranch(path, ctx.Params)) and if not then return a 404 or a link to a ./templates/errors/404.html
|
||||
// but we don't have access to the context itself(so we will have some memory allocations), although it's a good idea but let's keep things simple here.
|
||||
argsLen := len(args)
|
||||
// we have named parameters but arguments not given
|
||||
if argsLen == 0 && r.formattedParts > 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// we have arguments but they are much more than the named parameters
|
||||
|
||||
// 1 check if we have /*, if yes then join all arguments to one as path and pass that as parameter
|
||||
if argsLen > r.formattedParts {
|
||||
if r.fullpath[len(r.fullpath)-1] == MatchEverythingByte {
|
||||
// we have to convert each argument to a string in this case
|
||||
|
||||
argsString := make([]string, argsLen, argsLen)
|
||||
|
||||
for i, v := range args {
|
||||
if s, ok := v.(string); ok {
|
||||
argsString[i] = s
|
||||
} else if num, ok := v.(int); ok {
|
||||
argsString[i] = strconv.Itoa(num)
|
||||
} else if b, ok := v.(bool); ok {
|
||||
argsString[i] = strconv.FormatBool(b)
|
||||
}
|
||||
}
|
||||
|
||||
parameter := strings.Join(argsString, Slash)
|
||||
result := fmt.Sprintf(r.formattedPath, parameter)
|
||||
return result, true
|
||||
}
|
||||
// 2 if !1 return false
|
||||
return "", false
|
||||
}
|
||||
|
||||
return fmt.Sprintf(r.formattedPath, args...), true
|
||||
}
|
||||
|
||||
// RouteConflicts checks for route's middleware conflicts
|
||||
func RouteConflicts(r *Route, with string) bool {
|
||||
for _, h := range r.middleware {
|
||||
|
|
20
router.go
20
router.go
|
@ -59,6 +59,9 @@ type router struct {
|
|||
garden *Garden
|
||||
methodMatch func(m1, m2 string) bool
|
||||
getRequestPath func(*fasthttp.RequestCtx) []byte
|
||||
// routes useful information, this info can be used to make custom links inside templates
|
||||
// the route's information (can be) changed after its registration
|
||||
lookups []IRoute
|
||||
ServeRequest func(reqCtx *fasthttp.RequestCtx)
|
||||
// errorPool is responsible to get the Context to handle not found errors
|
||||
errorPool sync.Pool
|
||||
|
@ -89,6 +92,7 @@ func newRouter(station *Iris) *router {
|
|||
garden: &Garden{},
|
||||
methodMatch: methodMatchFunc,
|
||||
getRequestPath: getRequestPathDefault,
|
||||
lookups: make([]IRoute, 0),
|
||||
HTTPErrorContainer: defaultHTTPErrors(),
|
||||
GardenParty: &GardenParty{relativePath: "/", station: station, root: true},
|
||||
errorPool: station.newContextPool()}
|
||||
|
@ -99,13 +103,27 @@ func newRouter(station *Iris) *router {
|
|||
|
||||
}
|
||||
|
||||
// addRoute calls the Plant, is created to set the router's station
|
||||
// addRoute is a middleware between router and garden
|
||||
// it just calls the garden's Plant method
|
||||
// is 'thread-safe'
|
||||
func (r *router) addRoute(route IRoute) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.lookups = append(r.lookups, route)
|
||||
r.garden.Plant(r.station, route)
|
||||
}
|
||||
|
||||
// RouteByName returns a route by its name,if not found then returns a route with empty path
|
||||
// Note that the searching is case-sensitive
|
||||
func (r *router) RouteByName(lookUpName string) IRoute {
|
||||
for _, route := range r.lookups {
|
||||
if route.GetName() == lookUpName {
|
||||
return route
|
||||
}
|
||||
}
|
||||
return &Route{}
|
||||
}
|
||||
|
||||
//check if any tree has cors setted to true, means that cors middleware is added
|
||||
func (r *router) cors() (has bool) {
|
||||
r.garden.visitAll(func(i int, tree *tree) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user