mirror of
https://github.com/astaxie/beego.git
synced 2024-11-22 13:00:54 +00:00
Merge branch 'develop' of github.com:dvwallin/beego into develop
This commit is contained in:
commit
edbad60782
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.swo
|
||||
beego.iml
|
||||
|
26
README.md
26
README.md
@ -3,14 +3,36 @@
|
||||
[![Build Status](https://drone.io/github.com/astaxie/beego/status.png)](https://drone.io/github.com/astaxie/beego/latest)
|
||||
[![GoDoc](http://godoc.org/github.com/astaxie/beego?status.svg)](http://godoc.org/github.com/astaxie/beego)
|
||||
|
||||
beego is an open-source, high-performance, modular, full-stack web framework.
|
||||
beego is used for rapid development of RESTful APIs, web apps and backend services in Go.
|
||||
It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific features such as interfaces and struct embedding.
|
||||
|
||||
More info [beego.me](http://beego.me)
|
||||
|
||||
## Installation
|
||||
##Quick Start
|
||||
######Download and install
|
||||
|
||||
go get github.com/astaxie/beego
|
||||
|
||||
######Create file `hello.go`
|
||||
```go
|
||||
package main
|
||||
|
||||
import "github.com/astaxie/beego"
|
||||
|
||||
func main(){
|
||||
beego.Run()
|
||||
}
|
||||
```
|
||||
######Build and run
|
||||
```bash
|
||||
go build hello.go
|
||||
./hello
|
||||
```
|
||||
######Congratulations!
|
||||
You just built your first beego app.
|
||||
Open your browser and visit `http://localhost:8000`.
|
||||
Please see [Documentation](http://beego.me/docs) for more.
|
||||
|
||||
## Features
|
||||
|
||||
* RESTful support
|
||||
|
32
admin.go
32
admin.go
@ -101,11 +101,11 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
|
||||
m["AppConfigPath"] = AppConfigPath
|
||||
m["StaticDir"] = StaticDir
|
||||
m["StaticExtensionsToGzip"] = StaticExtensionsToGzip
|
||||
m["HttpAddr"] = HttpAddr
|
||||
m["HttpPort"] = HttpPort
|
||||
m["HttpTLS"] = EnableHttpTLS
|
||||
m["HttpCertFile"] = HttpCertFile
|
||||
m["HttpKeyFile"] = HttpKeyFile
|
||||
m["HTTPAddr"] = HTTPAddr
|
||||
m["HTTPPort"] = HTTPPort
|
||||
m["HTTPTLS"] = EnableHTTPTLS
|
||||
m["HTTPCertFile"] = HTTPCertFile
|
||||
m["HTTPKeyFile"] = HTTPKeyFile
|
||||
m["RecoverPanic"] = RecoverPanic
|
||||
m["AutoRender"] = AutoRender
|
||||
m["ViewsPath"] = ViewsPath
|
||||
@ -114,14 +114,14 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
|
||||
m["SessionProvider"] = SessionProvider
|
||||
m["SessionName"] = SessionName
|
||||
m["SessionGCMaxLifetime"] = SessionGCMaxLifetime
|
||||
m["SessionSavePath"] = SessionSavePath
|
||||
m["SessionProviderConfig"] = SessionProviderConfig
|
||||
m["SessionCookieLifeTime"] = SessionCookieLifeTime
|
||||
m["UseFcgi"] = UseFcgi
|
||||
m["EnabelFcgi"] = EnabelFcgi
|
||||
m["MaxMemory"] = MaxMemory
|
||||
m["EnableGzip"] = EnableGzip
|
||||
m["DirectoryIndex"] = DirectoryIndex
|
||||
m["HttpServerTimeOut"] = HttpServerTimeOut
|
||||
m["ErrorsShow"] = ErrorsShow
|
||||
m["HTTPServerTimeOut"] = HTTPServerTimeOut
|
||||
m["EnableErrorsShow"] = EnableErrorsShow
|
||||
m["XSRFKEY"] = XSRFKEY
|
||||
m["EnableXSRF"] = EnableXSRF
|
||||
m["XSRFExpire"] = XSRFExpire
|
||||
@ -130,8 +130,8 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
|
||||
m["TemplateRight"] = TemplateRight
|
||||
m["BeegoServerName"] = BeegoServerName
|
||||
m["EnableAdmin"] = EnableAdmin
|
||||
m["AdminHttpAddr"] = AdminHttpAddr
|
||||
m["AdminHttpPort"] = AdminHttpPort
|
||||
m["AdminHTTPAddr"] = AdminHTTPAddr
|
||||
m["AdminHTTPPort"] = AdminHTTPPort
|
||||
|
||||
tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
|
||||
tmpl = template.Must(tmpl.Parse(configTpl))
|
||||
@ -314,14 +314,14 @@ func profIndex(rw http.ResponseWriter, r *http.Request) {
|
||||
data["Content"] = result.String()
|
||||
|
||||
if format == "json" && command == "gc summary" {
|
||||
dataJson, err := json.Marshal(data)
|
||||
dataJSON, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
rw.Write(dataJson)
|
||||
rw.Write(dataJSON)
|
||||
return
|
||||
}
|
||||
|
||||
@ -451,10 +451,10 @@ func (admin *adminApp) Run() {
|
||||
if len(toolbox.AdminTaskList) > 0 {
|
||||
toolbox.StartTask()
|
||||
}
|
||||
addr := AdminHttpAddr
|
||||
addr := AdminHTTPAddr
|
||||
|
||||
if AdminHttpPort != 0 {
|
||||
addr = fmt.Sprintf("%s:%d", AdminHttpAddr, AdminHttpPort)
|
||||
if AdminHTTPPort != 0 {
|
||||
addr = fmt.Sprintf("%s:%d", AdminHTTPAddr, AdminHTTPPort)
|
||||
}
|
||||
for p, f := range admin.routers {
|
||||
http.Handle(p, f)
|
||||
|
236
app.go
236
app.go
@ -20,15 +20,26 @@ import (
|
||||
"net/http"
|
||||
"net/http/fcgi"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego/grace"
|
||||
"github.com/astaxie/beego/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
// BeeApp is an application instance
|
||||
BeeApp *App
|
||||
)
|
||||
|
||||
func init() {
|
||||
// create beego application
|
||||
BeeApp = NewApp()
|
||||
}
|
||||
|
||||
// App defines beego application with a new PatternServeMux.
|
||||
type App struct {
|
||||
Handlers *ControllerRegistor
|
||||
Handlers *ControllerRegister
|
||||
Server *http.Server
|
||||
}
|
||||
|
||||
@ -41,10 +52,10 @@ func NewApp() *App {
|
||||
|
||||
// Run beego application.
|
||||
func (app *App) Run() {
|
||||
addr := HttpAddr
|
||||
addr := HTTPAddr
|
||||
|
||||
if HttpPort != 0 {
|
||||
addr = fmt.Sprintf("%s:%d", HttpAddr, HttpPort)
|
||||
if HTTPPort != 0 {
|
||||
addr = fmt.Sprintf("%s:%d", HTTPAddr, HTTPPort)
|
||||
}
|
||||
|
||||
var (
|
||||
@ -53,8 +64,8 @@ func (app *App) Run() {
|
||||
)
|
||||
endRunning := make(chan bool, 1)
|
||||
|
||||
if UseFcgi {
|
||||
if UseStdIo {
|
||||
if EnabelFcgi {
|
||||
if EnableStdIo {
|
||||
err = fcgi.Serve(nil, app.Handlers) // standard I/O
|
||||
if err == nil {
|
||||
BeeLogger.Info("Use FCGI via standard I/O")
|
||||
@ -62,7 +73,7 @@ func (app *App) Run() {
|
||||
BeeLogger.Info("Cannot use FCGI via standard I/O", err)
|
||||
}
|
||||
} else {
|
||||
if HttpPort == 0 {
|
||||
if HTTPPort == 0 {
|
||||
// remove the Socket file before start
|
||||
if utils.FileExists(addr) {
|
||||
os.Remove(addr)
|
||||
@ -80,18 +91,18 @@ func (app *App) Run() {
|
||||
if Graceful {
|
||||
app.Server.Addr = addr
|
||||
app.Server.Handler = app.Handlers
|
||||
app.Server.ReadTimeout = time.Duration(HttpServerTimeOut) * time.Second
|
||||
app.Server.WriteTimeout = time.Duration(HttpServerTimeOut) * time.Second
|
||||
if EnableHttpTLS {
|
||||
app.Server.ReadTimeout = time.Duration(HTTPServerTimeOut) * time.Second
|
||||
app.Server.WriteTimeout = time.Duration(HTTPServerTimeOut) * time.Second
|
||||
if EnableHTTPTLS {
|
||||
go func() {
|
||||
time.Sleep(20 * time.Microsecond)
|
||||
if HttpsPort != 0 {
|
||||
addr = fmt.Sprintf("%s:%d", HttpAddr, HttpsPort)
|
||||
if HTTPSPort != 0 {
|
||||
addr = fmt.Sprintf("%s:%d", HTTPAddr, HTTPSPort)
|
||||
app.Server.Addr = addr
|
||||
}
|
||||
server := grace.NewServer(addr, app.Handlers)
|
||||
server.Server = app.Server
|
||||
err := server.ListenAndServeTLS(HttpCertFile, HttpKeyFile)
|
||||
err := server.ListenAndServeTLS(HTTPCertFile, HTTPKeyFile)
|
||||
if err != nil {
|
||||
BeeLogger.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid()))
|
||||
time.Sleep(100 * time.Microsecond)
|
||||
@ -99,11 +110,11 @@ func (app *App) Run() {
|
||||
}
|
||||
}()
|
||||
}
|
||||
if EnableHttpListen {
|
||||
if EnableHTTPListen {
|
||||
go func() {
|
||||
server := grace.NewServer(addr, app.Handlers)
|
||||
server.Server = app.Server
|
||||
if ListenTCP4 && HttpAddr == "" {
|
||||
if ListenTCP4 && HTTPAddr == "" {
|
||||
server.Network = "tcp4"
|
||||
}
|
||||
err := server.ListenAndServe()
|
||||
@ -117,17 +128,17 @@ func (app *App) Run() {
|
||||
} else {
|
||||
app.Server.Addr = addr
|
||||
app.Server.Handler = app.Handlers
|
||||
app.Server.ReadTimeout = time.Duration(HttpServerTimeOut) * time.Second
|
||||
app.Server.WriteTimeout = time.Duration(HttpServerTimeOut) * time.Second
|
||||
app.Server.ReadTimeout = time.Duration(HTTPServerTimeOut) * time.Second
|
||||
app.Server.WriteTimeout = time.Duration(HTTPServerTimeOut) * time.Second
|
||||
|
||||
if EnableHttpTLS {
|
||||
if EnableHTTPTLS {
|
||||
go func() {
|
||||
time.Sleep(20 * time.Microsecond)
|
||||
if HttpsPort != 0 {
|
||||
app.Server.Addr = fmt.Sprintf("%s:%d", HttpAddr, HttpsPort)
|
||||
if HTTPSPort != 0 {
|
||||
app.Server.Addr = fmt.Sprintf("%s:%d", HTTPAddr, HTTPSPort)
|
||||
}
|
||||
BeeLogger.Info("https server Running on %s", app.Server.Addr)
|
||||
err := app.Server.ListenAndServeTLS(HttpCertFile, HttpKeyFile)
|
||||
err := app.Server.ListenAndServeTLS(HTTPCertFile, HTTPKeyFile)
|
||||
if err != nil {
|
||||
BeeLogger.Critical("ListenAndServeTLS: ", err)
|
||||
time.Sleep(100 * time.Microsecond)
|
||||
@ -136,11 +147,11 @@ func (app *App) Run() {
|
||||
}()
|
||||
}
|
||||
|
||||
if EnableHttpListen {
|
||||
if EnableHTTPListen {
|
||||
go func() {
|
||||
app.Server.Addr = addr
|
||||
BeeLogger.Info("http server Running on %s", app.Server.Addr)
|
||||
if ListenTCP4 && HttpAddr == "" {
|
||||
if ListenTCP4 && HTTPAddr == "" {
|
||||
ln, err := net.Listen("tcp4", app.Server.Addr)
|
||||
if err != nil {
|
||||
BeeLogger.Critical("ListenAndServe: ", err)
|
||||
@ -170,3 +181,182 @@ func (app *App) Run() {
|
||||
}
|
||||
<-endRunning
|
||||
}
|
||||
|
||||
// Router adds a patterned controller handler to BeeApp.
|
||||
// it's an alias method of App.Router.
|
||||
// usage:
|
||||
// simple router
|
||||
// beego.Router("/admin", &admin.UserController{})
|
||||
// beego.Router("/admin/index", &admin.ArticleController{})
|
||||
//
|
||||
// regex router
|
||||
//
|
||||
// beego.Router("/api/:id([0-9]+)", &controllers.RController{})
|
||||
//
|
||||
// custom rules
|
||||
// beego.Router("/api/list",&RestController{},"*:ListFood")
|
||||
// beego.Router("/api/create",&RestController{},"post:CreateFood")
|
||||
// beego.Router("/api/update",&RestController{},"put:UpdateFood")
|
||||
// beego.Router("/api/delete",&RestController{},"delete:DeleteFood")
|
||||
func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *App {
|
||||
BeeApp.Handlers.Add(rootpath, c, mappingMethods...)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// Include will generate router file in the router/xxx.go from the controller's comments
|
||||
// usage:
|
||||
// beego.Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{})
|
||||
// type BankAccount struct{
|
||||
// beego.Controller
|
||||
// }
|
||||
//
|
||||
// register the function
|
||||
// func (b *BankAccount)Mapping(){
|
||||
// b.Mapping("ShowAccount" , b.ShowAccount)
|
||||
// b.Mapping("ModifyAccount", b.ModifyAccount)
|
||||
//}
|
||||
//
|
||||
// //@router /account/:id [get]
|
||||
// func (b *BankAccount) ShowAccount(){
|
||||
// //logic
|
||||
// }
|
||||
//
|
||||
//
|
||||
// //@router /account/:id [post]
|
||||
// func (b *BankAccount) ModifyAccount(){
|
||||
// //logic
|
||||
// }
|
||||
//
|
||||
// the comments @router url methodlist
|
||||
// url support all the function Router's pattern
|
||||
// methodlist [get post head put delete options *]
|
||||
func Include(cList ...ControllerInterface) *App {
|
||||
BeeApp.Handlers.Include(cList...)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// RESTRouter adds a restful controller handler to BeeApp.
|
||||
// its' controller implements beego.ControllerInterface and
|
||||
// defines a param "pattern/:objectId" to visit each resource.
|
||||
func RESTRouter(rootpath string, c ControllerInterface) *App {
|
||||
Router(rootpath, c)
|
||||
Router(path.Join(rootpath, ":objectId"), c)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// AutoRouter adds defined controller handler to BeeApp.
|
||||
// it's same to App.AutoRouter.
|
||||
// if beego.AddAuto(&MainContorlller{}) and MainController has methods List and Page,
|
||||
// visit the url /main/list to exec List function or /main/page to exec Page function.
|
||||
func AutoRouter(c ControllerInterface) *App {
|
||||
BeeApp.Handlers.AddAuto(c)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// AutoPrefix adds controller handler to BeeApp with prefix.
|
||||
// it's same to App.AutoRouterWithPrefix.
|
||||
// if beego.AutoPrefix("/admin",&MainContorlller{}) and MainController has methods List and Page,
|
||||
// visit the url /admin/main/list to exec List function or /admin/main/page to exec Page function.
|
||||
func AutoPrefix(prefix string, c ControllerInterface) *App {
|
||||
BeeApp.Handlers.AddAutoPrefix(prefix, c)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// Get used to register router for Get method
|
||||
// usage:
|
||||
// beego.Get("/", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Get(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Get(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// Post used to register router for Post method
|
||||
// usage:
|
||||
// beego.Post("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Post(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Post(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// Delete used to register router for Delete method
|
||||
// usage:
|
||||
// beego.Delete("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Delete(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Delete(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// Put used to register router for Put method
|
||||
// usage:
|
||||
// beego.Put("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Put(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Put(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// Head used to register router for Head method
|
||||
// usage:
|
||||
// beego.Head("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Head(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Head(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// Options used to register router for Options method
|
||||
// usage:
|
||||
// beego.Options("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Options(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Options(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// Patch used to register router for Patch method
|
||||
// usage:
|
||||
// beego.Patch("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Patch(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Patch(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// Any used to register router for all methods
|
||||
// usage:
|
||||
// beego.Any("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Any(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Any(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// Handler used to register a Handler router
|
||||
// usage:
|
||||
// beego.Handler("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Handler(rootpath string, h http.Handler, options ...interface{}) *App {
|
||||
BeeApp.Handlers.Handler(rootpath, h, options...)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// InsertFilter adds a FilterFunc with pattern condition and action constant.
|
||||
// The pos means action constant including
|
||||
// beego.BeforeStatic, beego.BeforeRouter, beego.BeforeExec, beego.AfterExec and beego.FinishRouter.
|
||||
// The bool params is for setting the returnOnOutput value (false allows multiple filters to execute)
|
||||
func InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) *App {
|
||||
BeeApp.Handlers.InsertFilter(pattern, pos, filter, params...)
|
||||
return BeeApp
|
||||
}
|
||||
|
298
beego.go
298
beego.go
@ -12,243 +12,27 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// beego is an open-source, high-performance, modularity, full-stack web framework
|
||||
//
|
||||
// package main
|
||||
//
|
||||
// import "github.com/astaxie/beego"
|
||||
//
|
||||
// func main() {
|
||||
// beego.Run()
|
||||
// }
|
||||
//
|
||||
// more infomation: http://beego.me
|
||||
package beego
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/astaxie/beego/session"
|
||||
)
|
||||
|
||||
// beego web framework version.
|
||||
const VERSION = "1.5.0"
|
||||
|
||||
type hookfunc func() error //hook function to run
|
||||
var hooks []hookfunc //hook function slice to store the hookfunc
|
||||
//hook function to run
|
||||
type hookfunc func() error
|
||||
|
||||
// Router adds a patterned controller handler to BeeApp.
|
||||
// it's an alias method of App.Router.
|
||||
// usage:
|
||||
// simple router
|
||||
// beego.Router("/admin", &admin.UserController{})
|
||||
// beego.Router("/admin/index", &admin.ArticleController{})
|
||||
//
|
||||
// regex router
|
||||
//
|
||||
// beego.Router("/api/:id([0-9]+)", &controllers.RController{})
|
||||
//
|
||||
// custom rules
|
||||
// beego.Router("/api/list",&RestController{},"*:ListFood")
|
||||
// beego.Router("/api/create",&RestController{},"post:CreateFood")
|
||||
// beego.Router("/api/update",&RestController{},"put:UpdateFood")
|
||||
// beego.Router("/api/delete",&RestController{},"delete:DeleteFood")
|
||||
func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *App {
|
||||
BeeApp.Handlers.Add(rootpath, c, mappingMethods...)
|
||||
return BeeApp
|
||||
}
|
||||
var (
|
||||
hooks = make([]hookfunc, 0) //hook function slice to store the hookfunc
|
||||
)
|
||||
|
||||
// Router add list from
|
||||
// usage:
|
||||
// beego.Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{})
|
||||
// type BankAccount struct{
|
||||
// beego.Controller
|
||||
// }
|
||||
//
|
||||
// register the function
|
||||
// func (b *BankAccount)Mapping(){
|
||||
// b.Mapping("ShowAccount" , b.ShowAccount)
|
||||
// b.Mapping("ModifyAccount", b.ModifyAccount)
|
||||
//}
|
||||
//
|
||||
// //@router /account/:id [get]
|
||||
// func (b *BankAccount) ShowAccount(){
|
||||
// //logic
|
||||
// }
|
||||
//
|
||||
//
|
||||
// //@router /account/:id [post]
|
||||
// func (b *BankAccount) ModifyAccount(){
|
||||
// //logic
|
||||
// }
|
||||
//
|
||||
// the comments @router url methodlist
|
||||
// url support all the function Router's pattern
|
||||
// methodlist [get post head put delete options *]
|
||||
func Include(cList ...ControllerInterface) *App {
|
||||
BeeApp.Handlers.Include(cList...)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// RESTRouter adds a restful controller handler to BeeApp.
|
||||
// its' controller implements beego.ControllerInterface and
|
||||
// defines a param "pattern/:objectId" to visit each resource.
|
||||
func RESTRouter(rootpath string, c ControllerInterface) *App {
|
||||
Router(rootpath, c)
|
||||
Router(path.Join(rootpath, ":objectId"), c)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// AutoRouter adds defined controller handler to BeeApp.
|
||||
// it's same to App.AutoRouter.
|
||||
// if beego.AddAuto(&MainContorlller{}) and MainController has methods List and Page,
|
||||
// visit the url /main/list to exec List function or /main/page to exec Page function.
|
||||
func AutoRouter(c ControllerInterface) *App {
|
||||
BeeApp.Handlers.AddAuto(c)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// AutoPrefix adds controller handler to BeeApp with prefix.
|
||||
// it's same to App.AutoRouterWithPrefix.
|
||||
// if beego.AutoPrefix("/admin",&MainContorlller{}) and MainController has methods List and Page,
|
||||
// visit the url /admin/main/list to exec List function or /admin/main/page to exec Page function.
|
||||
func AutoPrefix(prefix string, c ControllerInterface) *App {
|
||||
BeeApp.Handlers.AddAutoPrefix(prefix, c)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for Get method
|
||||
// usage:
|
||||
// beego.Get("/", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Get(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Get(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for Post method
|
||||
// usage:
|
||||
// beego.Post("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Post(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Post(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for Delete method
|
||||
// usage:
|
||||
// beego.Delete("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Delete(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Delete(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for Put method
|
||||
// usage:
|
||||
// beego.Put("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Put(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Put(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for Head method
|
||||
// usage:
|
||||
// beego.Head("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Head(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Head(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for Options method
|
||||
// usage:
|
||||
// beego.Options("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Options(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Options(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for Patch method
|
||||
// usage:
|
||||
// beego.Patch("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Patch(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Patch(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for all method
|
||||
// usage:
|
||||
// beego.Any("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Any(rootpath string, f FilterFunc) *App {
|
||||
BeeApp.Handlers.Any(rootpath, f)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// register router for own Handler
|
||||
// usage:
|
||||
// beego.Handler("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func Handler(rootpath string, h http.Handler, options ...interface{}) *App {
|
||||
BeeApp.Handlers.Handler(rootpath, h, options...)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// SetViewsPath sets view directory path in beego application.
|
||||
func SetViewsPath(path string) *App {
|
||||
ViewsPath = path
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// SetStaticPath sets static directory path and proper url pattern in beego application.
|
||||
// if beego.SetStaticPath("static","public"), visit /static/* to load static file in folder "public".
|
||||
func SetStaticPath(url string, path string) *App {
|
||||
if !strings.HasPrefix(url, "/") {
|
||||
url = "/" + url
|
||||
}
|
||||
url = strings.TrimRight(url, "/")
|
||||
StaticDir[url] = path
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// DelStaticPath removes the static folder setting in this url pattern in beego application.
|
||||
func DelStaticPath(url string) *App {
|
||||
if !strings.HasPrefix(url, "/") {
|
||||
url = "/" + url
|
||||
}
|
||||
url = strings.TrimRight(url, "/")
|
||||
delete(StaticDir, url)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// InsertFilter adds a FilterFunc with pattern condition and action constant.
|
||||
// The pos means action constant including
|
||||
// beego.BeforeStatic, beego.BeforeRouter, beego.BeforeExec, beego.AfterExec and beego.FinishRouter.
|
||||
// The bool params is for setting the returnOnOutput value (false allows multiple filters to execute)
|
||||
func InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) *App {
|
||||
BeeApp.Handlers.InsertFilter(pattern, pos, filter, params...)
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// The hookfunc will run in beego.Run()
|
||||
// AddAPPStartHook is used to register the hookfunc
|
||||
// The hookfuncs will run in beego.Run()
|
||||
// such as sessionInit, middlerware start, buildtemplate, admin start
|
||||
func AddAPPStartHook(hf hookfunc) {
|
||||
hooks = append(hooks, hf)
|
||||
@ -259,25 +43,22 @@ func AddAPPStartHook(hf hookfunc) {
|
||||
// beego.Run(":8089")
|
||||
// beego.Run("127.0.0.1:8089")
|
||||
func Run(params ...string) {
|
||||
initBeforeHTTPRun()
|
||||
|
||||
if len(params) > 0 && params[0] != "" {
|
||||
strs := strings.Split(params[0], ":")
|
||||
if len(strs) > 0 && strs[0] != "" {
|
||||
HttpAddr = strs[0]
|
||||
HTTPAddr = strs[0]
|
||||
}
|
||||
if len(strs) > 1 && strs[1] != "" {
|
||||
HttpPort, _ = strconv.Atoi(strs[1])
|
||||
HTTPPort, _ = strconv.Atoi(strs[1])
|
||||
}
|
||||
}
|
||||
initBeforeHttpRun()
|
||||
|
||||
if EnableAdmin {
|
||||
go beeAdminApp.Run()
|
||||
}
|
||||
|
||||
BeeApp.Run()
|
||||
}
|
||||
|
||||
func initBeforeHttpRun() {
|
||||
func initBeforeHTTPRun() {
|
||||
// if AppConfigPath not In the conf/app.conf reParse config
|
||||
if AppConfigPath != filepath.Join(AppPath, "conf", "app.conf") {
|
||||
err := ParseConfig()
|
||||
@ -287,53 +68,22 @@ func initBeforeHttpRun() {
|
||||
}
|
||||
}
|
||||
|
||||
//init mime
|
||||
AddAPPStartHook(initMime)
|
||||
//init hooks
|
||||
AddAPPStartHook(registerMime)
|
||||
AddAPPStartHook(registerDefaultErrorHandler)
|
||||
AddAPPStartHook(registerSession)
|
||||
AddAPPStartHook(registerDocs)
|
||||
AddAPPStartHook(registerTemplate)
|
||||
AddAPPStartHook(registerAdmin)
|
||||
|
||||
// do hooks function
|
||||
for _, hk := range hooks {
|
||||
err := hk()
|
||||
if err != nil {
|
||||
if err := hk(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
if SessionOn {
|
||||
var err error
|
||||
sessionConfig := AppConfig.String("sessionConfig")
|
||||
if sessionConfig == "" {
|
||||
sessionConfig = `{"cookieName":"` + SessionName + `",` +
|
||||
`"gclifetime":` + strconv.FormatInt(SessionGCMaxLifetime, 10) + `,` +
|
||||
`"providerConfig":"` + filepath.ToSlash(SessionSavePath) + `",` +
|
||||
`"secure":` + strconv.FormatBool(EnableHttpTLS) + `,` +
|
||||
`"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` +
|
||||
`"domain":"` + SessionDomain + `",` +
|
||||
`"cookieLifeTime":` + strconv.Itoa(SessionCookieLifeTime) + `}`
|
||||
}
|
||||
GlobalSessions, err = session.NewManager(SessionProvider,
|
||||
sessionConfig)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
go GlobalSessions.GC()
|
||||
}
|
||||
|
||||
err := BuildTemplate(ViewsPath)
|
||||
if err != nil {
|
||||
if RunMode == "dev" {
|
||||
Warn(err)
|
||||
}
|
||||
}
|
||||
|
||||
registerDefaultErrorHandler()
|
||||
|
||||
if EnableDocs {
|
||||
Get("/docs", serverDocs)
|
||||
Get("/docs/*", serverDocs)
|
||||
}
|
||||
}
|
||||
|
||||
// this function is for test package init
|
||||
// TestBeegoInit is for test package init
|
||||
func TestBeegoInit(apppath string) {
|
||||
AppPath = apppath
|
||||
os.Setenv("BEEGO_RUNMODE", "test")
|
||||
@ -344,9 +94,5 @@ func TestBeegoInit(apppath string) {
|
||||
Info(err)
|
||||
}
|
||||
os.Chdir(AppPath)
|
||||
initBeforeHttpRun()
|
||||
}
|
||||
|
||||
func init() {
|
||||
hooks = make([]hookfunc, 0)
|
||||
initBeforeHTTPRun()
|
||||
}
|
||||
|
4
cache/README.md
vendored
4
cache/README.md
vendored
@ -43,7 +43,7 @@ interval means the gc time. The cache will check at each time interval, whether
|
||||
|
||||
## Memcache adapter
|
||||
|
||||
Memcache adapter use the vitess's [Memcache](http://code.google.com/p/vitess/go/memcache) client.
|
||||
Memcache adapter use the [gomemcache](http://github.com/bradfitz/gomemcache) client.
|
||||
|
||||
Configure like this:
|
||||
|
||||
@ -52,7 +52,7 @@ Configure like this:
|
||||
|
||||
## Redis adapter
|
||||
|
||||
Redis adapter use the [redigo](http://github.com/garyburd/redigo/redis) client.
|
||||
Redis adapter use the [redigo](http://github.com/garyburd/redigo) client.
|
||||
|
||||
Configure like this:
|
||||
|
||||
|
3
cache/cache.go
vendored
3
cache/cache.go
vendored
@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package cache provide a Cache interface and some implemetn engine
|
||||
// Usage:
|
||||
//
|
||||
// import(
|
||||
@ -80,7 +81,7 @@ func Register(name string, adapter Cache) {
|
||||
adapters[name] = adapter
|
||||
}
|
||||
|
||||
// Create a new cache driver by adapter name and config string.
|
||||
// NewCache Create a new cache driver by adapter name and config string.
|
||||
// config need to be correct JSON as string: {"interval":360}.
|
||||
// it will start gc automatically.
|
||||
func NewCache(adapterName, config string) (adapter Cache, err error) {
|
||||
|
12
cache/conv.go
vendored
12
cache/conv.go
vendored
@ -19,7 +19,7 @@ import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// convert interface to string.
|
||||
// GetString convert interface to string.
|
||||
func GetString(v interface{}) string {
|
||||
switch result := v.(type) {
|
||||
case string:
|
||||
@ -34,7 +34,7 @@ func GetString(v interface{}) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// convert interface to int.
|
||||
// GetInt convert interface to int.
|
||||
func GetInt(v interface{}) int {
|
||||
switch result := v.(type) {
|
||||
case int:
|
||||
@ -52,7 +52,7 @@ func GetInt(v interface{}) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// convert interface to int64.
|
||||
// GetInt64 convert interface to int64.
|
||||
func GetInt64(v interface{}) int64 {
|
||||
switch result := v.(type) {
|
||||
case int:
|
||||
@ -71,7 +71,7 @@ func GetInt64(v interface{}) int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// convert interface to float64.
|
||||
// GetFloat64 convert interface to float64.
|
||||
func GetFloat64(v interface{}) float64 {
|
||||
switch result := v.(type) {
|
||||
case float64:
|
||||
@ -85,7 +85,7 @@ func GetFloat64(v interface{}) float64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// convert interface to bool.
|
||||
// GetBool convert interface to bool.
|
||||
func GetBool(v interface{}) bool {
|
||||
switch result := v.(type) {
|
||||
case bool:
|
||||
@ -99,7 +99,7 @@ func GetBool(v interface{}) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// convert interface to byte slice.
|
||||
// getByteArray convert interface to byte slice.
|
||||
func getByteArray(v interface{}) []byte {
|
||||
switch result := v.(type) {
|
||||
case []byte:
|
||||
|
14
cache/conv_test.go
vendored
14
cache/conv_test.go
vendored
@ -27,7 +27,7 @@ func TestGetString(t *testing.T) {
|
||||
if "test2" != GetString(t2) {
|
||||
t.Error("get string from byte array error")
|
||||
}
|
||||
var t3 int = 1
|
||||
var t3 = 1
|
||||
if "1" != GetString(t3) {
|
||||
t.Error("get string from int error")
|
||||
}
|
||||
@ -35,7 +35,7 @@ func TestGetString(t *testing.T) {
|
||||
if "1" != GetString(t4) {
|
||||
t.Error("get string from int64 error")
|
||||
}
|
||||
var t5 float64 = 1.1
|
||||
var t5 = 1.1
|
||||
if "1.1" != GetString(t5) {
|
||||
t.Error("get string from float64 error")
|
||||
}
|
||||
@ -46,7 +46,7 @@ func TestGetString(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetInt(t *testing.T) {
|
||||
var t1 int = 1
|
||||
var t1 = 1
|
||||
if 1 != GetInt(t1) {
|
||||
t.Error("get int from int error")
|
||||
}
|
||||
@ -69,7 +69,7 @@ func TestGetInt(t *testing.T) {
|
||||
|
||||
func TestGetInt64(t *testing.T) {
|
||||
var i int64 = 1
|
||||
var t1 int = 1
|
||||
var t1 = 1
|
||||
if i != GetInt64(t1) {
|
||||
t.Error("get int64 from int error")
|
||||
}
|
||||
@ -91,12 +91,12 @@ func TestGetInt64(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetFloat64(t *testing.T) {
|
||||
var f float64 = 1.11
|
||||
var f = 1.11
|
||||
var t1 float32 = 1.11
|
||||
if f != GetFloat64(t1) {
|
||||
t.Error("get float64 from float32 error")
|
||||
}
|
||||
var t2 float64 = 1.11
|
||||
var t2 = 1.11
|
||||
if f != GetFloat64(t2) {
|
||||
t.Error("get float64 from float64 error")
|
||||
}
|
||||
@ -106,7 +106,7 @@ func TestGetFloat64(t *testing.T) {
|
||||
}
|
||||
|
||||
var f2 float64 = 1
|
||||
var t4 int = 1
|
||||
var t4 = 1
|
||||
if f2 != GetFloat64(t4) {
|
||||
t.Error("get float64 from int error")
|
||||
}
|
||||
|
45
cache/file.go
vendored
45
cache/file.go
vendored
@ -41,11 +41,12 @@ type FileCacheItem struct {
|
||||
Expired int64
|
||||
}
|
||||
|
||||
// FileCache Config
|
||||
var (
|
||||
FileCachePath string = "cache" // cache directory
|
||||
FileCacheFileSuffix string = ".bin" // cache file suffix
|
||||
FileCacheDirectoryLevel int = 2 // cache file deep level if auto generated cache files.
|
||||
FileCacheEmbedExpiry int64 = 0 // cache expire time, default is no expire forever.
|
||||
FileCachePath = "cache" // cache directory
|
||||
FileCacheFileSuffix = ".bin" // cache file suffix
|
||||
FileCacheDirectoryLevel = 2 // cache file deep level if auto generated cache files.
|
||||
FileCacheEmbedExpiry int64 // cache expire time, default is no expire forever.
|
||||
)
|
||||
|
||||
// FileCache is cache adapter for file storage.
|
||||
@ -56,14 +57,14 @@ type FileCache struct {
|
||||
EmbedExpiry int
|
||||
}
|
||||
|
||||
// Create new file cache with no config.
|
||||
// NewFileCache Create new file cache with no config.
|
||||
// the level and expiry need set in method StartAndGC as config string.
|
||||
func NewFileCache() *FileCache {
|
||||
// return &FileCache{CachePath:FileCachePath, FileSuffix:FileCacheFileSuffix}
|
||||
return &FileCache{}
|
||||
}
|
||||
|
||||
// Start and begin gc for file cache.
|
||||
// StartAndGC will start and begin gc for file cache.
|
||||
// the config need to be like {CachePath:"/cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}
|
||||
func (fc *FileCache) StartAndGC(config string) error {
|
||||
|
||||
@ -120,12 +121,12 @@ func (fc *FileCache) getCacheFileName(key string) string {
|
||||
// Get value from file cache.
|
||||
// if non-exist or expired, return empty string.
|
||||
func (fc *FileCache) Get(key string) interface{} {
|
||||
fileData, err := File_get_contents(fc.getCacheFileName(key))
|
||||
fileData, err := FileGetContents(fc.getCacheFileName(key))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
var to FileCacheItem
|
||||
Gob_decode(fileData, &to)
|
||||
GobDecode(fileData, &to)
|
||||
if to.Expired < time.Now().Unix() {
|
||||
return ""
|
||||
}
|
||||
@ -155,11 +156,11 @@ func (fc *FileCache) Put(key string, val interface{}, timeout int64) error {
|
||||
item.Expired = time.Now().Unix() + timeout
|
||||
}
|
||||
item.Lastaccess = time.Now().Unix()
|
||||
data, err := Gob_encode(item)
|
||||
data, err := GobEncode(item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return File_put_contents(fc.getCacheFileName(key), data)
|
||||
return FilePutContents(fc.getCacheFileName(key), data)
|
||||
}
|
||||
|
||||
// Delete file cache value.
|
||||
@ -171,7 +172,7 @@ func (fc *FileCache) Delete(key string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Increase cached int value.
|
||||
// Incr will increase cached int value.
|
||||
// fc value is saving forever unless Delete.
|
||||
func (fc *FileCache) Incr(key string) error {
|
||||
data := fc.Get(key)
|
||||
@ -185,7 +186,7 @@ func (fc *FileCache) Incr(key string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decrease cached int value.
|
||||
// Decr will decrease cached int value.
|
||||
func (fc *FileCache) Decr(key string) error {
|
||||
data := fc.Get(key)
|
||||
var decr int
|
||||
@ -198,13 +199,13 @@ func (fc *FileCache) Decr(key string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check value is exist.
|
||||
// IsExist check value is exist.
|
||||
func (fc *FileCache) IsExist(key string) bool {
|
||||
ret, _ := exists(fc.getCacheFileName(key))
|
||||
return ret
|
||||
}
|
||||
|
||||
// Clean cached files.
|
||||
// ClearAll will clean cached files.
|
||||
// not implemented.
|
||||
func (fc *FileCache) ClearAll() error {
|
||||
return nil
|
||||
@ -222,9 +223,9 @@ func exists(path string) (bool, error) {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Get bytes to file.
|
||||
// FileGetContents Get bytes to file.
|
||||
// if non-exist, create this file.
|
||||
func File_get_contents(filename string) (data []byte, e error) {
|
||||
func FileGetContents(filename string) (data []byte, e error) {
|
||||
f, e := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm)
|
||||
if e != nil {
|
||||
return
|
||||
@ -242,9 +243,9 @@ func File_get_contents(filename string) (data []byte, e error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Put bytes to file.
|
||||
// FilePutContents Put bytes to file.
|
||||
// if non-exist, create this file.
|
||||
func File_put_contents(filename string, content []byte) error {
|
||||
func FilePutContents(filename string, content []byte) error {
|
||||
fp, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -254,8 +255,8 @@ func File_put_contents(filename string, content []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Gob encodes file cache item.
|
||||
func Gob_encode(data interface{}) ([]byte, error) {
|
||||
// GobEncode Gob encodes file cache item.
|
||||
func GobEncode(data interface{}) ([]byte, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := gob.NewEncoder(buf)
|
||||
err := enc.Encode(data)
|
||||
@ -265,8 +266,8 @@ func Gob_encode(data interface{}) ([]byte, error) {
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
// Gob decodes file cache item.
|
||||
func Gob_decode(data []byte, to *FileCacheItem) error {
|
||||
// GobDecode Gob decodes file cache item.
|
||||
func GobDecode(data []byte, to *FileCacheItem) error {
|
||||
buf := bytes.NewBuffer(data)
|
||||
dec := gob.NewDecoder(buf)
|
||||
return dec.Decode(&to)
|
||||
|
59
cache/memcache/memcache.go
vendored
59
cache/memcache/memcache.go
vendored
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// package memcahe for cache provider
|
||||
// Package memcache for cache provider
|
||||
//
|
||||
// depend on github.com/bradfitz/gomemcache/memcache
|
||||
//
|
||||
@ -39,19 +39,19 @@ import (
|
||||
"github.com/astaxie/beego/cache"
|
||||
)
|
||||
|
||||
// Memcache adapter.
|
||||
type MemcacheCache struct {
|
||||
// Cache Memcache adapter.
|
||||
type Cache struct {
|
||||
conn *memcache.Client
|
||||
conninfo []string
|
||||
}
|
||||
|
||||
// create new memcache adapter.
|
||||
func NewMemCache() *MemcacheCache {
|
||||
return &MemcacheCache{}
|
||||
// NewMemCache create new memcache adapter.
|
||||
func NewMemCache() *Cache {
|
||||
return &Cache{}
|
||||
}
|
||||
|
||||
// get value from memcache.
|
||||
func (rc *MemcacheCache) Get(key string) interface{} {
|
||||
// Get get value from memcache.
|
||||
func (rc *Cache) Get(key string) interface{} {
|
||||
if rc.conn == nil {
|
||||
if err := rc.connectInit(); err != nil {
|
||||
return err
|
||||
@ -63,8 +63,8 @@ func (rc *MemcacheCache) Get(key string) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
// get value from memcache.
|
||||
func (rc *MemcacheCache) GetMulti(keys []string) []interface{} {
|
||||
// GetMulti get value from memcache.
|
||||
func (rc *Cache) GetMulti(keys []string) []interface{} {
|
||||
size := len(keys)
|
||||
var rv []interface{}
|
||||
if rc.conn == nil {
|
||||
@ -81,16 +81,15 @@ func (rc *MemcacheCache) GetMulti(keys []string) []interface{} {
|
||||
rv = append(rv, string(v.Value))
|
||||
}
|
||||
return rv
|
||||
} else {
|
||||
for i := 0; i < size; i++ {
|
||||
rv = append(rv, err)
|
||||
}
|
||||
return rv
|
||||
}
|
||||
for i := 0; i < size; i++ {
|
||||
rv = append(rv, err)
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
// put value to memcache. only support string.
|
||||
func (rc *MemcacheCache) Put(key string, val interface{}, timeout int64) error {
|
||||
// Put put value to memcache. only support string.
|
||||
func (rc *Cache) Put(key string, val interface{}, timeout int64) error {
|
||||
if rc.conn == nil {
|
||||
if err := rc.connectInit(); err != nil {
|
||||
return err
|
||||
@ -104,8 +103,8 @@ func (rc *MemcacheCache) Put(key string, val interface{}, timeout int64) error {
|
||||
return rc.conn.Set(&item)
|
||||
}
|
||||
|
||||
// delete value in memcache.
|
||||
func (rc *MemcacheCache) Delete(key string) error {
|
||||
// Delete delete value in memcache.
|
||||
func (rc *Cache) Delete(key string) error {
|
||||
if rc.conn == nil {
|
||||
if err := rc.connectInit(); err != nil {
|
||||
return err
|
||||
@ -114,8 +113,8 @@ func (rc *MemcacheCache) Delete(key string) error {
|
||||
return rc.conn.Delete(key)
|
||||
}
|
||||
|
||||
// increase counter.
|
||||
func (rc *MemcacheCache) Incr(key string) error {
|
||||
// Incr increase counter.
|
||||
func (rc *Cache) Incr(key string) error {
|
||||
if rc.conn == nil {
|
||||
if err := rc.connectInit(); err != nil {
|
||||
return err
|
||||
@ -125,8 +124,8 @@ func (rc *MemcacheCache) Incr(key string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// decrease counter.
|
||||
func (rc *MemcacheCache) Decr(key string) error {
|
||||
// Decr decrease counter.
|
||||
func (rc *Cache) Decr(key string) error {
|
||||
if rc.conn == nil {
|
||||
if err := rc.connectInit(); err != nil {
|
||||
return err
|
||||
@ -136,8 +135,8 @@ func (rc *MemcacheCache) Decr(key string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// check value exists in memcache.
|
||||
func (rc *MemcacheCache) IsExist(key string) bool {
|
||||
// IsExist check value exists in memcache.
|
||||
func (rc *Cache) IsExist(key string) bool {
|
||||
if rc.conn == nil {
|
||||
if err := rc.connectInit(); err != nil {
|
||||
return false
|
||||
@ -150,8 +149,8 @@ func (rc *MemcacheCache) IsExist(key string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// clear all cached in memcache.
|
||||
func (rc *MemcacheCache) ClearAll() error {
|
||||
// ClearAll clear all cached in memcache.
|
||||
func (rc *Cache) ClearAll() error {
|
||||
if rc.conn == nil {
|
||||
if err := rc.connectInit(); err != nil {
|
||||
return err
|
||||
@ -160,10 +159,10 @@ func (rc *MemcacheCache) ClearAll() error {
|
||||
return rc.conn.FlushAll()
|
||||
}
|
||||
|
||||
// start memcache adapter.
|
||||
// StartAndGC start memcache adapter.
|
||||
// config string is like {"conn":"connection info"}.
|
||||
// if connecting error, return.
|
||||
func (rc *MemcacheCache) StartAndGC(config string) error {
|
||||
func (rc *Cache) StartAndGC(config string) error {
|
||||
var cf map[string]string
|
||||
json.Unmarshal([]byte(config), &cf)
|
||||
if _, ok := cf["conn"]; !ok {
|
||||
@ -179,7 +178,7 @@ func (rc *MemcacheCache) StartAndGC(config string) error {
|
||||
}
|
||||
|
||||
// connect to memcache and keep the connection.
|
||||
func (rc *MemcacheCache) connectInit() error {
|
||||
func (rc *Cache) connectInit() error {
|
||||
rc.conn = memcache.New(rc.conninfo...)
|
||||
return nil
|
||||
}
|
||||
|
2
cache/memcache/memcache_test.go
vendored
2
cache/memcache/memcache_test.go
vendored
@ -23,7 +23,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestRedisCache(t *testing.T) {
|
||||
func TestMemcacheCache(t *testing.T) {
|
||||
bm, err := cache.NewCache("memcache", `{"conn": "127.0.0.1:11211"}`)
|
||||
if err != nil {
|
||||
t.Error("init err")
|
||||
|
26
cache/memory.go
vendored
26
cache/memory.go
vendored
@ -23,18 +23,18 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// clock time of recycling the expired cache items in memory.
|
||||
DefaultEvery int = 60 // 1 minute
|
||||
// DefaultEvery means the clock time of recycling the expired cache items in memory.
|
||||
DefaultEvery = 60 // 1 minute
|
||||
)
|
||||
|
||||
// Memory cache item.
|
||||
// MemoryItem store enery cache item.
|
||||
type MemoryItem struct {
|
||||
val interface{}
|
||||
Lastaccess time.Time
|
||||
expired int64
|
||||
}
|
||||
|
||||
// Memory cache adapter.
|
||||
// MemoryCache is Memory cache adapter.
|
||||
// it contains a RW locker for safe map storage.
|
||||
type MemoryCache struct {
|
||||
lock sync.RWMutex
|
||||
@ -87,7 +87,7 @@ func (bc *MemoryCache) Put(name string, value interface{}, expired int64) error
|
||||
return nil
|
||||
}
|
||||
|
||||
/// Delete cache in memory.
|
||||
// Delete cache in memory.
|
||||
func (bc *MemoryCache) Delete(name string) error {
|
||||
bc.lock.Lock()
|
||||
defer bc.lock.Unlock()
|
||||
@ -101,7 +101,7 @@ func (bc *MemoryCache) Delete(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Increase cache counter in memory.
|
||||
// Incr increase cache counter in memory.
|
||||
// it supports int,int64,int32,uint,uint64,uint32.
|
||||
func (bc *MemoryCache) Incr(key string) error {
|
||||
bc.lock.RLock()
|
||||
@ -129,7 +129,7 @@ func (bc *MemoryCache) Incr(key string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decrease counter in memory.
|
||||
// Decr decrease counter in memory.
|
||||
func (bc *MemoryCache) Decr(key string) error {
|
||||
bc.lock.RLock()
|
||||
defer bc.lock.RUnlock()
|
||||
@ -168,7 +168,7 @@ func (bc *MemoryCache) Decr(key string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// check cache exist in memory.
|
||||
// IsExist check cache exist in memory.
|
||||
func (bc *MemoryCache) IsExist(name string) bool {
|
||||
bc.lock.RLock()
|
||||
defer bc.lock.RUnlock()
|
||||
@ -176,7 +176,7 @@ func (bc *MemoryCache) IsExist(name string) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// delete all cache in memory.
|
||||
// ClearAll will delete all cache in memory.
|
||||
func (bc *MemoryCache) ClearAll() error {
|
||||
bc.lock.Lock()
|
||||
defer bc.lock.Unlock()
|
||||
@ -184,7 +184,7 @@ func (bc *MemoryCache) ClearAll() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// start memory cache. it will check expiration in every clock time.
|
||||
// StartAndGC start memory cache. it will check expiration in every clock time.
|
||||
func (bc *MemoryCache) StartAndGC(config string) error {
|
||||
var cf map[string]int
|
||||
json.Unmarshal([]byte(config), &cf)
|
||||
@ -213,13 +213,13 @@ func (bc *MemoryCache) vaccuum() {
|
||||
return
|
||||
}
|
||||
for name := range bc.items {
|
||||
bc.item_expired(name)
|
||||
bc.itemExpired(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// item_expired returns true if an item is expired.
|
||||
func (bc *MemoryCache) item_expired(name string) bool {
|
||||
// itemExpired returns true if an item is expired.
|
||||
func (bc *MemoryCache) itemExpired(name string) bool {
|
||||
bc.lock.Lock()
|
||||
defer bc.lock.Unlock()
|
||||
itm, ok := bc.items[name]
|
||||
|
52
cache/redis/redis.go
vendored
52
cache/redis/redis.go
vendored
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// package redis for cache provider
|
||||
// Package redis for cache provider
|
||||
//
|
||||
// depend on github.com/garyburd/redigo/redis
|
||||
//
|
||||
@ -41,12 +41,12 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// the collection name of redis for cache adapter.
|
||||
DefaultKey string = "beecacheRedis"
|
||||
// DefaultKey the collection name of redis for cache adapter.
|
||||
DefaultKey = "beecacheRedis"
|
||||
)
|
||||
|
||||
// Redis cache adapter.
|
||||
type RedisCache struct {
|
||||
// Cache is Redis cache adapter.
|
||||
type Cache struct {
|
||||
p *redis.Pool // redis connection pool
|
||||
conninfo string
|
||||
dbNum int
|
||||
@ -54,13 +54,13 @@ type RedisCache struct {
|
||||
password string
|
||||
}
|
||||
|
||||
// create new redis cache with default collection name.
|
||||
func NewRedisCache() *RedisCache {
|
||||
return &RedisCache{key: DefaultKey}
|
||||
// NewRedisCache create new redis cache with default collection name.
|
||||
func NewRedisCache() *Cache {
|
||||
return &Cache{key: DefaultKey}
|
||||
}
|
||||
|
||||
// actually do the redis cmds
|
||||
func (rc *RedisCache) do(commandName string, args ...interface{}) (reply interface{}, err error) {
|
||||
func (rc *Cache) do(commandName string, args ...interface{}) (reply interface{}, err error) {
|
||||
c := rc.p.Get()
|
||||
defer c.Close()
|
||||
|
||||
@ -68,7 +68,7 @@ func (rc *RedisCache) do(commandName string, args ...interface{}) (reply interfa
|
||||
}
|
||||
|
||||
// Get cache from redis.
|
||||
func (rc *RedisCache) Get(key string) interface{} {
|
||||
func (rc *Cache) Get(key string) interface{} {
|
||||
if v, err := rc.do("GET", key); err == nil {
|
||||
return v
|
||||
}
|
||||
@ -76,7 +76,7 @@ func (rc *RedisCache) Get(key string) interface{} {
|
||||
}
|
||||
|
||||
// GetMulti get cache from redis.
|
||||
func (rc *RedisCache) GetMulti(keys []string) []interface{} {
|
||||
func (rc *Cache) GetMulti(keys []string) []interface{} {
|
||||
size := len(keys)
|
||||
var rv []interface{}
|
||||
c := rc.p.Get()
|
||||
@ -108,8 +108,8 @@ ERROR:
|
||||
return rv
|
||||
}
|
||||
|
||||
// put cache to redis.
|
||||
func (rc *RedisCache) Put(key string, val interface{}, timeout int64) error {
|
||||
// Put put cache to redis.
|
||||
func (rc *Cache) Put(key string, val interface{}, timeout int64) error {
|
||||
var err error
|
||||
if _, err = rc.do("SETEX", key, timeout, val); err != nil {
|
||||
return err
|
||||
@ -121,8 +121,8 @@ func (rc *RedisCache) Put(key string, val interface{}, timeout int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// delete cache in redis.
|
||||
func (rc *RedisCache) Delete(key string) error {
|
||||
// Delete delete cache in redis.
|
||||
func (rc *Cache) Delete(key string) error {
|
||||
var err error
|
||||
if _, err = rc.do("DEL", key); err != nil {
|
||||
return err
|
||||
@ -131,8 +131,8 @@ func (rc *RedisCache) Delete(key string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// check cache's existence in redis.
|
||||
func (rc *RedisCache) IsExist(key string) bool {
|
||||
// IsExist check cache's existence in redis.
|
||||
func (rc *Cache) IsExist(key string) bool {
|
||||
v, err := redis.Bool(rc.do("EXISTS", key))
|
||||
if err != nil {
|
||||
return false
|
||||
@ -145,20 +145,20 @@ func (rc *RedisCache) IsExist(key string) bool {
|
||||
return v
|
||||
}
|
||||
|
||||
// increase counter in redis.
|
||||
func (rc *RedisCache) Incr(key string) error {
|
||||
// Incr increase counter in redis.
|
||||
func (rc *Cache) Incr(key string) error {
|
||||
_, err := redis.Bool(rc.do("INCRBY", key, 1))
|
||||
return err
|
||||
}
|
||||
|
||||
// decrease counter in redis.
|
||||
func (rc *RedisCache) Decr(key string) error {
|
||||
// Decr decrease counter in redis.
|
||||
func (rc *Cache) Decr(key string) error {
|
||||
_, err := redis.Bool(rc.do("INCRBY", key, -1))
|
||||
return err
|
||||
}
|
||||
|
||||
// clean all cache in redis. delete this redis collection.
|
||||
func (rc *RedisCache) ClearAll() error {
|
||||
// ClearAll clean all cache in redis. delete this redis collection.
|
||||
func (rc *Cache) ClearAll() error {
|
||||
cachedKeys, err := redis.Strings(rc.do("HKEYS", rc.key))
|
||||
if err != nil {
|
||||
return err
|
||||
@ -172,11 +172,11 @@ func (rc *RedisCache) ClearAll() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// start redis cache adapter.
|
||||
// StartAndGC start redis cache adapter.
|
||||
// config is like {"key":"collection key","conn":"connection info","dbNum":"0"}
|
||||
// the cache item in redis are stored forever,
|
||||
// so no gc operation.
|
||||
func (rc *RedisCache) StartAndGC(config string) error {
|
||||
func (rc *Cache) StartAndGC(config string) error {
|
||||
var cf map[string]string
|
||||
json.Unmarshal([]byte(config), &cf)
|
||||
|
||||
@ -206,7 +206,7 @@ func (rc *RedisCache) StartAndGC(config string) error {
|
||||
}
|
||||
|
||||
// connect to redis.
|
||||
func (rc *RedisCache) connectInit() {
|
||||
func (rc *Cache) connectInit() {
|
||||
dialFunc := func() (c redis.Conn, err error) {
|
||||
c, err = redis.Dial("tcp", rc.conninfo)
|
||||
if err != nil {
|
||||
|
239
config.go
239
config.go
@ -29,60 +29,115 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
BeeApp *App // beego application
|
||||
AppName string
|
||||
AppPath string
|
||||
workPath string
|
||||
AppConfigPath string
|
||||
StaticDir map[string]string
|
||||
TemplateCache map[string]*template.Template // template caching map
|
||||
StaticExtensionsToGzip []string // files with should be compressed with gzip (.js,.css,etc)
|
||||
EnableHttpListen bool
|
||||
HttpAddr string
|
||||
HttpPort int
|
||||
ListenTCP4 bool
|
||||
EnableHttpTLS bool
|
||||
HttpsPort int
|
||||
HttpCertFile string
|
||||
HttpKeyFile string
|
||||
RecoverPanic bool // flag of auto recover panic
|
||||
AutoRender bool // flag of render template automatically
|
||||
ViewsPath string
|
||||
AppConfig *beegoAppConfig
|
||||
RunMode string // run mode, "dev" or "prod"
|
||||
GlobalSessions *session.Manager // global session mananger
|
||||
SessionOn bool // flag of starting session auto. default is false.
|
||||
SessionProvider string // default session provider, memory, mysql , redis ,etc.
|
||||
SessionName string // the cookie name when saving session id into cookie.
|
||||
SessionGCMaxLifetime int64 // session gc time for auto cleaning expired session.
|
||||
SessionSavePath string // if use mysql/redis/file provider, define save path to connection info.
|
||||
SessionCookieLifeTime int // the life time of session id in cookie.
|
||||
SessionAutoSetCookie bool // auto setcookie
|
||||
SessionDomain string // the cookie domain default is empty
|
||||
UseFcgi bool
|
||||
UseStdIo bool
|
||||
MaxMemory int64
|
||||
EnableGzip bool // flag of enable gzip
|
||||
DirectoryIndex bool // flag of display directory index. default is false.
|
||||
HttpServerTimeOut int64
|
||||
ErrorsShow bool // flag of show errors in page. if true, show error and trace info in page rendered with error template.
|
||||
XSRFKEY string // xsrf hash salt string.
|
||||
EnableXSRF bool // flag of enable xsrf.
|
||||
XSRFExpire int // the expiry of xsrf value.
|
||||
CopyRequestBody bool // flag of copy raw request body in context.
|
||||
TemplateLeft string
|
||||
TemplateRight string
|
||||
BeegoServerName string // beego server name exported in response header.
|
||||
EnableAdmin bool // flag of enable admin module to log every request info.
|
||||
AdminHttpAddr string // http server configurations for admin module.
|
||||
AdminHttpPort int
|
||||
FlashName string // name of the flash variable found in response header and cookie
|
||||
FlashSeperator string // used to seperate flash key:value
|
||||
AppConfigProvider string // config provider
|
||||
EnableDocs bool // enable generate docs & server docs API Swagger
|
||||
RouterCaseSensitive bool // router case sensitive default is true
|
||||
AccessLogs bool // print access logs, default is false
|
||||
Graceful bool // use graceful start the server
|
||||
// AccessLogs represent whether output the access logs, default is false
|
||||
AccessLogs bool
|
||||
// AdminHTTPAddr is address for admin
|
||||
AdminHTTPAddr string
|
||||
// AdminHTTPPort is listens port for admin
|
||||
AdminHTTPPort int
|
||||
// AppConfig is the instance of Config, store the config information from file
|
||||
AppConfig *beegoAppConfig
|
||||
// AppName represent Application name, always the project folder name
|
||||
AppName string
|
||||
// AppPath is the path to the application
|
||||
AppPath string
|
||||
// AppConfigPath is the path to the config files
|
||||
AppConfigPath string
|
||||
// AppConfigProvider is the provider for the config, default is ini
|
||||
AppConfigProvider string
|
||||
// AutoRender is a flag of render template automatically. It's always turn off in API application
|
||||
// default is true
|
||||
AutoRender bool
|
||||
// BeegoServerName exported in response header.
|
||||
BeegoServerName string
|
||||
// CopyRequestBody is just useful for raw request body in context. default is false
|
||||
CopyRequestBody bool
|
||||
// DirectoryIndex wheather display directory index. default is false.
|
||||
DirectoryIndex bool
|
||||
// EnableAdmin means turn on admin module to log every request info.
|
||||
EnableAdmin bool
|
||||
// EnableDocs enable generate docs & server docs API Swagger
|
||||
EnableDocs bool
|
||||
// EnableErrorsShow wheather show errors in page. if true, show error and trace info in page rendered with error template.
|
||||
EnableErrorsShow bool
|
||||
// EnabelFcgi turn on the fcgi Listen, default is false
|
||||
EnabelFcgi bool
|
||||
// EnableGzip means gzip the response
|
||||
EnableGzip bool
|
||||
// EnableHTTPListen represent whether turn on the HTTP, default is true
|
||||
EnableHTTPListen bool
|
||||
// EnableHTTPTLS represent whether turn on the HTTPS, default is true
|
||||
EnableHTTPTLS bool
|
||||
// EnableStdIo works with EnabelFcgi Use FCGI via standard I/O
|
||||
EnableStdIo bool
|
||||
// EnableXSRF whether turn on xsrf. default is false
|
||||
EnableXSRF bool
|
||||
// FlashName is the name of the flash variable found in response header and cookie
|
||||
FlashName string
|
||||
// FlashSeperator used to seperate flash key:value, default is BEEGOFLASH
|
||||
FlashSeperator string
|
||||
// GlobalSessions is the instance for the session manager
|
||||
GlobalSessions *session.Manager
|
||||
// Graceful means use graceful module to start the server
|
||||
Graceful bool
|
||||
// workPath is always the same as AppPath, but sometime when it started with other
|
||||
// program, like supervisor
|
||||
workPath string
|
||||
// ListenTCP4 represent only Listen in TCP4, default is false
|
||||
ListenTCP4 bool
|
||||
// MaxMemory The whole request body is parsed and up to a total of maxMemory
|
||||
// bytes of its file parts are stored in memory, with the remainder stored on disk in temporary files
|
||||
MaxMemory int64
|
||||
// HTTPAddr is the TCP network address addr for HTTP
|
||||
HTTPAddr string
|
||||
// HTTPPort is listens port for HTTP
|
||||
HTTPPort int
|
||||
// HTTPSPort is listens port for HTTPS
|
||||
HTTPSPort int
|
||||
// HTTPCertFile is the path to certificate file
|
||||
HTTPCertFile string
|
||||
// HTTPKeyFile is the path to private key file
|
||||
HTTPKeyFile string
|
||||
// HTTPServerTimeOut HTTP server timeout. default is 0, no timeout
|
||||
HTTPServerTimeOut int64
|
||||
// RecoverPanic is a flag for auto recover panic, default is true
|
||||
RecoverPanic bool
|
||||
// RouterCaseSensitive means whether router case sensitive, default is true
|
||||
RouterCaseSensitive bool
|
||||
// RunMode represent the staging, "dev" or "prod"
|
||||
RunMode string
|
||||
// SessionOn means whether turn on the session auto when application started. default is false.
|
||||
SessionOn bool
|
||||
// SessionProvider means session provider, e.q memory, mysql, redis,etc.
|
||||
SessionProvider string
|
||||
// SessionName is the cookie name when saving session id into cookie.
|
||||
SessionName string
|
||||
// SessionGCMaxLifetime for auto cleaning expired session.
|
||||
SessionGCMaxLifetime int64
|
||||
// SessionProviderConfig is for the provider config, define save path or connection info.
|
||||
SessionProviderConfig string
|
||||
// SessionCookieLifeTime means the life time of session id in cookie.
|
||||
SessionCookieLifeTime int
|
||||
// SessionAutoSetCookie auto setcookie
|
||||
SessionAutoSetCookie bool
|
||||
// SessionDomain means the cookie domain default is empty
|
||||
SessionDomain string
|
||||
// StaticDir store the static path, key is path, value is the folder
|
||||
StaticDir map[string]string
|
||||
// StaticExtensionsToGzip stores the extensions which need to gzip(.js,.css,etc)
|
||||
StaticExtensionsToGzip []string
|
||||
// TemplateCache store the caching template
|
||||
TemplateCache map[string]*template.Template
|
||||
// TemplateLeft left delimiter
|
||||
TemplateLeft string
|
||||
// TemplateRight right delimiter
|
||||
TemplateRight string
|
||||
// ViewsPath means the template folder
|
||||
ViewsPath string
|
||||
// XSRFKEY xsrf hash salt string.
|
||||
XSRFKEY string
|
||||
// XSRFExpire is the expiry of xsrf value.
|
||||
XSRFExpire int
|
||||
)
|
||||
|
||||
type beegoAppConfig struct {
|
||||
@ -215,9 +270,6 @@ func (b *beegoAppConfig) SaveConfigFile(filename string) error {
|
||||
}
|
||||
|
||||
func init() {
|
||||
// create beego application
|
||||
BeeApp = NewApp()
|
||||
|
||||
workPath, _ = os.Getwd()
|
||||
workPath, _ = filepath.Abs(workPath)
|
||||
// initialize default configurations
|
||||
@ -243,12 +295,12 @@ func init() {
|
||||
TemplateCache = make(map[string]*template.Template)
|
||||
|
||||
// set this to 0.0.0.0 to make this app available to externally
|
||||
EnableHttpListen = true //default enable http Listen
|
||||
EnableHTTPListen = true //default enable http Listen
|
||||
|
||||
HttpAddr = ""
|
||||
HttpPort = 8080
|
||||
HTTPAddr = ""
|
||||
HTTPPort = 8080
|
||||
|
||||
HttpsPort = 10443
|
||||
HTTPSPort = 10443
|
||||
|
||||
AppName = "beego"
|
||||
|
||||
@ -264,20 +316,15 @@ func init() {
|
||||
SessionProvider = "memory"
|
||||
SessionName = "beegosessionID"
|
||||
SessionGCMaxLifetime = 3600
|
||||
SessionSavePath = ""
|
||||
SessionProviderConfig = ""
|
||||
SessionCookieLifeTime = 0 //set cookie default is the brower life
|
||||
SessionAutoSetCookie = true
|
||||
|
||||
UseFcgi = false
|
||||
UseStdIo = false
|
||||
|
||||
MaxMemory = 1 << 26 //64MB
|
||||
|
||||
EnableGzip = false
|
||||
HTTPServerTimeOut = 0
|
||||
|
||||
HttpServerTimeOut = 0
|
||||
|
||||
ErrorsShow = true
|
||||
EnableErrorsShow = true
|
||||
|
||||
XSRFKEY = "beegoxsrf"
|
||||
XSRFExpire = 0
|
||||
@ -288,8 +335,8 @@ func init() {
|
||||
BeegoServerName = "beegoServer:" + VERSION
|
||||
|
||||
EnableAdmin = false
|
||||
AdminHttpAddr = "127.0.0.1"
|
||||
AdminHttpPort = 8088
|
||||
AdminHTTPAddr = "127.0.0.1"
|
||||
AdminHTTPPort = 8088
|
||||
|
||||
FlashName = "BEEGO_FLASH"
|
||||
FlashSeperator = "BEEGOFLASH"
|
||||
@ -330,18 +377,18 @@ func ParseConfig() (err error) {
|
||||
RunMode = runmode
|
||||
}
|
||||
|
||||
HttpAddr = AppConfig.String("HttpAddr")
|
||||
HTTPAddr = AppConfig.String("HTTPAddr")
|
||||
|
||||
if v, err := AppConfig.Int("HttpPort"); err == nil {
|
||||
HttpPort = v
|
||||
if v, err := AppConfig.Int("HTTPPort"); err == nil {
|
||||
HTTPPort = v
|
||||
}
|
||||
|
||||
if v, err := AppConfig.Bool("ListenTCP4"); err == nil {
|
||||
ListenTCP4 = v
|
||||
}
|
||||
|
||||
if v, err := AppConfig.Bool("EnableHttpListen"); err == nil {
|
||||
EnableHttpListen = v
|
||||
if v, err := AppConfig.Bool("EnableHTTPListen"); err == nil {
|
||||
EnableHTTPListen = v
|
||||
}
|
||||
|
||||
if maxmemory, err := AppConfig.Int64("MaxMemory"); err == nil {
|
||||
@ -376,8 +423,8 @@ func ParseConfig() (err error) {
|
||||
SessionName = sessName
|
||||
}
|
||||
|
||||
if sesssavepath := AppConfig.String("SessionSavePath"); sesssavepath != "" {
|
||||
SessionSavePath = sesssavepath
|
||||
if sessProvConfig := AppConfig.String("SessionProviderConfig"); sessProvConfig != "" {
|
||||
SessionProviderConfig = sessProvConfig
|
||||
}
|
||||
|
||||
if sessMaxLifeTime, err := AppConfig.Int64("SessionGCMaxLifetime"); err == nil && sessMaxLifeTime != 0 {
|
||||
@ -388,8 +435,8 @@ func ParseConfig() (err error) {
|
||||
SessionCookieLifeTime = sesscookielifetime
|
||||
}
|
||||
|
||||
if usefcgi, err := AppConfig.Bool("UseFcgi"); err == nil {
|
||||
UseFcgi = usefcgi
|
||||
if enabelFcgi, err := AppConfig.Bool("EnabelFcgi"); err == nil {
|
||||
EnabelFcgi = enabelFcgi
|
||||
}
|
||||
|
||||
if enablegzip, err := AppConfig.Bool("EnableGzip"); err == nil {
|
||||
@ -400,12 +447,12 @@ func ParseConfig() (err error) {
|
||||
DirectoryIndex = directoryindex
|
||||
}
|
||||
|
||||
if timeout, err := AppConfig.Int64("HttpServerTimeOut"); err == nil {
|
||||
HttpServerTimeOut = timeout
|
||||
if timeout, err := AppConfig.Int64("HTTPServerTimeOut"); err == nil {
|
||||
HTTPServerTimeOut = timeout
|
||||
}
|
||||
|
||||
if errorsshow, err := AppConfig.Bool("ErrorsShow"); err == nil {
|
||||
ErrorsShow = errorsshow
|
||||
if errorsshow, err := AppConfig.Bool("EnableErrorsShow"); err == nil {
|
||||
EnableErrorsShow = errorsshow
|
||||
}
|
||||
|
||||
if copyrequestbody, err := AppConfig.Bool("CopyRequestBody"); err == nil {
|
||||
@ -432,20 +479,20 @@ func ParseConfig() (err error) {
|
||||
TemplateRight = tplright
|
||||
}
|
||||
|
||||
if httptls, err := AppConfig.Bool("EnableHttpTLS"); err == nil {
|
||||
EnableHttpTLS = httptls
|
||||
if httptls, err := AppConfig.Bool("EnableHTTPTLS"); err == nil {
|
||||
EnableHTTPTLS = httptls
|
||||
}
|
||||
|
||||
if httpsport, err := AppConfig.Int("HttpsPort"); err == nil {
|
||||
HttpsPort = httpsport
|
||||
if httpsport, err := AppConfig.Int("HTTPSPort"); err == nil {
|
||||
HTTPSPort = httpsport
|
||||
}
|
||||
|
||||
if certfile := AppConfig.String("HttpCertFile"); certfile != "" {
|
||||
HttpCertFile = certfile
|
||||
if certfile := AppConfig.String("HTTPCertFile"); certfile != "" {
|
||||
HTTPCertFile = certfile
|
||||
}
|
||||
|
||||
if keyfile := AppConfig.String("HttpKeyFile"); keyfile != "" {
|
||||
HttpKeyFile = keyfile
|
||||
if keyfile := AppConfig.String("HTTPKeyFile"); keyfile != "" {
|
||||
HTTPKeyFile = keyfile
|
||||
}
|
||||
|
||||
if serverName := AppConfig.String("BeegoServerName"); serverName != "" {
|
||||
@ -495,12 +542,12 @@ func ParseConfig() (err error) {
|
||||
EnableAdmin = enableadmin
|
||||
}
|
||||
|
||||
if adminhttpaddr := AppConfig.String("AdminHttpAddr"); adminhttpaddr != "" {
|
||||
AdminHttpAddr = adminhttpaddr
|
||||
if adminhttpaddr := AppConfig.String("AdminHTTPAddr"); adminhttpaddr != "" {
|
||||
AdminHTTPAddr = adminhttpaddr
|
||||
}
|
||||
|
||||
if adminhttpport, err := AppConfig.Int("AdminHttpPort"); err == nil {
|
||||
AdminHttpPort = adminhttpport
|
||||
if adminhttpport, err := AppConfig.Int("AdminHTTPPort"); err == nil {
|
||||
AdminHTTPPort = adminhttpport
|
||||
}
|
||||
|
||||
if enabledocs, err := AppConfig.Bool("EnableDocs"); err == nil {
|
||||
|
@ -88,12 +88,12 @@ func Register(name string, adapter Config) {
|
||||
|
||||
// adapterName is ini/json/xml/yaml.
|
||||
// filename is the config file path.
|
||||
func NewConfig(adapterName, fileaname string) (ConfigContainer, error) {
|
||||
func NewConfig(adapterName, filename string) (ConfigContainer, error) {
|
||||
adapter, ok := adapters[adapterName]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("config: unknown adaptername %q (forgotten import?)", adapterName)
|
||||
}
|
||||
return adapter.Parse(fileaname)
|
||||
return adapter.Parse(filename)
|
||||
}
|
||||
|
||||
// adapterName is ini/json/xml/yaml.
|
||||
|
@ -353,7 +353,7 @@ func (input *BeegoInput) Bind(dest interface{}, key string) error {
|
||||
}
|
||||
|
||||
func (input *BeegoInput) bind(key string, typ reflect.Type) reflect.Value {
|
||||
rv := reflect.Zero(reflect.TypeOf(0))
|
||||
rv := reflect.Zero(typ)
|
||||
switch typ.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
val := input.Query(key)
|
||||
@ -398,7 +398,7 @@ func (input *BeegoInput) bind(key string, typ reflect.Type) reflect.Value {
|
||||
}
|
||||
|
||||
func (input *BeegoInput) bindValue(val string, typ reflect.Type) reflect.Value {
|
||||
rv := reflect.Zero(reflect.TypeOf(0))
|
||||
rv := reflect.Zero(typ)
|
||||
switch typ.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
rv = input.bindInt(val, typ)
|
||||
|
147
controller.go
147
controller.go
@ -34,18 +34,19 @@ import (
|
||||
|
||||
//commonly used mime-types
|
||||
const (
|
||||
applicationJson = "application/json"
|
||||
applicationXml = "application/xml"
|
||||
textXml = "text/xml"
|
||||
applicationJSON = "application/json"
|
||||
applicationXML = "application/xml"
|
||||
textXML = "text/xml"
|
||||
)
|
||||
|
||||
var (
|
||||
// custom error when user stop request handler manually.
|
||||
USERSTOPRUN = errors.New("User stop run")
|
||||
GlobalControllerRouter map[string][]ControllerComments = make(map[string][]ControllerComments) //pkgpath+controller:comments
|
||||
// ErrAbort custom error when user stop request handler manually.
|
||||
ErrAbort = errors.New("User stop run")
|
||||
// GlobalControllerRouter store comments with controller. pkgpath+controller:comments
|
||||
GlobalControllerRouter = make(map[string][]ControllerComments)
|
||||
)
|
||||
|
||||
// store the comment for the controller method
|
||||
// ControllerComments store the comment for the controller method
|
||||
type ControllerComments struct {
|
||||
Method string
|
||||
Router string
|
||||
@ -64,7 +65,7 @@ type Controller struct {
|
||||
Layout string
|
||||
LayoutSections map[string]string // the key is the section name and the value is the template name
|
||||
TplExt string
|
||||
_xsrf_token string
|
||||
_xsrfToken string
|
||||
gotofunc string
|
||||
CruSession session.SessionStore
|
||||
XSRFExpire int
|
||||
@ -87,8 +88,8 @@ type ControllerInterface interface {
|
||||
Options()
|
||||
Finish()
|
||||
Render() error
|
||||
XsrfToken() string
|
||||
CheckXsrfCookie() bool
|
||||
XSRFToken() string
|
||||
CheckXSRFCookie() bool
|
||||
HandlerFunc(fn string) bool
|
||||
URLMapping()
|
||||
}
|
||||
@ -153,20 +154,20 @@ func (c *Controller) Options() {
|
||||
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
|
||||
}
|
||||
|
||||
// call function fn
|
||||
// HandlerFunc call function with the name
|
||||
func (c *Controller) HandlerFunc(fnname string) bool {
|
||||
if v, ok := c.methodMapping[fnname]; ok {
|
||||
v()
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// URLMapping register the internal Controller router.
|
||||
func (c *Controller) URLMapping() {
|
||||
}
|
||||
|
||||
// Mapping the method to function
|
||||
func (c *Controller) Mapping(method string, fn func()) {
|
||||
c.methodMapping[method] = fn
|
||||
}
|
||||
@ -177,13 +178,11 @@ func (c *Controller) Render() error {
|
||||
return nil
|
||||
}
|
||||
rb, err := c.RenderBytes()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8")
|
||||
c.Ctx.Output.Body(rb)
|
||||
}
|
||||
c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8")
|
||||
c.Ctx.Output.Body(rb)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -200,8 +199,19 @@ func (c *Controller) RenderBytes() ([]byte, error) {
|
||||
if c.TplNames == "" {
|
||||
c.TplNames = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt
|
||||
}
|
||||
|
||||
if RunMode == "dev" {
|
||||
BuildTemplate(ViewsPath)
|
||||
buildFiles := make([]string, 1)
|
||||
buildFiles = append(buildFiles, c.TplNames)
|
||||
if c.LayoutSections != nil {
|
||||
for _, sectionTpl := range c.LayoutSections {
|
||||
if sectionTpl == "" {
|
||||
continue
|
||||
}
|
||||
buildFiles = append(buildFiles, sectionTpl)
|
||||
}
|
||||
}
|
||||
BuildTemplate(ViewsPath, buildFiles...)
|
||||
}
|
||||
newbytes := bytes.NewBufferString("")
|
||||
if _, ok := BeeTemplates[c.TplNames]; !ok {
|
||||
@ -241,25 +251,25 @@ func (c *Controller) RenderBytes() ([]byte, error) {
|
||||
}
|
||||
icontent, _ := ioutil.ReadAll(ibytes)
|
||||
return icontent, nil
|
||||
} else {
|
||||
if c.TplNames == "" {
|
||||
c.TplNames = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt
|
||||
}
|
||||
if RunMode == "dev" {
|
||||
BuildTemplate(ViewsPath)
|
||||
}
|
||||
ibytes := bytes.NewBufferString("")
|
||||
if _, ok := BeeTemplates[c.TplNames]; !ok {
|
||||
panic("can't find templatefile in the path:" + c.TplNames)
|
||||
}
|
||||
err := BeeTemplates[c.TplNames].ExecuteTemplate(ibytes, c.TplNames, c.Data)
|
||||
if err != nil {
|
||||
Trace("template Execute err:", err)
|
||||
return nil, err
|
||||
}
|
||||
icontent, _ := ioutil.ReadAll(ibytes)
|
||||
return icontent, nil
|
||||
}
|
||||
|
||||
if c.TplNames == "" {
|
||||
c.TplNames = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt
|
||||
}
|
||||
if RunMode == "dev" {
|
||||
BuildTemplate(ViewsPath, c.TplNames)
|
||||
}
|
||||
ibytes := bytes.NewBufferString("")
|
||||
if _, ok := BeeTemplates[c.TplNames]; !ok {
|
||||
panic("can't find templatefile in the path:" + c.TplNames)
|
||||
}
|
||||
err := BeeTemplates[c.TplNames].ExecuteTemplate(ibytes, c.TplNames, c.Data)
|
||||
if err != nil {
|
||||
Trace("template Execute err:", err)
|
||||
return nil, err
|
||||
}
|
||||
icontent, _ := ioutil.ReadAll(ibytes)
|
||||
return icontent, nil
|
||||
}
|
||||
|
||||
// Redirect sends the redirection response to url with status code.
|
||||
@ -267,7 +277,7 @@ func (c *Controller) Redirect(url string, code int) {
|
||||
c.Ctx.Redirect(code, url)
|
||||
}
|
||||
|
||||
// Aborts stops controller handler and show the error data if code is defined in ErrorMap or code string.
|
||||
// Abort stops controller handler and show the error data if code is defined in ErrorMap or code string.
|
||||
func (c *Controller) Abort(code string) {
|
||||
status, err := strconv.Atoi(code)
|
||||
if err != nil {
|
||||
@ -285,29 +295,28 @@ func (c *Controller) CustomAbort(status int, body string) {
|
||||
}
|
||||
// last panic user string
|
||||
c.Ctx.ResponseWriter.Write([]byte(body))
|
||||
panic(USERSTOPRUN)
|
||||
panic(ErrAbort)
|
||||
}
|
||||
|
||||
// StopRun makes panic of USERSTOPRUN error and go to recover function if defined.
|
||||
func (c *Controller) StopRun() {
|
||||
panic(USERSTOPRUN)
|
||||
panic(ErrAbort)
|
||||
}
|
||||
|
||||
// UrlFor does another controller handler in this request function.
|
||||
// URLFor does another controller handler in this request function.
|
||||
// it goes to this controller method if endpoint is not clear.
|
||||
func (c *Controller) UrlFor(endpoint string, values ...interface{}) string {
|
||||
func (c *Controller) URLFor(endpoint string, values ...interface{}) string {
|
||||
if len(endpoint) <= 0 {
|
||||
return ""
|
||||
}
|
||||
if endpoint[0] == '.' {
|
||||
return UrlFor(reflect.Indirect(reflect.ValueOf(c.AppController)).Type().Name()+endpoint, values...)
|
||||
} else {
|
||||
return UrlFor(endpoint, values...)
|
||||
return URLFor(reflect.Indirect(reflect.ValueOf(c.AppController)).Type().Name()+endpoint, values...)
|
||||
}
|
||||
return URLFor(endpoint, values...)
|
||||
}
|
||||
|
||||
// ServeJson sends a json response with encoding charset.
|
||||
func (c *Controller) ServeJson(encoding ...bool) {
|
||||
// ServeJSON sends a json response with encoding charset.
|
||||
func (c *Controller) ServeJSON(encoding ...bool) {
|
||||
var hasIndent bool
|
||||
var hasencoding bool
|
||||
if RunMode == "prod" {
|
||||
@ -321,8 +330,8 @@ func (c *Controller) ServeJson(encoding ...bool) {
|
||||
c.Ctx.Output.Json(c.Data["json"], hasIndent, hasencoding)
|
||||
}
|
||||
|
||||
// ServeJsonp sends a jsonp response.
|
||||
func (c *Controller) ServeJsonp() {
|
||||
// ServeJSONP sends a jsonp response.
|
||||
func (c *Controller) ServeJSONP() {
|
||||
var hasIndent bool
|
||||
if RunMode == "prod" {
|
||||
hasIndent = false
|
||||
@ -332,8 +341,8 @@ func (c *Controller) ServeJsonp() {
|
||||
c.Ctx.Output.Jsonp(c.Data["jsonp"], hasIndent)
|
||||
}
|
||||
|
||||
// ServeXml sends xml response.
|
||||
func (c *Controller) ServeXml() {
|
||||
// ServeXML sends xml response.
|
||||
func (c *Controller) ServeXML() {
|
||||
var hasIndent bool
|
||||
if RunMode == "prod" {
|
||||
hasIndent = false
|
||||
@ -347,12 +356,12 @@ func (c *Controller) ServeXml() {
|
||||
func (c *Controller) ServeFormatted() {
|
||||
accept := c.Ctx.Input.Header("Accept")
|
||||
switch accept {
|
||||
case applicationJson:
|
||||
c.ServeJson()
|
||||
case applicationXml, textXml:
|
||||
c.ServeXml()
|
||||
case applicationJSON:
|
||||
c.ServeJSON()
|
||||
case applicationXML, textXML:
|
||||
c.ServeXML()
|
||||
default:
|
||||
c.ServeJson()
|
||||
c.ServeJSON()
|
||||
}
|
||||
}
|
||||
|
||||
@ -378,9 +387,8 @@ func (c *Controller) GetString(key string, def ...string) string {
|
||||
|
||||
if v := c.Ctx.Input.Query(key); v != "" {
|
||||
return v
|
||||
} else {
|
||||
return defv
|
||||
}
|
||||
return defv
|
||||
}
|
||||
|
||||
// GetStrings returns the input string slice by key string or the default value while it's present and input is blank
|
||||
@ -399,9 +407,8 @@ func (c *Controller) GetStrings(key string, def ...[]string) []string {
|
||||
vs := f[key]
|
||||
if len(vs) > 0 {
|
||||
return vs
|
||||
} else {
|
||||
return defv
|
||||
}
|
||||
return defv
|
||||
}
|
||||
|
||||
// GetInt returns input as an int or the default value while it's present and input is blank
|
||||
@ -575,7 +582,7 @@ func (c *Controller) GetSession(name interface{}) interface{} {
|
||||
return c.CruSession.Get(name)
|
||||
}
|
||||
|
||||
// SetSession removes value from session.
|
||||
// DelSession removes value from session.
|
||||
func (c *Controller) DelSession(name interface{}) {
|
||||
if c.CruSession == nil {
|
||||
c.StartSession()
|
||||
@ -614,34 +621,34 @@ func (c *Controller) SetSecureCookie(Secret, name, value string, others ...inter
|
||||
c.Ctx.SetSecureCookie(Secret, name, value, others...)
|
||||
}
|
||||
|
||||
// XsrfToken creates a xsrf token string and returns.
|
||||
func (c *Controller) XsrfToken() string {
|
||||
if c._xsrf_token == "" {
|
||||
// XSRFToken creates a CSRF token string and returns.
|
||||
func (c *Controller) XSRFToken() string {
|
||||
if c._xsrfToken == "" {
|
||||
var expire int64
|
||||
if c.XSRFExpire > 0 {
|
||||
expire = int64(c.XSRFExpire)
|
||||
} else {
|
||||
expire = int64(XSRFExpire)
|
||||
}
|
||||
c._xsrf_token = c.Ctx.XsrfToken(XSRFKEY, expire)
|
||||
c._xsrfToken = c.Ctx.XsrfToken(XSRFKEY, expire)
|
||||
}
|
||||
return c._xsrf_token
|
||||
return c._xsrfToken
|
||||
}
|
||||
|
||||
// CheckXsrfCookie checks xsrf token in this request is valid or not.
|
||||
// CheckXSRFCookie checks xsrf token in this request is valid or not.
|
||||
// the token can provided in request header "X-Xsrftoken" and "X-CsrfToken"
|
||||
// or in form field value named as "_xsrf".
|
||||
func (c *Controller) CheckXsrfCookie() bool {
|
||||
func (c *Controller) CheckXSRFCookie() bool {
|
||||
if !c.EnableXSRF {
|
||||
return true
|
||||
}
|
||||
return c.Ctx.CheckXsrfCookie()
|
||||
}
|
||||
|
||||
// XsrfFormHtml writes an input field contains xsrf token value.
|
||||
func (c *Controller) XsrfFormHtml() string {
|
||||
// XSRFFormHTML writes an input field contains xsrf token value.
|
||||
func (c *Controller) XSRFFormHTML() string {
|
||||
return "<input type=\"hidden\" name=\"_xsrf\" value=\"" +
|
||||
c._xsrf_token + "\"/>"
|
||||
c._xsrfToken + "\"/>"
|
||||
}
|
||||
|
||||
// GetControllerAndAction gets the executing controller name and action name.
|
||||
|
17
doc.go
Normal file
17
doc.go
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
Package beego provide a MVC framework
|
||||
beego: an open-source, high-performance, modular, full-stack web framework
|
||||
|
||||
It is used for rapid development of RESTful APIs, web apps and backend services in Go.
|
||||
beego is inspired by Tornado, Sinatra and Flask with the added benefit of some Go-specific features such as interfaces and struct embedding.
|
||||
|
||||
package main
|
||||
import "github.com/astaxie/beego"
|
||||
|
||||
func main() {
|
||||
beego.Run()
|
||||
}
|
||||
|
||||
more infomation: http://beego.me
|
||||
*/
|
||||
package beego
|
9
docs.go
9
docs.go
@ -20,20 +20,21 @@ import (
|
||||
"github.com/astaxie/beego/context"
|
||||
)
|
||||
|
||||
var GlobalDocApi map[string]interface{}
|
||||
// GlobalDocAPI store the swagger api documents
|
||||
var GlobalDocAPI map[string]interface{}
|
||||
|
||||
func init() {
|
||||
if EnableDocs {
|
||||
GlobalDocApi = make(map[string]interface{})
|
||||
GlobalDocAPI = make(map[string]interface{})
|
||||
}
|
||||
}
|
||||
|
||||
func serverDocs(ctx *context.Context) {
|
||||
var obj interface{}
|
||||
if splat := ctx.Input.Param(":splat"); splat == "" {
|
||||
obj = GlobalDocApi["Root"]
|
||||
obj = GlobalDocAPI["Root"]
|
||||
} else {
|
||||
if v, ok := GlobalDocApi[splat]; ok {
|
||||
if v, ok := GlobalDocAPI[splat]; ok {
|
||||
obj = v
|
||||
}
|
||||
}
|
||||
|
48
error.go
48
error.go
@ -358,52 +358,11 @@ func gatewayTimeout(rw http.ResponseWriter, r *http.Request) {
|
||||
t.Execute(rw, data)
|
||||
}
|
||||
|
||||
// register default error http handlers, 404,401,403,500 and 503.
|
||||
func registerDefaultErrorHandler() {
|
||||
if _, ok := ErrorMaps["401"]; !ok {
|
||||
Errorhandler("401", unauthorized)
|
||||
}
|
||||
|
||||
if _, ok := ErrorMaps["402"]; !ok {
|
||||
Errorhandler("402", paymentRequired)
|
||||
}
|
||||
|
||||
if _, ok := ErrorMaps["403"]; !ok {
|
||||
Errorhandler("403", forbidden)
|
||||
}
|
||||
|
||||
if _, ok := ErrorMaps["404"]; !ok {
|
||||
Errorhandler("404", notFound)
|
||||
}
|
||||
|
||||
if _, ok := ErrorMaps["405"]; !ok {
|
||||
Errorhandler("405", methodNotAllowed)
|
||||
}
|
||||
|
||||
if _, ok := ErrorMaps["500"]; !ok {
|
||||
Errorhandler("500", internalServerError)
|
||||
}
|
||||
if _, ok := ErrorMaps["501"]; !ok {
|
||||
Errorhandler("501", notImplemented)
|
||||
}
|
||||
if _, ok := ErrorMaps["502"]; !ok {
|
||||
Errorhandler("502", badGateway)
|
||||
}
|
||||
|
||||
if _, ok := ErrorMaps["503"]; !ok {
|
||||
Errorhandler("503", serviceUnavailable)
|
||||
}
|
||||
|
||||
if _, ok := ErrorMaps["504"]; !ok {
|
||||
Errorhandler("504", gatewayTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorHandler registers http.HandlerFunc to each http err code string.
|
||||
// usage:
|
||||
// beego.ErrorHandler("404",NotFound)
|
||||
// beego.ErrorHandler("500",InternalServerError)
|
||||
func Errorhandler(code string, h http.HandlerFunc) *App {
|
||||
func ErrorHandler(code string, h http.HandlerFunc) *App {
|
||||
errinfo := &errorInfo{}
|
||||
errinfo.errorType = errorTypeHandler
|
||||
errinfo.handler = h
|
||||
@ -414,7 +373,7 @@ func Errorhandler(code string, h http.HandlerFunc) *App {
|
||||
|
||||
// ErrorController registers ControllerInterface to each http err code string.
|
||||
// usage:
|
||||
// beego.ErrorHandler(&controllers.ErrorController{})
|
||||
// beego.ErrorController(&controllers.ErrorController{})
|
||||
func ErrorController(c ControllerInterface) *App {
|
||||
reflectVal := reflect.ValueOf(c)
|
||||
rt := reflectVal.Type()
|
||||
@ -453,7 +412,6 @@ func exception(errcode string, ctx *context.Context) {
|
||||
|
||||
func executeError(err *errorInfo, ctx *context.Context, code int) {
|
||||
if err.errorType == errorTypeHandler {
|
||||
ctx.ResponseWriter.WriteHeader(code)
|
||||
err.handler(ctx.ResponseWriter, ctx.Request)
|
||||
return
|
||||
}
|
||||
@ -473,7 +431,7 @@ func executeError(err *errorInfo, ctx *context.Context, code int) {
|
||||
|
||||
execController.URLMapping()
|
||||
|
||||
in := make([]reflect.Value, 0)
|
||||
var in []reflect.Value
|
||||
method := vc.MethodByName(err.method)
|
||||
method.Call(in)
|
||||
|
||||
|
@ -54,14 +54,13 @@ func (c *connection) readPump() {
|
||||
}()
|
||||
c.ws.SetReadLimit(maxMessageSize)
|
||||
c.ws.SetReadDeadline(time.Now().Add(readWait))
|
||||
c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(readWait)); return nil })
|
||||
for {
|
||||
op, r, err := c.ws.NextReader()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
switch op {
|
||||
case websocket.PongMessage:
|
||||
c.ws.SetReadDeadline(time.Now().Add(readWait))
|
||||
case websocket.TextMessage:
|
||||
message, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
|
@ -39,7 +39,6 @@ func (f *FilterRouter) ValidRouter(url string) (bool, map[string]string) {
|
||||
}
|
||||
if isok, ok := isok.(bool); ok {
|
||||
return isok, params
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ func (t *TestFlashController) TestWriteFlash() {
|
||||
flash.Notice("TestFlashString")
|
||||
flash.Store(&t.Controller)
|
||||
// we choose to serve json because we don't want to load a template html file
|
||||
t.ServeJson(true)
|
||||
t.ServeJSON(true)
|
||||
}
|
||||
|
||||
func TestFlashHeader(t *testing.T) {
|
||||
|
@ -32,7 +32,7 @@
|
||||
// mux := http.NewServeMux()
|
||||
// mux.HandleFunc("/hello", handler)
|
||||
//
|
||||
// err := grace.ListenAndServe("localhost:8080", mux1)
|
||||
// err := grace.ListenAndServe("localhost:8080", mux)
|
||||
// if err != nil {
|
||||
// log.Println(err)
|
||||
// }
|
||||
|
106
hooks.go
Normal file
106
hooks.go
Normal file
@ -0,0 +1,106 @@
|
||||
package beego
|
||||
|
||||
import (
|
||||
"mime"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/astaxie/beego/session"
|
||||
)
|
||||
|
||||
//
|
||||
func registerMime() error {
|
||||
for k, v := range mimemaps {
|
||||
mime.AddExtensionType(k, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// register default error http handlers, 404,401,403,500 and 503.
|
||||
func registerDefaultErrorHandler() error {
|
||||
if _, ok := ErrorMaps["401"]; !ok {
|
||||
ErrorHandler("401", unauthorized)
|
||||
}
|
||||
|
||||
if _, ok := ErrorMaps["402"]; !ok {
|
||||
ErrorHandler("402", paymentRequired)
|
||||
}
|
||||
|
||||
if _, ok := ErrorMaps["403"]; !ok {
|
||||
ErrorHandler("403", forbidden)
|
||||
}
|
||||
|
||||
if _, ok := ErrorMaps["404"]; !ok {
|
||||
ErrorHandler("404", notFound)
|
||||
}
|
||||
|
||||
if _, ok := ErrorMaps["405"]; !ok {
|
||||
ErrorHandler("405", methodNotAllowed)
|
||||
}
|
||||
|
||||
if _, ok := ErrorMaps["500"]; !ok {
|
||||
ErrorHandler("500", internalServerError)
|
||||
}
|
||||
if _, ok := ErrorMaps["501"]; !ok {
|
||||
ErrorHandler("501", notImplemented)
|
||||
}
|
||||
if _, ok := ErrorMaps["502"]; !ok {
|
||||
ErrorHandler("502", badGateway)
|
||||
}
|
||||
|
||||
if _, ok := ErrorMaps["503"]; !ok {
|
||||
ErrorHandler("503", serviceUnavailable)
|
||||
}
|
||||
|
||||
if _, ok := ErrorMaps["504"]; !ok {
|
||||
ErrorHandler("504", gatewayTimeout)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func registerSession() error {
|
||||
if SessionOn {
|
||||
var err error
|
||||
sessionConfig := AppConfig.String("sessionConfig")
|
||||
if sessionConfig == "" {
|
||||
sessionConfig = `{"cookieName":"` + SessionName + `",` +
|
||||
`"gclifetime":` + strconv.FormatInt(SessionGCMaxLifetime, 10) + `,` +
|
||||
`"providerConfig":"` + filepath.ToSlash(SessionProviderConfig) + `",` +
|
||||
`"secure":` + strconv.FormatBool(EnableHTTPTLS) + `,` +
|
||||
`"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` +
|
||||
`"domain":"` + SessionDomain + `",` +
|
||||
`"cookieLifeTime":` + strconv.Itoa(SessionCookieLifeTime) + `}`
|
||||
}
|
||||
GlobalSessions, err = session.NewManager(SessionProvider, sessionConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go GlobalSessions.GC()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func registerTemplate() error {
|
||||
if AutoRender {
|
||||
err := BuildTemplate(ViewsPath)
|
||||
if err != nil && RunMode == "dev" {
|
||||
Warn(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func registerDocs() error {
|
||||
if EnableDocs {
|
||||
Get("/docs", serverDocs)
|
||||
Get("/docs/*", serverDocs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func registerAdmin() error {
|
||||
if EnableAdmin {
|
||||
go beeAdminApp.Run()
|
||||
}
|
||||
return nil
|
||||
}
|
@ -74,12 +74,6 @@ func SetDefaultSetting(setting BeegoHttpSettings) {
|
||||
settingMutex.Lock()
|
||||
defer settingMutex.Unlock()
|
||||
defaultSetting = setting
|
||||
if defaultSetting.ConnectTimeout == 0 {
|
||||
defaultSetting.ConnectTimeout = 60 * time.Second
|
||||
}
|
||||
if defaultSetting.ReadWriteTimeout == 0 {
|
||||
defaultSetting.ReadWriteTimeout = 60 * time.Second
|
||||
}
|
||||
}
|
||||
|
||||
// return *BeegoHttpRequest with specific method
|
||||
@ -100,7 +94,7 @@ func NewBeegoRequest(rawurl, method string) *BeegoHttpRequest {
|
||||
return &BeegoHttpRequest{
|
||||
url: rawurl,
|
||||
req: &req,
|
||||
params: map[string]string{},
|
||||
params: map[string][]string{},
|
||||
files: map[string]string{},
|
||||
setting: defaultSetting,
|
||||
resp: &resp,
|
||||
@ -150,7 +144,7 @@ type BeegoHttpSettings struct {
|
||||
type BeegoHttpRequest struct {
|
||||
url string
|
||||
req *http.Request
|
||||
params map[string]string
|
||||
params map[string][]string
|
||||
files map[string]string
|
||||
setting BeegoHttpSettings
|
||||
resp *http.Response
|
||||
@ -273,7 +267,11 @@ func (b *BeegoHttpRequest) SetProxy(proxy func(*http.Request) (*url.URL, error))
|
||||
// Param adds query param in to request.
|
||||
// params build query string as ?key1=value1&key2=value2...
|
||||
func (b *BeegoHttpRequest) Param(key, value string) *BeegoHttpRequest {
|
||||
b.params[key] = value
|
||||
if param, ok := b.params[key]; ok {
|
||||
b.params[key] = append(param, value)
|
||||
} else {
|
||||
b.params[key] = []string{value}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
@ -348,7 +346,9 @@ func (b *BeegoHttpRequest) buildUrl(paramBody string) {
|
||||
}
|
||||
}
|
||||
for k, v := range b.params {
|
||||
bodyWriter.WriteField(k, v)
|
||||
for _, vv := range v {
|
||||
bodyWriter.WriteField(k, vv)
|
||||
}
|
||||
}
|
||||
bodyWriter.Close()
|
||||
pw.Close()
|
||||
@ -383,10 +383,12 @@ func (b *BeegoHttpRequest) SendOut() (*http.Response, error) {
|
||||
if len(b.params) > 0 {
|
||||
var buf bytes.Buffer
|
||||
for k, v := range b.params {
|
||||
buf.WriteString(url.QueryEscape(k))
|
||||
buf.WriteByte('=')
|
||||
buf.WriteString(url.QueryEscape(v))
|
||||
buf.WriteByte('&')
|
||||
for _, vv := range v {
|
||||
buf.WriteString(url.QueryEscape(k))
|
||||
buf.WriteByte('=')
|
||||
buf.WriteString(url.QueryEscape(vv))
|
||||
buf.WriteByte('&')
|
||||
}
|
||||
}
|
||||
paramBody = buf.String()
|
||||
paramBody = paramBody[0 : len(paramBody)-1]
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestResponse(t *testing.T) {
|
||||
@ -153,6 +154,7 @@ func TestWithSetting(t *testing.T) {
|
||||
setting.EnableCookie = true
|
||||
setting.UserAgent = v
|
||||
setting.Transport = nil
|
||||
setting.ReadWriteTimeout = 5 * time.Second
|
||||
SetDefaultSetting(setting)
|
||||
|
||||
str, err := Get("http://httpbin.org/get").String()
|
||||
|
15
log.go
15
log.go
@ -32,18 +32,18 @@ const (
|
||||
LevelDebug
|
||||
)
|
||||
|
||||
// SetLogLevel sets the global log level used by the simple
|
||||
// logger.
|
||||
// SetLevel sets the global log level used by the simple logger.
|
||||
func SetLevel(l int) {
|
||||
BeeLogger.SetLevel(l)
|
||||
}
|
||||
|
||||
// SetLogFuncCall set the CallDepth, default is 3
|
||||
func SetLogFuncCall(b bool) {
|
||||
BeeLogger.EnableFuncCallDepth(b)
|
||||
BeeLogger.SetLogFuncCallDepth(3)
|
||||
}
|
||||
|
||||
// logger references the used application logger.
|
||||
// BeeLogger references the used application logger.
|
||||
var BeeLogger *logs.BeeLogger
|
||||
|
||||
// SetLogger sets a new logger.
|
||||
@ -55,10 +55,12 @@ func SetLogger(adaptername string, config string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Emergency logs a message at emergency level.
|
||||
func Emergency(v ...interface{}) {
|
||||
BeeLogger.Emergency(generateFmtStr(len(v)), v...)
|
||||
}
|
||||
|
||||
// Alert logs a message at alert level.
|
||||
func Alert(v ...interface{}) {
|
||||
BeeLogger.Alert(generateFmtStr(len(v)), v...)
|
||||
}
|
||||
@ -78,21 +80,22 @@ func Warning(v ...interface{}) {
|
||||
BeeLogger.Warning(generateFmtStr(len(v)), v...)
|
||||
}
|
||||
|
||||
// compatibility alias for Warning()
|
||||
// Warn compatibility alias for Warning()
|
||||
func Warn(v ...interface{}) {
|
||||
BeeLogger.Warn(generateFmtStr(len(v)), v...)
|
||||
}
|
||||
|
||||
// Notice logs a message at notice level.
|
||||
func Notice(v ...interface{}) {
|
||||
BeeLogger.Notice(generateFmtStr(len(v)), v...)
|
||||
}
|
||||
|
||||
// Info logs a message at info level.
|
||||
// Informational logs a message at info level.
|
||||
func Informational(v ...interface{}) {
|
||||
BeeLogger.Informational(generateFmtStr(len(v)), v...)
|
||||
}
|
||||
|
||||
// compatibility alias for Warning()
|
||||
// Info compatibility alias for Warning()
|
||||
func Info(v ...interface{}) {
|
||||
BeeLogger.Info(generateFmtStr(len(v)), v...)
|
||||
}
|
||||
|
@ -205,15 +205,20 @@ func (w *FileLogWriter) lines() (int, error) {
|
||||
}
|
||||
|
||||
// DoRotate means it need to write file in new file.
|
||||
// new file name like xx.log.2013-01-01.2
|
||||
// new file name like xx.2013-01-01.2.log
|
||||
func (w *FileLogWriter) DoRotate() error {
|
||||
_, err := os.Lstat(w.Filename)
|
||||
if err == nil { // file exists
|
||||
// Find the next available number
|
||||
num := 1
|
||||
fname := ""
|
||||
suffix := filepath.Ext(w.Filename)
|
||||
filenameOnly := strings.TrimSuffix(w.Filename, suffix)
|
||||
if suffix == "" {
|
||||
suffix = ".log"
|
||||
}
|
||||
for ; err == nil && num <= 999; num++ {
|
||||
fname = w.Filename + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), num)
|
||||
fname = filenameOnly + fmt.Sprintf(".%s.%03d%s", time.Now().Format("2006-01-02"), num, suffix)
|
||||
_, err = os.Lstat(fname)
|
||||
}
|
||||
// return error if the last file checked still existed
|
||||
|
@ -103,7 +103,7 @@ func TestFileRotate(t *testing.T) {
|
||||
log.Critical("critical")
|
||||
log.Emergency("emergency")
|
||||
time.Sleep(time.Second * 4)
|
||||
rotatename := "test3.log" + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), 1)
|
||||
rotatename := "test3" + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), 1) + ".log"
|
||||
b, err := exists(rotatename)
|
||||
if !b || err != nil {
|
||||
t.Fatal("rotate not generated")
|
||||
|
@ -31,9 +31,9 @@ const (
|
||||
|
||||
// smtpWriter implements LoggerInterface and is used to send emails via given SMTP-server.
|
||||
type SmtpWriter struct {
|
||||
Username string `json:"Username"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Host string `json:"Host"`
|
||||
Host string `json:"host"`
|
||||
Subject string `json:"subject"`
|
||||
FromAddress string `json:"fromAddress"`
|
||||
RecipientAddresses []string `json:"sendTos"`
|
||||
|
@ -28,8 +28,10 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var gmfim map[string]*memFileInfo = make(map[string]*memFileInfo)
|
||||
var lock sync.RWMutex
|
||||
var (
|
||||
gmfim = make(map[string]*memFileInfo)
|
||||
lock sync.RWMutex
|
||||
)
|
||||
|
||||
// OpenMemZipFile returns MemFile object with a compressed static file.
|
||||
// it's used for serve static file if gzip enable.
|
||||
|
13
mime.go
13
mime.go
@ -14,11 +14,7 @@
|
||||
|
||||
package beego
|
||||
|
||||
import (
|
||||
"mime"
|
||||
)
|
||||
|
||||
var mimemaps map[string]string = map[string]string{
|
||||
var mimemaps = map[string]string{
|
||||
".3dm": "x-world/x-3dmf",
|
||||
".3dmf": "x-world/x-3dmf",
|
||||
".7z": "application/x-7z-compressed",
|
||||
@ -558,10 +554,3 @@ var mimemaps map[string]string = map[string]string{
|
||||
".oex": "application/x-opera-extension",
|
||||
".mustache": "text/html",
|
||||
}
|
||||
|
||||
func initMime() error {
|
||||
for k, v := range mimemaps {
|
||||
mime.AddExtensionType(k, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
107
namespace.go
107
namespace.go
@ -23,16 +23,17 @@ import (
|
||||
|
||||
type namespaceCond func(*beecontext.Context) bool
|
||||
|
||||
type innnerNamespace func(*Namespace)
|
||||
// LinkNamespace used as link action
|
||||
type LinkNamespace func(*Namespace)
|
||||
|
||||
// Namespace is store all the info
|
||||
type Namespace struct {
|
||||
prefix string
|
||||
handlers *ControllerRegistor
|
||||
handlers *ControllerRegister
|
||||
}
|
||||
|
||||
// get new Namespace
|
||||
func NewNamespace(prefix string, params ...innnerNamespace) *Namespace {
|
||||
// NewNamespace get new Namespace
|
||||
func NewNamespace(prefix string, params ...LinkNamespace) *Namespace {
|
||||
ns := &Namespace{
|
||||
prefix: prefix,
|
||||
handlers: NewControllerRegister(),
|
||||
@ -43,7 +44,7 @@ func NewNamespace(prefix string, params ...innnerNamespace) *Namespace {
|
||||
return ns
|
||||
}
|
||||
|
||||
// set condtion function
|
||||
// Cond set condtion function
|
||||
// if cond return true can run this namespace, else can't
|
||||
// usage:
|
||||
// ns.Cond(func (ctx *context.Context) bool{
|
||||
@ -72,7 +73,7 @@ func (n *Namespace) Cond(cond namespaceCond) *Namespace {
|
||||
return n
|
||||
}
|
||||
|
||||
// add filter in the Namespace
|
||||
// Filter add filter in the Namespace
|
||||
// action has before & after
|
||||
// FilterFunc
|
||||
// usage:
|
||||
@ -95,98 +96,98 @@ func (n *Namespace) Filter(action string, filter ...FilterFunc) *Namespace {
|
||||
return n
|
||||
}
|
||||
|
||||
// same as beego.Rourer
|
||||
// Router same as beego.Rourer
|
||||
// refer: https://godoc.org/github.com/astaxie/beego#Router
|
||||
func (n *Namespace) Router(rootpath string, c ControllerInterface, mappingMethods ...string) *Namespace {
|
||||
n.handlers.Add(rootpath, c, mappingMethods...)
|
||||
return n
|
||||
}
|
||||
|
||||
// same as beego.AutoRouter
|
||||
// AutoRouter same as beego.AutoRouter
|
||||
// refer: https://godoc.org/github.com/astaxie/beego#AutoRouter
|
||||
func (n *Namespace) AutoRouter(c ControllerInterface) *Namespace {
|
||||
n.handlers.AddAuto(c)
|
||||
return n
|
||||
}
|
||||
|
||||
// same as beego.AutoPrefix
|
||||
// AutoPrefix same as beego.AutoPrefix
|
||||
// refer: https://godoc.org/github.com/astaxie/beego#AutoPrefix
|
||||
func (n *Namespace) AutoPrefix(prefix string, c ControllerInterface) *Namespace {
|
||||
n.handlers.AddAutoPrefix(prefix, c)
|
||||
return n
|
||||
}
|
||||
|
||||
// same as beego.Get
|
||||
// Get same as beego.Get
|
||||
// refer: https://godoc.org/github.com/astaxie/beego#Get
|
||||
func (n *Namespace) Get(rootpath string, f FilterFunc) *Namespace {
|
||||
n.handlers.Get(rootpath, f)
|
||||
return n
|
||||
}
|
||||
|
||||
// same as beego.Post
|
||||
// Post same as beego.Post
|
||||
// refer: https://godoc.org/github.com/astaxie/beego#Post
|
||||
func (n *Namespace) Post(rootpath string, f FilterFunc) *Namespace {
|
||||
n.handlers.Post(rootpath, f)
|
||||
return n
|
||||
}
|
||||
|
||||
// same as beego.Delete
|
||||
// Delete same as beego.Delete
|
||||
// refer: https://godoc.org/github.com/astaxie/beego#Delete
|
||||
func (n *Namespace) Delete(rootpath string, f FilterFunc) *Namespace {
|
||||
n.handlers.Delete(rootpath, f)
|
||||
return n
|
||||
}
|
||||
|
||||
// same as beego.Put
|
||||
// Put same as beego.Put
|
||||
// refer: https://godoc.org/github.com/astaxie/beego#Put
|
||||
func (n *Namespace) Put(rootpath string, f FilterFunc) *Namespace {
|
||||
n.handlers.Put(rootpath, f)
|
||||
return n
|
||||
}
|
||||
|
||||
// same as beego.Head
|
||||
// Head same as beego.Head
|
||||
// refer: https://godoc.org/github.com/astaxie/beego#Head
|
||||
func (n *Namespace) Head(rootpath string, f FilterFunc) *Namespace {
|
||||
n.handlers.Head(rootpath, f)
|
||||
return n
|
||||
}
|
||||
|
||||
// same as beego.Options
|
||||
// Options same as beego.Options
|
||||
// refer: https://godoc.org/github.com/astaxie/beego#Options
|
||||
func (n *Namespace) Options(rootpath string, f FilterFunc) *Namespace {
|
||||
n.handlers.Options(rootpath, f)
|
||||
return n
|
||||
}
|
||||
|
||||
// same as beego.Patch
|
||||
// Patch same as beego.Patch
|
||||
// refer: https://godoc.org/github.com/astaxie/beego#Patch
|
||||
func (n *Namespace) Patch(rootpath string, f FilterFunc) *Namespace {
|
||||
n.handlers.Patch(rootpath, f)
|
||||
return n
|
||||
}
|
||||
|
||||
// same as beego.Any
|
||||
// Any same as beego.Any
|
||||
// refer: https://godoc.org/github.com/astaxie/beego#Any
|
||||
func (n *Namespace) Any(rootpath string, f FilterFunc) *Namespace {
|
||||
n.handlers.Any(rootpath, f)
|
||||
return n
|
||||
}
|
||||
|
||||
// same as beego.Handler
|
||||
// Handler same as beego.Handler
|
||||
// refer: https://godoc.org/github.com/astaxie/beego#Handler
|
||||
func (n *Namespace) Handler(rootpath string, h http.Handler) *Namespace {
|
||||
n.handlers.Handler(rootpath, h)
|
||||
return n
|
||||
}
|
||||
|
||||
// add include class
|
||||
// Include add include class
|
||||
// refer: https://godoc.org/github.com/astaxie/beego#Include
|
||||
func (n *Namespace) Include(cList ...ControllerInterface) *Namespace {
|
||||
n.handlers.Include(cList...)
|
||||
return n
|
||||
}
|
||||
|
||||
// nest Namespace
|
||||
// Namespace add nest Namespace
|
||||
// usage:
|
||||
//ns := beego.NewNamespace(“/v1”).
|
||||
//Namespace(
|
||||
@ -230,7 +231,7 @@ func (n *Namespace) Namespace(ns ...*Namespace) *Namespace {
|
||||
return n
|
||||
}
|
||||
|
||||
// register Namespace into beego.Handler
|
||||
// AddNamespace register Namespace into beego.Handler
|
||||
// support multi Namespace
|
||||
func AddNamespace(nl ...*Namespace) {
|
||||
for _, n := range nl {
|
||||
@ -275,113 +276,113 @@ func addPrefix(t *Tree, prefix string) {
|
||||
|
||||
}
|
||||
|
||||
// Namespace Condition
|
||||
func NSCond(cond namespaceCond) innnerNamespace {
|
||||
// NSCond is Namespace Condition
|
||||
func NSCond(cond namespaceCond) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
ns.Cond(cond)
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace BeforeRouter filter
|
||||
func NSBefore(filiterList ...FilterFunc) innnerNamespace {
|
||||
// NSBefore Namespace BeforeRouter filter
|
||||
func NSBefore(filiterList ...FilterFunc) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
ns.Filter("before", filiterList...)
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace FinishRouter filter
|
||||
func NSAfter(filiterList ...FilterFunc) innnerNamespace {
|
||||
// NSAfter add Namespace FinishRouter filter
|
||||
func NSAfter(filiterList ...FilterFunc) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
ns.Filter("after", filiterList...)
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace Include ControllerInterface
|
||||
func NSInclude(cList ...ControllerInterface) innnerNamespace {
|
||||
// NSInclude Namespace Include ControllerInterface
|
||||
func NSInclude(cList ...ControllerInterface) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
ns.Include(cList...)
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace Router
|
||||
func NSRouter(rootpath string, c ControllerInterface, mappingMethods ...string) innnerNamespace {
|
||||
// NSRouter call Namespace Router
|
||||
func NSRouter(rootpath string, c ControllerInterface, mappingMethods ...string) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
ns.Router(rootpath, c, mappingMethods...)
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace Get
|
||||
func NSGet(rootpath string, f FilterFunc) innnerNamespace {
|
||||
// NSGet call Namespace Get
|
||||
func NSGet(rootpath string, f FilterFunc) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
ns.Get(rootpath, f)
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace Post
|
||||
func NSPost(rootpath string, f FilterFunc) innnerNamespace {
|
||||
// NSPost call Namespace Post
|
||||
func NSPost(rootpath string, f FilterFunc) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
ns.Post(rootpath, f)
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace Head
|
||||
func NSHead(rootpath string, f FilterFunc) innnerNamespace {
|
||||
// NSHead call Namespace Head
|
||||
func NSHead(rootpath string, f FilterFunc) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
ns.Head(rootpath, f)
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace Put
|
||||
func NSPut(rootpath string, f FilterFunc) innnerNamespace {
|
||||
// NSPut call Namespace Put
|
||||
func NSPut(rootpath string, f FilterFunc) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
ns.Put(rootpath, f)
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace Delete
|
||||
func NSDelete(rootpath string, f FilterFunc) innnerNamespace {
|
||||
// NSDelete call Namespace Delete
|
||||
func NSDelete(rootpath string, f FilterFunc) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
ns.Delete(rootpath, f)
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace Any
|
||||
func NSAny(rootpath string, f FilterFunc) innnerNamespace {
|
||||
// NSAny call Namespace Any
|
||||
func NSAny(rootpath string, f FilterFunc) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
ns.Any(rootpath, f)
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace Options
|
||||
func NSOptions(rootpath string, f FilterFunc) innnerNamespace {
|
||||
// NSOptions call Namespace Options
|
||||
func NSOptions(rootpath string, f FilterFunc) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
ns.Options(rootpath, f)
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace Patch
|
||||
func NSPatch(rootpath string, f FilterFunc) innnerNamespace {
|
||||
// NSPatch call Namespace Patch
|
||||
func NSPatch(rootpath string, f FilterFunc) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
ns.Patch(rootpath, f)
|
||||
}
|
||||
}
|
||||
|
||||
//Namespace AutoRouter
|
||||
func NSAutoRouter(c ControllerInterface) innnerNamespace {
|
||||
// NSAutoRouter call Namespace AutoRouter
|
||||
func NSAutoRouter(c ControllerInterface) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
ns.AutoRouter(c)
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace AutoPrefix
|
||||
func NSAutoPrefix(prefix string, c ControllerInterface) innnerNamespace {
|
||||
// NSAutoPrefix call Namespace AutoPrefix
|
||||
func NSAutoPrefix(prefix string, c ControllerInterface) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
ns.AutoPrefix(prefix, c)
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace add sub Namespace
|
||||
func NSNamespace(prefix string, params ...innnerNamespace) innnerNamespace {
|
||||
// NSNamespace add sub Namespace
|
||||
func NSNamespace(prefix string, params ...LinkNamespace) LinkNamespace {
|
||||
return func(ns *Namespace) {
|
||||
n := NewNamespace(prefix, params...)
|
||||
ns.Namespace(n)
|
||||
|
10
orm/db.go
10
orm/db.go
@ -802,6 +802,7 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
|
||||
tables.parseRelated(qs.related, qs.relDepth)
|
||||
|
||||
where, args := tables.getCondSql(cond, false, tz)
|
||||
groupBy := tables.getGroupSql(qs.groups)
|
||||
orderBy := tables.getOrderSql(qs.orders)
|
||||
limit := tables.getLimitSql(mi, offset, rlimit)
|
||||
join := tables.getJoinSql()
|
||||
@ -814,7 +815,11 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
|
||||
}
|
||||
}
|
||||
|
||||
query := fmt.Sprintf("SELECT %s FROM %s%s%s T0 %s%s%s%s", sels, Q, mi.table, Q, join, where, orderBy, limit)
|
||||
sqlSelect := "SELECT"
|
||||
if qs.distinct {
|
||||
sqlSelect += " DISTINCT"
|
||||
}
|
||||
query := fmt.Sprintf("%s %s FROM %s%s%s T0 %s%s%s%s%s", sqlSelect, sels, Q, mi.table, Q, join, where, groupBy, orderBy, limit)
|
||||
|
||||
d.ins.ReplaceMarks(&query)
|
||||
|
||||
@ -1444,13 +1449,14 @@ func (d *dbBase) ReadValues(q dbQuerier, qs *querySet, mi *modelInfo, cond *Cond
|
||||
}
|
||||
|
||||
where, args := tables.getCondSql(cond, false, tz)
|
||||
groupBy := tables.getGroupSql(qs.groups)
|
||||
orderBy := tables.getOrderSql(qs.orders)
|
||||
limit := tables.getLimitSql(mi, qs.offset, qs.limit)
|
||||
join := tables.getJoinSql()
|
||||
|
||||
sels := strings.Join(cols, ", ")
|
||||
|
||||
query := fmt.Sprintf("SELECT %s FROM %s%s%s T0 %s%s%s%s", sels, Q, mi.table, Q, join, where, orderBy, limit)
|
||||
query := fmt.Sprintf("SELECT %s FROM %s%s%s T0 %s%s%s%s%s", sels, Q, mi.table, Q, join, where, groupBy,orderBy, limit)
|
||||
|
||||
d.ins.ReplaceMarks(&query)
|
||||
|
||||
|
@ -390,6 +390,30 @@ func (t *dbTables) getCondSql(cond *Condition, sub bool, tz *time.Location) (whe
|
||||
return
|
||||
}
|
||||
|
||||
// generate group sql.
|
||||
func (t *dbTables) getGroupSql(groups []string) (groupSql string) {
|
||||
if len(groups) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
Q := t.base.TableQuote()
|
||||
|
||||
groupSqls := make([]string, 0, len(groups))
|
||||
for _, group := range groups {
|
||||
exprs := strings.Split(group, ExprSep)
|
||||
|
||||
index, _, fi, suc := t.parseExprs(t.mi, exprs)
|
||||
if suc == false {
|
||||
panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(exprs, ExprSep)))
|
||||
}
|
||||
|
||||
groupSqls = append(groupSqls, fmt.Sprintf("%s.%s%s%s", index, Q, fi.column, Q))
|
||||
}
|
||||
|
||||
groupSql = fmt.Sprintf("GROUP BY %s ", strings.Join(groupSqls, ", "))
|
||||
return
|
||||
}
|
||||
|
||||
// generate order sql.
|
||||
func (t *dbTables) getOrderSql(orders []string) (orderSql string) {
|
||||
if len(orders) == 0 {
|
||||
|
@ -60,7 +60,9 @@ type querySet struct {
|
||||
relDepth int
|
||||
limit int64
|
||||
offset int64
|
||||
groups []string
|
||||
orders []string
|
||||
distinct bool
|
||||
orm *orm
|
||||
}
|
||||
|
||||
@ -105,6 +107,12 @@ func (o querySet) Offset(offset interface{}) QuerySeter {
|
||||
return &o
|
||||
}
|
||||
|
||||
// add GROUP expression
|
||||
func (o querySet) GroupBy(exprs ...string) QuerySeter {
|
||||
o.groups = exprs
|
||||
return &o
|
||||
}
|
||||
|
||||
// add ORDER expression.
|
||||
// "column" means ASC, "-column" means DESC.
|
||||
func (o querySet) OrderBy(exprs ...string) QuerySeter {
|
||||
@ -112,6 +120,12 @@ func (o querySet) OrderBy(exprs ...string) QuerySeter {
|
||||
return &o
|
||||
}
|
||||
|
||||
// add DISTINCT to SELECT
|
||||
func (o querySet) Distinct() QuerySeter {
|
||||
o.distinct = true
|
||||
return &o
|
||||
}
|
||||
|
||||
// set relation model to query together.
|
||||
// it will query relation models and assign to parent model.
|
||||
func (o querySet) RelatedSel(params ...interface{}) QuerySeter {
|
||||
|
@ -66,7 +66,9 @@ type QuerySeter interface {
|
||||
SetCond(*Condition) QuerySeter
|
||||
Limit(interface{}, ...interface{}) QuerySeter
|
||||
Offset(interface{}) QuerySeter
|
||||
GroupBy(...string) QuerySeter
|
||||
OrderBy(...string) QuerySeter
|
||||
Distinct() QuerySeter
|
||||
RelatedSel(...interface{}) QuerySeter
|
||||
Count() (int64, error)
|
||||
Exist() bool
|
||||
|
14
parser.go
14
parser.go
@ -42,13 +42,13 @@ func init() {
|
||||
`
|
||||
|
||||
var (
|
||||
lastupdateFilename string = "lastupdate.tmp"
|
||||
lastupdateFilename = "lastupdate.tmp"
|
||||
commentFilename string
|
||||
pkgLastupdate map[string]int64
|
||||
genInfoList map[string][]ControllerComments
|
||||
)
|
||||
|
||||
const COMMENTFL = "commentsRouter_"
|
||||
const coomentPrefix = "commentsRouter_"
|
||||
|
||||
func init() {
|
||||
pkgLastupdate = make(map[string]int64)
|
||||
@ -56,7 +56,7 @@ func init() {
|
||||
|
||||
func parserPkg(pkgRealpath, pkgpath string) error {
|
||||
rep := strings.NewReplacer("/", "_", ".", "_")
|
||||
commentFilename = COMMENTFL + rep.Replace(pkgpath) + ".go"
|
||||
commentFilename = coomentPrefix + rep.Replace(pkgpath) + ".go"
|
||||
if !compareFile(pkgRealpath) {
|
||||
Info(pkgRealpath + " has not changed, not reloading")
|
||||
return nil
|
||||
@ -132,9 +132,11 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
|
||||
func genRouterCode() {
|
||||
os.Mkdir(path.Join(workPath, "routers"), 0755)
|
||||
Info("generate router from comments")
|
||||
var globalinfo string
|
||||
sortKey := make([]string, 0)
|
||||
for k, _ := range genInfoList {
|
||||
var (
|
||||
globalinfo string
|
||||
sortKey []string
|
||||
)
|
||||
for k := range genInfoList {
|
||||
sortKey = append(sortKey, k)
|
||||
}
|
||||
sort.Strings(sortKey)
|
||||
|
@ -83,41 +83,41 @@ func APIBaiscAuth(appid, appkey string) beego.FilterFunc {
|
||||
func APIAuthWithFunc(f AppIdToAppSecret, timeout int) beego.FilterFunc {
|
||||
return func(ctx *context.Context) {
|
||||
if ctx.Input.Query("appid") == "" {
|
||||
ctx.Output.SetStatus(403)
|
||||
ctx.ResponseWriter.WriteHeader(403)
|
||||
ctx.WriteString("miss query param: appid")
|
||||
return
|
||||
}
|
||||
appsecret := f(ctx.Input.Query("appid"))
|
||||
if appsecret == "" {
|
||||
ctx.Output.SetStatus(403)
|
||||
ctx.ResponseWriter.WriteHeader(403)
|
||||
ctx.WriteString("not exist this appid")
|
||||
return
|
||||
}
|
||||
if ctx.Input.Query("signature") == "" {
|
||||
ctx.Output.SetStatus(403)
|
||||
ctx.ResponseWriter.WriteHeader(403)
|
||||
ctx.WriteString("miss query param: signature")
|
||||
return
|
||||
}
|
||||
if ctx.Input.Query("timestamp") == "" {
|
||||
ctx.Output.SetStatus(403)
|
||||
ctx.ResponseWriter.WriteHeader(403)
|
||||
ctx.WriteString("miss query param: timestamp")
|
||||
return
|
||||
}
|
||||
u, err := time.Parse("2006-01-02 15:04:05", ctx.Input.Query("timestamp"))
|
||||
if err != nil {
|
||||
ctx.Output.SetStatus(403)
|
||||
ctx.ResponseWriter.WriteHeader(403)
|
||||
ctx.WriteString("timestamp format is error, should 2006-01-02 15:04:05")
|
||||
return
|
||||
}
|
||||
t := time.Now()
|
||||
if t.Sub(u).Seconds() > float64(timeout) {
|
||||
ctx.Output.SetStatus(403)
|
||||
ctx.ResponseWriter.WriteHeader(403)
|
||||
ctx.WriteString("timeout! the request time is long ago, please try again")
|
||||
return
|
||||
}
|
||||
if ctx.Input.Query("signature") !=
|
||||
Signature(appsecret, ctx.Input.Method(), ctx.Request.Form, ctx.Input.Uri()) {
|
||||
ctx.Output.SetStatus(403)
|
||||
ctx.ResponseWriter.WriteHeader(403)
|
||||
ctx.WriteString("auth failed")
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
// // - PUT and PATCH methods
|
||||
// // - Origin header
|
||||
// // - Credentials share
|
||||
// beego.InsertFilter("*", beego.BeforeRouter,cors.Allow(&cors.Options{
|
||||
// beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{
|
||||
// AllowOrigins: []string{"https://*.foo.com"},
|
||||
// AllowMethods: []string{"PUT", "PATCH"},
|
||||
// AllowHeaders: []string{"Origin"},
|
||||
@ -36,7 +36,6 @@
|
||||
package cors
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -216,8 +215,6 @@ func Allow(opts *Options) beego.FilterFunc {
|
||||
for key, value := range headers {
|
||||
ctx.Output.Header(key, value)
|
||||
}
|
||||
ctx.Output.SetStatus(http.StatusOK)
|
||||
ctx.WriteString("")
|
||||
return
|
||||
}
|
||||
headers = opts.Header(origin)
|
||||
|
135
plugins/jwt/jwt.go
Normal file
135
plugins/jwt/jwt.go
Normal file
@ -0,0 +1,135 @@
|
||||
// Copyright 2014 beego Author. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package jwt provides JWT (Json Web Token) authentication
|
||||
//
|
||||
// Usage
|
||||
// In file main.go
|
||||
//
|
||||
// import (
|
||||
// "github.com/astaxie/beego"
|
||||
// "github.com/astaxie/beego/plugins/jwt"
|
||||
// )
|
||||
//
|
||||
// func main() {
|
||||
// // JWT for Url matching /v1/*
|
||||
// // PrivateKeyPath: The path for the private RSA key used by JWT
|
||||
// // PublicKeyPath: The path for the public RSA key used by JWT
|
||||
// // The list of Urls should be excluded from the JWT Auth
|
||||
// beego.InsertFilter("/v1/*", beego.BeforeRouter, jwt.AuthRequest(&jwt.Options{
|
||||
// PrivateKeyPath: "conf/beeblog.rsa",
|
||||
// PublicKeyPath: "conf/beeblog.rsa.pub",
|
||||
// WhiteList: []string{"/v1/jwt/issue-token", "/docs"},
|
||||
// }))
|
||||
// beego.Run()
|
||||
// }
|
||||
//
|
||||
// In file routers/router.go
|
||||
//
|
||||
// import (
|
||||
// "github.com/astaxie/beego"
|
||||
// "github.com/astaxie/beego/plugins/jwt"
|
||||
// )
|
||||
// func init() {
|
||||
// ns := beego.NSNamespace("/jwt",
|
||||
// beego.NSInclude(
|
||||
// &jwt.JwtController{},
|
||||
// ),
|
||||
// )
|
||||
// beego.AddNamespace(ns)
|
||||
// }
|
||||
//
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/context"
|
||||
"github.com/astaxie/beego/logs"
|
||||
goJwt "github.com/dgrijalva/jwt-go"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Options for the JWT Auth
|
||||
type Options struct {
|
||||
PrivateKeyPath string
|
||||
PublicKeyPath string
|
||||
WhiteList []string
|
||||
}
|
||||
|
||||
var RSAKeys struct {
|
||||
PrivateKey []byte
|
||||
PublicKey []byte
|
||||
}
|
||||
|
||||
func AuthRequest(o *Options) beego.FilterFunc {
|
||||
RSAKeys.PrivateKey, _ = ioutil.ReadFile(o.PrivateKeyPath)
|
||||
RSAKeys.PublicKey, _ = ioutil.ReadFile(o.PublicKeyPath)
|
||||
|
||||
return func(ctx *context.Context) {
|
||||
// :TODO the url patterns should be considered here.
|
||||
// Shouldn't only use the string equal
|
||||
for _, method := range o.WhiteList {
|
||||
if method == ctx.Request.URL.Path {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
parsedToken, err := goJwt.ParseFromRequest(ctx.Request, func(t *goJwt.Token) (interface{}, error) {
|
||||
return RSAKeys.PublicKey, nil
|
||||
})
|
||||
|
||||
if err == nil && parsedToken.Valid {
|
||||
ctx.Output.SetStatus(http.StatusOK)
|
||||
} else {
|
||||
ctx.Output.SetStatus(http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// oprations for Jwt
|
||||
type JwtController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *JwtController) URLMapping() {
|
||||
this.Mapping("IssueToken", this.IssueToken)
|
||||
}
|
||||
|
||||
// @Title IssueToken
|
||||
// @Description Issue a Json Web Token
|
||||
// @Success 200 string
|
||||
// @Failure 403 no privilege to access
|
||||
// @Failure 500 server inner error
|
||||
// @router /issue-token [get]
|
||||
func (this *JwtController) IssueToken() {
|
||||
this.Data["json"] = CreateToken()
|
||||
this.ServeJson()
|
||||
}
|
||||
|
||||
func CreateToken() map[string]string {
|
||||
log := logs.NewLogger(10000)
|
||||
log.SetLogger("console", "")
|
||||
|
||||
token := goJwt.New(goJwt.GetSigningMethod("RS256")) // Create a Token that will be signed with RSA 256.
|
||||
token.Claims["ID"] = "This is my super fake ID"
|
||||
token.Claims["exp"] = time.Now().Unix() + 36000
|
||||
// The claims object allows you to store information in the actual token.
|
||||
tokenString, _ := token.SignedString(RSAKeys.PrivateKey)
|
||||
// tokenString Contains the actual token you should share with your client.
|
||||
return map[string]string{"token": tokenString}
|
||||
}
|
88
plugins/jwt/jwt_test.go
Normal file
88
plugins/jwt/jwt_test.go
Normal file
@ -0,0 +1,88 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testRequest(method, path string) (*httptest.ResponseRecorder, *http.Request) {
|
||||
request, _ := http.NewRequest(method, path, nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
return recorder, request
|
||||
}
|
||||
|
||||
func Test_IssueTokenAction(t *testing.T) {
|
||||
url := "/v1/jwt/issue-token"
|
||||
|
||||
mux := beego.NewControllerRegister()
|
||||
|
||||
mux.InsertFilter("*", beego.BeforeRouter, AuthRequest(&Options{
|
||||
PrivateKeyPath: "test/jwt.rsa",
|
||||
PublicKeyPath: "test/jwt.rsa.pub",
|
||||
WhiteList: []string{"/v1/jwt/issue-token", "/docs"},
|
||||
}))
|
||||
|
||||
mux.Add("/v1/jwt/issue-token", &JwtController{}, "get:IssueToken")
|
||||
|
||||
rw, r := testRequest("GET", url)
|
||||
mux.ServeHTTP(rw, r)
|
||||
|
||||
if rw.Code != http.StatusOK {
|
||||
t.Errorf("Shoud return 200")
|
||||
}
|
||||
}
|
||||
|
||||
func (tc *JwtController) Foo() {
|
||||
tc.Ctx.Output.Body([]byte("ok"))
|
||||
}
|
||||
|
||||
func Test_AuthRequestWithAuthorizationHeader(t *testing.T) {
|
||||
|
||||
url := "/foo"
|
||||
|
||||
mux := beego.NewControllerRegister()
|
||||
|
||||
mux.InsertFilter("*", beego.BeforeRouter, AuthRequest(&Options{
|
||||
PrivateKeyPath: "test/jwt.rsa",
|
||||
PublicKeyPath: "test/jwt.rsa.pub",
|
||||
WhiteList: []string{"/v1/jwt/issue-token", "/docs"},
|
||||
}))
|
||||
|
||||
mux.Add("/foo", &JwtController{}, "get:Foo")
|
||||
newToken := CreateToken()
|
||||
|
||||
rw, r := testRequest("GET", url)
|
||||
r.Header.Add("Authorization", "Bearer "+newToken["token"])
|
||||
mux.ServeHTTP(rw, r)
|
||||
|
||||
if rw.Code != http.StatusOK {
|
||||
t.Errorf("Shoud return 200")
|
||||
}
|
||||
if rw.Body.String() != "ok" {
|
||||
t.Errorf("Should output ok")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AuthRequestWithoutAuthorizationHeader(t *testing.T) {
|
||||
url := "/foo"
|
||||
|
||||
mux := beego.NewControllerRegister()
|
||||
|
||||
mux.InsertFilter("*", beego.BeforeRouter, AuthRequest(&Options{
|
||||
PrivateKeyPath: "test/jwt.rsa",
|
||||
PublicKeyPath: "test/jwt.rsa.pub",
|
||||
WhiteList: []string{"/v1/jwt/issue-token", "/docs"},
|
||||
}))
|
||||
|
||||
mux.Add("/foo", &JwtController{}, "get:Foo")
|
||||
|
||||
rw, r := testRequest("GET", url)
|
||||
mux.ServeHTTP(rw, r)
|
||||
|
||||
if rw.Code != http.StatusUnauthorized {
|
||||
t.Errorf("Shoud return 401")
|
||||
}
|
||||
}
|
15
plugins/jwt/test/jwt.rsa
Normal file
15
plugins/jwt/test/jwt.rsa
Normal file
@ -0,0 +1,15 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICWwIBAAKBgQCdu+23Y/0J/FTQKnIPnxupoOo9/OYCv90DPXN/KLLRAMjYzgcC
|
||||
DsBST2xVR5jlimI/gyfCpVB62dwpSzzr0cA3MoDhbaGWuTdQUX9zmiLoQ4I7X6h0
|
||||
dwyiihOz+CzOMlAg5+qBhiTGcKvIFlfEc1FUcn/tB3PVRG9j6B1Ibz5CnQIDAQAB
|
||||
AoGAFGg+/i4ai9MwqeoD7c95Bb5C8BgrLgnir0uhCL+cOvwuABbPw01jRoLuEi58
|
||||
Mp5vzaXLXByFSA+ts03/qMbvZkDGac5g5kLli5TjHIONMxVBrdfGQ1+OApnaPayN
|
||||
N+HYjZKs6xao6J5iFqfA0FqzDR9kQhUoeosdQoo1GlxDckECQQDO/0LJrFiLzYWe
|
||||
qS/DxfAnFu2BlClKZjxRJ3vIkRRaON6HPl8BeJW901bFKG5+WSfO+OwQ9egWaf3X
|
||||
fFm/oEHRAkEAwxMor4fOkBZbL4KPW7sen169vwnXuYusqj0t3dIeiIVrCigkOMT4
|
||||
OvX/63u4CTdXh1D5u/4Z/1HTYH92VCP7DQJAJPxbNKnE0IYSf/z++d4eQP3JxkNw
|
||||
9Ug7Msz5QycZGd3bdRLh6uNe7iIa+PN2esD3afX0SDuIEqkxoBUp/CFoYQJAUmi3
|
||||
mV+/7bLkFrALK+9iwmTdt+TKk4HkEY8C32CysW3biFDo7GqZix79XFfJqWsNuQaG
|
||||
WdrA1NGWgH+YV3dTyQJAIWEZGAuUXRkQB20LfjGzpsKgQFbqjTisMS0qe3JjnDwu
|
||||
0JR8sYXapgeEEEisH+OtkZKIfyeFOwoUyNC83bcvgw==
|
||||
-----END RSA PRIVATE KEY-----
|
6
plugins/jwt/test/jwt.rsa.pub
Normal file
6
plugins/jwt/test/jwt.rsa.pub
Normal file
@ -0,0 +1,6 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdu+23Y/0J/FTQKnIPnxupoOo9
|
||||
/OYCv90DPXN/KLLRAMjYzgcCDsBST2xVR5jlimI/gyfCpVB62dwpSzzr0cA3MoDh
|
||||
baGWuTdQUX9zmiLoQ4I7X6h0dwyiihOz+CzOMlAg5+qBhiTGcKvIFlfEc1FUcn/t
|
||||
B3PVRG9j6B1Ibz5CnQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
204
router.go
204
router.go
@ -34,8 +34,8 @@ import (
|
||||
"github.com/astaxie/beego/utils"
|
||||
)
|
||||
|
||||
// default filter execution points
|
||||
const (
|
||||
// default filter execution points
|
||||
BeforeStatic = iota
|
||||
BeforeRouter
|
||||
BeforeExec
|
||||
@ -50,7 +50,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// supported http methods.
|
||||
// HTTPMETHOD list the supported http methods.
|
||||
HTTPMETHOD = map[string]string{
|
||||
"GET": "GET",
|
||||
"POST": "POST",
|
||||
@ -71,10 +71,12 @@ var (
|
||||
"SetSecureCookie", "XsrfToken", "CheckXsrfCookie", "XsrfFormHtml",
|
||||
"GetControllerAndAction"}
|
||||
|
||||
url_placeholder = "{{placeholder}}"
|
||||
DefaultLogFilter FilterHandler = &logFilter{}
|
||||
urlPlaceholder = "{{placeholder}}"
|
||||
// DefaultAccessLogFilter will skip the accesslog if return true
|
||||
DefaultAccessLogFilter FilterHandler = &logFilter{}
|
||||
)
|
||||
|
||||
// FilterHandler is an interface for
|
||||
type FilterHandler interface {
|
||||
Filter(*beecontext.Context) bool
|
||||
}
|
||||
@ -96,7 +98,7 @@ func (l *logFilter) Filter(ctx *beecontext.Context) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// To append a slice's value into "exceptMethod", for controller's methods shouldn't reflect to AutoRouter
|
||||
// ExceptMethodAppend to append a slice's value into "exceptMethod", for controller's methods shouldn't reflect to AutoRouter
|
||||
func ExceptMethodAppend(action string) {
|
||||
exceptMethod = append(exceptMethod, action)
|
||||
}
|
||||
@ -110,22 +112,22 @@ type controllerInfo struct {
|
||||
routerType int
|
||||
}
|
||||
|
||||
// ControllerRegistor containers registered router rules, controller handlers and filters.
|
||||
type ControllerRegistor struct {
|
||||
// ControllerRegister containers registered router rules, controller handlers and filters.
|
||||
type ControllerRegister struct {
|
||||
routers map[string]*Tree
|
||||
enableFilter bool
|
||||
filters map[int][]*FilterRouter
|
||||
}
|
||||
|
||||
// NewControllerRegister returns a new ControllerRegistor.
|
||||
func NewControllerRegister() *ControllerRegistor {
|
||||
return &ControllerRegistor{
|
||||
// NewControllerRegister returns a new ControllerRegister.
|
||||
func NewControllerRegister() *ControllerRegister {
|
||||
return &ControllerRegister{
|
||||
routers: make(map[string]*Tree),
|
||||
filters: make(map[int][]*FilterRouter),
|
||||
}
|
||||
}
|
||||
|
||||
// Add controller handler and pattern rules to ControllerRegistor.
|
||||
// Add controller handler and pattern rules to ControllerRegister.
|
||||
// usage:
|
||||
// default methods is the same name as method
|
||||
// Add("/user",&UserController{})
|
||||
@ -135,7 +137,7 @@ func NewControllerRegister() *ControllerRegistor {
|
||||
// Add("/api/delete",&RestController{},"delete:DeleteFood")
|
||||
// Add("/api",&RestController{},"get,post:ApiFunc")
|
||||
// Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
|
||||
func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingMethods ...string) {
|
||||
func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingMethods ...string) {
|
||||
reflectVal := reflect.ValueOf(c)
|
||||
t := reflect.Indirect(reflectVal).Type()
|
||||
methods := make(map[string]string)
|
||||
@ -183,7 +185,7 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ControllerRegistor) addToRouter(method, pattern string, r *controllerInfo) {
|
||||
func (p *ControllerRegister) addToRouter(method, pattern string, r *controllerInfo) {
|
||||
if !RouterCaseSensitive {
|
||||
pattern = strings.ToLower(pattern)
|
||||
}
|
||||
@ -196,9 +198,9 @@ func (p *ControllerRegistor) addToRouter(method, pattern string, r *controllerIn
|
||||
}
|
||||
}
|
||||
|
||||
// only when the Runmode is dev will generate router file in the router/auto.go from the controller
|
||||
// Include only when the Runmode is dev will generate router file in the router/auto.go from the controller
|
||||
// Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{})
|
||||
func (p *ControllerRegistor) Include(cList ...ControllerInterface) {
|
||||
func (p *ControllerRegister) Include(cList ...ControllerInterface) {
|
||||
if RunMode == "dev" {
|
||||
skip := make(map[string]bool, 10)
|
||||
for _, c := range cList {
|
||||
@ -238,84 +240,84 @@ func (p *ControllerRegistor) Include(cList ...ControllerInterface) {
|
||||
}
|
||||
}
|
||||
|
||||
// add get method
|
||||
// Get add get method
|
||||
// usage:
|
||||
// Get("/", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Get(pattern string, f FilterFunc) {
|
||||
func (p *ControllerRegister) Get(pattern string, f FilterFunc) {
|
||||
p.AddMethod("get", pattern, f)
|
||||
}
|
||||
|
||||
// add post method
|
||||
// Post add post method
|
||||
// usage:
|
||||
// Post("/api", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Post(pattern string, f FilterFunc) {
|
||||
func (p *ControllerRegister) Post(pattern string, f FilterFunc) {
|
||||
p.AddMethod("post", pattern, f)
|
||||
}
|
||||
|
||||
// add put method
|
||||
// Put add put method
|
||||
// usage:
|
||||
// Put("/api/:id", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Put(pattern string, f FilterFunc) {
|
||||
func (p *ControllerRegister) Put(pattern string, f FilterFunc) {
|
||||
p.AddMethod("put", pattern, f)
|
||||
}
|
||||
|
||||
// add delete method
|
||||
// Delete add delete method
|
||||
// usage:
|
||||
// Delete("/api/:id", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Delete(pattern string, f FilterFunc) {
|
||||
func (p *ControllerRegister) Delete(pattern string, f FilterFunc) {
|
||||
p.AddMethod("delete", pattern, f)
|
||||
}
|
||||
|
||||
// add head method
|
||||
// Head add head method
|
||||
// usage:
|
||||
// Head("/api/:id", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Head(pattern string, f FilterFunc) {
|
||||
func (p *ControllerRegister) Head(pattern string, f FilterFunc) {
|
||||
p.AddMethod("head", pattern, f)
|
||||
}
|
||||
|
||||
// add patch method
|
||||
// Patch add patch method
|
||||
// usage:
|
||||
// Patch("/api/:id", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Patch(pattern string, f FilterFunc) {
|
||||
func (p *ControllerRegister) Patch(pattern string, f FilterFunc) {
|
||||
p.AddMethod("patch", pattern, f)
|
||||
}
|
||||
|
||||
// add options method
|
||||
// Options add options method
|
||||
// usage:
|
||||
// Options("/api/:id", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Options(pattern string, f FilterFunc) {
|
||||
func (p *ControllerRegister) Options(pattern string, f FilterFunc) {
|
||||
p.AddMethod("options", pattern, f)
|
||||
}
|
||||
|
||||
// add all method
|
||||
// Any add all method
|
||||
// usage:
|
||||
// Any("/api/:id", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) Any(pattern string, f FilterFunc) {
|
||||
func (p *ControllerRegister) Any(pattern string, f FilterFunc) {
|
||||
p.AddMethod("*", pattern, f)
|
||||
}
|
||||
|
||||
// add http method router
|
||||
// AddMethod add http method router
|
||||
// usage:
|
||||
// AddMethod("get","/api/:id", func(ctx *context.Context){
|
||||
// ctx.Output.Body("hello world")
|
||||
// })
|
||||
func (p *ControllerRegistor) AddMethod(method, pattern string, f FilterFunc) {
|
||||
func (p *ControllerRegister) AddMethod(method, pattern string, f FilterFunc) {
|
||||
if _, ok := HTTPMETHOD[strings.ToUpper(method)]; method != "*" && !ok {
|
||||
panic("not support http method: " + method)
|
||||
}
|
||||
@ -343,8 +345,8 @@ func (p *ControllerRegistor) AddMethod(method, pattern string, f FilterFunc) {
|
||||
}
|
||||
}
|
||||
|
||||
// add user defined Handler
|
||||
func (p *ControllerRegistor) Handler(pattern string, h http.Handler, options ...interface{}) {
|
||||
// Handler add user defined Handler
|
||||
func (p *ControllerRegister) Handler(pattern string, h http.Handler, options ...interface{}) {
|
||||
route := &controllerInfo{}
|
||||
route.pattern = pattern
|
||||
route.routerType = routerTypeHandler
|
||||
@ -359,21 +361,21 @@ func (p *ControllerRegistor) Handler(pattern string, h http.Handler, options ...
|
||||
}
|
||||
}
|
||||
|
||||
// Add auto router to ControllerRegistor.
|
||||
// AddAuto router to ControllerRegister.
|
||||
// example beego.AddAuto(&MainContorlller{}),
|
||||
// MainController has method List and Page.
|
||||
// visit the url /main/list to execute List function
|
||||
// /main/page to execute Page function.
|
||||
func (p *ControllerRegistor) AddAuto(c ControllerInterface) {
|
||||
func (p *ControllerRegister) AddAuto(c ControllerInterface) {
|
||||
p.AddAutoPrefix("/", c)
|
||||
}
|
||||
|
||||
// Add auto router to ControllerRegistor with prefix.
|
||||
// AddAutoPrefix Add auto router to ControllerRegister with prefix.
|
||||
// example beego.AddAutoPrefix("/admin",&MainContorlller{}),
|
||||
// MainController has method List and Page.
|
||||
// visit the url /admin/main/list to execute List function
|
||||
// /admin/main/page to execute Page function.
|
||||
func (p *ControllerRegistor) AddAutoPrefix(prefix string, c ControllerInterface) {
|
||||
func (p *ControllerRegister) AddAutoPrefix(prefix string, c ControllerInterface) {
|
||||
reflectVal := reflect.ValueOf(c)
|
||||
rt := reflectVal.Type()
|
||||
ct := reflect.Indirect(reflectVal).Type()
|
||||
@ -399,9 +401,9 @@ func (p *ControllerRegistor) AddAutoPrefix(prefix string, c ControllerInterface)
|
||||
}
|
||||
}
|
||||
|
||||
// Add a FilterFunc with pattern rule and action constant.
|
||||
// InsertFilter Add a FilterFunc with pattern rule and action constant.
|
||||
// The bool params is for setting the returnOnOutput value (false allows multiple filters to execute)
|
||||
func (p *ControllerRegistor) InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) error {
|
||||
func (p *ControllerRegister) InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) error {
|
||||
|
||||
mr := new(FilterRouter)
|
||||
mr.tree = NewTree()
|
||||
@ -420,15 +422,15 @@ func (p *ControllerRegistor) InsertFilter(pattern string, pos int, filter Filter
|
||||
}
|
||||
|
||||
// add Filter into
|
||||
func (p *ControllerRegistor) insertFilterRouter(pos int, mr *FilterRouter) error {
|
||||
func (p *ControllerRegister) insertFilterRouter(pos int, mr *FilterRouter) error {
|
||||
p.filters[pos] = append(p.filters[pos], mr)
|
||||
p.enableFilter = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// UrlFor does another controller handler in this request function.
|
||||
// URLFor does another controller handler in this request function.
|
||||
// it can access any controller method.
|
||||
func (p *ControllerRegistor) UrlFor(endpoint string, values ...interface{}) string {
|
||||
func (p *ControllerRegister) URLFor(endpoint string, values ...interface{}) string {
|
||||
paths := strings.Split(endpoint, ".")
|
||||
if len(paths) <= 1 {
|
||||
Warn("urlfor endpoint must like path.controller.method")
|
||||
@ -460,7 +462,7 @@ func (p *ControllerRegistor) UrlFor(endpoint string, values ...interface{}) stri
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName string, params map[string]string, httpMethod string) (bool, string) {
|
||||
func (p *ControllerRegister) geturl(t *Tree, url, controllName, methodName string, params map[string]string, httpMethod string) (bool, string) {
|
||||
for k, subtree := range t.fixrouters {
|
||||
u := path.Join(url, k)
|
||||
ok, u := p.geturl(subtree, u, controllName, methodName, params, httpMethod)
|
||||
@ -469,7 +471,7 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin
|
||||
}
|
||||
}
|
||||
if t.wildcard != nil {
|
||||
u := path.Join(url, url_placeholder)
|
||||
u := path.Join(url, urlPlaceholder)
|
||||
ok, u := p.geturl(t.wildcard, u, controllName, methodName, params, httpMethod)
|
||||
if ok {
|
||||
return ok, u
|
||||
@ -499,22 +501,21 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin
|
||||
if find {
|
||||
if l.regexps == nil {
|
||||
if len(l.wildcards) == 0 {
|
||||
return true, strings.Replace(url, "/"+url_placeholder, "", 1) + tourl(params)
|
||||
return true, strings.Replace(url, "/"+urlPlaceholder, "", 1) + tourl(params)
|
||||
}
|
||||
if len(l.wildcards) == 1 {
|
||||
if v, ok := params[l.wildcards[0]]; ok {
|
||||
delete(params, l.wildcards[0])
|
||||
return true, strings.Replace(url, url_placeholder, v, 1) + tourl(params)
|
||||
} else {
|
||||
return false, ""
|
||||
return true, strings.Replace(url, urlPlaceholder, v, 1) + tourl(params)
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
if len(l.wildcards) == 3 && l.wildcards[0] == "." {
|
||||
if p, ok := params[":path"]; ok {
|
||||
if e, isok := params[":ext"]; isok {
|
||||
delete(params, ":path")
|
||||
delete(params, ":ext")
|
||||
return true, strings.Replace(url, url_placeholder, p+"."+e, -1) + tourl(params)
|
||||
return true, strings.Replace(url, urlPlaceholder, p+"."+e, -1) + tourl(params)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -526,45 +527,43 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin
|
||||
}
|
||||
if u, ok := params[v]; ok {
|
||||
delete(params, v)
|
||||
url = strings.Replace(url, url_placeholder, u, 1)
|
||||
url = strings.Replace(url, urlPlaceholder, u, 1)
|
||||
} else {
|
||||
if canskip {
|
||||
canskip = false
|
||||
continue
|
||||
} else {
|
||||
return false, ""
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
}
|
||||
return true, url + tourl(params)
|
||||
} else {
|
||||
var i int
|
||||
var startreg bool
|
||||
regurl := ""
|
||||
for _, v := range strings.Trim(l.regexps.String(), "^$") {
|
||||
if v == '(' {
|
||||
startreg = true
|
||||
continue
|
||||
} else if v == ')' {
|
||||
startreg = false
|
||||
if v, ok := params[l.wildcards[i]]; ok {
|
||||
delete(params, l.wildcards[i])
|
||||
regurl = regurl + v
|
||||
i++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
} else if !startreg {
|
||||
regurl = string(append([]rune(regurl), v))
|
||||
}
|
||||
var i int
|
||||
var startreg bool
|
||||
regurl := ""
|
||||
for _, v := range strings.Trim(l.regexps.String(), "^$") {
|
||||
if v == '(' {
|
||||
startreg = true
|
||||
continue
|
||||
} else if v == ')' {
|
||||
startreg = false
|
||||
if v, ok := params[l.wildcards[i]]; ok {
|
||||
delete(params, l.wildcards[i])
|
||||
regurl = regurl + v
|
||||
i++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
} else if !startreg {
|
||||
regurl = string(append([]rune(regurl), v))
|
||||
}
|
||||
if l.regexps.MatchString(regurl) {
|
||||
ps := strings.Split(regurl, "/")
|
||||
for _, p := range ps {
|
||||
url = strings.Replace(url, url_placeholder, p, 1)
|
||||
}
|
||||
return true, url + tourl(params)
|
||||
}
|
||||
if l.regexps.MatchString(regurl) {
|
||||
ps := strings.Split(regurl, "/")
|
||||
for _, p := range ps {
|
||||
url = strings.Replace(url, urlPlaceholder, p, 1)
|
||||
}
|
||||
return true, url + tourl(params)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -575,7 +574,7 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin
|
||||
}
|
||||
|
||||
// Implement http.Handler interface.
|
||||
func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
starttime := time.Now()
|
||||
var runrouter reflect.Type
|
||||
var findrouter bool
|
||||
@ -607,7 +606,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
urlPath = r.URL.Path
|
||||
}
|
||||
// defined filter function
|
||||
do_filter := func(pos int) (started bool) {
|
||||
doFilter := func(pos int) (started bool) {
|
||||
if p.enableFilter {
|
||||
if l, ok := p.filters[pos]; ok {
|
||||
for _, filterR := range l {
|
||||
@ -639,7 +638,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
// filter for static file
|
||||
if do_filter(BeforeStatic) {
|
||||
if doFilter(BeforeStatic) {
|
||||
goto Admin
|
||||
}
|
||||
|
||||
@ -670,7 +669,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
context.Input.ParseFormOrMulitForm(MaxMemory)
|
||||
}
|
||||
|
||||
if do_filter(BeforeRouter) {
|
||||
if doFilter(BeforeRouter) {
|
||||
goto Admin
|
||||
}
|
||||
|
||||
@ -681,17 +680,17 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
if !findrouter {
|
||||
http_method := r.Method
|
||||
httpMethod := r.Method
|
||||
|
||||
if http_method == "POST" && context.Input.Query("_method") == "PUT" {
|
||||
http_method = "PUT"
|
||||
if httpMethod == "POST" && context.Input.Query("_method") == "PUT" {
|
||||
httpMethod = "PUT"
|
||||
}
|
||||
|
||||
if http_method == "POST" && context.Input.Query("_method") == "DELETE" {
|
||||
http_method = "DELETE"
|
||||
if httpMethod == "POST" && context.Input.Query("_method") == "DELETE" {
|
||||
httpMethod = "DELETE"
|
||||
}
|
||||
|
||||
if t, ok := p.routers[http_method]; ok {
|
||||
if t, ok := p.routers[httpMethod]; ok {
|
||||
runObject, p := t.Match(urlPath)
|
||||
if r, ok := runObject.(*controllerInfo); ok {
|
||||
routerInfo = r
|
||||
@ -718,7 +717,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
|
||||
if findrouter {
|
||||
//execute middleware filters
|
||||
if do_filter(BeforeExec) {
|
||||
if doFilter(BeforeExec) {
|
||||
goto Admin
|
||||
}
|
||||
isRunable := false
|
||||
@ -770,10 +769,10 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
|
||||
//if XSRF is Enable then check cookie where there has any cookie in the request's cookie _csrf
|
||||
if EnableXSRF {
|
||||
execController.XsrfToken()
|
||||
execController.XSRFToken()
|
||||
if r.Method == "POST" || r.Method == "DELETE" || r.Method == "PUT" ||
|
||||
(r.Method == "POST" && (context.Input.Query("_method") == "DELETE" || context.Input.Query("_method") == "PUT")) {
|
||||
execController.CheckXsrfCookie()
|
||||
execController.CheckXSRFCookie()
|
||||
}
|
||||
}
|
||||
|
||||
@ -798,7 +797,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
execController.Options()
|
||||
default:
|
||||
if !execController.HandlerFunc(runMethod) {
|
||||
in := make([]reflect.Value, 0)
|
||||
var in []reflect.Value
|
||||
method := vc.MethodByName(runMethod)
|
||||
method.Call(in)
|
||||
}
|
||||
@ -819,12 +818,12 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
//execute middleware filters
|
||||
if do_filter(AfterExec) {
|
||||
if doFilter(AfterExec) {
|
||||
goto Admin
|
||||
}
|
||||
}
|
||||
|
||||
do_filter(FinishRouter)
|
||||
doFilter(FinishRouter)
|
||||
|
||||
Admin:
|
||||
timeend := time.Since(starttime)
|
||||
@ -850,7 +849,7 @@ Admin:
|
||||
} else {
|
||||
devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeend.String(), "notmatch")
|
||||
}
|
||||
if DefaultLogFilter == nil || !DefaultLogFilter.Filter(context) {
|
||||
if DefaultAccessLogFilter == nil || !DefaultAccessLogFilter.Filter(context) {
|
||||
Debug(devinfo)
|
||||
}
|
||||
}
|
||||
@ -861,15 +860,15 @@ Admin:
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ControllerRegistor) recoverPanic(context *beecontext.Context) {
|
||||
func (p *ControllerRegister) recoverPanic(context *beecontext.Context) {
|
||||
if err := recover(); err != nil {
|
||||
if err == USERSTOPRUN {
|
||||
if err == ErrAbort {
|
||||
return
|
||||
}
|
||||
if !RecoverPanic {
|
||||
panic(err)
|
||||
} else {
|
||||
if ErrorsShow {
|
||||
if EnableErrorsShow {
|
||||
if _, ok := ErrorMaps[fmt.Sprint(err)]; ok {
|
||||
exception(fmt.Sprint(err), context)
|
||||
return
|
||||
@ -931,6 +930,13 @@ func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return hj.Hijack()
|
||||
}
|
||||
|
||||
func (w *responseWriter) Flush() {
|
||||
f, ok := w.writer.(http.Flusher)
|
||||
if ok {
|
||||
f.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
func tourl(params map[string]string) string {
|
||||
if len(params) == 0 {
|
||||
return ""
|
||||
|
@ -52,17 +52,17 @@ func (tc *TestController) Myext() {
|
||||
tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Param(":ext")))
|
||||
}
|
||||
|
||||
func (tc *TestController) GetUrl() {
|
||||
tc.Ctx.Output.Body([]byte(tc.UrlFor(".Myext")))
|
||||
func (tc *TestController) GetURL() {
|
||||
tc.Ctx.Output.Body([]byte(tc.URLFor(".Myext")))
|
||||
}
|
||||
|
||||
func (t *TestController) GetParams() {
|
||||
t.Ctx.WriteString(t.Ctx.Input.Query(":last") + "+" +
|
||||
t.Ctx.Input.Query(":first") + "+" + t.Ctx.Input.Query("learn"))
|
||||
func (tc *TestController) GetParams() {
|
||||
tc.Ctx.WriteString(tc.Ctx.Input.Query(":last") + "+" +
|
||||
tc.Ctx.Input.Query(":first") + "+" + tc.Ctx.Input.Query("learn"))
|
||||
}
|
||||
|
||||
func (t *TestController) GetManyRouter() {
|
||||
t.Ctx.WriteString(t.Ctx.Input.Query(":id") + t.Ctx.Input.Query(":page"))
|
||||
func (tc *TestController) GetManyRouter() {
|
||||
tc.Ctx.WriteString(tc.Ctx.Input.Query(":id") + tc.Ctx.Input.Query(":page"))
|
||||
}
|
||||
|
||||
type ResStatus struct {
|
||||
@ -70,29 +70,29 @@ type ResStatus struct {
|
||||
Msg string
|
||||
}
|
||||
|
||||
type JsonController struct {
|
||||
type JSONController struct {
|
||||
Controller
|
||||
}
|
||||
|
||||
func (this *JsonController) Prepare() {
|
||||
this.Data["json"] = "prepare"
|
||||
this.ServeJson(true)
|
||||
func (jc *JSONController) Prepare() {
|
||||
jc.Data["json"] = "prepare"
|
||||
jc.ServeJSON(true)
|
||||
}
|
||||
|
||||
func (this *JsonController) Get() {
|
||||
this.Data["Username"] = "astaxie"
|
||||
this.Ctx.Output.Body([]byte("ok"))
|
||||
func (jc *JSONController) Get() {
|
||||
jc.Data["Username"] = "astaxie"
|
||||
jc.Ctx.Output.Body([]byte("ok"))
|
||||
}
|
||||
|
||||
func TestUrlFor(t *testing.T) {
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/api/list", &TestController{}, "*:List")
|
||||
handler.Add("/person/:last/:first", &TestController{}, "*:Param")
|
||||
if a := handler.UrlFor("TestController.List"); a != "/api/list" {
|
||||
if a := handler.URLFor("TestController.List"); a != "/api/list" {
|
||||
Info(a)
|
||||
t.Errorf("TestController.List must equal to /api/list")
|
||||
}
|
||||
if a := handler.UrlFor("TestController.Param", ":last", "xie", ":first", "asta"); a != "/person/xie/asta" {
|
||||
if a := handler.URLFor("TestController.Param", ":last", "xie", ":first", "asta"); a != "/person/xie/asta" {
|
||||
t.Errorf("TestController.Param must equal to /person/xie/asta, but get " + a)
|
||||
}
|
||||
}
|
||||
@ -100,39 +100,39 @@ func TestUrlFor(t *testing.T) {
|
||||
func TestUrlFor3(t *testing.T) {
|
||||
handler := NewControllerRegister()
|
||||
handler.AddAuto(&TestController{})
|
||||
if a := handler.UrlFor("TestController.Myext"); a != "/test/myext" && a != "/Test/Myext" {
|
||||
if a := handler.URLFor("TestController.Myext"); a != "/test/myext" && a != "/Test/Myext" {
|
||||
t.Errorf("TestController.Myext must equal to /test/myext, but get " + a)
|
||||
}
|
||||
if a := handler.UrlFor("TestController.GetUrl"); a != "/test/geturl" && a != "/Test/GetUrl" {
|
||||
t.Errorf("TestController.GetUrl must equal to /test/geturl, but get " + a)
|
||||
if a := handler.URLFor("TestController.GetURL"); a != "/test/geturl" && a != "/Test/GetURL" {
|
||||
t.Errorf("TestController.GetURL must equal to /test/geturl, but get " + a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUrlFor2(t *testing.T) {
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/v1/:v/cms_:id(.+)_:page(.+).html", &TestController{}, "*:List")
|
||||
handler.Add("/v1/:username/edit", &TestController{}, "get:GetUrl")
|
||||
handler.Add("/v1/:username/edit", &TestController{}, "get:GetURL")
|
||||
handler.Add("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", &TestController{}, "*:Param")
|
||||
handler.Add("/:year:int/:month:int/:title/:entid", &TestController{})
|
||||
if handler.UrlFor("TestController.GetUrl", ":username", "astaxie") != "/v1/astaxie/edit" {
|
||||
Info(handler.UrlFor("TestController.GetUrl"))
|
||||
if handler.URLFor("TestController.GetURL", ":username", "astaxie") != "/v1/astaxie/edit" {
|
||||
Info(handler.URLFor("TestController.GetURL"))
|
||||
t.Errorf("TestController.List must equal to /v1/astaxie/edit")
|
||||
}
|
||||
|
||||
if handler.UrlFor("TestController.List", ":v", "za", ":id", "12", ":page", "123") !=
|
||||
if handler.URLFor("TestController.List", ":v", "za", ":id", "12", ":page", "123") !=
|
||||
"/v1/za/cms_12_123.html" {
|
||||
Info(handler.UrlFor("TestController.List"))
|
||||
Info(handler.URLFor("TestController.List"))
|
||||
t.Errorf("TestController.List must equal to /v1/za/cms_12_123.html")
|
||||
}
|
||||
if handler.UrlFor("TestController.Param", ":v", "za", ":id", "12", ":page", "123") !=
|
||||
if handler.URLFor("TestController.Param", ":v", "za", ":id", "12", ":page", "123") !=
|
||||
"/v1/za_cms/ttt_12_123.html" {
|
||||
Info(handler.UrlFor("TestController.Param"))
|
||||
Info(handler.URLFor("TestController.Param"))
|
||||
t.Errorf("TestController.List must equal to /v1/za_cms/ttt_12_123.html")
|
||||
}
|
||||
if handler.UrlFor("TestController.Get", ":year", "1111", ":month", "11",
|
||||
if handler.URLFor("TestController.Get", ":year", "1111", ":month", "11",
|
||||
":title", "aaaa", ":entid", "aaaa") !=
|
||||
"/1111/11/aaaa/aaaa" {
|
||||
Info(handler.UrlFor("TestController.Get"))
|
||||
Info(handler.URLFor("TestController.Get"))
|
||||
t.Errorf("TestController.Get must equal to /1111/11/aaaa/aaaa")
|
||||
}
|
||||
}
|
||||
@ -270,7 +270,7 @@ func TestPrepare(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/json/list", &JsonController{})
|
||||
handler.Add("/json/list", &JSONController{})
|
||||
handler.ServeHTTP(w, r)
|
||||
if w.Body.String() != `"prepare"` {
|
||||
t.Errorf(w.Body.String() + "user define func can't run")
|
||||
|
@ -51,7 +51,10 @@ import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
var mysqlpder = &MysqlProvider{}
|
||||
var (
|
||||
TableName = "session"
|
||||
mysqlpder = &MysqlProvider{}
|
||||
)
|
||||
|
||||
// mysql session store
|
||||
type MysqlSessionStore struct {
|
||||
@ -110,7 +113,7 @@ func (st *MysqlSessionStore) SessionRelease(w http.ResponseWriter) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
st.c.Exec("UPDATE session set `session_data`=?, `session_expiry`=? where session_key=?",
|
||||
st.c.Exec("UPDATE "+TableName+" set `session_data`=?, `session_expiry`=? where session_key=?",
|
||||
b, time.Now().Unix(), st.sid)
|
||||
|
||||
}
|
||||
@ -141,11 +144,11 @@ func (mp *MysqlProvider) SessionInit(maxlifetime int64, savePath string) error {
|
||||
// get mysql session by sid
|
||||
func (mp *MysqlProvider) SessionRead(sid string) (session.SessionStore, error) {
|
||||
c := mp.connectInit()
|
||||
row := c.QueryRow("select session_data from session where session_key=?", sid)
|
||||
row := c.QueryRow("select session_data from "+TableName+" where session_key=?", sid)
|
||||
var sessiondata []byte
|
||||
err := row.Scan(&sessiondata)
|
||||
if err == sql.ErrNoRows {
|
||||
c.Exec("insert into session(`session_key`,`session_data`,`session_expiry`) values(?,?,?)",
|
||||
c.Exec("insert into "+TableName+"(`session_key`,`session_data`,`session_expiry`) values(?,?,?)",
|
||||
sid, "", time.Now().Unix())
|
||||
}
|
||||
var kv map[interface{}]interface{}
|
||||
@ -165,7 +168,7 @@ func (mp *MysqlProvider) SessionRead(sid string) (session.SessionStore, error) {
|
||||
func (mp *MysqlProvider) SessionExist(sid string) bool {
|
||||
c := mp.connectInit()
|
||||
defer c.Close()
|
||||
row := c.QueryRow("select session_data from session where session_key=?", sid)
|
||||
row := c.QueryRow("select session_data from "+TableName+" where session_key=?", sid)
|
||||
var sessiondata []byte
|
||||
err := row.Scan(&sessiondata)
|
||||
if err == sql.ErrNoRows {
|
||||
@ -178,13 +181,13 @@ func (mp *MysqlProvider) SessionExist(sid string) bool {
|
||||
// generate new sid for mysql session
|
||||
func (mp *MysqlProvider) SessionRegenerate(oldsid, sid string) (session.SessionStore, error) {
|
||||
c := mp.connectInit()
|
||||
row := c.QueryRow("select session_data from session where session_key=?", oldsid)
|
||||
row := c.QueryRow("select session_data from "+TableName+" where session_key=?", oldsid)
|
||||
var sessiondata []byte
|
||||
err := row.Scan(&sessiondata)
|
||||
if err == sql.ErrNoRows {
|
||||
c.Exec("insert into session(`session_key`,`session_data`,`session_expiry`) values(?,?,?)", oldsid, "", time.Now().Unix())
|
||||
c.Exec("insert into "+TableName+"(`session_key`,`session_data`,`session_expiry`) values(?,?,?)", oldsid, "", time.Now().Unix())
|
||||
}
|
||||
c.Exec("update session set `session_key`=? where session_key=?", sid, oldsid)
|
||||
c.Exec("update "+TableName+" set `session_key`=? where session_key=?", sid, oldsid)
|
||||
var kv map[interface{}]interface{}
|
||||
if len(sessiondata) == 0 {
|
||||
kv = make(map[interface{}]interface{})
|
||||
@ -201,7 +204,7 @@ func (mp *MysqlProvider) SessionRegenerate(oldsid, sid string) (session.SessionS
|
||||
// delete mysql session by sid
|
||||
func (mp *MysqlProvider) SessionDestroy(sid string) error {
|
||||
c := mp.connectInit()
|
||||
c.Exec("DELETE FROM session where session_key=?", sid)
|
||||
c.Exec("DELETE FROM "+TableName+" where session_key=?", sid)
|
||||
c.Close()
|
||||
return nil
|
||||
}
|
||||
@ -209,7 +212,7 @@ func (mp *MysqlProvider) SessionDestroy(sid string) error {
|
||||
// delete expired values in mysql session
|
||||
func (mp *MysqlProvider) SessionGC() {
|
||||
c := mp.connectInit()
|
||||
c.Exec("DELETE from session where session_expiry < ?", time.Now().Unix()-mp.maxlifetime)
|
||||
c.Exec("DELETE from "+TableName+" where session_expiry < ?", time.Now().Unix()-mp.maxlifetime)
|
||||
c.Close()
|
||||
return
|
||||
}
|
||||
@ -219,7 +222,7 @@ func (mp *MysqlProvider) SessionAll() int {
|
||||
c := mp.connectInit()
|
||||
defer c.Close()
|
||||
var total int
|
||||
err := c.QueryRow("SELECT count(*) as num from session").Scan(&total)
|
||||
err := c.QueryRow("SELECT count(*) as num from " + TableName).Scan(&total)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
@ -40,15 +40,13 @@ func serverStaticRouter(ctx *context.Context) {
|
||||
if utils.FileExists(file) {
|
||||
http.ServeFile(ctx.ResponseWriter, ctx.Request, file)
|
||||
return
|
||||
} else {
|
||||
i++
|
||||
if i == len(StaticDir) {
|
||||
http.NotFound(ctx.ResponseWriter, ctx.Request)
|
||||
return
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
i++
|
||||
if i == len(StaticDir) {
|
||||
http.NotFound(ctx.ResponseWriter, ctx.Request)
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(requestPath, prefix) {
|
||||
if len(requestPath) > len(prefix) && requestPath[len(prefix)] != '/' {
|
||||
|
80
template.go
80
template.go
@ -28,17 +28,14 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
beegoTplFuncMap template.FuncMap
|
||||
// beego template caching map and supported template file extensions.
|
||||
BeeTemplates map[string]*template.Template
|
||||
BeeTemplateExt []string
|
||||
beegoTplFuncMap = make(template.FuncMap)
|
||||
// BeeTemplates caching map and supported template file extensions.
|
||||
BeeTemplates = make(map[string]*template.Template)
|
||||
// BeeTemplateExt stores the template extention which will build
|
||||
BeeTemplateExt = []string{"tpl", "html"}
|
||||
)
|
||||
|
||||
func init() {
|
||||
BeeTemplates = make(map[string]*template.Template)
|
||||
beegoTplFuncMap = make(template.FuncMap)
|
||||
BeeTemplateExt = make([]string, 0)
|
||||
BeeTemplateExt = append(BeeTemplateExt, "tpl", "html")
|
||||
beegoTplFuncMap["dateformat"] = DateFormat
|
||||
beegoTplFuncMap["date"] = Date
|
||||
beegoTplFuncMap["compare"] = Compare
|
||||
@ -46,14 +43,15 @@ func init() {
|
||||
beegoTplFuncMap["not_nil"] = NotNil
|
||||
beegoTplFuncMap["not_null"] = NotNil
|
||||
beegoTplFuncMap["substr"] = Substr
|
||||
beegoTplFuncMap["html2str"] = Html2str
|
||||
beegoTplFuncMap["html2str"] = HTML2str
|
||||
beegoTplFuncMap["str2html"] = Str2html
|
||||
beegoTplFuncMap["htmlquote"] = Htmlquote
|
||||
beegoTplFuncMap["htmlunquote"] = Htmlunquote
|
||||
beegoTplFuncMap["renderform"] = RenderForm
|
||||
beegoTplFuncMap["assets_js"] = AssetsJs
|
||||
beegoTplFuncMap["assets_css"] = AssetsCss
|
||||
beegoTplFuncMap["assets_css"] = AssetsCSS
|
||||
beegoTplFuncMap["config"] = Config
|
||||
beegoTplFuncMap["map_get"] = MapGet
|
||||
|
||||
// go1.2 added template funcs
|
||||
// Comparisons
|
||||
@ -64,7 +62,7 @@ func init() {
|
||||
beegoTplFuncMap["lt"] = lt // <
|
||||
beegoTplFuncMap["ne"] = ne // !=
|
||||
|
||||
beegoTplFuncMap["urlfor"] = UrlFor // !=
|
||||
beegoTplFuncMap["urlfor"] = URLFor // !=
|
||||
}
|
||||
|
||||
// AddFuncMap let user to register a func in the template.
|
||||
@ -78,7 +76,7 @@ type templatefile struct {
|
||||
files map[string][]string
|
||||
}
|
||||
|
||||
func (self *templatefile) visit(paths string, f os.FileInfo, err error) error {
|
||||
func (tf *templatefile) visit(paths string, f os.FileInfo, err error) error {
|
||||
if f == nil {
|
||||
return err
|
||||
}
|
||||
@ -91,21 +89,21 @@ func (self *templatefile) visit(paths string, f os.FileInfo, err error) error {
|
||||
|
||||
replace := strings.NewReplacer("\\", "/")
|
||||
a := []byte(paths)
|
||||
a = a[len([]byte(self.root)):]
|
||||
a = a[len([]byte(tf.root)):]
|
||||
file := strings.TrimLeft(replace.Replace(string(a)), "/")
|
||||
subdir := filepath.Dir(file)
|
||||
if _, ok := self.files[subdir]; ok {
|
||||
self.files[subdir] = append(self.files[subdir], file)
|
||||
if _, ok := tf.files[subdir]; ok {
|
||||
tf.files[subdir] = append(tf.files[subdir], file)
|
||||
} else {
|
||||
m := make([]string, 1)
|
||||
m[0] = file
|
||||
self.files[subdir] = m
|
||||
tf.files[subdir] = m
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// return this path contains supported template extension of beego or not.
|
||||
// HasTemplateExt return this path contains supported template extension of beego or not.
|
||||
func HasTemplateExt(paths string) bool {
|
||||
for _, v := range BeeTemplateExt {
|
||||
if strings.HasSuffix(paths, "."+v) {
|
||||
@ -115,7 +113,7 @@ func HasTemplateExt(paths string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// add new extension for template.
|
||||
// AddTemplateExt add new extension for template.
|
||||
func AddTemplateExt(ext string) {
|
||||
for _, v := range BeeTemplateExt {
|
||||
if v == ext {
|
||||
@ -125,15 +123,14 @@ func AddTemplateExt(ext string) {
|
||||
BeeTemplateExt = append(BeeTemplateExt, ext)
|
||||
}
|
||||
|
||||
// build all template files in a directory.
|
||||
// BuildTemplate will build all template files in a directory.
|
||||
// it makes beego can render any template file in view directory.
|
||||
func BuildTemplate(dir string) error {
|
||||
func BuildTemplate(dir string, files ...string) error {
|
||||
if _, err := os.Stat(dir); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("dir open err")
|
||||
}
|
||||
return errors.New("dir open err")
|
||||
}
|
||||
self := &templatefile{
|
||||
root: dir,
|
||||
@ -148,11 +145,13 @@ func BuildTemplate(dir string) error {
|
||||
}
|
||||
for _, v := range self.files {
|
||||
for _, file := range v {
|
||||
t, err := getTemplate(self.root, file, v...)
|
||||
if err != nil {
|
||||
Trace("parse template err:", file, err)
|
||||
} else {
|
||||
BeeTemplates[file] = t
|
||||
if len(files) == 0 || utils.InSlice(file, files) {
|
||||
t, err := getTemplate(self.root, file, v...)
|
||||
if err != nil {
|
||||
Trace("parse template err:", file, err)
|
||||
} else {
|
||||
BeeTemplates[file] = t
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -260,3 +259,30 @@ func _getTemplate(t0 *template.Template, root string, submods [][]string, others
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetViewsPath sets view directory path in beego application.
|
||||
func SetViewsPath(path string) *App {
|
||||
ViewsPath = path
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// SetStaticPath sets static directory path and proper url pattern in beego application.
|
||||
// if beego.SetStaticPath("static","public"), visit /static/* to load static file in folder "public".
|
||||
func SetStaticPath(url string, path string) *App {
|
||||
if !strings.HasPrefix(url, "/") {
|
||||
url = "/" + url
|
||||
}
|
||||
url = strings.TrimRight(url, "/")
|
||||
StaticDir[url] = path
|
||||
return BeeApp
|
||||
}
|
||||
|
||||
// DelStaticPath removes the static folder setting in this url pattern in beego application.
|
||||
func DelStaticPath(url string) *App {
|
||||
if !strings.HasPrefix(url, "/") {
|
||||
url = "/" + url
|
||||
}
|
||||
url = strings.TrimRight(url, "/")
|
||||
delete(StaticDir, url)
|
||||
return BeeApp
|
||||
}
|
||||
|
@ -20,11 +20,11 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var header string = `{{define "header"}}
|
||||
var header = `{{define "header"}}
|
||||
<h1>Hello, astaxie!</h1>
|
||||
{{end}}`
|
||||
|
||||
var index string = `<!DOCTYPE html>
|
||||
var index = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>beego welcome template</title>
|
||||
@ -37,7 +37,7 @@ var index string = `<!DOCTYPE html>
|
||||
</html>
|
||||
`
|
||||
|
||||
var block string = `{{define "block"}}
|
||||
var block = `{{define "block"}}
|
||||
<h1>Hello, blocks!</h1>
|
||||
{{end}}`
|
||||
|
||||
@ -82,7 +82,7 @@ func TestTemplate(t *testing.T) {
|
||||
os.RemoveAll(dir)
|
||||
}
|
||||
|
||||
var menu string = `<div class="menu">
|
||||
var menu = `<div class="menu">
|
||||
<ul>
|
||||
<li>menu1</li>
|
||||
<li>menu2</li>
|
||||
@ -90,7 +90,7 @@ var menu string = `<div class="menu">
|
||||
</ul>
|
||||
</div>
|
||||
`
|
||||
var user string = `<!DOCTYPE html>
|
||||
var user = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>beego welcome template</title>
|
||||
@ -123,7 +123,7 @@ func TestRelativeTemplate(t *testing.T) {
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
if err := BuildTemplate(dir); err != nil {
|
||||
if err := BuildTemplate(dir, files[1]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := BeeTemplates["easyui/rbac/user.tpl"].ExecuteTemplate(os.Stdout, "easyui/rbac/user.tpl", nil); err != nil {
|
||||
|
122
templatefunc.go
122
templatefunc.go
@ -44,8 +44,8 @@ func Substr(s string, start, length int) string {
|
||||
return string(bt[start:end])
|
||||
}
|
||||
|
||||
// Html2str returns escaping text convert from html.
|
||||
func Html2str(html string) string {
|
||||
// HTML2str returns escaping text convert from html.
|
||||
func HTML2str(html string) string {
|
||||
src := string(html)
|
||||
|
||||
re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
|
||||
@ -115,7 +115,7 @@ var datePatterns = []string{
|
||||
"r", time.RFC1123Z,
|
||||
}
|
||||
|
||||
// Parse Date use PHP time format.
|
||||
// DateParse Parse Date use PHP time format.
|
||||
func DateParse(dateString, format string) (time.Time, error) {
|
||||
replacer := strings.NewReplacer(datePatterns...)
|
||||
format = replacer.Replace(format)
|
||||
@ -139,14 +139,17 @@ func Compare(a, b interface{}) (equal bool) {
|
||||
return
|
||||
}
|
||||
|
||||
// CompareNot !Compare
|
||||
func CompareNot(a, b interface{}) (equal bool) {
|
||||
return ! Compare(a, b)
|
||||
return !Compare(a, b)
|
||||
}
|
||||
|
||||
func NotNil(a interface{}) (is_nil bool) {
|
||||
return CompareNot(a, nil)
|
||||
// NotNil the same as CompareNot
|
||||
func NotNil(a interface{}) (isNil bool) {
|
||||
return CompareNot(a, nil)
|
||||
}
|
||||
|
||||
// Config get the Appconfig
|
||||
func Config(returnType, key string, defaultVal interface{}) (value interface{}, err error) {
|
||||
switch returnType {
|
||||
case "String":
|
||||
@ -162,12 +165,12 @@ func Config(returnType, key string, defaultVal interface{}) (value interface{},
|
||||
case "DIY":
|
||||
value, err = AppConfig.DIY(key)
|
||||
default:
|
||||
err = errors.New("Config keys must be of type String, Bool, Int, Int64, Float, or DIY!")
|
||||
err = errors.New("Config keys must be of type String, Bool, Int, Int64, Float, or DIY")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if reflect.TypeOf(returnType) != reflect.TypeOf(defaultVal) {
|
||||
err = errors.New("defaultVal type does not match returnType!")
|
||||
err = errors.New("defaultVal type does not match returnType")
|
||||
} else {
|
||||
value, err = defaultVal, nil
|
||||
}
|
||||
@ -184,7 +187,7 @@ func Config(returnType, key string, defaultVal interface{}) (value interface{},
|
||||
return
|
||||
}
|
||||
|
||||
// Convert string to template.HTML type.
|
||||
// Str2html Convert string to template.HTML type.
|
||||
func Str2html(raw string) template.HTML {
|
||||
return template.HTML(raw)
|
||||
}
|
||||
@ -237,14 +240,14 @@ func Htmlunquote(src string) string {
|
||||
return strings.TrimSpace(text)
|
||||
}
|
||||
|
||||
// UrlFor returns url string with another registered controller handler with params.
|
||||
// URLFor returns url string with another registered controller handler with params.
|
||||
// usage:
|
||||
//
|
||||
// UrlFor(".index")
|
||||
// print UrlFor("index")
|
||||
// URLFor(".index")
|
||||
// print URLFor("index")
|
||||
// router /login
|
||||
// print UrlFor("login")
|
||||
// print UrlFor("login", "next","/"")
|
||||
// print URLFor("login")
|
||||
// print URLFor("login", "next","/"")
|
||||
// router /profile/:username
|
||||
// print UrlFor("profile", ":username","John Doe")
|
||||
// result:
|
||||
@ -254,11 +257,11 @@ func Htmlunquote(src string) string {
|
||||
// /user/John%20Doe
|
||||
//
|
||||
// more detail http://beego.me/docs/mvc/controller/urlbuilding.md
|
||||
func UrlFor(endpoint string, values ...interface{}) string {
|
||||
return BeeApp.Handlers.UrlFor(endpoint, values...)
|
||||
func URLFor(endpoint string, values ...interface{}) string {
|
||||
return BeeApp.Handlers.URLFor(endpoint, values...)
|
||||
}
|
||||
|
||||
// returns script tag with src string.
|
||||
// AssetsJs returns script tag with src string.
|
||||
func AssetsJs(src string) template.HTML {
|
||||
text := string(src)
|
||||
|
||||
@ -267,8 +270,8 @@ func AssetsJs(src string) template.HTML {
|
||||
return template.HTML(text)
|
||||
}
|
||||
|
||||
// returns stylesheet link tag with src string.
|
||||
func AssetsCss(src string) template.HTML {
|
||||
// AssetsCSS returns stylesheet link tag with src string.
|
||||
func AssetsCSS(src string) template.HTML {
|
||||
text := string(src)
|
||||
|
||||
text = "<link href=\"" + src + "\" rel=\"stylesheet\" />"
|
||||
@ -276,7 +279,7 @@ func AssetsCss(src string) template.HTML {
|
||||
return template.HTML(text)
|
||||
}
|
||||
|
||||
// parse form values to struct via tag.
|
||||
// ParseForm will parse form values to struct via tag.
|
||||
func ParseForm(form url.Values, obj interface{}) error {
|
||||
objT := reflect.TypeOf(obj)
|
||||
objV := reflect.ValueOf(obj)
|
||||
@ -352,7 +355,7 @@ func ParseForm(form url.Values, obj interface{}) error {
|
||||
if len(tags) > 1 {
|
||||
format = tags[1]
|
||||
}
|
||||
t, err := time.Parse(format, value)
|
||||
t, err := time.ParseInLocation(format, value, time.Local)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -398,7 +401,7 @@ var unKind = map[reflect.Kind]bool{
|
||||
reflect.UnsafePointer: true,
|
||||
}
|
||||
|
||||
// render object to form html.
|
||||
// RenderForm will render object to form html.
|
||||
// obj must be a struct pointer.
|
||||
func RenderForm(obj interface{}) template.HTML {
|
||||
objT := reflect.TypeOf(obj)
|
||||
@ -651,4 +654,77 @@ func ge(arg1, arg2 interface{}) (bool, error) {
|
||||
return !lessThan, nil
|
||||
}
|
||||
|
||||
// go1.2 added template funcs. end
|
||||
// MapGet getting value from map by keys
|
||||
// usage:
|
||||
// Data["m"] = map[string]interface{} {
|
||||
// "a": 1,
|
||||
// "1": map[string]float64{
|
||||
// "c": 4,
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// {{ map_get m "a" }} // return 1
|
||||
// {{ map_get m 1 "c" }} // return 4
|
||||
func MapGet(arg1 interface{}, arg2 ...interface{}) (interface{}, error) {
|
||||
arg1Type := reflect.TypeOf(arg1)
|
||||
arg1Val := reflect.ValueOf(arg1)
|
||||
|
||||
if arg1Type.Kind() == reflect.Map && len(arg2) > 0 {
|
||||
// check whether arg2[0] type equals to arg1 key type
|
||||
// if they are different, make convertion
|
||||
arg2Val := reflect.ValueOf(arg2[0])
|
||||
arg2Type := reflect.TypeOf(arg2[0])
|
||||
if arg2Type.Kind() != arg1Type.Key().Kind() {
|
||||
// convert arg2Value to string
|
||||
var arg2ConvertedVal interface{}
|
||||
arg2String := fmt.Sprintf("%v", arg2[0])
|
||||
|
||||
// convert string representation to any other type
|
||||
switch arg1Type.Key().Kind() {
|
||||
case reflect.Bool:
|
||||
arg2ConvertedVal, _ = strconv.ParseBool(arg2String)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
arg2ConvertedVal, _ = strconv.ParseInt(arg2String, 0, 64)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
arg2ConvertedVal, _ = strconv.ParseUint(arg2String, 0, 64)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
arg2ConvertedVal, _ = strconv.ParseFloat(arg2String, 64)
|
||||
case reflect.String:
|
||||
arg2ConvertedVal = arg2String
|
||||
default:
|
||||
arg2ConvertedVal = arg2Val.Interface()
|
||||
}
|
||||
arg2Val = reflect.ValueOf(arg2ConvertedVal)
|
||||
}
|
||||
|
||||
storedVal := arg1Val.MapIndex(arg2Val)
|
||||
|
||||
if storedVal.IsValid() {
|
||||
var result interface{}
|
||||
|
||||
switch arg1Type.Elem().Kind() {
|
||||
case reflect.Bool:
|
||||
result = storedVal.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
result = storedVal.Int()
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
result = storedVal.Uint()
|
||||
case reflect.Float32, reflect.Float64:
|
||||
result = storedVal.Float()
|
||||
case reflect.String:
|
||||
result = storedVal.String()
|
||||
default:
|
||||
result = storedVal.Interface()
|
||||
}
|
||||
|
||||
// if there is more keys, handle this recursively
|
||||
if len(arg2) > 1 {
|
||||
return MapGet(result, arg2[1:]...)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, nil
|
||||
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ func TestHtml2str(t *testing.T) {
|
||||
|
||||
|
||||
\n`
|
||||
if Html2str(h) != "123\\n\n\\n" {
|
||||
if HTML2str(h) != "123\\n\n\\n" {
|
||||
t.Error("should be equal")
|
||||
}
|
||||
}
|
||||
@ -82,15 +82,15 @@ func TestCompareRelated(t *testing.T) {
|
||||
if !Compare("1", 1) {
|
||||
t.Error("should be equal")
|
||||
}
|
||||
if CompareNot("abc", "abc") {
|
||||
t.Error("should be equal")
|
||||
}
|
||||
if !CompareNot("abc", "aBc") {
|
||||
t.Error("should be not equal")
|
||||
}
|
||||
if !NotNil("a string") {
|
||||
t.Error("should not be nil")
|
||||
}
|
||||
if CompareNot("abc", "abc") {
|
||||
t.Error("should be equal")
|
||||
}
|
||||
if !CompareNot("abc", "aBc") {
|
||||
t.Error("should be not equal")
|
||||
}
|
||||
if !NotNil("a string") {
|
||||
t.Error("should not be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHtmlquote(t *testing.T) {
|
||||
@ -111,7 +111,7 @@ func TestHtmlunquote(t *testing.T) {
|
||||
|
||||
func TestParseForm(t *testing.T) {
|
||||
type user struct {
|
||||
Id int `form:"-"`
|
||||
ID int `form:"-"`
|
||||
tag string `form:"tag"`
|
||||
Name interface{} `form:"username"`
|
||||
Age int `form:"age,text"`
|
||||
@ -123,7 +123,7 @@ func TestParseForm(t *testing.T) {
|
||||
|
||||
u := user{}
|
||||
form := url.Values{
|
||||
"Id": []string{"1"},
|
||||
"ID": []string{"1"},
|
||||
"-": []string{"1"},
|
||||
"tag": []string{"no"},
|
||||
"username": []string{"test"},
|
||||
@ -139,8 +139,8 @@ func TestParseForm(t *testing.T) {
|
||||
if err := ParseForm(form, &u); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if u.Id != 0 {
|
||||
t.Errorf("Id should equal 0 but got %v", u.Id)
|
||||
if u.ID != 0 {
|
||||
t.Errorf("ID should equal 0 but got %v", u.ID)
|
||||
}
|
||||
if len(u.tag) != 0 {
|
||||
t.Errorf("tag's length should equal 0 but got %v", len(u.tag))
|
||||
@ -168,7 +168,7 @@ func TestParseForm(t *testing.T) {
|
||||
|
||||
func TestRenderForm(t *testing.T) {
|
||||
type user struct {
|
||||
Id int `form:"-"`
|
||||
ID int `form:"-"`
|
||||
tag string `form:"tag"`
|
||||
Name interface{} `form:"username"`
|
||||
Age int `form:"age,text,年龄:"`
|
||||
@ -244,3 +244,80 @@ func TestParseFormTag(t *testing.T) {
|
||||
t.Errorf("Form Tag that should be ignored was not correctly parsed.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapGet(t *testing.T) {
|
||||
// test one level map
|
||||
m1 := map[string]int64{
|
||||
"a": 1,
|
||||
"1": 2,
|
||||
}
|
||||
|
||||
if res, err := MapGet(m1, "a"); err == nil {
|
||||
if res.(int64) != 1 {
|
||||
t.Errorf("Should return 1, but return %v", res)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Error happens %v", err)
|
||||
}
|
||||
|
||||
if res, err := MapGet(m1, "1"); err == nil {
|
||||
if res.(int64) != 2 {
|
||||
t.Errorf("Should return 2, but return %v", res)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Error happens %v", err)
|
||||
}
|
||||
|
||||
if res, err := MapGet(m1, 1); err == nil {
|
||||
if res.(int64) != 2 {
|
||||
t.Errorf("Should return 2, but return %v", res)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Error happens %v", err)
|
||||
}
|
||||
|
||||
// test 2 level map
|
||||
m2 := map[string]interface{}{
|
||||
"1": map[string]float64{
|
||||
"2": 3.5,
|
||||
},
|
||||
}
|
||||
|
||||
if res, err := MapGet(m2, 1, 2); err == nil {
|
||||
if res.(float64) != 3.5 {
|
||||
t.Errorf("Should return 3.5, but return %v", res)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Error happens %v", err)
|
||||
}
|
||||
|
||||
// test 5 level map
|
||||
m5 := map[string]interface{}{
|
||||
"1": map[string]interface{}{
|
||||
"2": map[string]interface{}{
|
||||
"3": map[string]interface{}{
|
||||
"4": map[string]interface{}{
|
||||
"5": 1.2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if res, err := MapGet(m5, 1, 2, 3, 4, 5); err == nil {
|
||||
if res.(float64) != 1.2 {
|
||||
t.Errorf("Should return 1.2, but return %v", res)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Error happens %v", err)
|
||||
}
|
||||
|
||||
// check whether element not exists in map
|
||||
if res, err := MapGet(m5, 5, 4, 3, 2, 1); err == nil {
|
||||
if res != nil {
|
||||
t.Errorf("Should return nil, but return %v", res)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Error happens %v", err)
|
||||
}
|
||||
}
|
||||
|
31
tree.go
31
tree.go
@ -22,6 +22,10 @@ import (
|
||||
"github.com/astaxie/beego/utils"
|
||||
)
|
||||
|
||||
// Tree has three elements: FixRouter/wildcard/leaves
|
||||
// fixRouter sotres Fixed Router
|
||||
// wildcard stores params
|
||||
// leaves store the endpoint information
|
||||
type Tree struct {
|
||||
//search fix route first
|
||||
fixrouters map[string]*Tree
|
||||
@ -33,13 +37,14 @@ type Tree struct {
|
||||
leaves []*leafInfo
|
||||
}
|
||||
|
||||
// NewTree return a new Tree
|
||||
func NewTree() *Tree {
|
||||
return &Tree{
|
||||
fixrouters: make(map[string]*Tree),
|
||||
}
|
||||
}
|
||||
|
||||
// add Tree to the exist Tree
|
||||
// AddTree will add tree to the exist Tree
|
||||
// prefix should has no params
|
||||
func (t *Tree) AddTree(prefix string, tree *Tree) {
|
||||
t.addtree(splitPath(prefix), tree, nil, "")
|
||||
@ -187,7 +192,7 @@ func filterTreeWithPrefix(t *Tree, wildcards []string, reg string) {
|
||||
}
|
||||
}
|
||||
|
||||
// call addseg function
|
||||
// AddRouter call addseg function
|
||||
func (t *Tree) AddRouter(pattern string, runObject interface{}) {
|
||||
t.addseg(splitPath(pattern), runObject, nil, "")
|
||||
}
|
||||
@ -266,7 +271,7 @@ func (t *Tree) addseg(segments []string, route interface{}, wildcards []string,
|
||||
}
|
||||
}
|
||||
|
||||
// match router to runObject & params
|
||||
// Match router to runObject & params
|
||||
func (t *Tree) Match(pattern string) (runObject interface{}, params map[string]string) {
|
||||
if len(pattern) == 0 || pattern[0] != '/' {
|
||||
return nil, nil
|
||||
@ -349,7 +354,7 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string
|
||||
continue
|
||||
}
|
||||
params[v] = ""
|
||||
j += 1
|
||||
j++
|
||||
}
|
||||
return true, params
|
||||
}
|
||||
@ -402,7 +407,7 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string
|
||||
return false, nil
|
||||
}
|
||||
params[v] = wildcardValues[j]
|
||||
j += 1
|
||||
j++
|
||||
}
|
||||
if len(params) != len(wildcardValues) {
|
||||
return false, nil
|
||||
@ -453,9 +458,8 @@ func splitSegment(key string) (bool, []string, string) {
|
||||
if strings.HasPrefix(key, "*") {
|
||||
if key == "*.*" {
|
||||
return true, []string{".", ":path", ":ext"}, ""
|
||||
} else {
|
||||
return true, []string{":splat"}, ""
|
||||
}
|
||||
return true, []string{":splat"}, ""
|
||||
}
|
||||
if strings.ContainsAny(key, ":") {
|
||||
var paramsNum int
|
||||
@ -469,7 +473,7 @@ func splitSegment(key string) (bool, []string, string) {
|
||||
reg := regexp.MustCompile(`[a-zA-Z0-9_]+`)
|
||||
for i, v := range key {
|
||||
if skipnum > 0 {
|
||||
skipnum -= 1
|
||||
skipnum--
|
||||
continue
|
||||
}
|
||||
if start {
|
||||
@ -483,7 +487,7 @@ func splitSegment(key string) (bool, []string, string) {
|
||||
startexp = false
|
||||
skipnum = 3
|
||||
param = make([]rune, 0)
|
||||
paramsNum += 1
|
||||
paramsNum++
|
||||
continue
|
||||
}
|
||||
}
|
||||
@ -491,7 +495,7 @@ func splitSegment(key string) (bool, []string, string) {
|
||||
if key[i+1:i+7] == "string" {
|
||||
out = append(out, []rune(`([\w]+)`)...)
|
||||
params = append(params, ":"+string(param))
|
||||
paramsNum += 1
|
||||
paramsNum++
|
||||
start = false
|
||||
startexp = false
|
||||
skipnum = 6
|
||||
@ -509,7 +513,7 @@ func splitSegment(key string) (bool, []string, string) {
|
||||
out = append(out, []rune(`(.+)`)...)
|
||||
params = append(params, ":"+string(param))
|
||||
param = make([]rune, 0)
|
||||
paramsNum += 1
|
||||
paramsNum++
|
||||
start = false
|
||||
startexp = false
|
||||
}
|
||||
@ -527,7 +531,7 @@ func splitSegment(key string) (bool, []string, string) {
|
||||
startexp = true
|
||||
start = false
|
||||
params = append(params, ":"+string(param))
|
||||
paramsNum += 1
|
||||
paramsNum++
|
||||
expt = make([]rune, 0)
|
||||
expt = append(expt, '(')
|
||||
} else if v == ')' {
|
||||
@ -548,7 +552,6 @@ func splitSegment(key string) (bool, []string, string) {
|
||||
params = append(params, ":"+string(param))
|
||||
}
|
||||
return true, params, string(out)
|
||||
} else {
|
||||
return false, nil, ""
|
||||
}
|
||||
return false, nil, ""
|
||||
}
|
||||
|
@ -457,7 +457,7 @@ func (b Base64) GetLimitValue() interface{} {
|
||||
}
|
||||
|
||||
// just for chinese mobile phone number
|
||||
var mobilePattern = regexp.MustCompile("^((\\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][67]|[4][579]))\\d{8}$")
|
||||
var mobilePattern = regexp.MustCompile("^((\\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][067]|[4][579]))\\d{8}$")
|
||||
|
||||
type Mobile struct {
|
||||
Match
|
||||
|
Loading…
Reference in New Issue
Block a user