mirror of
https://github.com/astaxie/beego.git
synced 2024-11-22 15:00:54 +00:00
Merge branch 'astaxie/develop' into environmentVar
This commit is contained in:
commit
5bd7d8c43f
17
.github/ISSUE_TEMPLATE
vendored
Normal file
17
.github/ISSUE_TEMPLATE
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Please answer these questions before submitting your issue. Thanks!
|
||||||
|
|
||||||
|
1. What version of Go and beego are you using (`bee version`)?
|
||||||
|
|
||||||
|
|
||||||
|
2. What operating system and processor architecture are you using (`go env`)?
|
||||||
|
|
||||||
|
|
||||||
|
3. What did you do?
|
||||||
|
If possible, provide a recipe for reproducing the error.
|
||||||
|
A complete runnable program is good.
|
||||||
|
|
||||||
|
|
||||||
|
4. What did you expect to see?
|
||||||
|
|
||||||
|
|
||||||
|
5. What did you see instead?
|
@ -1,8 +1,7 @@
|
|||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- tip
|
- 1.6
|
||||||
- 1.6.0
|
|
||||||
- 1.5.3
|
- 1.5.3
|
||||||
- 1.4.3
|
- 1.4.3
|
||||||
services:
|
services:
|
||||||
@ -32,12 +31,12 @@ install:
|
|||||||
- go get github.com/siddontang/ledisdb/config
|
- go get github.com/siddontang/ledisdb/config
|
||||||
- go get github.com/siddontang/ledisdb/ledis
|
- go get github.com/siddontang/ledisdb/ledis
|
||||||
- go get golang.org/x/tools/cmd/vet
|
- go get golang.org/x/tools/cmd/vet
|
||||||
- go get github.com/golang/lint/golint
|
|
||||||
- go get github.com/ssdb/gossdb/ssdb
|
- go get github.com/ssdb/gossdb/ssdb
|
||||||
before_script:
|
before_script:
|
||||||
- sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi"
|
- sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi"
|
||||||
- sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi"
|
- sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi"
|
||||||
- sh -c "if [ '$ORM_DRIVER' = 'sqlite' ]; then touch $TRAVIS_BUILD_DIR/orm_test.db; fi"
|
- sh -c "if [ '$ORM_DRIVER' = 'sqlite' ]; then touch $TRAVIS_BUILD_DIR/orm_test.db; fi"
|
||||||
|
- sh -c "if [ $(go version) == *1.[5-9]* ]; then go get github.com/golang/lint/golint; golint ./...; fi"
|
||||||
- mkdir -p res/var
|
- mkdir -p res/var
|
||||||
- ./ssdb/ssdb-server ./ssdb/ssdb.conf -d
|
- ./ssdb/ssdb-server ./ssdb/ssdb.conf -d
|
||||||
after_script:
|
after_script:
|
||||||
@ -45,7 +44,4 @@ after_script:
|
|||||||
- rm -rf ./res/var/*
|
- rm -rf ./res/var/*
|
||||||
script:
|
script:
|
||||||
- go vet -x ./...
|
- go vet -x ./...
|
||||||
- $HOME/gopath/bin/golint ./...
|
|
||||||
- go test -v ./...
|
- go test -v ./...
|
||||||
notifications:
|
|
||||||
webhooks: https://hooks.pubu.im/services/z7m9bvybl3rgtg9
|
|
||||||
|
7
admin.go
7
admin.go
@ -24,6 +24,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/astaxie/beego/grace"
|
"github.com/astaxie/beego/grace"
|
||||||
|
"github.com/astaxie/beego/logs"
|
||||||
"github.com/astaxie/beego/toolbox"
|
"github.com/astaxie/beego/toolbox"
|
||||||
"github.com/astaxie/beego/utils"
|
"github.com/astaxie/beego/utils"
|
||||||
)
|
)
|
||||||
@ -196,7 +197,7 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
|
|||||||
BeforeExec: "Before Exec",
|
BeforeExec: "Before Exec",
|
||||||
AfterExec: "After Exec",
|
AfterExec: "After Exec",
|
||||||
FinishRouter: "Finish Router"} {
|
FinishRouter: "Finish Router"} {
|
||||||
if bf, ok := BeeApp.Handlers.filters[k]; ok {
|
if bf := BeeApp.Handlers.filters[k]; len(bf) > 0 {
|
||||||
filterType = fr
|
filterType = fr
|
||||||
filterTypes = append(filterTypes, filterType)
|
filterTypes = append(filterTypes, filterType)
|
||||||
resultList := new([][]string)
|
resultList := new([][]string)
|
||||||
@ -410,7 +411,7 @@ func (admin *adminApp) Run() {
|
|||||||
for p, f := range admin.routers {
|
for p, f := range admin.routers {
|
||||||
http.Handle(p, f)
|
http.Handle(p, f)
|
||||||
}
|
}
|
||||||
BeeLogger.Info("Admin server Running on %s", addr)
|
logs.Info("Admin server Running on %s", addr)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if BConfig.Listen.Graceful {
|
if BConfig.Listen.Graceful {
|
||||||
@ -419,6 +420,6 @@ func (admin *adminApp) Run() {
|
|||||||
err = http.ListenAndServe(addr, nil)
|
err = http.ListenAndServe(addr, nil)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
BeeLogger.Critical("Admin ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid()))
|
logs.Critical("Admin ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
app.go
26
app.go
@ -24,6 +24,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/astaxie/beego/grace"
|
"github.com/astaxie/beego/grace"
|
||||||
|
"github.com/astaxie/beego/logs"
|
||||||
"github.com/astaxie/beego/utils"
|
"github.com/astaxie/beego/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -68,9 +69,9 @@ func (app *App) Run() {
|
|||||||
if BConfig.Listen.EnableFcgi {
|
if BConfig.Listen.EnableFcgi {
|
||||||
if BConfig.Listen.EnableStdIo {
|
if BConfig.Listen.EnableStdIo {
|
||||||
if err = fcgi.Serve(nil, app.Handlers); err == nil { // standard I/O
|
if err = fcgi.Serve(nil, app.Handlers); err == nil { // standard I/O
|
||||||
BeeLogger.Info("Use FCGI via standard I/O")
|
logs.Info("Use FCGI via standard I/O")
|
||||||
} else {
|
} else {
|
||||||
BeeLogger.Critical("Cannot use FCGI via standard I/O", err)
|
logs.Critical("Cannot use FCGI via standard I/O", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -84,10 +85,10 @@ func (app *App) Run() {
|
|||||||
l, err = net.Listen("tcp", addr)
|
l, err = net.Listen("tcp", addr)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
BeeLogger.Critical("Listen: ", err)
|
logs.Critical("Listen: ", err)
|
||||||
}
|
}
|
||||||
if err = fcgi.Serve(l, app.Handlers); err != nil {
|
if err = fcgi.Serve(l, app.Handlers); err != nil {
|
||||||
BeeLogger.Critical("fcgi.Serve: ", err)
|
logs.Critical("fcgi.Serve: ", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -95,6 +96,7 @@ func (app *App) Run() {
|
|||||||
app.Server.Handler = app.Handlers
|
app.Server.Handler = app.Handlers
|
||||||
app.Server.ReadTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second
|
app.Server.ReadTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second
|
||||||
app.Server.WriteTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second
|
app.Server.WriteTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second
|
||||||
|
app.Server.ErrorLog = logs.GetLogger("HTTP")
|
||||||
|
|
||||||
// run graceful mode
|
// run graceful mode
|
||||||
if BConfig.Listen.Graceful {
|
if BConfig.Listen.Graceful {
|
||||||
@ -111,7 +113,7 @@ func (app *App) Run() {
|
|||||||
server.Server.ReadTimeout = app.Server.ReadTimeout
|
server.Server.ReadTimeout = app.Server.ReadTimeout
|
||||||
server.Server.WriteTimeout = app.Server.WriteTimeout
|
server.Server.WriteTimeout = app.Server.WriteTimeout
|
||||||
if err := server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil {
|
if err := server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil {
|
||||||
BeeLogger.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid()))
|
logs.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid()))
|
||||||
time.Sleep(100 * time.Microsecond)
|
time.Sleep(100 * time.Microsecond)
|
||||||
endRunning <- true
|
endRunning <- true
|
||||||
}
|
}
|
||||||
@ -126,7 +128,7 @@ func (app *App) Run() {
|
|||||||
server.Network = "tcp4"
|
server.Network = "tcp4"
|
||||||
}
|
}
|
||||||
if err := server.ListenAndServe(); err != nil {
|
if err := server.ListenAndServe(); err != nil {
|
||||||
BeeLogger.Critical("ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid()))
|
logs.Critical("ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid()))
|
||||||
time.Sleep(100 * time.Microsecond)
|
time.Sleep(100 * time.Microsecond)
|
||||||
endRunning <- true
|
endRunning <- true
|
||||||
}
|
}
|
||||||
@ -144,9 +146,9 @@ func (app *App) Run() {
|
|||||||
if BConfig.Listen.HTTPSPort != 0 {
|
if BConfig.Listen.HTTPSPort != 0 {
|
||||||
app.Server.Addr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPSAddr, BConfig.Listen.HTTPSPort)
|
app.Server.Addr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPSAddr, BConfig.Listen.HTTPSPort)
|
||||||
}
|
}
|
||||||
BeeLogger.Info("https server Running on %s", app.Server.Addr)
|
logs.Info("https server Running on %s", app.Server.Addr)
|
||||||
if err := app.Server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil {
|
if err := app.Server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil {
|
||||||
BeeLogger.Critical("ListenAndServeTLS: ", err)
|
logs.Critical("ListenAndServeTLS: ", err)
|
||||||
time.Sleep(100 * time.Microsecond)
|
time.Sleep(100 * time.Microsecond)
|
||||||
endRunning <- true
|
endRunning <- true
|
||||||
}
|
}
|
||||||
@ -155,24 +157,24 @@ func (app *App) Run() {
|
|||||||
if BConfig.Listen.EnableHTTP {
|
if BConfig.Listen.EnableHTTP {
|
||||||
go func() {
|
go func() {
|
||||||
app.Server.Addr = addr
|
app.Server.Addr = addr
|
||||||
BeeLogger.Info("http server Running on %s", app.Server.Addr)
|
logs.Info("http server Running on %s", app.Server.Addr)
|
||||||
if BConfig.Listen.ListenTCP4 {
|
if BConfig.Listen.ListenTCP4 {
|
||||||
ln, err := net.Listen("tcp4", app.Server.Addr)
|
ln, err := net.Listen("tcp4", app.Server.Addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
BeeLogger.Critical("ListenAndServe: ", err)
|
logs.Critical("ListenAndServe: ", err)
|
||||||
time.Sleep(100 * time.Microsecond)
|
time.Sleep(100 * time.Microsecond)
|
||||||
endRunning <- true
|
endRunning <- true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = app.Server.Serve(ln); err != nil {
|
if err = app.Server.Serve(ln); err != nil {
|
||||||
BeeLogger.Critical("ListenAndServe: ", err)
|
logs.Critical("ListenAndServe: ", err)
|
||||||
time.Sleep(100 * time.Microsecond)
|
time.Sleep(100 * time.Microsecond)
|
||||||
endRunning <- true
|
endRunning <- true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := app.Server.ListenAndServe(); err != nil {
|
if err := app.Server.ListenAndServe(); err != nil {
|
||||||
BeeLogger.Critical("ListenAndServe: ", err)
|
logs.Critical("ListenAndServe: ", err)
|
||||||
time.Sleep(100 * time.Microsecond)
|
time.Sleep(100 * time.Microsecond)
|
||||||
endRunning <- true
|
endRunning <- true
|
||||||
}
|
}
|
||||||
|
5
beego.go
5
beego.go
@ -23,7 +23,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// VERSION represent beego web framework version.
|
// VERSION represent beego web framework version.
|
||||||
VERSION = "1.6.0"
|
VERSION = "1.6.1"
|
||||||
|
|
||||||
// DEV is for develop
|
// DEV is for develop
|
||||||
DEV = "dev"
|
DEV = "dev"
|
||||||
@ -51,6 +51,7 @@ func AddAPPStartHook(hf hookfunc) {
|
|||||||
// beego.Run(":8089")
|
// beego.Run(":8089")
|
||||||
// beego.Run("127.0.0.1:8089")
|
// beego.Run("127.0.0.1:8089")
|
||||||
func Run(params ...string) {
|
func Run(params ...string) {
|
||||||
|
|
||||||
initBeforeHTTPRun()
|
initBeforeHTTPRun()
|
||||||
|
|
||||||
if len(params) > 0 && params[0] != "" {
|
if len(params) > 0 && params[0] != "" {
|
||||||
@ -74,6 +75,7 @@ func initBeforeHTTPRun() {
|
|||||||
AddAPPStartHook(registerDocs)
|
AddAPPStartHook(registerDocs)
|
||||||
AddAPPStartHook(registerTemplate)
|
AddAPPStartHook(registerTemplate)
|
||||||
AddAPPStartHook(registerAdmin)
|
AddAPPStartHook(registerAdmin)
|
||||||
|
AddAPPStartHook(registerGzip)
|
||||||
|
|
||||||
for _, hk := range hooks {
|
for _, hk := range hooks {
|
||||||
if err := hk(); err != nil {
|
if err := hk(); err != nil {
|
||||||
@ -87,5 +89,6 @@ func TestBeegoInit(ap string) {
|
|||||||
os.Setenv("BEEGO_RUNMODE", "test")
|
os.Setenv("BEEGO_RUNMODE", "test")
|
||||||
appConfigPath = filepath.Join(ap, "conf", "app.conf")
|
appConfigPath = filepath.Join(ap, "conf", "app.conf")
|
||||||
os.Chdir(ap)
|
os.Chdir(ap)
|
||||||
|
LoadAppConfig(appConfigProvider, appConfigPath)
|
||||||
initBeforeHTTPRun()
|
initBeforeHTTPRun()
|
||||||
}
|
}
|
||||||
|
3
cache/redis/redis_test.go
vendored
3
cache/redis/redis_test.go
vendored
@ -18,9 +18,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/garyburd/redigo/redis"
|
|
||||||
|
|
||||||
"github.com/astaxie/beego/cache"
|
"github.com/astaxie/beego/cache"
|
||||||
|
"github.com/garyburd/redigo/redis"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRedisCache(t *testing.T) {
|
func TestRedisCache(t *testing.T) {
|
||||||
|
3
cache/ssdb/ssdb_test.go
vendored
3
cache/ssdb/ssdb_test.go
vendored
@ -1,10 +1,11 @@
|
|||||||
package ssdb
|
package ssdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/astaxie/beego/cache"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/astaxie/beego/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSsdbcacheCache(t *testing.T) {
|
func TestSsdbcacheCache(t *testing.T) {
|
||||||
|
13
config.go
13
config.go
@ -21,6 +21,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/astaxie/beego/config"
|
"github.com/astaxie/beego/config"
|
||||||
|
"github.com/astaxie/beego/logs"
|
||||||
"github.com/astaxie/beego/session"
|
"github.com/astaxie/beego/session"
|
||||||
"github.com/astaxie/beego/utils"
|
"github.com/astaxie/beego/utils"
|
||||||
)
|
)
|
||||||
@ -293,14 +294,14 @@ func parseConfig(appConfigPath string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//init log
|
//init log
|
||||||
BeeLogger.Reset()
|
logs.Reset()
|
||||||
for adaptor, config := range BConfig.Log.Outputs {
|
for adaptor, config := range BConfig.Log.Outputs {
|
||||||
err = BeeLogger.SetLogger(adaptor, config)
|
err = logs.SetLogger(adaptor, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%s with the config `%s` got err:%s\n", adaptor, config, err)
|
fmt.Printf("%s with the config `%s` got err:%s\n", adaptor, config, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetLogFuncCall(BConfig.Log.FileLineNum)
|
logs.SetLogFuncCall(BConfig.Log.FileLineNum)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -316,10 +317,6 @@ func LoadAppConfig(adapterName, configPath string) error {
|
|||||||
return fmt.Errorf("the target config file: %s don't exist", configPath)
|
return fmt.Errorf("the target config file: %s don't exist", configPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if absConfigPath == appConfigPath {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
appConfigPath = absConfigPath
|
appConfigPath = absConfigPath
|
||||||
appConfigProvider = adapterName
|
appConfigProvider = adapterName
|
||||||
|
|
||||||
@ -353,7 +350,7 @@ func (b *beegoAppConfig) String(key string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *beegoAppConfig) Strings(key string) []string {
|
func (b *beegoAppConfig) Strings(key string) []string {
|
||||||
if v := b.innerConfig.Strings(BConfig.RunMode + "::" + key); v[0] != "" {
|
if v := b.innerConfig.Strings(BConfig.RunMode + "::" + key); len(v) > 0 {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
return b.innerConfig.Strings(key)
|
return b.innerConfig.Strings(key)
|
||||||
|
@ -82,6 +82,10 @@ func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) {
|
|||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
//It might be a good idea to throw a error on all unknonw errors?
|
||||||
|
if _, ok := err.(*os.PathError); ok {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if bytes.Equal(line, bEmpty) {
|
if bytes.Equal(line, bEmpty) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,33 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//Default size==20B same as nginx
|
||||||
|
defaultGzipMinLength = 20
|
||||||
|
//Content will only be compressed if content length is either unknown or greater than gzipMinLength.
|
||||||
|
gzipMinLength = defaultGzipMinLength
|
||||||
|
//The compression level used for deflate compression. (0-9).
|
||||||
|
gzipCompressLevel int
|
||||||
|
//List of HTTP methods to compress. If not set, only GET requests are compressed.
|
||||||
|
includedMethods map[string]bool
|
||||||
|
getMethodOnly bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitGzip(minLength, compressLevel int, methods []string) {
|
||||||
|
if minLength >= 0 {
|
||||||
|
gzipMinLength = minLength
|
||||||
|
}
|
||||||
|
gzipCompressLevel = compressLevel
|
||||||
|
if gzipCompressLevel < flate.NoCompression || gzipCompressLevel > flate.BestCompression {
|
||||||
|
gzipCompressLevel = flate.BestSpeed
|
||||||
|
}
|
||||||
|
getMethodOnly = (len(methods) == 0) || (len(methods) == 1 && strings.ToUpper(methods[0]) == "GET")
|
||||||
|
includedMethods = make(map[string]bool, len(methods))
|
||||||
|
for _, v := range methods {
|
||||||
|
includedMethods[strings.ToUpper(v)] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type resetWriter interface {
|
type resetWriter interface {
|
||||||
io.Writer
|
io.Writer
|
||||||
Reset(w io.Writer)
|
Reset(w io.Writer)
|
||||||
@ -41,20 +68,20 @@ func (n nopResetWriter) Reset(w io.Writer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type acceptEncoder struct {
|
type acceptEncoder struct {
|
||||||
name string
|
name string
|
||||||
levelEncode func(int) resetWriter
|
levelEncode func(int) resetWriter
|
||||||
bestSpeedPool *sync.Pool
|
customCompressLevelPool *sync.Pool
|
||||||
bestCompressionPool *sync.Pool
|
bestCompressionPool *sync.Pool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ac acceptEncoder) encode(wr io.Writer, level int) resetWriter {
|
func (ac acceptEncoder) encode(wr io.Writer, level int) resetWriter {
|
||||||
if ac.bestSpeedPool == nil || ac.bestCompressionPool == nil {
|
if ac.customCompressLevelPool == nil || ac.bestCompressionPool == nil {
|
||||||
return nopResetWriter{wr}
|
return nopResetWriter{wr}
|
||||||
}
|
}
|
||||||
var rwr resetWriter
|
var rwr resetWriter
|
||||||
switch level {
|
switch level {
|
||||||
case flate.BestSpeed:
|
case flate.BestSpeed:
|
||||||
rwr = ac.bestSpeedPool.Get().(resetWriter)
|
rwr = ac.customCompressLevelPool.Get().(resetWriter)
|
||||||
case flate.BestCompression:
|
case flate.BestCompression:
|
||||||
rwr = ac.bestCompressionPool.Get().(resetWriter)
|
rwr = ac.bestCompressionPool.Get().(resetWriter)
|
||||||
default:
|
default:
|
||||||
@ -65,13 +92,18 @@ func (ac acceptEncoder) encode(wr io.Writer, level int) resetWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ac acceptEncoder) put(wr resetWriter, level int) {
|
func (ac acceptEncoder) put(wr resetWriter, level int) {
|
||||||
if ac.bestSpeedPool == nil || ac.bestCompressionPool == nil {
|
if ac.customCompressLevelPool == nil || ac.bestCompressionPool == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
wr.Reset(nil)
|
wr.Reset(nil)
|
||||||
|
|
||||||
|
//notice
|
||||||
|
//compressionLevel==BestCompression DOES NOT MATTER
|
||||||
|
//sync.Pool will not memory leak
|
||||||
|
|
||||||
switch level {
|
switch level {
|
||||||
case flate.BestSpeed:
|
case gzipCompressLevel:
|
||||||
ac.bestSpeedPool.Put(wr)
|
ac.customCompressLevelPool.Put(wr)
|
||||||
case flate.BestCompression:
|
case flate.BestCompression:
|
||||||
ac.bestCompressionPool.Put(wr)
|
ac.bestCompressionPool.Put(wr)
|
||||||
}
|
}
|
||||||
@ -79,28 +111,22 @@ func (ac acceptEncoder) put(wr resetWriter, level int) {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
noneCompressEncoder = acceptEncoder{"", nil, nil, nil}
|
noneCompressEncoder = acceptEncoder{"", nil, nil, nil}
|
||||||
gzipCompressEncoder = acceptEncoder{"gzip",
|
gzipCompressEncoder = acceptEncoder{
|
||||||
func(level int) resetWriter { wr, _ := gzip.NewWriterLevel(nil, level); return wr },
|
name: "gzip",
|
||||||
&sync.Pool{
|
levelEncode: func(level int) resetWriter { wr, _ := gzip.NewWriterLevel(nil, level); return wr },
|
||||||
New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestSpeed); return wr },
|
customCompressLevelPool: &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, gzipCompressLevel); return wr }},
|
||||||
},
|
bestCompressionPool: &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestCompression); return wr }},
|
||||||
&sync.Pool{
|
|
||||||
New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestCompression); return wr },
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed
|
//according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed
|
||||||
//deflate
|
//deflate
|
||||||
//The "zlib" format defined in RFC 1950 [31] in combination with
|
//The "zlib" format defined in RFC 1950 [31] in combination with
|
||||||
//the "deflate" compression mechanism described in RFC 1951 [29].
|
//the "deflate" compression mechanism described in RFC 1951 [29].
|
||||||
deflateCompressEncoder = acceptEncoder{"deflate",
|
deflateCompressEncoder = acceptEncoder{
|
||||||
func(level int) resetWriter { wr, _ := zlib.NewWriterLevel(nil, level); return wr },
|
name: "deflate",
|
||||||
&sync.Pool{
|
levelEncode: func(level int) resetWriter { wr, _ := zlib.NewWriterLevel(nil, level); return wr },
|
||||||
New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestSpeed); return wr },
|
customCompressLevelPool: &sync.Pool{New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, gzipCompressLevel); return wr }},
|
||||||
},
|
bestCompressionPool: &sync.Pool{New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestCompression); return wr }},
|
||||||
&sync.Pool{
|
|
||||||
New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestCompression); return wr },
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -120,7 +146,11 @@ func WriteFile(encoding string, writer io.Writer, file *os.File) (bool, string,
|
|||||||
|
|
||||||
// WriteBody reads writes content to writer by the specific encoding(gzip/deflate)
|
// WriteBody reads writes content to writer by the specific encoding(gzip/deflate)
|
||||||
func WriteBody(encoding string, writer io.Writer, content []byte) (bool, string, error) {
|
func WriteBody(encoding string, writer io.Writer, content []byte) (bool, string, error) {
|
||||||
return writeLevel(encoding, writer, bytes.NewReader(content), flate.BestSpeed)
|
if encoding == "" || len(content) < gzipMinLength {
|
||||||
|
_, err := writer.Write(content)
|
||||||
|
return false, "", err
|
||||||
|
}
|
||||||
|
return writeLevel(encoding, writer, bytes.NewReader(content), gzipCompressLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeLevel reads from reader,writes to writer by specific encoding and compress level
|
// writeLevel reads from reader,writes to writer by specific encoding and compress level
|
||||||
@ -156,7 +186,10 @@ func ParseEncoding(r *http.Request) string {
|
|||||||
if r == nil {
|
if r == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return parseEncoding(r)
|
if (getMethodOnly && r.Method == "GET") || includedMethods[r.Method] {
|
||||||
|
return parseEncoding(r)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
type q struct {
|
type q struct {
|
||||||
|
@ -24,13 +24,11 @@ package context
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -79,6 +77,7 @@ func (ctx *Context) Redirect(status int, localurl string) {
|
|||||||
// Abort stops this request.
|
// Abort stops this request.
|
||||||
// if beego.ErrorMaps exists, panic body.
|
// if beego.ErrorMaps exists, panic body.
|
||||||
func (ctx *Context) Abort(status int, body string) {
|
func (ctx *Context) Abort(status int, body string) {
|
||||||
|
ctx.Output.SetStatus(status)
|
||||||
panic(body)
|
panic(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,34 +189,26 @@ func (r *Response) reset(rw http.ResponseWriter) {
|
|||||||
// Write writes the data to the connection as part of an HTTP reply,
|
// Write writes the data to the connection as part of an HTTP reply,
|
||||||
// and sets `started` to true.
|
// and sets `started` to true.
|
||||||
// started means the response has sent out.
|
// started means the response has sent out.
|
||||||
func (w *Response) Write(p []byte) (int, error) {
|
func (r *Response) Write(p []byte) (int, error) {
|
||||||
w.Started = true
|
r.Started = true
|
||||||
return w.ResponseWriter.Write(p)
|
return r.ResponseWriter.Write(p)
|
||||||
}
|
|
||||||
|
|
||||||
// Write writes the data to the connection as part of an HTTP reply,
|
|
||||||
// and sets `started` to true.
|
|
||||||
// started means the response has sent out.
|
|
||||||
func (w *Response) Copy(buf *bytes.Buffer) (int64, error) {
|
|
||||||
w.Started = true
|
|
||||||
return io.Copy(w.ResponseWriter, buf)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteHeader sends an HTTP response header with status code,
|
// WriteHeader sends an HTTP response header with status code,
|
||||||
// and sets `started` to true.
|
// and sets `started` to true.
|
||||||
func (w *Response) WriteHeader(code int) {
|
func (r *Response) WriteHeader(code int) {
|
||||||
if w.Status > 0 {
|
if r.Status > 0 {
|
||||||
//prevent multiple response.WriteHeader calls
|
//prevent multiple response.WriteHeader calls
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Status = code
|
r.Status = code
|
||||||
w.Started = true
|
r.Started = true
|
||||||
w.ResponseWriter.WriteHeader(code)
|
r.ResponseWriter.WriteHeader(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hijack hijacker for http
|
// Hijack hijacker for http
|
||||||
func (w *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
hj, ok := w.ResponseWriter.(http.Hijacker)
|
hj, ok := r.ResponseWriter.(http.Hijacker)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, nil, errors.New("webserver doesn't support hijacking")
|
return nil, nil, errors.New("webserver doesn't support hijacking")
|
||||||
}
|
}
|
||||||
@ -225,15 +216,15 @@ func (w *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Flush http.Flusher
|
// Flush http.Flusher
|
||||||
func (w *Response) Flush() {
|
func (r *Response) Flush() {
|
||||||
if f, ok := w.ResponseWriter.(http.Flusher); ok {
|
if f, ok := r.ResponseWriter.(http.Flusher); ok {
|
||||||
f.Flush()
|
f.Flush()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloseNotify http.CloseNotifier
|
// CloseNotify http.CloseNotifier
|
||||||
func (w *Response) CloseNotify() <-chan bool {
|
func (r *Response) CloseNotify() <-chan bool {
|
||||||
if cn, ok := w.ResponseWriter.(http.CloseNotifier); ok {
|
if cn, ok := r.ResponseWriter.(http.CloseNotifier); ok {
|
||||||
return cn.CloseNotify()
|
return cn.CloseNotify()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -100,7 +100,7 @@ func TestSubDomain(t *testing.T) {
|
|||||||
|
|
||||||
/* TODO Fix this
|
/* TODO Fix this
|
||||||
r, _ = http.NewRequest("GET", "http://127.0.0.1/", nil)
|
r, _ = http.NewRequest("GET", "http://127.0.0.1/", nil)
|
||||||
beegoInput.Request = r
|
beegoInput.Context.Request = r
|
||||||
if beegoInput.SubDomains() != "" {
|
if beegoInput.SubDomains() != "" {
|
||||||
t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
|
t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -72,10 +74,11 @@ func (output *BeegoOutput) Body(content []byte) error {
|
|||||||
if output.Status != 0 {
|
if output.Status != 0 {
|
||||||
output.Context.ResponseWriter.WriteHeader(output.Status)
|
output.Context.ResponseWriter.WriteHeader(output.Status)
|
||||||
output.Status = 0
|
output.Status = 0
|
||||||
|
} else {
|
||||||
|
output.Context.ResponseWriter.Started = true
|
||||||
}
|
}
|
||||||
|
io.Copy(output.Context.ResponseWriter, buf)
|
||||||
_, err := output.Context.ResponseWriter.Copy(buf)
|
return nil
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cookie sets cookie value via given key.
|
// Cookie sets cookie value via given key.
|
||||||
@ -235,6 +238,12 @@ func (output *BeegoOutput) XML(data interface{}, hasIndent bool) error {
|
|||||||
// Download forces response for download file.
|
// Download forces response for download file.
|
||||||
// it prepares the download response header automatically.
|
// it prepares the download response header automatically.
|
||||||
func (output *BeegoOutput) Download(file string, filename ...string) {
|
func (output *BeegoOutput) Download(file string, filename ...string) {
|
||||||
|
// check get file error, file not found or other error.
|
||||||
|
if _, err := os.Stat(file); err != nil {
|
||||||
|
http.ServeFile(output.Context.ResponseWriter, output.Context.Request, file)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
output.Header("Content-Description", "File Transfer")
|
output.Header("Content-Description", "File Transfer")
|
||||||
output.Header("Content-Type", "application/octet-stream")
|
output.Header("Content-Type", "application/octet-stream")
|
||||||
if len(filename) > 0 && filename[0] != "" {
|
if len(filename) > 0 && filename[0] != "" {
|
||||||
|
@ -261,12 +261,13 @@ func (c *Controller) Abort(code string) {
|
|||||||
|
|
||||||
// CustomAbort stops controller handler and show the error data, it's similar Aborts, but support status code and body.
|
// CustomAbort stops controller handler and show the error data, it's similar Aborts, but support status code and body.
|
||||||
func (c *Controller) CustomAbort(status int, body string) {
|
func (c *Controller) CustomAbort(status int, body string) {
|
||||||
c.Ctx.Output.Status = status
|
|
||||||
// first panic from ErrorMaps, is is user defined error functions.
|
// first panic from ErrorMaps, is is user defined error functions.
|
||||||
if _, ok := ErrorMaps[body]; ok {
|
if _, ok := ErrorMaps[body]; ok {
|
||||||
|
c.Ctx.Output.Status = status
|
||||||
panic(body)
|
panic(body)
|
||||||
}
|
}
|
||||||
// last panic user string
|
// last panic user string
|
||||||
|
c.Ctx.ResponseWriter.WriteHeader(status)
|
||||||
c.Ctx.ResponseWriter.Write([]byte(body))
|
c.Ctx.ResponseWriter.Write([]byte(body))
|
||||||
panic(ErrAbort)
|
panic(ErrAbort)
|
||||||
}
|
}
|
||||||
|
213
error.go
213
error.go
@ -210,159 +210,139 @@ var ErrorMaps = make(map[string]*errorInfo, 10)
|
|||||||
|
|
||||||
// show 401 unauthorized error.
|
// show 401 unauthorized error.
|
||||||
func unauthorized(rw http.ResponseWriter, r *http.Request) {
|
func unauthorized(rw http.ResponseWriter, r *http.Request) {
|
||||||
t, _ := template.New("beegoerrortemp").Parse(errtpl)
|
responseError(rw, r,
|
||||||
data := map[string]interface{}{
|
401,
|
||||||
"Title": http.StatusText(401),
|
"<br>The page you have requested can't be authorized."+
|
||||||
"BeegoVersion": VERSION,
|
"<br>Perhaps you are here because:"+
|
||||||
}
|
"<br><br><ul>"+
|
||||||
data["Content"] = template.HTML("<br>The page you have requested can't be authorized." +
|
"<br>The credentials you supplied are incorrect"+
|
||||||
"<br>Perhaps you are here because:" +
|
"<br>There are errors in the website address"+
|
||||||
"<br><br><ul>" +
|
"</ul>",
|
||||||
"<br>The credentials you supplied are incorrect" +
|
)
|
||||||
"<br>There are errors in the website address" +
|
|
||||||
"</ul>")
|
|
||||||
t.Execute(rw, data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// show 402 Payment Required
|
// show 402 Payment Required
|
||||||
func paymentRequired(rw http.ResponseWriter, r *http.Request) {
|
func paymentRequired(rw http.ResponseWriter, r *http.Request) {
|
||||||
t, _ := template.New("beegoerrortemp").Parse(errtpl)
|
responseError(rw, r,
|
||||||
data := map[string]interface{}{
|
402,
|
||||||
"Title": http.StatusText(402),
|
"<br>The page you have requested Payment Required."+
|
||||||
"BeegoVersion": VERSION,
|
"<br>Perhaps you are here because:"+
|
||||||
}
|
"<br><br><ul>"+
|
||||||
data["Content"] = template.HTML("<br>The page you have requested Payment Required." +
|
"<br>The credentials you supplied are incorrect"+
|
||||||
"<br>Perhaps you are here because:" +
|
"<br>There are errors in the website address"+
|
||||||
"<br><br><ul>" +
|
"</ul>",
|
||||||
"<br>The credentials you supplied are incorrect" +
|
)
|
||||||
"<br>There are errors in the website address" +
|
|
||||||
"</ul>")
|
|
||||||
t.Execute(rw, data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// show 403 forbidden error.
|
// show 403 forbidden error.
|
||||||
func forbidden(rw http.ResponseWriter, r *http.Request) {
|
func forbidden(rw http.ResponseWriter, r *http.Request) {
|
||||||
t, _ := template.New("beegoerrortemp").Parse(errtpl)
|
responseError(rw, r,
|
||||||
data := map[string]interface{}{
|
403,
|
||||||
"Title": http.StatusText(403),
|
"<br>The page you have requested is forbidden."+
|
||||||
"BeegoVersion": VERSION,
|
"<br>Perhaps you are here because:"+
|
||||||
}
|
"<br><br><ul>"+
|
||||||
data["Content"] = template.HTML("<br>The page you have requested is forbidden." +
|
"<br>Your address may be blocked"+
|
||||||
"<br>Perhaps you are here because:" +
|
"<br>The site may be disabled"+
|
||||||
"<br><br><ul>" +
|
"<br>You need to log in"+
|
||||||
"<br>Your address may be blocked" +
|
"</ul>",
|
||||||
"<br>The site may be disabled" +
|
)
|
||||||
"<br>You need to log in" +
|
|
||||||
"</ul>")
|
|
||||||
t.Execute(rw, data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// show 404 notfound error.
|
// show 404 not found error.
|
||||||
func notFound(rw http.ResponseWriter, r *http.Request) {
|
func notFound(rw http.ResponseWriter, r *http.Request) {
|
||||||
t, _ := template.New("beegoerrortemp").Parse(errtpl)
|
responseError(rw, r,
|
||||||
data := map[string]interface{}{
|
404,
|
||||||
"Title": http.StatusText(404),
|
"<br>The page you have requested has flown the coop."+
|
||||||
"BeegoVersion": VERSION,
|
"<br>Perhaps you are here because:"+
|
||||||
}
|
"<br><br><ul>"+
|
||||||
data["Content"] = template.HTML("<br>The page you have requested has flown the coop." +
|
"<br>The page has moved"+
|
||||||
"<br>Perhaps you are here because:" +
|
"<br>The page no longer exists"+
|
||||||
"<br><br><ul>" +
|
"<br>You were looking for your puppy and got lost"+
|
||||||
"<br>The page has moved" +
|
"<br>You like 404 pages"+
|
||||||
"<br>The page no longer exists" +
|
"</ul>",
|
||||||
"<br>You were looking for your puppy and got lost" +
|
)
|
||||||
"<br>You like 404 pages" +
|
|
||||||
"</ul>")
|
|
||||||
t.Execute(rw, data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// show 405 Method Not Allowed
|
// show 405 Method Not Allowed
|
||||||
func methodNotAllowed(rw http.ResponseWriter, r *http.Request) {
|
func methodNotAllowed(rw http.ResponseWriter, r *http.Request) {
|
||||||
t, _ := template.New("beegoerrortemp").Parse(errtpl)
|
responseError(rw, r,
|
||||||
data := map[string]interface{}{
|
405,
|
||||||
"Title": http.StatusText(405),
|
"<br>The method you have requested Not Allowed."+
|
||||||
"BeegoVersion": VERSION,
|
"<br>Perhaps you are here because:"+
|
||||||
}
|
"<br><br><ul>"+
|
||||||
data["Content"] = template.HTML("<br>The method you have requested Not Allowed." +
|
"<br>The method specified in the Request-Line is not allowed for the resource identified by the Request-URI"+
|
||||||
"<br>Perhaps you are here because:" +
|
"<br>The response MUST include an Allow header containing a list of valid methods for the requested resource."+
|
||||||
"<br><br><ul>" +
|
"</ul>",
|
||||||
"<br>The method specified in the Request-Line is not allowed for the resource identified by the Request-URI" +
|
)
|
||||||
"<br>The response MUST include an Allow header containing a list of valid methods for the requested resource." +
|
|
||||||
"</ul>")
|
|
||||||
t.Execute(rw, data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// show 500 internal server error.
|
// show 500 internal server error.
|
||||||
func internalServerError(rw http.ResponseWriter, r *http.Request) {
|
func internalServerError(rw http.ResponseWriter, r *http.Request) {
|
||||||
t, _ := template.New("beegoerrortemp").Parse(errtpl)
|
responseError(rw, r,
|
||||||
data := map[string]interface{}{
|
500,
|
||||||
"Title": http.StatusText(500),
|
"<br>The page you have requested is down right now."+
|
||||||
"BeegoVersion": VERSION,
|
"<br><br><ul>"+
|
||||||
}
|
"<br>Please try again later and report the error to the website administrator"+
|
||||||
data["Content"] = template.HTML("<br>The page you have requested is down right now." +
|
"<br></ul>",
|
||||||
"<br><br><ul>" +
|
)
|
||||||
"<br>Please try again later and report the error to the website administrator" +
|
|
||||||
"<br></ul>")
|
|
||||||
t.Execute(rw, data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// show 501 Not Implemented.
|
// show 501 Not Implemented.
|
||||||
func notImplemented(rw http.ResponseWriter, r *http.Request) {
|
func notImplemented(rw http.ResponseWriter, r *http.Request) {
|
||||||
t, _ := template.New("beegoerrortemp").Parse(errtpl)
|
responseError(rw, r,
|
||||||
data := map[string]interface{}{
|
501,
|
||||||
"Title": http.StatusText(504),
|
"<br>The page you have requested is Not Implemented."+
|
||||||
"BeegoVersion": VERSION,
|
"<br><br><ul>"+
|
||||||
}
|
"<br>Please try again later and report the error to the website administrator"+
|
||||||
data["Content"] = template.HTML("<br>The page you have requested is Not Implemented." +
|
"<br></ul>",
|
||||||
"<br><br><ul>" +
|
)
|
||||||
"<br>Please try again later and report the error to the website administrator" +
|
|
||||||
"<br></ul>")
|
|
||||||
t.Execute(rw, data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// show 502 Bad Gateway.
|
// show 502 Bad Gateway.
|
||||||
func badGateway(rw http.ResponseWriter, r *http.Request) {
|
func badGateway(rw http.ResponseWriter, r *http.Request) {
|
||||||
t, _ := template.New("beegoerrortemp").Parse(errtpl)
|
responseError(rw, r,
|
||||||
data := map[string]interface{}{
|
502,
|
||||||
"Title": http.StatusText(502),
|
"<br>The page you have requested is down right now."+
|
||||||
"BeegoVersion": VERSION,
|
"<br><br><ul>"+
|
||||||
}
|
"<br>The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request."+
|
||||||
data["Content"] = template.HTML("<br>The page you have requested is down right now." +
|
"<br>Please try again later and report the error to the website administrator"+
|
||||||
"<br><br><ul>" +
|
"<br></ul>",
|
||||||
"<br>The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request." +
|
)
|
||||||
"<br>Please try again later and report the error to the website administrator" +
|
|
||||||
"<br></ul>")
|
|
||||||
t.Execute(rw, data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// show 503 service unavailable error.
|
// show 503 service unavailable error.
|
||||||
func serviceUnavailable(rw http.ResponseWriter, r *http.Request) {
|
func serviceUnavailable(rw http.ResponseWriter, r *http.Request) {
|
||||||
t, _ := template.New("beegoerrortemp").Parse(errtpl)
|
responseError(rw, r,
|
||||||
data := map[string]interface{}{
|
503,
|
||||||
"Title": http.StatusText(503),
|
"<br>The page you have requested is unavailable."+
|
||||||
"BeegoVersion": VERSION,
|
"<br>Perhaps you are here because:"+
|
||||||
}
|
"<br><br><ul>"+
|
||||||
data["Content"] = template.HTML("<br>The page you have requested is unavailable." +
|
"<br><br>The page is overloaded"+
|
||||||
"<br>Perhaps you are here because:" +
|
"<br>Please try again later."+
|
||||||
"<br><br><ul>" +
|
"</ul>",
|
||||||
"<br><br>The page is overloaded" +
|
)
|
||||||
"<br>Please try again later." +
|
|
||||||
"</ul>")
|
|
||||||
t.Execute(rw, data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// show 504 Gateway Timeout.
|
// show 504 Gateway Timeout.
|
||||||
func gatewayTimeout(rw http.ResponseWriter, r *http.Request) {
|
func gatewayTimeout(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
responseError(rw, r,
|
||||||
|
504,
|
||||||
|
"<br>The page you have requested is unavailable"+
|
||||||
|
"<br>Perhaps you are here because:"+
|
||||||
|
"<br><br><ul>"+
|
||||||
|
"<br><br>The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI."+
|
||||||
|
"<br>Please try again later."+
|
||||||
|
"</ul>",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func responseError(rw http.ResponseWriter, r *http.Request, errCode int, errContent string) {
|
||||||
t, _ := template.New("beegoerrortemp").Parse(errtpl)
|
t, _ := template.New("beegoerrortemp").Parse(errtpl)
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"Title": http.StatusText(504),
|
"Title": http.StatusText(errCode),
|
||||||
"BeegoVersion": VERSION,
|
"BeegoVersion": VERSION,
|
||||||
|
"Content": errContent,
|
||||||
}
|
}
|
||||||
data["Content"] = template.HTML("<br>The page you have requested is unavailable." +
|
|
||||||
"<br>Perhaps you are here because:" +
|
|
||||||
"<br><br><ul>" +
|
|
||||||
"<br><br>The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI." +
|
|
||||||
"<br>Please try again later." +
|
|
||||||
"</ul>")
|
|
||||||
t.Execute(rw, data)
|
t.Execute(rw, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,7 +388,10 @@ func exception(errCode string, ctx *context.Context) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
return 503
|
if ctx.Output.Status == 0 {
|
||||||
|
return 503
|
||||||
|
}
|
||||||
|
return ctx.Output.Status
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ec := range []string{errCode, "503", "500"} {
|
for _, ec := range []string{errCode, "503", "500"} {
|
||||||
|
88
error_test.go
Normal file
88
error_test.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// Copyright 2016 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 beego
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type errorTestController struct {
|
||||||
|
Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseCodeError = "parse code error"
|
||||||
|
|
||||||
|
func (ec *errorTestController) Get() {
|
||||||
|
errorCode, err := ec.GetInt("code")
|
||||||
|
if err != nil {
|
||||||
|
ec.Abort(parseCodeError)
|
||||||
|
}
|
||||||
|
if errorCode != 0 {
|
||||||
|
ec.CustomAbort(errorCode, ec.GetString("code"))
|
||||||
|
}
|
||||||
|
ec.Abort("404")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrorCode_01(t *testing.T) {
|
||||||
|
registerDefaultErrorHandler()
|
||||||
|
for k := range ErrorMaps {
|
||||||
|
r, _ := http.NewRequest("GET", "/error?code="+k, nil)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
handler := NewControllerRegister()
|
||||||
|
handler.Add("/error", &errorTestController{})
|
||||||
|
handler.ServeHTTP(w, r)
|
||||||
|
code, _ := strconv.Atoi(k)
|
||||||
|
if w.Code != code {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(w.Body.Bytes()), http.StatusText(code)) {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrorCode_02(t *testing.T) {
|
||||||
|
registerDefaultErrorHandler()
|
||||||
|
r, _ := http.NewRequest("GET", "/error?code=0", nil)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
handler := NewControllerRegister()
|
||||||
|
handler.Add("/error", &errorTestController{})
|
||||||
|
handler.ServeHTTP(w, r)
|
||||||
|
if w.Code != 404 {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrorCode_03(t *testing.T) {
|
||||||
|
registerDefaultErrorHandler()
|
||||||
|
r, _ := http.NewRequest("GET", "/error?code=panic", nil)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
handler := NewControllerRegister()
|
||||||
|
handler.Add("/error", &errorTestController{})
|
||||||
|
handler.ServeHTTP(w, r)
|
||||||
|
if w.Code != 200 {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if string(w.Body.Bytes()) != parseCodeError {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
@ -20,14 +20,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/astaxie/beego/context"
|
"github.com/astaxie/beego/context"
|
||||||
"github.com/astaxie/beego/logs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
BeeLogger = logs.NewLogger(10000)
|
|
||||||
BeeLogger.SetLogger("console", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
var FilterUser = func(ctx *context.Context) {
|
var FilterUser = func(ctx *context.Context) {
|
||||||
ctx.Output.Body([]byte("i am " + ctx.Input.Param(":last") + ctx.Input.Param(":first")))
|
ctx.Output.Body([]byte("i am " + ctx.Input.Param(":last") + ctx.Input.Param(":first")))
|
||||||
}
|
}
|
||||||
|
15
hooks.go
15
hooks.go
@ -6,6 +6,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/astaxie/beego/context"
|
||||||
|
"github.com/astaxie/beego/logs"
|
||||||
"github.com/astaxie/beego/session"
|
"github.com/astaxie/beego/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -70,7 +72,7 @@ func registerSession() error {
|
|||||||
func registerTemplate() error {
|
func registerTemplate() error {
|
||||||
if err := BuildTemplate(BConfig.WebConfig.ViewsPath); err != nil {
|
if err := BuildTemplate(BConfig.WebConfig.ViewsPath); err != nil {
|
||||||
if BConfig.RunMode == DEV {
|
if BConfig.RunMode == DEV {
|
||||||
Warn(err)
|
logs.Warn(err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -91,3 +93,14 @@ func registerAdmin() error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func registerGzip() error {
|
||||||
|
if BConfig.EnableGzip {
|
||||||
|
context.InitGzip(
|
||||||
|
AppConfig.DefaultInt("gzipMinLength", -1),
|
||||||
|
AppConfig.DefaultInt("gzipCompressLevel", -1),
|
||||||
|
AppConfig.DefaultStrings("includedMethods", []string{"GET"}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
35
log.go
35
log.go
@ -33,82 +33,77 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// BeeLogger references the used application logger.
|
// BeeLogger references the used application logger.
|
||||||
var BeeLogger = logs.NewLogger(100)
|
var BeeLogger = logs.GetBeeLogger()
|
||||||
|
|
||||||
// SetLevel 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) {
|
func SetLevel(l int) {
|
||||||
BeeLogger.SetLevel(l)
|
logs.SetLevel(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLogFuncCall set the CallDepth, default is 3
|
// SetLogFuncCall set the CallDepth, default is 3
|
||||||
func SetLogFuncCall(b bool) {
|
func SetLogFuncCall(b bool) {
|
||||||
BeeLogger.EnableFuncCallDepth(b)
|
logs.SetLogFuncCall(b)
|
||||||
BeeLogger.SetLogFuncCallDepth(3)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLogger sets a new logger.
|
// SetLogger sets a new logger.
|
||||||
func SetLogger(adaptername string, config string) error {
|
func SetLogger(adaptername string, config string) error {
|
||||||
err := BeeLogger.SetLogger(adaptername, config)
|
return logs.SetLogger(adaptername, config)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emergency logs a message at emergency level.
|
// Emergency logs a message at emergency level.
|
||||||
func Emergency(v ...interface{}) {
|
func Emergency(v ...interface{}) {
|
||||||
BeeLogger.Emergency(generateFmtStr(len(v)), v...)
|
logs.Emergency(generateFmtStr(len(v)), v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alert logs a message at alert level.
|
// Alert logs a message at alert level.
|
||||||
func Alert(v ...interface{}) {
|
func Alert(v ...interface{}) {
|
||||||
BeeLogger.Alert(generateFmtStr(len(v)), v...)
|
logs.Alert(generateFmtStr(len(v)), v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Critical logs a message at critical level.
|
// Critical logs a message at critical level.
|
||||||
func Critical(v ...interface{}) {
|
func Critical(v ...interface{}) {
|
||||||
BeeLogger.Critical(generateFmtStr(len(v)), v...)
|
logs.Critical(generateFmtStr(len(v)), v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error logs a message at error level.
|
// Error logs a message at error level.
|
||||||
func Error(v ...interface{}) {
|
func Error(v ...interface{}) {
|
||||||
BeeLogger.Error(generateFmtStr(len(v)), v...)
|
logs.Error(generateFmtStr(len(v)), v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning logs a message at warning level.
|
// Warning logs a message at warning level.
|
||||||
func Warning(v ...interface{}) {
|
func Warning(v ...interface{}) {
|
||||||
BeeLogger.Warning(generateFmtStr(len(v)), v...)
|
logs.Warning(generateFmtStr(len(v)), v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warn compatibility alias for Warning()
|
// Warn compatibility alias for Warning()
|
||||||
func Warn(v ...interface{}) {
|
func Warn(v ...interface{}) {
|
||||||
BeeLogger.Warn(generateFmtStr(len(v)), v...)
|
logs.Warn(generateFmtStr(len(v)), v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notice logs a message at notice level.
|
// Notice logs a message at notice level.
|
||||||
func Notice(v ...interface{}) {
|
func Notice(v ...interface{}) {
|
||||||
BeeLogger.Notice(generateFmtStr(len(v)), v...)
|
logs.Notice(generateFmtStr(len(v)), v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Informational logs a message at info level.
|
// Informational logs a message at info level.
|
||||||
func Informational(v ...interface{}) {
|
func Informational(v ...interface{}) {
|
||||||
BeeLogger.Informational(generateFmtStr(len(v)), v...)
|
logs.Informational(generateFmtStr(len(v)), v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info compatibility alias for Warning()
|
// Info compatibility alias for Warning()
|
||||||
func Info(v ...interface{}) {
|
func Info(v ...interface{}) {
|
||||||
BeeLogger.Info(generateFmtStr(len(v)), v...)
|
logs.Info(generateFmtStr(len(v)), v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug logs a message at debug level.
|
// Debug logs a message at debug level.
|
||||||
func Debug(v ...interface{}) {
|
func Debug(v ...interface{}) {
|
||||||
BeeLogger.Debug(generateFmtStr(len(v)), v...)
|
logs.Debug(generateFmtStr(len(v)), v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trace logs a message at trace level.
|
// Trace logs a message at trace level.
|
||||||
// compatibility alias for Warning()
|
// compatibility alias for Warning()
|
||||||
func Trace(v ...interface{}) {
|
func Trace(v ...interface{}) {
|
||||||
BeeLogger.Trace(generateFmtStr(len(v)), v...)
|
logs.Trace(generateFmtStr(len(v)), v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateFmtStr(n int) string {
|
func generateFmtStr(n int) string {
|
||||||
|
@ -113,5 +113,5 @@ func (c *connWriter) needToConnectOnMsg() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Register("conn", NewConn)
|
Register(AdapterConn, NewConn)
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ func NewConsole() Logger {
|
|||||||
cw := &consoleWriter{
|
cw := &consoleWriter{
|
||||||
lg: newLogWriter(os.Stdout),
|
lg: newLogWriter(os.Stdout),
|
||||||
Level: LevelDebug,
|
Level: LevelDebug,
|
||||||
Colorful: true,
|
Colorful: runtime.GOOS != "windows",
|
||||||
}
|
}
|
||||||
return cw
|
return cw
|
||||||
}
|
}
|
||||||
@ -97,5 +97,5 @@ func (c *consoleWriter) Flush() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Register("console", NewConsole)
|
Register(AdapterConsole, NewConsole)
|
||||||
}
|
}
|
||||||
|
@ -76,5 +76,5 @@ func (el *esLogger) Flush() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
logs.Register("es", NewES)
|
logs.Register(logs.AdapterEs, NewES)
|
||||||
}
|
}
|
||||||
|
27
logs/file.go
27
logs/file.go
@ -30,7 +30,7 @@ import (
|
|||||||
// fileLogWriter implements LoggerInterface.
|
// fileLogWriter implements LoggerInterface.
|
||||||
// It writes messages by lines limit, file size limit, or time frequency.
|
// It writes messages by lines limit, file size limit, or time frequency.
|
||||||
type fileLogWriter struct {
|
type fileLogWriter struct {
|
||||||
sync.Mutex // write log order by order and atomic incr maxLinesCurLines and maxSizeCurSize
|
sync.RWMutex // write log order by order and atomic incr maxLinesCurLines and maxSizeCurSize
|
||||||
// The opened file
|
// The opened file
|
||||||
Filename string `json:"filename"`
|
Filename string `json:"filename"`
|
||||||
fileWriter *os.File
|
fileWriter *os.File
|
||||||
@ -60,14 +60,11 @@ type fileLogWriter struct {
|
|||||||
// newFileWriter create a FileLogWriter returning as LoggerInterface.
|
// newFileWriter create a FileLogWriter returning as LoggerInterface.
|
||||||
func newFileWriter() Logger {
|
func newFileWriter() Logger {
|
||||||
w := &fileLogWriter{
|
w := &fileLogWriter{
|
||||||
Filename: "",
|
Daily: true,
|
||||||
MaxLines: 1000000,
|
MaxDays: 7,
|
||||||
MaxSize: 1 << 28, //256 MB
|
Rotate: true,
|
||||||
Daily: true,
|
Level: LevelTrace,
|
||||||
MaxDays: 7,
|
Perm: 0660,
|
||||||
Rotate: true,
|
|
||||||
Level: LevelTrace,
|
|
||||||
Perm: 0660,
|
|
||||||
}
|
}
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
@ -77,7 +74,7 @@ func newFileWriter() Logger {
|
|||||||
// {
|
// {
|
||||||
// "filename":"logs/beego.log",
|
// "filename":"logs/beego.log",
|
||||||
// "maxLines":10000,
|
// "maxLines":10000,
|
||||||
// "maxsize":1<<30,
|
// "maxsize":1024,
|
||||||
// "daily":true,
|
// "daily":true,
|
||||||
// "maxDays":15,
|
// "maxDays":15,
|
||||||
// "rotate":true,
|
// "rotate":true,
|
||||||
@ -128,7 +125,9 @@ func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error {
|
|||||||
h, d := formatTimeHeader(when)
|
h, d := formatTimeHeader(when)
|
||||||
msg = string(h) + msg + "\n"
|
msg = string(h) + msg + "\n"
|
||||||
if w.Rotate {
|
if w.Rotate {
|
||||||
|
w.RLock()
|
||||||
if w.needRotate(len(msg), d) {
|
if w.needRotate(len(msg), d) {
|
||||||
|
w.RUnlock()
|
||||||
w.Lock()
|
w.Lock()
|
||||||
if w.needRotate(len(msg), d) {
|
if w.needRotate(len(msg), d) {
|
||||||
if err := w.doRotate(when); err != nil {
|
if err := w.doRotate(when); err != nil {
|
||||||
@ -136,6 +135,8 @@ func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Unlock()
|
w.Unlock()
|
||||||
|
} else {
|
||||||
|
w.RUnlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,8 +256,8 @@ func (w *fileLogWriter) deleteOldLog() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*w.MaxDays) {
|
if !info.IsDir() && info.ModTime().Add(24*time.Hour*time.Duration(w.MaxDays)).Before(time.Now()) {
|
||||||
if strings.HasPrefix(filepath.Base(path), w.fileNameOnly) &&
|
if strings.HasPrefix(filepath.Base(path), filepath.Base(w.fileNameOnly)) &&
|
||||||
strings.HasSuffix(filepath.Base(path), w.suffix) {
|
strings.HasSuffix(filepath.Base(path), w.suffix) {
|
||||||
os.Remove(path)
|
os.Remove(path)
|
||||||
}
|
}
|
||||||
@ -278,5 +279,5 @@ func (w *fileLogWriter) Flush() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Register("file", newFileWriter)
|
Register(AdapterFile, newFileWriter)
|
||||||
}
|
}
|
||||||
|
345
logs/log.go
345
logs/log.go
@ -35,10 +35,12 @@ package logs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -55,16 +57,28 @@ const (
|
|||||||
LevelDebug
|
LevelDebug
|
||||||
)
|
)
|
||||||
|
|
||||||
// Legacy loglevel constants to ensure backwards compatibility.
|
// levelLogLogger is defined to implement log.Logger
|
||||||
//
|
// the real log level will be LevelEmergency
|
||||||
// Deprecated: will be removed in 1.5.0.
|
const levelLoggerImpl = -1
|
||||||
|
|
||||||
|
// Name for adapter with beego official support
|
||||||
|
const (
|
||||||
|
AdapterConsole = "console"
|
||||||
|
AdapterFile = "file"
|
||||||
|
AdapterMultiFile = "multifile"
|
||||||
|
AdapterMail = "stmp"
|
||||||
|
AdapterConn = "conn"
|
||||||
|
AdapterEs = "es"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Legacy log level constants to ensure backwards compatibility.
|
||||||
const (
|
const (
|
||||||
LevelInfo = LevelInformational
|
LevelInfo = LevelInformational
|
||||||
LevelTrace = LevelDebug
|
LevelTrace = LevelDebug
|
||||||
LevelWarn = LevelWarning
|
LevelWarn = LevelWarning
|
||||||
)
|
)
|
||||||
|
|
||||||
type loggerType func() Logger
|
type newLoggerFunc func() Logger
|
||||||
|
|
||||||
// Logger defines the behavior of a log provider.
|
// Logger defines the behavior of a log provider.
|
||||||
type Logger interface {
|
type Logger interface {
|
||||||
@ -74,12 +88,13 @@ type Logger interface {
|
|||||||
Flush()
|
Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
var adapters = make(map[string]loggerType)
|
var adapters = make(map[string]newLoggerFunc)
|
||||||
|
var levelPrefix = [LevelDebug + 1]string{"[M] ", "[A] ", "[C] ", "[E] ", "[W] ", "[N] ", "[I] ", "[D] "}
|
||||||
|
|
||||||
// Register makes a log provide available by the provided name.
|
// Register makes a log provide available by the provided name.
|
||||||
// If Register is called twice with the same name or if driver is nil,
|
// If Register is called twice with the same name or if driver is nil,
|
||||||
// it panics.
|
// it panics.
|
||||||
func Register(name string, log loggerType) {
|
func Register(name string, log newLoggerFunc) {
|
||||||
if log == nil {
|
if log == nil {
|
||||||
panic("logs: Register provide is nil")
|
panic("logs: Register provide is nil")
|
||||||
}
|
}
|
||||||
@ -94,15 +109,19 @@ func Register(name string, log loggerType) {
|
|||||||
type BeeLogger struct {
|
type BeeLogger struct {
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
level int
|
level int
|
||||||
|
init bool
|
||||||
enableFuncCallDepth bool
|
enableFuncCallDepth bool
|
||||||
loggerFuncCallDepth int
|
loggerFuncCallDepth int
|
||||||
asynchronous bool
|
asynchronous bool
|
||||||
|
msgChanLen int64
|
||||||
msgChan chan *logMsg
|
msgChan chan *logMsg
|
||||||
signalChan chan string
|
signalChan chan string
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
outputs []*nameLogger
|
outputs []*nameLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultAsyncMsgLen = 1e3
|
||||||
|
|
||||||
type nameLogger struct {
|
type nameLogger struct {
|
||||||
Logger
|
Logger
|
||||||
name string
|
name string
|
||||||
@ -119,18 +138,31 @@ var logMsgPool *sync.Pool
|
|||||||
// NewLogger returns a new BeeLogger.
|
// NewLogger returns a new BeeLogger.
|
||||||
// channelLen means the number of messages in chan(used where asynchronous is true).
|
// channelLen means the number of messages in chan(used where asynchronous is true).
|
||||||
// if the buffering chan is full, logger adapters write to file or other way.
|
// if the buffering chan is full, logger adapters write to file or other way.
|
||||||
func NewLogger(channelLen int64) *BeeLogger {
|
func NewLogger(channelLens ...int64) *BeeLogger {
|
||||||
bl := new(BeeLogger)
|
bl := new(BeeLogger)
|
||||||
bl.level = LevelDebug
|
bl.level = LevelDebug
|
||||||
bl.loggerFuncCallDepth = 2
|
bl.loggerFuncCallDepth = 2
|
||||||
bl.msgChan = make(chan *logMsg, channelLen)
|
bl.msgChanLen = append(channelLens, 0)[0]
|
||||||
|
if bl.msgChanLen <= 0 {
|
||||||
|
bl.msgChanLen = defaultAsyncMsgLen
|
||||||
|
}
|
||||||
bl.signalChan = make(chan string, 1)
|
bl.signalChan = make(chan string, 1)
|
||||||
|
bl.setLogger(AdapterConsole)
|
||||||
return bl
|
return bl
|
||||||
}
|
}
|
||||||
|
|
||||||
// Async set the log to asynchronous and start the goroutine
|
// Async set the log to asynchronous and start the goroutine
|
||||||
func (bl *BeeLogger) Async() *BeeLogger {
|
func (bl *BeeLogger) Async(msgLen ...int64) *BeeLogger {
|
||||||
|
bl.lock.Lock()
|
||||||
|
defer bl.lock.Unlock()
|
||||||
|
if bl.asynchronous {
|
||||||
|
return bl
|
||||||
|
}
|
||||||
bl.asynchronous = true
|
bl.asynchronous = true
|
||||||
|
if len(msgLen) > 0 && msgLen[0] > 0 {
|
||||||
|
bl.msgChanLen = msgLen[0]
|
||||||
|
}
|
||||||
|
bl.msgChan = make(chan *logMsg, bl.msgChanLen)
|
||||||
logMsgPool = &sync.Pool{
|
logMsgPool = &sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
return &logMsg{}
|
return &logMsg{}
|
||||||
@ -143,23 +175,41 @@ func (bl *BeeLogger) Async() *BeeLogger {
|
|||||||
|
|
||||||
// SetLogger provides a given logger adapter into BeeLogger with config string.
|
// SetLogger provides a given logger adapter into BeeLogger with config string.
|
||||||
// config need to be correct JSON as string: {"interval":360}.
|
// config need to be correct JSON as string: {"interval":360}.
|
||||||
func (bl *BeeLogger) SetLogger(adapterName string, config string) error {
|
func (bl *BeeLogger) setLogger(adapterName string, configs ...string) error {
|
||||||
bl.lock.Lock()
|
config := append(configs, "{}")[0]
|
||||||
defer bl.lock.Unlock()
|
for _, l := range bl.outputs {
|
||||||
if log, ok := adapters[adapterName]; ok {
|
if l.name == adapterName {
|
||||||
lg := log()
|
return fmt.Errorf("logs: duplicate adaptername %q (you have set this logger before)", adapterName)
|
||||||
err := lg.Init(config)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, "logs.BeeLogger.SetLogger: "+err.Error())
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
bl.outputs = append(bl.outputs, &nameLogger{name: adapterName, Logger: lg})
|
}
|
||||||
} else {
|
|
||||||
|
log, ok := adapters[adapterName]
|
||||||
|
if !ok {
|
||||||
return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName)
|
return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lg := log()
|
||||||
|
err := lg.Init(config)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "logs.BeeLogger.SetLogger: "+err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
bl.outputs = append(bl.outputs, &nameLogger{name: adapterName, Logger: lg})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetLogger provides a given logger adapter into BeeLogger with config string.
|
||||||
|
// config need to be correct JSON as string: {"interval":360}.
|
||||||
|
func (bl *BeeLogger) SetLogger(adapterName string, configs ...string) error {
|
||||||
|
bl.lock.Lock()
|
||||||
|
defer bl.lock.Unlock()
|
||||||
|
if !bl.init {
|
||||||
|
bl.outputs = []*nameLogger{}
|
||||||
|
bl.init = true
|
||||||
|
}
|
||||||
|
return bl.setLogger(adapterName, configs...)
|
||||||
|
}
|
||||||
|
|
||||||
// DelLogger remove a logger adapter in BeeLogger.
|
// DelLogger remove a logger adapter in BeeLogger.
|
||||||
func (bl *BeeLogger) DelLogger(adapterName string) error {
|
func (bl *BeeLogger) DelLogger(adapterName string) error {
|
||||||
bl.lock.Lock()
|
bl.lock.Lock()
|
||||||
@ -188,7 +238,37 @@ func (bl *BeeLogger) writeToLoggers(when time.Time, msg string, level int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bl *BeeLogger) writeMsg(logLevel int, msg string) error {
|
func (bl *BeeLogger) Write(p []byte) (n int, err error) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
// writeMsg will always add a '\n' character
|
||||||
|
if p[len(p)-1] == '\n' {
|
||||||
|
p = p[0 : len(p)-1]
|
||||||
|
}
|
||||||
|
// set levelLoggerImpl to ensure all log message will be write out
|
||||||
|
err = bl.writeMsg(levelLoggerImpl, string(p))
|
||||||
|
if err == nil {
|
||||||
|
return len(p), err
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error {
|
||||||
|
if !beeLogger.init {
|
||||||
|
bl.lock.Lock()
|
||||||
|
bl.setLogger(AdapterConsole)
|
||||||
|
bl.lock.Unlock()
|
||||||
|
}
|
||||||
|
if logLevel == levelLoggerImpl {
|
||||||
|
// set to emergency to ensure all log will be print out correctly
|
||||||
|
logLevel = LevelEmergency
|
||||||
|
} else {
|
||||||
|
msg = levelPrefix[logLevel] + msg
|
||||||
|
}
|
||||||
|
if len(v) > 0 {
|
||||||
|
msg = fmt.Sprintf(msg, v...)
|
||||||
|
}
|
||||||
when := time.Now()
|
when := time.Now()
|
||||||
if bl.enableFuncCallDepth {
|
if bl.enableFuncCallDepth {
|
||||||
_, file, line, ok := runtime.Caller(bl.loggerFuncCallDepth)
|
_, file, line, ok := runtime.Caller(bl.loggerFuncCallDepth)
|
||||||
@ -197,7 +277,7 @@ func (bl *BeeLogger) writeMsg(logLevel int, msg string) error {
|
|||||||
line = 0
|
line = 0
|
||||||
}
|
}
|
||||||
_, filename := path.Split(file)
|
_, filename := path.Split(file)
|
||||||
msg = "[" + filename + ":" + strconv.FormatInt(int64(line), 10) + "]" + msg
|
msg = "[" + filename + ":" + strconv.FormatInt(int64(line), 10) + "] " + msg
|
||||||
}
|
}
|
||||||
if bl.asynchronous {
|
if bl.asynchronous {
|
||||||
lm := logMsgPool.Get().(*logMsg)
|
lm := logMsgPool.Get().(*logMsg)
|
||||||
@ -265,8 +345,7 @@ func (bl *BeeLogger) Emergency(format string, v ...interface{}) {
|
|||||||
if LevelEmergency > bl.level {
|
if LevelEmergency > bl.level {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
msg := fmt.Sprintf("[M] "+format, v...)
|
bl.writeMsg(LevelEmergency, format, v...)
|
||||||
bl.writeMsg(LevelEmergency, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alert Log ALERT level message.
|
// Alert Log ALERT level message.
|
||||||
@ -274,8 +353,7 @@ func (bl *BeeLogger) Alert(format string, v ...interface{}) {
|
|||||||
if LevelAlert > bl.level {
|
if LevelAlert > bl.level {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
msg := fmt.Sprintf("[A] "+format, v...)
|
bl.writeMsg(LevelAlert, format, v...)
|
||||||
bl.writeMsg(LevelAlert, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Critical Log CRITICAL level message.
|
// Critical Log CRITICAL level message.
|
||||||
@ -283,8 +361,7 @@ func (bl *BeeLogger) Critical(format string, v ...interface{}) {
|
|||||||
if LevelCritical > bl.level {
|
if LevelCritical > bl.level {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
msg := fmt.Sprintf("[C] "+format, v...)
|
bl.writeMsg(LevelCritical, format, v...)
|
||||||
bl.writeMsg(LevelCritical, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error Log ERROR level message.
|
// Error Log ERROR level message.
|
||||||
@ -292,17 +369,12 @@ func (bl *BeeLogger) Error(format string, v ...interface{}) {
|
|||||||
if LevelError > bl.level {
|
if LevelError > bl.level {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
msg := fmt.Sprintf("[E] "+format, v...)
|
bl.writeMsg(LevelError, format, v...)
|
||||||
bl.writeMsg(LevelError, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning Log WARNING level message.
|
// Warning Log WARNING level message.
|
||||||
func (bl *BeeLogger) Warning(format string, v ...interface{}) {
|
func (bl *BeeLogger) Warning(format string, v ...interface{}) {
|
||||||
if LevelWarning > bl.level {
|
bl.Warn(format, v...)
|
||||||
return
|
|
||||||
}
|
|
||||||
msg := fmt.Sprintf("[W] "+format, v...)
|
|
||||||
bl.writeMsg(LevelWarning, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notice Log NOTICE level message.
|
// Notice Log NOTICE level message.
|
||||||
@ -310,17 +382,12 @@ func (bl *BeeLogger) Notice(format string, v ...interface{}) {
|
|||||||
if LevelNotice > bl.level {
|
if LevelNotice > bl.level {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
msg := fmt.Sprintf("[N] "+format, v...)
|
bl.writeMsg(LevelNotice, format, v...)
|
||||||
bl.writeMsg(LevelNotice, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Informational Log INFORMATIONAL level message.
|
// Informational Log INFORMATIONAL level message.
|
||||||
func (bl *BeeLogger) Informational(format string, v ...interface{}) {
|
func (bl *BeeLogger) Informational(format string, v ...interface{}) {
|
||||||
if LevelInformational > bl.level {
|
bl.Info(format, v...)
|
||||||
return
|
|
||||||
}
|
|
||||||
msg := fmt.Sprintf("[I] "+format, v...)
|
|
||||||
bl.writeMsg(LevelInformational, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug Log DEBUG level message.
|
// Debug Log DEBUG level message.
|
||||||
@ -328,38 +395,31 @@ func (bl *BeeLogger) Debug(format string, v ...interface{}) {
|
|||||||
if LevelDebug > bl.level {
|
if LevelDebug > bl.level {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
msg := fmt.Sprintf("[D] "+format, v...)
|
bl.writeMsg(LevelDebug, format, v...)
|
||||||
bl.writeMsg(LevelDebug, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warn Log WARN level message.
|
// Warn Log WARN level message.
|
||||||
// compatibility alias for Warning()
|
// compatibility alias for Warning()
|
||||||
func (bl *BeeLogger) Warn(format string, v ...interface{}) {
|
func (bl *BeeLogger) Warn(format string, v ...interface{}) {
|
||||||
if LevelWarning > bl.level {
|
if LevelWarn > bl.level {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
msg := fmt.Sprintf("[W] "+format, v...)
|
bl.writeMsg(LevelWarn, format, v...)
|
||||||
bl.writeMsg(LevelWarning, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info Log INFO level message.
|
// Info Log INFO level message.
|
||||||
// compatibility alias for Informational()
|
// compatibility alias for Informational()
|
||||||
func (bl *BeeLogger) Info(format string, v ...interface{}) {
|
func (bl *BeeLogger) Info(format string, v ...interface{}) {
|
||||||
if LevelInformational > bl.level {
|
if LevelInfo > bl.level {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
msg := fmt.Sprintf("[I] "+format, v...)
|
bl.writeMsg(LevelInfo, format, v...)
|
||||||
bl.writeMsg(LevelInformational, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trace Log TRACE level message.
|
// Trace Log TRACE level message.
|
||||||
// compatibility alias for Debug()
|
// compatibility alias for Debug()
|
||||||
func (bl *BeeLogger) Trace(format string, v ...interface{}) {
|
func (bl *BeeLogger) Trace(format string, v ...interface{}) {
|
||||||
if LevelDebug > bl.level {
|
bl.Debug(format, v...)
|
||||||
return
|
|
||||||
}
|
|
||||||
msg := fmt.Sprintf("[D] "+format, v...)
|
|
||||||
bl.writeMsg(LevelDebug, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush flush all chan data.
|
// Flush flush all chan data.
|
||||||
@ -378,6 +438,7 @@ func (bl *BeeLogger) Close() {
|
|||||||
if bl.asynchronous {
|
if bl.asynchronous {
|
||||||
bl.signalChan <- "close"
|
bl.signalChan <- "close"
|
||||||
bl.wg.Wait()
|
bl.wg.Wait()
|
||||||
|
close(bl.msgChan)
|
||||||
} else {
|
} else {
|
||||||
bl.flush()
|
bl.flush()
|
||||||
for _, l := range bl.outputs {
|
for _, l := range bl.outputs {
|
||||||
@ -385,7 +446,6 @@ func (bl *BeeLogger) Close() {
|
|||||||
}
|
}
|
||||||
bl.outputs = nil
|
bl.outputs = nil
|
||||||
}
|
}
|
||||||
close(bl.msgChan)
|
|
||||||
close(bl.signalChan)
|
close(bl.signalChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,16 +459,175 @@ func (bl *BeeLogger) Reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (bl *BeeLogger) flush() {
|
func (bl *BeeLogger) flush() {
|
||||||
for {
|
if bl.asynchronous {
|
||||||
if len(bl.msgChan) > 0 {
|
for {
|
||||||
bm := <-bl.msgChan
|
if len(bl.msgChan) > 0 {
|
||||||
bl.writeToLoggers(bm.when, bm.msg, bm.level)
|
bm := <-bl.msgChan
|
||||||
logMsgPool.Put(bm)
|
bl.writeToLoggers(bm.when, bm.msg, bm.level)
|
||||||
continue
|
logMsgPool.Put(bm)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
for _, l := range bl.outputs {
|
for _, l := range bl.outputs {
|
||||||
l.Flush()
|
l.Flush()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// beeLogger references the used application logger.
|
||||||
|
var beeLogger *BeeLogger = NewLogger()
|
||||||
|
|
||||||
|
// GetLogger returns the default BeeLogger
|
||||||
|
func GetBeeLogger() *BeeLogger {
|
||||||
|
return beeLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
var beeLoggerMap = struct {
|
||||||
|
sync.RWMutex
|
||||||
|
logs map[string]*log.Logger
|
||||||
|
}{
|
||||||
|
logs: map[string]*log.Logger{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLogger returns the default BeeLogger
|
||||||
|
func GetLogger(prefixes ...string) *log.Logger {
|
||||||
|
prefix := append(prefixes, "")[0]
|
||||||
|
if prefix != "" {
|
||||||
|
prefix = fmt.Sprintf(`[%s] `, strings.ToUpper(prefix))
|
||||||
|
}
|
||||||
|
beeLoggerMap.RLock()
|
||||||
|
l, ok := beeLoggerMap.logs[prefix]
|
||||||
|
if ok {
|
||||||
|
beeLoggerMap.RUnlock()
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
beeLoggerMap.RUnlock()
|
||||||
|
beeLoggerMap.Lock()
|
||||||
|
defer beeLoggerMap.Unlock()
|
||||||
|
l, ok = beeLoggerMap.logs[prefix]
|
||||||
|
if !ok {
|
||||||
|
l = log.New(beeLogger, prefix, 0)
|
||||||
|
beeLoggerMap.logs[prefix] = l
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset will remove all the adapter
|
||||||
|
func Reset() {
|
||||||
|
beeLogger.Reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Async(msgLen ...int64) *BeeLogger {
|
||||||
|
return beeLogger.Async(msgLen...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLevel sets the global log level used by the simple logger.
|
||||||
|
func SetLevel(l int) {
|
||||||
|
beeLogger.SetLevel(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableFuncCallDepth enable log funcCallDepth
|
||||||
|
func EnableFuncCallDepth(b bool) {
|
||||||
|
beeLogger.enableFuncCallDepth = b
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLogFuncCall set the CallDepth, default is 3
|
||||||
|
func SetLogFuncCall(b bool) {
|
||||||
|
beeLogger.EnableFuncCallDepth(b)
|
||||||
|
beeLogger.SetLogFuncCallDepth(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLogFuncCallDepth set log funcCallDepth
|
||||||
|
func SetLogFuncCallDepth(d int) {
|
||||||
|
beeLogger.loggerFuncCallDepth = d
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLogger sets a new logger.
|
||||||
|
func SetLogger(adapter string, config ...string) error {
|
||||||
|
err := beeLogger.SetLogger(adapter, config...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emergency logs a message at emergency level.
|
||||||
|
func Emergency(f interface{}, v ...interface{}) {
|
||||||
|
beeLogger.Emergency(formatLog(f, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alert logs a message at alert level.
|
||||||
|
func Alert(f interface{}, v ...interface{}) {
|
||||||
|
beeLogger.Alert(formatLog(f, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Critical logs a message at critical level.
|
||||||
|
func Critical(f interface{}, v ...interface{}) {
|
||||||
|
beeLogger.Critical(formatLog(f, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error logs a message at error level.
|
||||||
|
func Error(f interface{}, v ...interface{}) {
|
||||||
|
beeLogger.Error(formatLog(f, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning logs a message at warning level.
|
||||||
|
func Warning(f interface{}, v ...interface{}) {
|
||||||
|
beeLogger.Warn(formatLog(f, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn compatibility alias for Warning()
|
||||||
|
func Warn(f interface{}, v ...interface{}) {
|
||||||
|
beeLogger.Warn(formatLog(f, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notice logs a message at notice level.
|
||||||
|
func Notice(f interface{}, v ...interface{}) {
|
||||||
|
beeLogger.Notice(formatLog(f, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Informational logs a message at info level.
|
||||||
|
func Informational(f interface{}, v ...interface{}) {
|
||||||
|
beeLogger.Info(formatLog(f, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info compatibility alias for Warning()
|
||||||
|
func Info(f interface{}, v ...interface{}) {
|
||||||
|
beeLogger.Info(formatLog(f, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug logs a message at debug level.
|
||||||
|
func Debug(f interface{}, v ...interface{}) {
|
||||||
|
beeLogger.Debug(formatLog(f, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trace logs a message at trace level.
|
||||||
|
// compatibility alias for Warning()
|
||||||
|
func Trace(f interface{}, v ...interface{}) {
|
||||||
|
beeLogger.Trace(formatLog(f, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatLog(f interface{}, v ...interface{}) string {
|
||||||
|
var msg string
|
||||||
|
switch f.(type) {
|
||||||
|
case string:
|
||||||
|
msg = f.(string)
|
||||||
|
if len(v) == 0 {
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
if strings.Contains(msg, "%") && !strings.Contains(msg, "%%") {
|
||||||
|
//format string
|
||||||
|
} else {
|
||||||
|
//do not contain format char
|
||||||
|
msg += strings.Repeat(" %v", len(v))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
msg = fmt.Sprint(f)
|
||||||
|
if len(v) == 0 {
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
msg += strings.Repeat(" %v", len(v))
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(msg, v...)
|
||||||
|
}
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
package logs
|
package logs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -112,5 +112,5 @@ func newFilesWriter() Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Register("multifile", newFilesWriter)
|
Register(AdapterMultiFile, newFilesWriter)
|
||||||
}
|
}
|
||||||
|
@ -156,5 +156,5 @@ func (s *SMTPWriter) Destroy() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Register("smtp", newSMTPWriter)
|
Register(AdapterMail, newSMTPWriter)
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego/logs"
|
||||||
"github.com/astaxie/beego/orm"
|
"github.com/astaxie/beego/orm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ func (m *Migration) Reset() {
|
|||||||
func (m *Migration) Exec(name, status string) error {
|
func (m *Migration) Exec(name, status string) error {
|
||||||
o := orm.NewOrm()
|
o := orm.NewOrm()
|
||||||
for _, s := range m.sqls {
|
for _, s := range m.sqls {
|
||||||
beego.Info("exec sql:", s)
|
logs.Info("exec sql:", s)
|
||||||
r := o.Raw(s)
|
r := o.Raw(s)
|
||||||
_, err := r.Exec()
|
_, err := r.Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -144,20 +144,20 @@ func Upgrade(lasttime int64) error {
|
|||||||
i := 0
|
i := 0
|
||||||
for _, v := range sm {
|
for _, v := range sm {
|
||||||
if v.created > lasttime {
|
if v.created > lasttime {
|
||||||
beego.Info("start upgrade", v.name)
|
logs.Info("start upgrade", v.name)
|
||||||
v.m.Reset()
|
v.m.Reset()
|
||||||
v.m.Up()
|
v.m.Up()
|
||||||
err := v.m.Exec(v.name, "up")
|
err := v.m.Exec(v.name, "up")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
beego.Error("execute error:", err)
|
logs.Error("execute error:", err)
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
beego.Info("end upgrade:", v.name)
|
logs.Info("end upgrade:", v.name)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
beego.Info("total success upgrade:", i, " migration")
|
logs.Info("total success upgrade:", i, " migration")
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -165,20 +165,20 @@ func Upgrade(lasttime int64) error {
|
|||||||
// Rollback rollback the migration by the name
|
// Rollback rollback the migration by the name
|
||||||
func Rollback(name string) error {
|
func Rollback(name string) error {
|
||||||
if v, ok := migrationMap[name]; ok {
|
if v, ok := migrationMap[name]; ok {
|
||||||
beego.Info("start rollback")
|
logs.Info("start rollback")
|
||||||
v.Reset()
|
v.Reset()
|
||||||
v.Down()
|
v.Down()
|
||||||
err := v.Exec(name, "down")
|
err := v.Exec(name, "down")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
beego.Error("execute error:", err)
|
logs.Error("execute error:", err)
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
beego.Info("end rollback")
|
logs.Info("end rollback")
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
beego.Error("not exist the migrationMap name:" + name)
|
logs.Error("not exist the migrationMap name:" + name)
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
return errors.New("not exist the migrationMap name:" + name)
|
return errors.New("not exist the migrationMap name:" + name)
|
||||||
}
|
}
|
||||||
@ -191,23 +191,23 @@ func Reset() error {
|
|||||||
for j := len(sm) - 1; j >= 0; j-- {
|
for j := len(sm) - 1; j >= 0; j-- {
|
||||||
v := sm[j]
|
v := sm[j]
|
||||||
if isRollBack(v.name) {
|
if isRollBack(v.name) {
|
||||||
beego.Info("skip the", v.name)
|
logs.Info("skip the", v.name)
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
beego.Info("start reset:", v.name)
|
logs.Info("start reset:", v.name)
|
||||||
v.m.Reset()
|
v.m.Reset()
|
||||||
v.m.Down()
|
v.m.Down()
|
||||||
err := v.m.Exec(v.name, "down")
|
err := v.m.Exec(v.name, "down")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
beego.Error("execute error:", err)
|
logs.Error("execute error:", err)
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
beego.Info("end reset:", v.name)
|
logs.Info("end reset:", v.name)
|
||||||
}
|
}
|
||||||
beego.Info("total success reset:", i, " migration")
|
logs.Info("total success reset:", i, " migration")
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -216,7 +216,7 @@ func Reset() error {
|
|||||||
func Refresh() error {
|
func Refresh() error {
|
||||||
err := Reset()
|
err := Reset()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
beego.Error("execute error:", err)
|
logs.Error("execute error:", err)
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -265,7 +265,7 @@ func isRollBack(name string) bool {
|
|||||||
var maps []orm.Params
|
var maps []orm.Params
|
||||||
num, err := o.Raw("select * from migrations where `name` = ? order by id_migration desc", name).Values(&maps)
|
num, err := o.Raw("select * from migrations where `name` = ? order by id_migration desc", name).Values(&maps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
beego.Info("get name has error", err)
|
logs.Info("get name has error", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if num <= 0 {
|
if num <= 0 {
|
||||||
|
11
namespace.go
11
namespace.go
@ -44,7 +44,7 @@ func NewNamespace(prefix string, params ...LinkNamespace) *Namespace {
|
|||||||
return ns
|
return ns
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cond set condtion function
|
// Cond set condition function
|
||||||
// if cond return true can run this namespace, else can't
|
// if cond return true can run this namespace, else can't
|
||||||
// usage:
|
// usage:
|
||||||
// ns.Cond(func (ctx *context.Context) bool{
|
// ns.Cond(func (ctx *context.Context) bool{
|
||||||
@ -60,7 +60,7 @@ func (n *Namespace) Cond(cond namespaceCond) *Namespace {
|
|||||||
exception("405", ctx)
|
exception("405", ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v, ok := n.handlers.filters[BeforeRouter]; ok {
|
if v := n.handlers.filters[BeforeRouter]; len(v) > 0 {
|
||||||
mr := new(FilterRouter)
|
mr := new(FilterRouter)
|
||||||
mr.tree = NewTree()
|
mr.tree = NewTree()
|
||||||
mr.pattern = "*"
|
mr.pattern = "*"
|
||||||
@ -388,3 +388,10 @@ func NSNamespace(prefix string, params ...LinkNamespace) LinkNamespace {
|
|||||||
ns.Namespace(n)
|
ns.Namespace(n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NSHandler add handler
|
||||||
|
func NSHandler(rootpath string, h http.Handler) LinkNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.Handler(rootpath, h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
84
orm/db.go
84
orm/db.go
@ -71,12 +71,12 @@ type dbBase struct {
|
|||||||
var _ dbBaser = new(dbBase)
|
var _ dbBaser = new(dbBase)
|
||||||
|
|
||||||
// get struct columns values as interface slice.
|
// get struct columns values as interface slice.
|
||||||
func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string, skipAuto bool, insert bool, names *[]string, tz *time.Location) (values []interface{}, err error) {
|
func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string, skipAuto bool, insert bool, names *[]string, tz *time.Location) (values []interface{}, autoFields []string, err error) {
|
||||||
var columns []string
|
if names == nil {
|
||||||
|
ns := make([]string, 0, len(cols))
|
||||||
if names != nil {
|
names = &ns
|
||||||
columns = *names
|
|
||||||
}
|
}
|
||||||
|
values = make([]interface{}, 0, len(cols))
|
||||||
|
|
||||||
for _, column := range cols {
|
for _, column := range cols {
|
||||||
var fi *fieldInfo
|
var fi *fieldInfo
|
||||||
@ -90,18 +90,24 @@ func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string,
|
|||||||
}
|
}
|
||||||
value, err := d.collectFieldValue(mi, fi, ind, insert, tz)
|
value, err := d.collectFieldValue(mi, fi, ind, insert, tz)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if names != nil {
|
// ignore empty value auto field
|
||||||
columns = append(columns, column)
|
if insert && fi.auto {
|
||||||
|
if fi.fieldType&IsPositiveIntegerField > 0 {
|
||||||
|
if vu, ok := value.(uint64); !ok || vu == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if vu, ok := value.(int64); !ok || vu == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
autoFields = append(autoFields, fi.column)
|
||||||
}
|
}
|
||||||
|
|
||||||
values = append(values, value)
|
*names, values = append(*names, column), append(values, value)
|
||||||
}
|
|
||||||
|
|
||||||
if names != nil {
|
|
||||||
*names = columns
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -181,7 +187,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
switch {
|
switch {
|
||||||
case fi.fieldType&IsPostiveIntegerField > 0:
|
case fi.fieldType&IsPositiveIntegerField > 0:
|
||||||
if field.Kind() == reflect.Ptr {
|
if field.Kind() == reflect.Ptr {
|
||||||
if field.IsNil() {
|
if field.IsNil() {
|
||||||
value = nil
|
value = nil
|
||||||
@ -273,7 +279,7 @@ func (d *dbBase) PrepareInsert(q dbQuerier, mi *modelInfo) (stmtQuerier, string,
|
|||||||
|
|
||||||
// insert struct with prepared statement and given struct reflect value.
|
// insert struct with prepared statement and given struct reflect value.
|
||||||
func (d *dbBase) InsertStmt(stmt stmtQuerier, mi *modelInfo, ind reflect.Value, tz *time.Location) (int64, error) {
|
func (d *dbBase) InsertStmt(stmt stmtQuerier, mi *modelInfo, ind reflect.Value, tz *time.Location) (int64, error) {
|
||||||
values, err := d.collectValues(mi, ind, mi.fields.dbcols, true, true, nil, tz)
|
values, _, err := d.collectValues(mi, ind, mi.fields.dbcols, true, true, nil, tz)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -300,7 +306,7 @@ func (d *dbBase) Read(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.Lo
|
|||||||
if len(cols) > 0 {
|
if len(cols) > 0 {
|
||||||
var err error
|
var err error
|
||||||
whereCols = make([]string, 0, len(cols))
|
whereCols = make([]string, 0, len(cols))
|
||||||
args, err = d.collectValues(mi, ind, cols, false, false, &whereCols, tz)
|
args, _, err = d.collectValues(mi, ind, cols, false, false, &whereCols, tz)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -349,13 +355,21 @@ func (d *dbBase) Read(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.Lo
|
|||||||
|
|
||||||
// execute insert sql dbQuerier with given struct reflect.Value.
|
// execute insert sql dbQuerier with given struct reflect.Value.
|
||||||
func (d *dbBase) Insert(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.Location) (int64, error) {
|
func (d *dbBase) Insert(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.Location) (int64, error) {
|
||||||
names := make([]string, 0, len(mi.fields.dbcols)-1)
|
names := make([]string, 0, len(mi.fields.dbcols))
|
||||||
values, err := d.collectValues(mi, ind, mi.fields.dbcols, true, true, &names, tz)
|
values, autoFields, err := d.collectValues(mi, ind, mi.fields.dbcols, false, true, &names, tz)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return d.InsertValue(q, mi, false, names, values)
|
id, err := d.InsertValue(q, mi, false, names, values)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(autoFields) > 0 {
|
||||||
|
err = d.ins.setval(q, mi, autoFields)
|
||||||
|
}
|
||||||
|
return id, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// multi-insert sql with given slice struct reflect.Value.
|
// multi-insert sql with given slice struct reflect.Value.
|
||||||
@ -369,7 +383,7 @@ func (d *dbBase) InsertMulti(q dbQuerier, mi *modelInfo, sind reflect.Value, bul
|
|||||||
|
|
||||||
// typ := reflect.Indirect(mi.addrField).Type()
|
// typ := reflect.Indirect(mi.addrField).Type()
|
||||||
|
|
||||||
length := sind.Len()
|
length, autoFields := sind.Len(), make([]string, 0, 1)
|
||||||
|
|
||||||
for i := 1; i <= length; i++ {
|
for i := 1; i <= length; i++ {
|
||||||
|
|
||||||
@ -381,16 +395,18 @@ func (d *dbBase) InsertMulti(q dbQuerier, mi *modelInfo, sind reflect.Value, bul
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
vus, err := d.collectValues(mi, ind, mi.fields.dbcols, true, true, &names, tz)
|
var (
|
||||||
|
vus []interface{}
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
vus, autoFields, err = d.collectValues(mi, ind, mi.fields.dbcols, false, true, &names, tz)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cnt, err
|
return cnt, err
|
||||||
}
|
}
|
||||||
values = make([]interface{}, bulk*len(vus))
|
values = make([]interface{}, bulk*len(vus))
|
||||||
nums += copy(values, vus)
|
nums += copy(values, vus)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
vus, _, err := d.collectValues(mi, ind, mi.fields.dbcols, false, true, nil, tz)
|
||||||
vus, err := d.collectValues(mi, ind, mi.fields.dbcols, true, true, nil, tz)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cnt, err
|
return cnt, err
|
||||||
}
|
}
|
||||||
@ -412,7 +428,12 @@ func (d *dbBase) InsertMulti(q dbQuerier, mi *modelInfo, sind reflect.Value, bul
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cnt, nil
|
var err error
|
||||||
|
if len(autoFields) > 0 {
|
||||||
|
err = d.ins.setval(q, mi, autoFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cnt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// execute insert sql with given struct and given values.
|
// execute insert sql with given struct and given values.
|
||||||
@ -472,7 +493,7 @@ func (d *dbBase) Update(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.
|
|||||||
setNames = make([]string, 0, len(cols))
|
setNames = make([]string, 0, len(cols))
|
||||||
}
|
}
|
||||||
|
|
||||||
setValues, err := d.collectValues(mi, ind, cols, true, false, &setNames, tz)
|
setValues, _, err := d.collectValues(mi, ind, cols, true, false, &setNames, tz)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -516,7 +537,7 @@ func (d *dbBase) Delete(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.
|
|||||||
}
|
}
|
||||||
if num > 0 {
|
if num > 0 {
|
||||||
if mi.fields.pk.auto {
|
if mi.fields.pk.auto {
|
||||||
if mi.fields.pk.fieldType&IsPostiveIntegerField > 0 {
|
if mi.fields.pk.fieldType&IsPositiveIntegerField > 0 {
|
||||||
ind.FieldByIndex(mi.fields.pk.fieldIndex).SetUint(0)
|
ind.FieldByIndex(mi.fields.pk.fieldIndex).SetUint(0)
|
||||||
} else {
|
} else {
|
||||||
ind.FieldByIndex(mi.fields.pk.fieldIndex).SetInt(0)
|
ind.FieldByIndex(mi.fields.pk.fieldIndex).SetInt(0)
|
||||||
@ -1140,7 +1161,7 @@ setValue:
|
|||||||
tErr = err
|
tErr = err
|
||||||
goto end
|
goto end
|
||||||
}
|
}
|
||||||
if fieldType&IsPostiveIntegerField > 0 {
|
if fieldType&IsPositiveIntegerField > 0 {
|
||||||
v, _ := str.Uint64()
|
v, _ := str.Uint64()
|
||||||
value = v
|
value = v
|
||||||
} else {
|
} else {
|
||||||
@ -1292,7 +1313,7 @@ setValue:
|
|||||||
field.Set(reflect.ValueOf(&v))
|
field.Set(reflect.ValueOf(&v))
|
||||||
}
|
}
|
||||||
case fieldType&IsIntegerField > 0:
|
case fieldType&IsIntegerField > 0:
|
||||||
if fieldType&IsPostiveIntegerField > 0 {
|
if fieldType&IsPositiveIntegerField > 0 {
|
||||||
if isNative {
|
if isNative {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
value = uint64(0)
|
value = uint64(0)
|
||||||
@ -1562,6 +1583,11 @@ func (d *dbBase) HasReturningID(*modelInfo, *string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sync auto key
|
||||||
|
func (d *dbBase) setval(db dbQuerier, mi *modelInfo, autoFields []string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// convert time from db.
|
// convert time from db.
|
||||||
func (d *dbBase) TimeFromDB(t *time.Time, tz *time.Location) {
|
func (d *dbBase) TimeFromDB(t *time.Time, tz *time.Location) {
|
||||||
*t = t.In(tz)
|
*t = t.In(tz)
|
||||||
|
@ -59,6 +59,7 @@ var (
|
|||||||
"postgres": DRPostgres,
|
"postgres": DRPostgres,
|
||||||
"sqlite3": DRSqlite,
|
"sqlite3": DRSqlite,
|
||||||
"tidb": DRTiDB,
|
"tidb": DRTiDB,
|
||||||
|
"oracle": DROracle,
|
||||||
}
|
}
|
||||||
dbBasers = map[DriverType]dbBaser{
|
dbBasers = map[DriverType]dbBaser{
|
||||||
DRMySQL: newdbBaseMysql(),
|
DRMySQL: newdbBaseMysql(),
|
||||||
@ -151,7 +152,7 @@ func detectTZ(al *alias) {
|
|||||||
al.Engine = "INNODB"
|
al.Engine = "INNODB"
|
||||||
}
|
}
|
||||||
|
|
||||||
case DRSqlite:
|
case DRSqlite, DROracle:
|
||||||
al.TZ = time.UTC
|
al.TZ = time.UTC
|
||||||
|
|
||||||
case DRPostgres:
|
case DRPostgres:
|
||||||
|
@ -14,6 +14,41 @@
|
|||||||
|
|
||||||
package orm
|
package orm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// oracle operators.
|
||||||
|
var oracleOperators = map[string]string{
|
||||||
|
"exact": "= ?",
|
||||||
|
"gt": "> ?",
|
||||||
|
"gte": ">= ?",
|
||||||
|
"lt": "< ?",
|
||||||
|
"lte": "<= ?",
|
||||||
|
"//iendswith": "LIKE ?",
|
||||||
|
}
|
||||||
|
|
||||||
|
// oracle column field types.
|
||||||
|
var oracleTypes = map[string]string{
|
||||||
|
"pk": "NOT NULL PRIMARY KEY",
|
||||||
|
"bool": "bool",
|
||||||
|
"string": "VARCHAR2(%d)",
|
||||||
|
"string-text": "VARCHAR2(%d)",
|
||||||
|
"time.Time-date": "DATE",
|
||||||
|
"time.Time": "TIMESTAMP",
|
||||||
|
"int8": "INTEGER",
|
||||||
|
"int16": "INTEGER",
|
||||||
|
"int32": "INTEGER",
|
||||||
|
"int64": "INTEGER",
|
||||||
|
"uint8": "INTEGER",
|
||||||
|
"uint16": "INTEGER",
|
||||||
|
"uint32": "INTEGER",
|
||||||
|
"uint64": "INTEGER",
|
||||||
|
"float64": "NUMBER",
|
||||||
|
"float64-decimal": "NUMBER(%d, %d)",
|
||||||
|
}
|
||||||
|
|
||||||
// oracle dbBaser
|
// oracle dbBaser
|
||||||
type dbBaseOracle struct {
|
type dbBaseOracle struct {
|
||||||
dbBase
|
dbBase
|
||||||
@ -27,3 +62,35 @@ func newdbBaseOracle() dbBaser {
|
|||||||
b.ins = b
|
b.ins = b
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OperatorSQL get oracle operator.
|
||||||
|
func (d *dbBaseOracle) OperatorSQL(operator string) string {
|
||||||
|
return oracleOperators[operator]
|
||||||
|
}
|
||||||
|
|
||||||
|
// DbTypes get oracle table field types.
|
||||||
|
func (d *dbBaseOracle) DbTypes() map[string]string {
|
||||||
|
return oracleTypes
|
||||||
|
}
|
||||||
|
|
||||||
|
//ShowTablesQuery show all the tables in database
|
||||||
|
func (d *dbBaseOracle) ShowTablesQuery() string {
|
||||||
|
return "SELECT TABLE_NAME FROM USER_TABLES"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Oracle
|
||||||
|
func (d *dbBaseOracle) ShowColumnsQuery(table string) string {
|
||||||
|
return fmt.Sprintf("SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS "+
|
||||||
|
"WHERE TABLE_NAME ='%s'", strings.ToUpper(table))
|
||||||
|
}
|
||||||
|
|
||||||
|
// check index is exist
|
||||||
|
func (d *dbBaseOracle) IndexExists(db dbQuerier, table string, name string) bool {
|
||||||
|
row := db.QueryRow("SELECT COUNT(*) FROM USER_IND_COLUMNS, USER_INDEXES "+
|
||||||
|
"WHERE USER_IND_COLUMNS.INDEX_NAME = USER_INDEXES.INDEX_NAME "+
|
||||||
|
"AND USER_IND_COLUMNS.TABLE_NAME = ? AND USER_IND_COLUMNS.INDEX_NAME = ?", strings.ToUpper(table), strings.ToUpper(name))
|
||||||
|
|
||||||
|
var cnt int
|
||||||
|
row.Scan(&cnt)
|
||||||
|
return cnt > 0
|
||||||
|
}
|
||||||
|
@ -123,14 +123,35 @@ func (d *dbBasePostgres) ReplaceMarks(query *string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make returning sql support for postgresql.
|
// make returning sql support for postgresql.
|
||||||
func (d *dbBasePostgres) HasReturningID(mi *modelInfo, query *string) (has bool) {
|
func (d *dbBasePostgres) HasReturningID(mi *modelInfo, query *string) bool {
|
||||||
if mi.fields.pk.auto {
|
fi := mi.fields.pk
|
||||||
if query != nil {
|
if fi.fieldType&IsPositiveIntegerField == 0 && fi.fieldType&IsIntegerField == 0 {
|
||||||
*query = fmt.Sprintf(`%s RETURNING "%s"`, *query, mi.fields.pk.column)
|
return false
|
||||||
}
|
|
||||||
has = true
|
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
if query != nil {
|
||||||
|
*query = fmt.Sprintf(`%s RETURNING "%s"`, *query, fi.column)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// sync auto key
|
||||||
|
func (d *dbBasePostgres) setval(db dbQuerier, mi *modelInfo, autoFields []string) error {
|
||||||
|
if len(autoFields) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
Q := d.ins.TableQuote()
|
||||||
|
for _, name := range autoFields {
|
||||||
|
query := fmt.Sprintf("SELECT setval(pg_get_serial_sequence('%s', '%s'), (SELECT MAX(%s%s%s) FROM %s%s%s));",
|
||||||
|
mi.table, name,
|
||||||
|
Q, name, Q,
|
||||||
|
Q, mi.table, Q)
|
||||||
|
if _, err := db.Exec(query); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// show table sql for postgresql.
|
// show table sql for postgresql.
|
||||||
|
@ -33,13 +33,13 @@ func getExistPk(mi *modelInfo, ind reflect.Value) (column string, value interfac
|
|||||||
fi := mi.fields.pk
|
fi := mi.fields.pk
|
||||||
|
|
||||||
v := ind.FieldByIndex(fi.fieldIndex)
|
v := ind.FieldByIndex(fi.fieldIndex)
|
||||||
if fi.fieldType&IsPostiveIntegerField > 0 {
|
if fi.fieldType&IsPositiveIntegerField > 0 {
|
||||||
vu := v.Uint()
|
vu := v.Uint()
|
||||||
exist = vu > 0
|
exist = vu > 0
|
||||||
value = vu
|
value = vu
|
||||||
} else if fi.fieldType&IsIntegerField > 0 {
|
} else if fi.fieldType&IsIntegerField > 0 {
|
||||||
vu := v.Int()
|
vu := v.Int()
|
||||||
exist = vu > 0
|
exist = true
|
||||||
value = vu
|
value = vu
|
||||||
} else {
|
} else {
|
||||||
vu := v.String()
|
vu := v.String()
|
||||||
|
@ -46,10 +46,10 @@ const (
|
|||||||
|
|
||||||
// Define some logic enum
|
// Define some logic enum
|
||||||
const (
|
const (
|
||||||
IsIntegerField = ^-TypePositiveBigIntegerField >> 4 << 5
|
IsIntegerField = ^-TypePositiveBigIntegerField >> 4 << 5
|
||||||
IsPostiveIntegerField = ^-TypePositiveBigIntegerField >> 8 << 9
|
IsPositiveIntegerField = ^-TypePositiveBigIntegerField >> 8 << 9
|
||||||
IsRelField = ^-RelReverseMany >> 14 << 15
|
IsRelField = ^-RelReverseMany >> 14 << 15
|
||||||
IsFieldType = ^-RelReverseMany<<1 + 1
|
IsFieldType = ^-RelReverseMany<<1 + 1
|
||||||
)
|
)
|
||||||
|
|
||||||
// BooleanField A true/false field.
|
// BooleanField A true/false field.
|
||||||
|
@ -352,7 +352,7 @@ type GroupPermissions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ModelID struct {
|
type ModelID struct {
|
||||||
Id int64
|
ID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModelBase struct {
|
type ModelBase struct {
|
||||||
@ -375,6 +375,28 @@ func NewInLine() *InLine {
|
|||||||
return new(InLine)
|
return new(InLine)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InLineOneToOne struct {
|
||||||
|
// Common Fields
|
||||||
|
ModelBase
|
||||||
|
|
||||||
|
Note string
|
||||||
|
InLine *InLine `orm:"rel(fk);column(inline)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInLineOneToOne() *InLineOneToOne {
|
||||||
|
return new(InLineOneToOne)
|
||||||
|
}
|
||||||
|
|
||||||
|
type IntegerPk struct {
|
||||||
|
Id int64 `orm:"pk"`
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type UintPk struct {
|
||||||
|
Id uint32 `orm:"pk"`
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
var DBARGS = struct {
|
var DBARGS = struct {
|
||||||
Driver string
|
Driver string
|
||||||
Source string
|
Source string
|
||||||
|
11
orm/orm.go
11
orm/orm.go
@ -140,7 +140,14 @@ func (o *orm) ReadOrCreate(md interface{}, col1 string, cols ...string) (bool, i
|
|||||||
return (err == nil), id, err
|
return (err == nil), id, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, ind.FieldByIndex(mi.fields.pk.fieldIndex).Int(), err
|
id, vid := int64(0), ind.FieldByIndex(mi.fields.pk.fieldIndex)
|
||||||
|
if mi.fields.pk.fieldType&IsPositiveIntegerField > 0 {
|
||||||
|
id = int64(vid.Uint())
|
||||||
|
} else {
|
||||||
|
id = vid.Int()
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, id, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert model data to database
|
// insert model data to database
|
||||||
@ -159,7 +166,7 @@ func (o *orm) Insert(md interface{}) (int64, error) {
|
|||||||
// set auto pk field
|
// set auto pk field
|
||||||
func (o *orm) setPk(mi *modelInfo, ind reflect.Value, id int64) {
|
func (o *orm) setPk(mi *modelInfo, ind reflect.Value, id int64) {
|
||||||
if mi.fields.pk.auto {
|
if mi.fields.pk.auto {
|
||||||
if mi.fields.pk.fieldType&IsPostiveIntegerField > 0 {
|
if mi.fields.pk.fieldType&IsPositiveIntegerField > 0 {
|
||||||
ind.FieldByIndex(mi.fields.pk.fieldIndex).SetUint(uint64(id))
|
ind.FieldByIndex(mi.fields.pk.fieldIndex).SetUint(uint64(id))
|
||||||
} else {
|
} else {
|
||||||
ind.FieldByIndex(mi.fields.pk.fieldIndex).SetInt(id)
|
ind.FieldByIndex(mi.fields.pk.fieldIndex).SetInt(id)
|
||||||
|
@ -31,7 +31,7 @@ type Log struct {
|
|||||||
// NewLog set io.Writer to create a Logger.
|
// NewLog set io.Writer to create a Logger.
|
||||||
func NewLog(out io.Writer) *Log {
|
func NewLog(out io.Writer) *Log {
|
||||||
d := new(Log)
|
d := new(Log)
|
||||||
d.Logger = log.New(out, "[ORM]", 1e9)
|
d.Logger = log.New(out, "[ORM]", log.LstdFlags)
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ func (o *insertSet) Insert(md interface{}) (int64, error) {
|
|||||||
}
|
}
|
||||||
if id > 0 {
|
if id > 0 {
|
||||||
if o.mi.fields.pk.auto {
|
if o.mi.fields.pk.auto {
|
||||||
if o.mi.fields.pk.fieldType&IsPostiveIntegerField > 0 {
|
if o.mi.fields.pk.fieldType&IsPositiveIntegerField > 0 {
|
||||||
ind.FieldByIndex(o.mi.fields.pk.fieldIndex).SetUint(uint64(id))
|
ind.FieldByIndex(o.mi.fields.pk.fieldIndex).SetUint(uint64(id))
|
||||||
} else {
|
} else {
|
||||||
ind.FieldByIndex(o.mi.fields.pk.fieldIndex).SetInt(id)
|
ind.FieldByIndex(o.mi.fields.pk.fieldIndex).SetInt(id)
|
||||||
|
126
orm/orm_test.go
126
orm/orm_test.go
@ -19,6 +19,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -188,6 +189,9 @@ func TestSyncDb(t *testing.T) {
|
|||||||
RegisterModel(new(Permission))
|
RegisterModel(new(Permission))
|
||||||
RegisterModel(new(GroupPermissions))
|
RegisterModel(new(GroupPermissions))
|
||||||
RegisterModel(new(InLine))
|
RegisterModel(new(InLine))
|
||||||
|
RegisterModel(new(InLineOneToOne))
|
||||||
|
RegisterModel(new(IntegerPk))
|
||||||
|
RegisterModel(new(UintPk))
|
||||||
|
|
||||||
err := RunSyncdb("default", true, Debug)
|
err := RunSyncdb("default", true, Debug)
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
@ -208,6 +212,9 @@ func TestRegisterModels(t *testing.T) {
|
|||||||
RegisterModel(new(Permission))
|
RegisterModel(new(Permission))
|
||||||
RegisterModel(new(GroupPermissions))
|
RegisterModel(new(GroupPermissions))
|
||||||
RegisterModel(new(InLine))
|
RegisterModel(new(InLine))
|
||||||
|
RegisterModel(new(InLineOneToOne))
|
||||||
|
RegisterModel(new(IntegerPk))
|
||||||
|
RegisterModel(new(UintPk))
|
||||||
|
|
||||||
BootStrap()
|
BootStrap()
|
||||||
|
|
||||||
@ -1943,7 +1950,7 @@ func TestInLine(t *testing.T) {
|
|||||||
throwFail(t, AssertIs(id, 1))
|
throwFail(t, AssertIs(id, 1))
|
||||||
|
|
||||||
il := NewInLine()
|
il := NewInLine()
|
||||||
il.Id = 1
|
il.ID = 1
|
||||||
err = dORM.Read(il)
|
err = dORM.Read(il)
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
|
|
||||||
@ -1952,3 +1959,120 @@ func TestInLine(t *testing.T) {
|
|||||||
throwFail(t, AssertIs(il.Created.In(DefaultTimeLoc), inline.Created.In(DefaultTimeLoc), testDate))
|
throwFail(t, AssertIs(il.Created.In(DefaultTimeLoc), inline.Created.In(DefaultTimeLoc), testDate))
|
||||||
throwFail(t, AssertIs(il.Updated.In(DefaultTimeLoc), inline.Updated.In(DefaultTimeLoc), testDateTime))
|
throwFail(t, AssertIs(il.Updated.In(DefaultTimeLoc), inline.Updated.In(DefaultTimeLoc), testDateTime))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInLineOneToOne(t *testing.T) {
|
||||||
|
name := "121"
|
||||||
|
email := "121@go.com"
|
||||||
|
inline := NewInLine()
|
||||||
|
inline.Name = name
|
||||||
|
inline.Email = email
|
||||||
|
|
||||||
|
id, err := dORM.Insert(inline)
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(id, 2))
|
||||||
|
|
||||||
|
note := "one2one"
|
||||||
|
il121 := NewInLineOneToOne()
|
||||||
|
il121.Note = note
|
||||||
|
il121.InLine = inline
|
||||||
|
_, err = dORM.Insert(il121)
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(il121.ID, 1))
|
||||||
|
|
||||||
|
il := NewInLineOneToOne()
|
||||||
|
err = dORM.QueryTable(il).Filter("Id", 1).RelatedSel().One(il)
|
||||||
|
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(il.Note, note))
|
||||||
|
throwFail(t, AssertIs(il.InLine.ID, id))
|
||||||
|
throwFail(t, AssertIs(il.InLine.Name, name))
|
||||||
|
throwFail(t, AssertIs(il.InLine.Email, email))
|
||||||
|
|
||||||
|
rinline := NewInLine()
|
||||||
|
err = dORM.QueryTable(rinline).Filter("InLineOneToOne__Id", 1).One(rinline)
|
||||||
|
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(rinline.ID, id))
|
||||||
|
throwFail(t, AssertIs(rinline.Name, name))
|
||||||
|
throwFail(t, AssertIs(rinline.Email, email))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntegerPk(t *testing.T) {
|
||||||
|
its := []IntegerPk{
|
||||||
|
{Id: math.MinInt64, Value: "-"},
|
||||||
|
{Id: 0, Value: "0"},
|
||||||
|
{Id: math.MaxInt64, Value: "+"},
|
||||||
|
}
|
||||||
|
|
||||||
|
num, err := dORM.InsertMulti(len(its), its)
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, len(its)))
|
||||||
|
|
||||||
|
for _, intPk := range its {
|
||||||
|
out := IntegerPk{Id: intPk.Id}
|
||||||
|
err = dORM.Read(&out)
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(out.Value, intPk.Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInsertAuto(t *testing.T) {
|
||||||
|
u := &User{
|
||||||
|
UserName: "autoPre",
|
||||||
|
Email: "autoPre@gmail.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := dORM.Insert(u)
|
||||||
|
throwFail(t, err)
|
||||||
|
|
||||||
|
id += 100
|
||||||
|
su := &User{
|
||||||
|
ID: int(id),
|
||||||
|
UserName: "auto",
|
||||||
|
Email: "auto@gmail.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
nid, err := dORM.Insert(su)
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(nid, id))
|
||||||
|
|
||||||
|
users := []User{
|
||||||
|
{ID: int(id + 100), UserName: "auto_100"},
|
||||||
|
{ID: int(id + 110), UserName: "auto_110"},
|
||||||
|
{ID: int(id + 120), UserName: "auto_120"},
|
||||||
|
}
|
||||||
|
num, err := dORM.InsertMulti(100, users)
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 3))
|
||||||
|
|
||||||
|
u = &User{
|
||||||
|
UserName: "auto_121",
|
||||||
|
}
|
||||||
|
|
||||||
|
nid, err = dORM.Insert(u)
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(nid, id+120+1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUintPk(t *testing.T) {
|
||||||
|
name := "go"
|
||||||
|
u := &UintPk{
|
||||||
|
Id: 8,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
|
||||||
|
created, pk, err := dORM.ReadOrCreate(u, "Id")
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(created, true))
|
||||||
|
throwFail(t, AssertIs(u.Name, name))
|
||||||
|
|
||||||
|
nu := &UintPk{Id: 8}
|
||||||
|
created, pk, err = dORM.ReadOrCreate(nu, "Id")
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(created, false))
|
||||||
|
throwFail(t, AssertIs(nu.Id, u.Id))
|
||||||
|
throwFail(t, AssertIs(pk, u.Id))
|
||||||
|
throwFail(t, AssertIs(nu.Name, name))
|
||||||
|
|
||||||
|
dORM.Delete(u)
|
||||||
|
}
|
||||||
|
@ -420,4 +420,5 @@ type dbBaser interface {
|
|||||||
ShowColumnsQuery(string) string
|
ShowColumnsQuery(string) string
|
||||||
IndexExists(dbQuerier, string, string) bool
|
IndexExists(dbQuerier, string, string) bool
|
||||||
collectFieldValue(*modelInfo, *fieldInfo, reflect.Value, bool, *time.Location) (interface{}, error)
|
collectFieldValue(*modelInfo, *fieldInfo, reflect.Value, bool, *time.Location) (interface{}, error)
|
||||||
|
setval(dbQuerier, *modelInfo, []string) error
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/astaxie/beego/logs"
|
||||||
"github.com/astaxie/beego/utils"
|
"github.com/astaxie/beego/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -58,7 +59,7 @@ func parserPkg(pkgRealpath, pkgpath string) error {
|
|||||||
rep := strings.NewReplacer("/", "_", ".", "_")
|
rep := strings.NewReplacer("/", "_", ".", "_")
|
||||||
commentFilename = coomentPrefix + rep.Replace(pkgpath) + ".go"
|
commentFilename = coomentPrefix + rep.Replace(pkgpath) + ".go"
|
||||||
if !compareFile(pkgRealpath) {
|
if !compareFile(pkgRealpath) {
|
||||||
Info(pkgRealpath + " has not changed, not reloading")
|
logs.Info(pkgRealpath + " no changed")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
genInfoList = make(map[string][]ControllerComments)
|
genInfoList = make(map[string][]ControllerComments)
|
||||||
@ -131,7 +132,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
|
|||||||
|
|
||||||
func genRouterCode() {
|
func genRouterCode() {
|
||||||
os.Mkdir(path.Join(AppPath, "routers"), 0755)
|
os.Mkdir(path.Join(AppPath, "routers"), 0755)
|
||||||
Info("generate router from comments")
|
logs.Info("generate router from comments")
|
||||||
var (
|
var (
|
||||||
globalinfo string
|
globalinfo string
|
||||||
sortKey []string
|
sortKey []string
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
//
|
//
|
||||||
// beego.InsertFilter("*", beego.BeforeRouter,apiauth.APISecretAuth(getAppSecret, 360))
|
// beego.InsertFilter("*", beego.BeforeRouter,apiauth.APISecretAuth(getAppSecret, 360))
|
||||||
//
|
//
|
||||||
// Infomation:
|
// Information:
|
||||||
//
|
//
|
||||||
// In the request user should include these params in the query
|
// In the request user should include these params in the query
|
||||||
//
|
//
|
||||||
|
111
router.go
111
router.go
@ -28,6 +28,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
beecontext "github.com/astaxie/beego/context"
|
beecontext "github.com/astaxie/beego/context"
|
||||||
|
"github.com/astaxie/beego/logs"
|
||||||
"github.com/astaxie/beego/toolbox"
|
"github.com/astaxie/beego/toolbox"
|
||||||
"github.com/astaxie/beego/utils"
|
"github.com/astaxie/beego/utils"
|
||||||
)
|
)
|
||||||
@ -114,7 +115,7 @@ type controllerInfo struct {
|
|||||||
type ControllerRegister struct {
|
type ControllerRegister struct {
|
||||||
routers map[string]*Tree
|
routers map[string]*Tree
|
||||||
enableFilter bool
|
enableFilter bool
|
||||||
filters map[int][]*FilterRouter
|
filters [FinishRouter + 1][]*FilterRouter
|
||||||
pool sync.Pool
|
pool sync.Pool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +123,6 @@ type ControllerRegister struct {
|
|||||||
func NewControllerRegister() *ControllerRegister {
|
func NewControllerRegister() *ControllerRegister {
|
||||||
cr := &ControllerRegister{
|
cr := &ControllerRegister{
|
||||||
routers: make(map[string]*Tree),
|
routers: make(map[string]*Tree),
|
||||||
filters: make(map[int][]*FilterRouter),
|
|
||||||
}
|
}
|
||||||
cr.pool.New = func() interface{} {
|
cr.pool.New = func() interface{} {
|
||||||
return beecontext.NewContext()
|
return beecontext.NewContext()
|
||||||
@ -408,7 +408,6 @@ func (p *ControllerRegister) AddAutoPrefix(prefix string, c ControllerInterface)
|
|||||||
// InsertFilter 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)
|
// The bool params is for setting the returnOnOutput value (false allows multiple filters to execute)
|
||||||
func (p *ControllerRegister) 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 := new(FilterRouter)
|
||||||
mr.tree = NewTree()
|
mr.tree = NewTree()
|
||||||
mr.pattern = pattern
|
mr.pattern = pattern
|
||||||
@ -426,9 +425,13 @@ func (p *ControllerRegister) InsertFilter(pattern string, pos int, filter Filter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add Filter into
|
// add Filter into
|
||||||
func (p *ControllerRegister) insertFilterRouter(pos int, mr *FilterRouter) error {
|
func (p *ControllerRegister) insertFilterRouter(pos int, mr *FilterRouter) (err error) {
|
||||||
p.filters[pos] = append(p.filters[pos], mr)
|
if pos < BeforeStatic || pos > FinishRouter {
|
||||||
|
err = fmt.Errorf("can not find your filter postion")
|
||||||
|
return
|
||||||
|
}
|
||||||
p.enableFilter = true
|
p.enableFilter = true
|
||||||
|
p.filters[pos] = append(p.filters[pos], mr)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,11 +440,11 @@ func (p *ControllerRegister) insertFilterRouter(pos int, mr *FilterRouter) error
|
|||||||
func (p *ControllerRegister) URLFor(endpoint string, values ...interface{}) string {
|
func (p *ControllerRegister) URLFor(endpoint string, values ...interface{}) string {
|
||||||
paths := strings.Split(endpoint, ".")
|
paths := strings.Split(endpoint, ".")
|
||||||
if len(paths) <= 1 {
|
if len(paths) <= 1 {
|
||||||
Warn("urlfor endpoint must like path.controller.method")
|
logs.Warn("urlfor endpoint must like path.controller.method")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if len(values)%2 != 0 {
|
if len(values)%2 != 0 {
|
||||||
Warn("urlfor params must key-value pair")
|
logs.Warn("urlfor params must key-value pair")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
params := make(map[string]string)
|
params := make(map[string]string)
|
||||||
@ -577,20 +580,16 @@ func (p *ControllerRegister) geturl(t *Tree, url, controllName, methodName strin
|
|||||||
return false, ""
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ControllerRegister) execFilter(context *beecontext.Context, pos int, urlPath string) (started bool) {
|
func (p *ControllerRegister) execFilter(context *beecontext.Context, urlPath string, pos int) (started bool) {
|
||||||
if p.enableFilter {
|
for _, filterR := range p.filters[pos] {
|
||||||
if l, ok := p.filters[pos]; ok {
|
if filterR.returnOnOutput && context.ResponseWriter.Started {
|
||||||
for _, filterR := range l {
|
return true
|
||||||
if filterR.returnOnOutput && context.ResponseWriter.Started {
|
}
|
||||||
return true
|
if ok := filterR.ValidRouter(urlPath, context); ok {
|
||||||
}
|
filterR.filterFunc(context)
|
||||||
if ok := filterR.ValidRouter(urlPath, context); ok {
|
}
|
||||||
filterR.filterFunc(context)
|
if filterR.returnOnOutput && context.ResponseWriter.Started {
|
||||||
}
|
return true
|
||||||
if filterR.returnOnOutput && context.ResponseWriter.Started {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -617,11 +616,10 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
|||||||
context.Output.Header("Server", BConfig.ServerName)
|
context.Output.Header("Server", BConfig.ServerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
var urlPath string
|
var urlPath = r.URL.Path
|
||||||
|
|
||||||
if !BConfig.RouterCaseSensitive {
|
if !BConfig.RouterCaseSensitive {
|
||||||
urlPath = strings.ToLower(r.URL.Path)
|
urlPath = strings.ToLower(urlPath)
|
||||||
} else {
|
|
||||||
urlPath = r.URL.Path
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter wrong http method
|
// filter wrong http method
|
||||||
@ -631,11 +629,12 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// filter for static file
|
// filter for static file
|
||||||
if p.execFilter(context, BeforeStatic, urlPath) {
|
if len(p.filters[BeforeStatic]) > 0 && p.execFilter(context, urlPath, BeforeStatic) {
|
||||||
goto Admin
|
goto Admin
|
||||||
}
|
}
|
||||||
|
|
||||||
serverStaticRouter(context)
|
serverStaticRouter(context)
|
||||||
|
|
||||||
if context.ResponseWriter.Started {
|
if context.ResponseWriter.Started {
|
||||||
findRouter = true
|
findRouter = true
|
||||||
goto Admin
|
goto Admin
|
||||||
@ -653,9 +652,9 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
|||||||
var err error
|
var err error
|
||||||
context.Input.CruSession, err = GlobalSessions.SessionStart(rw, r)
|
context.Input.CruSession, err = GlobalSessions.SessionStart(rw, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(err)
|
logs.Error(err)
|
||||||
exception("503", context)
|
exception("503", context)
|
||||||
return
|
goto Admin
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if context.Input.CruSession != nil {
|
if context.Input.CruSession != nil {
|
||||||
@ -663,8 +662,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
if len(p.filters[BeforeRouter]) > 0 && p.execFilter(context, urlPath, BeforeRouter) {
|
||||||
if p.execFilter(context, BeforeRouter, urlPath) {
|
|
||||||
goto Admin
|
goto Admin
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -693,7 +691,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
|||||||
|
|
||||||
if findRouter {
|
if findRouter {
|
||||||
//execute middleware filters
|
//execute middleware filters
|
||||||
if p.execFilter(context, BeforeExec, urlPath) {
|
if len(p.filters[BeforeExec]) > 0 && p.execFilter(context, urlPath, BeforeExec) {
|
||||||
goto Admin
|
goto Admin
|
||||||
}
|
}
|
||||||
isRunnable := false
|
isRunnable := false
|
||||||
@ -783,7 +781,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
|||||||
if !context.ResponseWriter.Started && context.Output.Status == 0 {
|
if !context.ResponseWriter.Started && context.Output.Status == 0 {
|
||||||
if BConfig.WebConfig.AutoRender {
|
if BConfig.WebConfig.AutoRender {
|
||||||
if err := execController.Render(); err != nil {
|
if err := execController.Render(); err != nil {
|
||||||
panic(err)
|
logs.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -794,17 +792,18 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//execute middleware filters
|
//execute middleware filters
|
||||||
if p.execFilter(context, AfterExec, urlPath) {
|
if len(p.filters[AfterExec]) > 0 && p.execFilter(context, urlPath, AfterExec) {
|
||||||
goto Admin
|
goto Admin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(p.filters[FinishRouter]) > 0 && p.execFilter(context, urlPath, FinishRouter) {
|
||||||
p.execFilter(context, FinishRouter, urlPath)
|
goto Admin
|
||||||
|
}
|
||||||
|
|
||||||
Admin:
|
Admin:
|
||||||
timeDur := time.Since(startTime)
|
|
||||||
//admin module record QPS
|
//admin module record QPS
|
||||||
if BConfig.Listen.EnableAdmin {
|
if BConfig.Listen.EnableAdmin {
|
||||||
|
timeDur := time.Since(startTime)
|
||||||
if FilterMonitorFunc(r.Method, r.URL.Path, timeDur) {
|
if FilterMonitorFunc(r.Method, r.URL.Path, timeDur) {
|
||||||
if runRouter != nil {
|
if runRouter != nil {
|
||||||
go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, runRouter.Name(), timeDur)
|
go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, runRouter.Name(), timeDur)
|
||||||
@ -815,6 +814,7 @@ Admin:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if BConfig.RunMode == DEV || BConfig.Log.AccessLogs {
|
if BConfig.RunMode == DEV || BConfig.Log.AccessLogs {
|
||||||
|
timeDur := time.Since(startTime)
|
||||||
var devInfo string
|
var devInfo string
|
||||||
if findRouter {
|
if findRouter {
|
||||||
if routerInfo != nil {
|
if routerInfo != nil {
|
||||||
@ -826,7 +826,7 @@ Admin:
|
|||||||
devInfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeDur.String(), "notmatch")
|
devInfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeDur.String(), "notmatch")
|
||||||
}
|
}
|
||||||
if DefaultAccessLogFilter == nil || !DefaultAccessLogFilter.Filter(context) {
|
if DefaultAccessLogFilter == nil || !DefaultAccessLogFilter.Filter(context) {
|
||||||
Debug(devInfo)
|
logs.Debug(devInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -843,27 +843,26 @@ func (p *ControllerRegister) recoverPanic(context *beecontext.Context) {
|
|||||||
}
|
}
|
||||||
if !BConfig.RecoverPanic {
|
if !BConfig.RecoverPanic {
|
||||||
panic(err)
|
panic(err)
|
||||||
} else {
|
}
|
||||||
if BConfig.EnableErrorsShow {
|
if BConfig.EnableErrorsShow {
|
||||||
if _, ok := ErrorMaps[fmt.Sprint(err)]; ok {
|
if _, ok := ErrorMaps[fmt.Sprint(err)]; ok {
|
||||||
exception(fmt.Sprint(err), context)
|
exception(fmt.Sprint(err), context)
|
||||||
return
|
return
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var stack string
|
}
|
||||||
Critical("the request url is ", context.Input.URL())
|
var stack string
|
||||||
Critical("Handler crashed with error", err)
|
logs.Critical("the request url is ", context.Input.URL())
|
||||||
for i := 1; ; i++ {
|
logs.Critical("Handler crashed with error", err)
|
||||||
_, file, line, ok := runtime.Caller(i)
|
for i := 1; ; i++ {
|
||||||
if !ok {
|
_, file, line, ok := runtime.Caller(i)
|
||||||
break
|
if !ok {
|
||||||
}
|
break
|
||||||
Critical(fmt.Sprintf("%s:%d", file, line))
|
|
||||||
stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
|
|
||||||
}
|
|
||||||
if BConfig.RunMode == DEV {
|
|
||||||
showErr(err, context, stack)
|
|
||||||
}
|
}
|
||||||
|
logs.Critical(fmt.Sprintf("%s:%d", file, line))
|
||||||
|
stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
|
||||||
|
}
|
||||||
|
if BConfig.RunMode == DEV {
|
||||||
|
showErr(err, context, stack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/astaxie/beego/context"
|
"github.com/astaxie/beego/context"
|
||||||
|
"github.com/astaxie/beego/logs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestController struct {
|
type TestController struct {
|
||||||
@ -94,7 +95,7 @@ func TestUrlFor(t *testing.T) {
|
|||||||
handler.Add("/api/list", &TestController{}, "*:List")
|
handler.Add("/api/list", &TestController{}, "*:List")
|
||||||
handler.Add("/person/:last/:first", &TestController{}, "*:Param")
|
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)
|
logs.Info(a)
|
||||||
t.Errorf("TestController.List must equal to /api/list")
|
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" {
|
||||||
@ -120,24 +121,24 @@ func TestUrlFor2(t *testing.T) {
|
|||||||
handler.Add("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", &TestController{}, "*:Param")
|
handler.Add("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", &TestController{}, "*:Param")
|
||||||
handler.Add("/:year:int/:month:int/:title/:entid", &TestController{})
|
handler.Add("/:year:int/:month:int/:title/:entid", &TestController{})
|
||||||
if handler.URLFor("TestController.GetURL", ":username", "astaxie") != "/v1/astaxie/edit" {
|
if handler.URLFor("TestController.GetURL", ":username", "astaxie") != "/v1/astaxie/edit" {
|
||||||
Info(handler.URLFor("TestController.GetURL"))
|
logs.Info(handler.URLFor("TestController.GetURL"))
|
||||||
t.Errorf("TestController.List must equal to /v1/astaxie/edit")
|
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" {
|
"/v1/za/cms_12_123.html" {
|
||||||
Info(handler.URLFor("TestController.List"))
|
logs.Info(handler.URLFor("TestController.List"))
|
||||||
t.Errorf("TestController.List must equal to /v1/za/cms_12_123.html")
|
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" {
|
"/v1/za_cms/ttt_12_123.html" {
|
||||||
Info(handler.URLFor("TestController.Param"))
|
logs.Info(handler.URLFor("TestController.Param"))
|
||||||
t.Errorf("TestController.List must equal to /v1/za_cms/ttt_12_123.html")
|
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") !=
|
":title", "aaaa", ":entid", "aaaa") !=
|
||||||
"/1111/11/aaaa/aaaa" {
|
"/1111/11/aaaa/aaaa" {
|
||||||
Info(handler.URLFor("TestController.Get"))
|
logs.Info(handler.URLFor("TestController.Get"))
|
||||||
t.Errorf("TestController.Get must equal to /1111/11/aaaa/aaaa")
|
t.Errorf("TestController.Get must equal to /1111/11/aaaa/aaaa")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,6 @@ func (st *SessionStore) SessionRelease(w http.ResponseWriter) {
|
|||||||
}
|
}
|
||||||
st.c.Exec("UPDATE "+TableName+" 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)
|
b, time.Now().Unix(), st.sid)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provider mysql session provider
|
// Provider mysql session provider
|
||||||
|
@ -16,7 +16,6 @@ package session
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -82,14 +81,17 @@ func (fs *FileSessionStore) SessionID() string {
|
|||||||
func (fs *FileSessionStore) SessionRelease(w http.ResponseWriter) {
|
func (fs *FileSessionStore) SessionRelease(w http.ResponseWriter) {
|
||||||
b, err := EncodeGob(fs.values)
|
b, err := EncodeGob(fs.values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
SLogger.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = os.Stat(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid))
|
_, err = os.Stat(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid))
|
||||||
var f *os.File
|
var f *os.File
|
||||||
if err == nil {
|
if err == nil {
|
||||||
f, err = os.OpenFile(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid), os.O_RDWR, 0777)
|
f, err = os.OpenFile(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid), os.O_RDWR, 0777)
|
||||||
|
SLogger.Println(err)
|
||||||
} else if os.IsNotExist(err) {
|
} else if os.IsNotExist(err) {
|
||||||
f, err = os.Create(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid))
|
f, err = os.Create(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid))
|
||||||
|
SLogger.Println(err)
|
||||||
} else {
|
} else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -123,7 +125,7 @@ func (fp *FileProvider) SessionRead(sid string) (Store, error) {
|
|||||||
|
|
||||||
err := os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777)
|
err := os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println(err.Error())
|
SLogger.Println(err.Error())
|
||||||
}
|
}
|
||||||
_, err = os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
|
_, err = os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
|
||||||
var f *os.File
|
var f *os.File
|
||||||
@ -191,7 +193,7 @@ func (fp *FileProvider) SessionAll() int {
|
|||||||
return a.visit(path, f, err)
|
return a.visit(path, f, err)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("filepath.Walk() returned %v\n", err)
|
SLogger.Printf("filepath.Walk() returned %v\n", err)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return a.total
|
return a.total
|
||||||
@ -205,11 +207,11 @@ func (fp *FileProvider) SessionRegenerate(oldsid, sid string) (Store, error) {
|
|||||||
|
|
||||||
err := os.MkdirAll(path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1])), 0777)
|
err := os.MkdirAll(path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1])), 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println(err.Error())
|
SLogger.Println(err.Error())
|
||||||
}
|
}
|
||||||
err = os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777)
|
err = os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println(err.Error())
|
SLogger.Println(err.Error())
|
||||||
}
|
}
|
||||||
_, err = os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
|
_, err = os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
|
||||||
var newf *os.File
|
var newf *os.File
|
||||||
|
@ -32,8 +32,11 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -61,6 +64,9 @@ type Provider interface {
|
|||||||
|
|
||||||
var provides = make(map[string]Provider)
|
var provides = make(map[string]Provider)
|
||||||
|
|
||||||
|
// SLogger a helpful variable to log information about session
|
||||||
|
var SLogger = NewSessionLog(os.Stderr)
|
||||||
|
|
||||||
// Register makes a session provide available by the provided name.
|
// Register makes a session provide available by the provided name.
|
||||||
// If Register is called twice with the same name or if driver is nil,
|
// If Register is called twice with the same name or if driver is nil,
|
||||||
// it panics.
|
// it panics.
|
||||||
@ -296,3 +302,15 @@ func (manager *Manager) isSecure(req *http.Request) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log implement the log.Logger
|
||||||
|
type Log struct {
|
||||||
|
*log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSessionLog set io.Writer to create a Logger for session.
|
||||||
|
func NewSessionLog(out io.Writer) *Log {
|
||||||
|
sl := new(Log)
|
||||||
|
sl.Logger = log.New(out, "[SESSION]", 1e9)
|
||||||
|
return sl
|
||||||
|
}
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/astaxie/beego/context"
|
"github.com/astaxie/beego/context"
|
||||||
|
"github.com/astaxie/beego/logs"
|
||||||
)
|
)
|
||||||
|
|
||||||
var errNotStaticRequest = errors.New("request not a static file request")
|
var errNotStaticRequest = errors.New("request not a static file request")
|
||||||
@ -48,14 +49,19 @@ func serverStaticRouter(ctx *context.Context) {
|
|||||||
|
|
||||||
if filePath == "" || fileInfo == nil {
|
if filePath == "" || fileInfo == nil {
|
||||||
if BConfig.RunMode == DEV {
|
if BConfig.RunMode == DEV {
|
||||||
Warn("Can't find/open the file:", filePath, err)
|
logs.Warn("Can't find/open the file:", filePath, err)
|
||||||
}
|
}
|
||||||
http.NotFound(ctx.ResponseWriter, ctx.Request)
|
http.NotFound(ctx.ResponseWriter, ctx.Request)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if fileInfo.IsDir() {
|
if fileInfo.IsDir() {
|
||||||
//serveFile will list dir
|
requestURL := ctx.Input.URL()
|
||||||
http.ServeFile(ctx.ResponseWriter, ctx.Request, filePath)
|
if requestURL[len(requestURL)-1] != '/' {
|
||||||
|
ctx.Redirect(302, requestURL+"/")
|
||||||
|
} else {
|
||||||
|
//serveFile will list dir
|
||||||
|
http.ServeFile(ctx.ResponseWriter, ctx.Request, filePath)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +73,7 @@ func serverStaticRouter(ctx *context.Context) {
|
|||||||
b, n, sch, err := openFile(filePath, fileInfo, acceptEncoding)
|
b, n, sch, err := openFile(filePath, fileInfo, acceptEncoding)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if BConfig.RunMode == DEV {
|
if BConfig.RunMode == DEV {
|
||||||
Warn("Can't compress the file:", filePath, err)
|
logs.Warn("Can't compress the file:", filePath, err)
|
||||||
}
|
}
|
||||||
http.NotFound(ctx.ResponseWriter, ctx.Request)
|
http.NotFound(ctx.ResponseWriter, ctx.Request)
|
||||||
return
|
return
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/astaxie/beego/logs"
|
||||||
"github.com/astaxie/beego/utils"
|
"github.com/astaxie/beego/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -46,7 +47,7 @@ func executeTemplate(wr io.Writer, name string, data interface{}) error {
|
|||||||
if t, ok := beeTemplates[name]; ok {
|
if t, ok := beeTemplates[name]; ok {
|
||||||
err := t.ExecuteTemplate(wr, name, data)
|
err := t.ExecuteTemplate(wr, name, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Trace("template Execute err:", err)
|
logs.Trace("template Execute err:", err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -162,7 +163,7 @@ func BuildTemplate(dir string, files ...string) error {
|
|||||||
templatesLock.Lock()
|
templatesLock.Lock()
|
||||||
t, err := getTemplate(self.root, file, v...)
|
t, err := getTemplate(self.root, file, v...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Trace("parse template err:", file, err)
|
logs.Trace("parse template err:", file, err)
|
||||||
} else {
|
} else {
|
||||||
beeTemplates[file] = t
|
beeTemplates[file] = t
|
||||||
}
|
}
|
||||||
@ -240,7 +241,7 @@ func _getTemplate(t0 *template.Template, root string, subMods [][]string, others
|
|||||||
var subMods1 [][]string
|
var subMods1 [][]string
|
||||||
t, subMods1, err = getTplDeep(root, otherFile, "", t)
|
t, subMods1, err = getTplDeep(root, otherFile, "", t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Trace("template parse file err:", err)
|
logs.Trace("template parse file err:", err)
|
||||||
} else if subMods1 != nil && len(subMods1) > 0 {
|
} else if subMods1 != nil && len(subMods1) > 0 {
|
||||||
t, err = _getTemplate(t, root, subMods1, others...)
|
t, err = _getTemplate(t, root, subMods1, others...)
|
||||||
}
|
}
|
||||||
@ -261,7 +262,7 @@ func _getTemplate(t0 *template.Template, root string, subMods [][]string, others
|
|||||||
var subMods1 [][]string
|
var subMods1 [][]string
|
||||||
t, subMods1, err = getTplDeep(root, otherFile, "", t)
|
t, subMods1, err = getTplDeep(root, otherFile, "", t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Trace("template parse file err:", err)
|
logs.Trace("template parse file err:", err)
|
||||||
} else if subMods1 != nil && len(subMods1) > 0 {
|
} else if subMods1 != nil && len(subMods1) > 0 {
|
||||||
t, err = _getTemplate(t, root, subMods1, others...)
|
t, err = _getTemplate(t, root, subMods1, others...)
|
||||||
}
|
}
|
||||||
|
6
tree.go
6
tree.go
@ -141,7 +141,7 @@ func (t *Tree) addtree(segments []string, tree *Tree, wildcards []string, reg st
|
|||||||
regexpStr = "([^.]+).(.+)"
|
regexpStr = "([^.]+).(.+)"
|
||||||
params = params[1:]
|
params = params[1:]
|
||||||
} else {
|
} else {
|
||||||
for _ = range params {
|
for range params {
|
||||||
regexpStr = "([^/]+)/" + regexpStr
|
regexpStr = "([^/]+)/" + regexpStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,7 +254,7 @@ func (t *Tree) addseg(segments []string, route interface{}, wildcards []string,
|
|||||||
regexpStr = "/([^.]+).(.+)"
|
regexpStr = "/([^.]+).(.+)"
|
||||||
params = params[1:]
|
params = params[1:]
|
||||||
} else {
|
} else {
|
||||||
for _ = range params {
|
for range params {
|
||||||
regexpStr = "/([^/]+)" + regexpStr
|
regexpStr = "/([^/]+)" + regexpStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -389,7 +389,7 @@ type leafInfo struct {
|
|||||||
func (leaf *leafInfo) match(wildcardValues []string, ctx *context.Context) (ok bool) {
|
func (leaf *leafInfo) match(wildcardValues []string, ctx *context.Context) (ok bool) {
|
||||||
//fmt.Println("Leaf:", wildcardValues, leaf.wildcards, leaf.regexps)
|
//fmt.Println("Leaf:", wildcardValues, leaf.wildcards, leaf.regexps)
|
||||||
if leaf.regexps == nil {
|
if leaf.regexps == nil {
|
||||||
if len(wildcardValues) == 0 { // static path
|
if len(wildcardValues) == 0 && len(leaf.wildcards) == 0 { // static path
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match *
|
// match *
|
||||||
|
15
tree_test.go
15
tree_test.go
@ -97,6 +97,21 @@ func TestTreeRouters(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStaticPath(t *testing.T) {
|
||||||
|
tr := NewTree()
|
||||||
|
tr.AddRouter("/topic/:id", "wildcard")
|
||||||
|
tr.AddRouter("/topic", "static")
|
||||||
|
ctx := context.NewContext()
|
||||||
|
obj := tr.Match("/topic", ctx)
|
||||||
|
if obj == nil || obj.(string) != "static" {
|
||||||
|
t.Fatal("/topic is a static route")
|
||||||
|
}
|
||||||
|
obj = tr.Match("/topic/1", ctx)
|
||||||
|
if obj == nil || obj.(string) != "wildcard" {
|
||||||
|
t.Fatal("/topic/1 is a wildcard route")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAddTree(t *testing.T) {
|
func TestAddTree(t *testing.T) {
|
||||||
tr := NewTree()
|
tr := NewTree()
|
||||||
tr.AddRouter("/shop/:id/account", "astaxie")
|
tr.AddRouter("/shop/:id/account", "astaxie")
|
||||||
|
@ -69,6 +69,7 @@ import (
|
|||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/astaxie/beego/cache"
|
"github.com/astaxie/beego/cache"
|
||||||
"github.com/astaxie/beego/context"
|
"github.com/astaxie/beego/context"
|
||||||
|
"github.com/astaxie/beego/logs"
|
||||||
"github.com/astaxie/beego/utils"
|
"github.com/astaxie/beego/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -139,7 +140,7 @@ func (c *Captcha) Handler(ctx *context.Context) {
|
|||||||
if err := c.store.Put(key, chars, c.Expiration); err != nil {
|
if err := c.store.Put(key, chars, c.Expiration); err != nil {
|
||||||
ctx.Output.SetStatus(500)
|
ctx.Output.SetStatus(500)
|
||||||
ctx.WriteString("captcha reload error")
|
ctx.WriteString("captcha reload error")
|
||||||
beego.Error("Reload Create Captcha Error:", err)
|
logs.Error("Reload Create Captcha Error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -154,7 +155,7 @@ func (c *Captcha) Handler(ctx *context.Context) {
|
|||||||
|
|
||||||
img := NewImage(chars, c.StdWidth, c.StdHeight)
|
img := NewImage(chars, c.StdWidth, c.StdHeight)
|
||||||
if _, err := img.WriteTo(ctx.ResponseWriter); err != nil {
|
if _, err := img.WriteTo(ctx.ResponseWriter); err != nil {
|
||||||
beego.Error("Write Captcha Image Error:", err)
|
logs.Error("Write Captcha Image Error:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +163,7 @@ func (c *Captcha) Handler(ctx *context.Context) {
|
|||||||
func (c *Captcha) CreateCaptchaHTML() template.HTML {
|
func (c *Captcha) CreateCaptchaHTML() template.HTML {
|
||||||
value, err := c.CreateCaptcha()
|
value, err := c.CreateCaptcha()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
beego.Error("Create Captcha Error:", err)
|
logs.Error("Create Captcha Error:", err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
"github.com/astaxie/beego/context"
|
"github.com/astaxie/beego/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetPaginator Instantiates a Paginator and assigns it to context.Input.Data["paginator"].
|
// SetPaginator Instantiates a Paginator and assigns it to context.Input.Data("paginator").
|
||||||
func SetPaginator(context *context.Context, per int, nums int64) (paginator *Paginator) {
|
func SetPaginator(context *context.Context, per int, nums int64) (paginator *Paginator) {
|
||||||
paginator = NewPaginator(context.Request, per, nums)
|
paginator = NewPaginator(context.Request, per, nums)
|
||||||
context.Input.SetData("paginator", &paginator)
|
context.Input.SetData("paginator", &paginator)
|
||||||
|
Loading…
Reference in New Issue
Block a user