mirror of
https://github.com/astaxie/beego.git
synced 2024-11-25 20:10:56 +00:00
Merge remote-tracking branch 'remotes/upstream/develop' into err_ctrler
This commit is contained in:
commit
3dd9020249
11
.travis.yml
11
.travis.yml
@ -14,6 +14,11 @@ env:
|
|||||||
- ORM_DRIVER=sqlite3 ORM_SOURCE=$TRAVIS_BUILD_DIR/orm_test.db
|
- ORM_DRIVER=sqlite3 ORM_SOURCE=$TRAVIS_BUILD_DIR/orm_test.db
|
||||||
- ORM_DRIVER=mysql ORM_SOURCE="root:@/orm_test?charset=utf8"
|
- ORM_DRIVER=mysql ORM_SOURCE="root:@/orm_test?charset=utf8"
|
||||||
- ORM_DRIVER=postgres ORM_SOURCE="user=postgres dbname=orm_test sslmode=disable"
|
- ORM_DRIVER=postgres ORM_SOURCE="user=postgres dbname=orm_test sslmode=disable"
|
||||||
|
before_install:
|
||||||
|
- git clone git://github.com/ideawu/ssdb.git
|
||||||
|
- cd ssdb
|
||||||
|
- make
|
||||||
|
- cd ..
|
||||||
install:
|
install:
|
||||||
- go get github.com/lib/pq
|
- go get github.com/lib/pq
|
||||||
- go get github.com/go-sql-driver/mysql
|
- go get github.com/go-sql-driver/mysql
|
||||||
@ -28,10 +33,16 @@ install:
|
|||||||
- 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/golang/lint/golint
|
||||||
|
- 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"
|
||||||
|
- mkdir -p res/var
|
||||||
|
- ./ssdb/ssdb-server ./ssdb/ssdb.conf -d
|
||||||
|
after_script:
|
||||||
|
-killall -w ssdb-server
|
||||||
|
- rm -rf ./res/var/*
|
||||||
script:
|
script:
|
||||||
- go vet -x ./...
|
- go vet -x ./...
|
||||||
- $HOME/gopath/bin/golint ./...
|
- $HOME/gopath/bin/golint ./...
|
||||||
|
240
cache/ssdb/ssdb.go
vendored
Normal file
240
cache/ssdb/ssdb.go
vendored
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
package ssdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ssdb/gossdb/ssdb"
|
||||||
|
|
||||||
|
"github.com/astaxie/beego/cache"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cache SSDB adapter
|
||||||
|
type Cache struct {
|
||||||
|
conn *ssdb.Client
|
||||||
|
conninfo []string
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewSsdbCache create new ssdb adapter.
|
||||||
|
func NewSsdbCache() cache.Cache {
|
||||||
|
return &Cache{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get get value from memcache.
|
||||||
|
func (rc *Cache) Get(key string) interface{} {
|
||||||
|
if rc.conn == nil {
|
||||||
|
if err := rc.connectInit(); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value, err := rc.conn.Get(key)
|
||||||
|
if err == nil {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMulti get value from memcache.
|
||||||
|
func (rc *Cache) GetMulti(keys []string) []interface{} {
|
||||||
|
size := len(keys)
|
||||||
|
var values []interface{}
|
||||||
|
if rc.conn == nil {
|
||||||
|
if err := rc.connectInit(); err != nil {
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
values = append(values, err)
|
||||||
|
}
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res, err := rc.conn.Do("multi_get", keys)
|
||||||
|
resSize := len(res)
|
||||||
|
if err == nil {
|
||||||
|
for i := 1; i < resSize; i += 2 {
|
||||||
|
values = append(values, string(res[i+1]))
|
||||||
|
}
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
values = append(values, err)
|
||||||
|
}
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelMulti get value from memcache.
|
||||||
|
func (rc *Cache) DelMulti(keys []string) error {
|
||||||
|
if rc.conn == nil {
|
||||||
|
if err := rc.connectInit(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err := rc.conn.Do("multi_del", keys)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put put value to memcache. only support string.
|
||||||
|
func (rc *Cache) Put(key string, value interface{}, timeout time.Duration) error {
|
||||||
|
if rc.conn == nil {
|
||||||
|
if err := rc.connectInit(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v, ok := value.(string)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("value must string")
|
||||||
|
}
|
||||||
|
var resp []string
|
||||||
|
var err error
|
||||||
|
ttl := int(timeout / time.Second)
|
||||||
|
if ttl < 0 {
|
||||||
|
resp, err = rc.conn.Do("set", key, v)
|
||||||
|
} else {
|
||||||
|
resp, err = rc.conn.Do("setx", key, v, ttl)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(resp) == 2 && resp[0] == "ok" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("bad response")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete delete value in memcache.
|
||||||
|
func (rc *Cache) Delete(key string) error {
|
||||||
|
if rc.conn == nil {
|
||||||
|
if err := rc.connectInit(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err := rc.conn.Del(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Incr increase counter.
|
||||||
|
func (rc *Cache) Incr(key string) error {
|
||||||
|
if rc.conn == nil {
|
||||||
|
if err := rc.connectInit(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err := rc.conn.Do("incr", key, 1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decr decrease counter.
|
||||||
|
func (rc *Cache) Decr(key string) error {
|
||||||
|
if rc.conn == nil {
|
||||||
|
if err := rc.connectInit(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err := rc.conn.Do("incr", key, -1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExist check value exists in memcache.
|
||||||
|
func (rc *Cache) IsExist(key string) bool {
|
||||||
|
if rc.conn == nil {
|
||||||
|
if err := rc.connectInit(); err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resp, err := rc.conn.Do("exists", key)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if resp[1] == "1" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearAll clear all cached in memcache.
|
||||||
|
func (rc *Cache) ClearAll() error {
|
||||||
|
if rc.conn == nil {
|
||||||
|
if err := rc.connectInit(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keyStart, keyEnd, limit := "", "", 50
|
||||||
|
resp, err := rc.Scan(keyStart, keyEnd, limit)
|
||||||
|
for err == nil {
|
||||||
|
size := len(resp)
|
||||||
|
if size == 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
keys := []string{}
|
||||||
|
for i := 1; i < size; i += 2 {
|
||||||
|
keys = append(keys, string(resp[i]))
|
||||||
|
}
|
||||||
|
_, e := rc.conn.Do("multi_del", keys)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
keyStart = resp[size-2]
|
||||||
|
resp, err = rc.Scan(keyStart, keyEnd, limit)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan key all cached in ssdb.
|
||||||
|
func (rc *Cache) Scan(keyStart string, keyEnd string, limit int) ([]string, error) {
|
||||||
|
if rc.conn == nil {
|
||||||
|
if err := rc.connectInit(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resp, err := rc.conn.Do("scan", keyStart, keyEnd, limit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartAndGC start memcache adapter.
|
||||||
|
// config string is like {"conn":"connection info"}.
|
||||||
|
// if connecting error, return.
|
||||||
|
func (rc *Cache) StartAndGC(config string) error {
|
||||||
|
var cf map[string]string
|
||||||
|
json.Unmarshal([]byte(config), &cf)
|
||||||
|
if _, ok := cf["conn"]; !ok {
|
||||||
|
return errors.New("config has no conn key")
|
||||||
|
}
|
||||||
|
rc.conninfo = strings.Split(cf["conn"], ";")
|
||||||
|
if rc.conn == nil {
|
||||||
|
if err := rc.connectInit(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// connect to memcache and keep the connection.
|
||||||
|
func (rc *Cache) connectInit() error {
|
||||||
|
conninfoArray := strings.Split(rc.conninfo[0], ":")
|
||||||
|
host := conninfoArray[0]
|
||||||
|
port, e := strconv.Atoi(conninfoArray[1])
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
rc.conn, err = ssdb.Connect(host, port)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cache.Register("ssdb", NewSsdbCache)
|
||||||
|
}
|
103
cache/ssdb/ssdb_test.go
vendored
Normal file
103
cache/ssdb/ssdb_test.go
vendored
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package ssdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/astaxie/beego/cache"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSsdbcacheCache(t *testing.T) {
|
||||||
|
ssdb, err := cache.NewCache("ssdb", `{"conn": "127.0.0.1:8888"}`)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("init err")
|
||||||
|
}
|
||||||
|
|
||||||
|
// test put and exist
|
||||||
|
if ssdb.IsExist("ssdb") {
|
||||||
|
t.Error("check err")
|
||||||
|
}
|
||||||
|
timeoutDuration := 10 * time.Second
|
||||||
|
//timeoutDuration := -10*time.Second if timeoutDuration is negtive,it means permanent
|
||||||
|
if err = ssdb.Put("ssdb", "ssdb", timeoutDuration); err != nil {
|
||||||
|
t.Error("set Error", err)
|
||||||
|
}
|
||||||
|
if !ssdb.IsExist("ssdb") {
|
||||||
|
t.Error("check err")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get test done
|
||||||
|
if err = ssdb.Put("ssdb", "ssdb", timeoutDuration); err != nil {
|
||||||
|
t.Error("set Error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := ssdb.Get("ssdb"); v != "ssdb" {
|
||||||
|
t.Error("get Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
//inc/dec test done
|
||||||
|
if err = ssdb.Put("ssdb", "2", timeoutDuration); err != nil {
|
||||||
|
t.Error("set Error", err)
|
||||||
|
}
|
||||||
|
if err = ssdb.Incr("ssdb"); err != nil {
|
||||||
|
t.Error("incr Error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := strconv.Atoi(ssdb.Get("ssdb").(string)); err != nil || v != 3 {
|
||||||
|
t.Error("get err")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = ssdb.Decr("ssdb"); err != nil {
|
||||||
|
t.Error("decr error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// test del
|
||||||
|
if err = ssdb.Put("ssdb", "3", timeoutDuration); err != nil {
|
||||||
|
t.Error("set Error", err)
|
||||||
|
}
|
||||||
|
if v, err := strconv.Atoi(ssdb.Get("ssdb").(string)); err != nil || v != 3 {
|
||||||
|
t.Error("get err")
|
||||||
|
}
|
||||||
|
if err := ssdb.Delete("ssdb"); err == nil {
|
||||||
|
if ssdb.IsExist("ssdb") {
|
||||||
|
t.Error("delete err")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//test string
|
||||||
|
if err = ssdb.Put("ssdb", "ssdb", -10*time.Second); err != nil {
|
||||||
|
t.Error("set Error", err)
|
||||||
|
}
|
||||||
|
if !ssdb.IsExist("ssdb") {
|
||||||
|
t.Error("check err")
|
||||||
|
}
|
||||||
|
if v := ssdb.Get("ssdb").(string); v != "ssdb" {
|
||||||
|
t.Error("get err")
|
||||||
|
}
|
||||||
|
|
||||||
|
//test GetMulti done
|
||||||
|
if err = ssdb.Put("ssdb1", "ssdb1", -10*time.Second); err != nil {
|
||||||
|
t.Error("set Error", err)
|
||||||
|
}
|
||||||
|
if !ssdb.IsExist("ssdb1") {
|
||||||
|
t.Error("check err")
|
||||||
|
}
|
||||||
|
vv := ssdb.GetMulti([]string{"ssdb", "ssdb1"})
|
||||||
|
if len(vv) != 2 {
|
||||||
|
t.Error("getmulti error")
|
||||||
|
}
|
||||||
|
if vv[0].(string) != "ssdb" {
|
||||||
|
t.Error("getmulti error")
|
||||||
|
}
|
||||||
|
if vv[1].(string) != "ssdb1" {
|
||||||
|
t.Error("getmulti error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// test clear all done
|
||||||
|
if err = ssdb.ClearAll(); err != nil {
|
||||||
|
t.Error("clear all err")
|
||||||
|
}
|
||||||
|
if ssdb.IsExist("ssdb") || ssdb.IsExist("ssdb1") {
|
||||||
|
t.Error("check err")
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,6 @@ package beego
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@ -106,8 +105,6 @@ var (
|
|||||||
AppConfig *beegoAppConfig
|
AppConfig *beegoAppConfig
|
||||||
// AppPath is the absolute path to the app
|
// AppPath is the absolute path to the app
|
||||||
AppPath string
|
AppPath string
|
||||||
// TemplateCache stores template caching
|
|
||||||
TemplateCache map[string]*template.Template
|
|
||||||
// GlobalSessions is the instance for the session manager
|
// GlobalSessions is the instance for the session manager
|
||||||
GlobalSessions *session.Manager
|
GlobalSessions *session.Manager
|
||||||
|
|
||||||
@ -188,7 +185,9 @@ func init() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
parseConfig(appConfigPath)
|
if err := parseConfig(appConfigPath); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// now only support ini, next will support json.
|
// now only support ini, next will support json.
|
||||||
|
@ -46,12 +46,16 @@ func (c *fakeConfigContainer) DefaultString(key string, defaultval string) strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeConfigContainer) Strings(key string) []string {
|
func (c *fakeConfigContainer) Strings(key string) []string {
|
||||||
return strings.Split(c.getData(key), ";")
|
v := c.getData(key)
|
||||||
|
if v == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return strings.Split(v, ";")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeConfigContainer) DefaultStrings(key string, defaultval []string) []string {
|
func (c *fakeConfigContainer) DefaultStrings(key string, defaultval []string) []string {
|
||||||
v := c.Strings(key)
|
v := c.Strings(key)
|
||||||
if len(v) == 0 {
|
if v == nil {
|
||||||
return defaultval
|
return defaultval
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
|
@ -269,15 +269,20 @@ func (c *IniConfigContainer) DefaultString(key string, defaultval string) string
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Strings returns the []string value for a given key.
|
// Strings returns the []string value for a given key.
|
||||||
|
// Return nil if config value does not exist or is empty.
|
||||||
func (c *IniConfigContainer) Strings(key string) []string {
|
func (c *IniConfigContainer) Strings(key string) []string {
|
||||||
return strings.Split(c.String(key), ";")
|
v := c.String(key)
|
||||||
|
if v == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return strings.Split(v, ";")
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultStrings returns the []string value for a given key.
|
// DefaultStrings returns the []string value for a given key.
|
||||||
// if err != nil return defaltval
|
// if err != nil return defaltval
|
||||||
func (c *IniConfigContainer) DefaultStrings(key string, defaultval []string) []string {
|
func (c *IniConfigContainer) DefaultStrings(key string, defaultval []string) []string {
|
||||||
v := c.Strings(key)
|
v := c.Strings(key)
|
||||||
if len(v) == 0 {
|
if v == nil {
|
||||||
return defaultval
|
return defaultval
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
|
@ -71,6 +71,7 @@ peers = one;two;three
|
|||||||
"null": "",
|
"null": "",
|
||||||
"demo2::key1": "",
|
"demo2::key1": "",
|
||||||
"error": "",
|
"error": "",
|
||||||
|
"emptystrings": []string{},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ func (c *JSONConfigContainer) DefaultString(key string, defaultval string) strin
|
|||||||
func (c *JSONConfigContainer) Strings(key string) []string {
|
func (c *JSONConfigContainer) Strings(key string) []string {
|
||||||
stringVal := c.String(key)
|
stringVal := c.String(key)
|
||||||
if stringVal == "" {
|
if stringVal == "" {
|
||||||
return []string{}
|
return nil
|
||||||
}
|
}
|
||||||
return strings.Split(c.String(key), ";")
|
return strings.Split(c.String(key), ";")
|
||||||
}
|
}
|
||||||
@ -181,7 +181,7 @@ func (c *JSONConfigContainer) Strings(key string) []string {
|
|||||||
// DefaultStrings returns the []string value for a given key.
|
// DefaultStrings returns the []string value for a given key.
|
||||||
// if err != nil return defaltval
|
// if err != nil return defaltval
|
||||||
func (c *JSONConfigContainer) DefaultStrings(key string, defaultval []string) []string {
|
func (c *JSONConfigContainer) DefaultStrings(key string, defaultval []string) []string {
|
||||||
if v := c.Strings(key); len(v) > 0 {
|
if v := c.Strings(key); v != nil {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
return defaultval
|
return defaultval
|
||||||
|
@ -174,14 +174,18 @@ func (c *ConfigContainer) DefaultString(key string, defaultval string) string {
|
|||||||
|
|
||||||
// Strings returns the []string value for a given key.
|
// Strings returns the []string value for a given key.
|
||||||
func (c *ConfigContainer) Strings(key string) []string {
|
func (c *ConfigContainer) Strings(key string) []string {
|
||||||
return strings.Split(c.String(key), ";")
|
v := c.String(key)
|
||||||
|
if v == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return strings.Split(v, ";")
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultStrings returns the []string value for a given key.
|
// DefaultStrings returns the []string value for a given key.
|
||||||
// if err != nil return defaltval
|
// if err != nil return defaltval
|
||||||
func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string {
|
func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string {
|
||||||
v := c.Strings(key)
|
v := c.Strings(key)
|
||||||
if len(v) == 0 {
|
if v == nil {
|
||||||
return defaultval
|
return defaultval
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
|
@ -82,4 +82,7 @@ func TestXML(t *testing.T) {
|
|||||||
if xmlconf.String("name") != "astaxie" {
|
if xmlconf.String("name") != "astaxie" {
|
||||||
t.Fatal("get name error")
|
t.Fatal("get name error")
|
||||||
}
|
}
|
||||||
|
if xmlconf.Strings("emptystrings") != nil {
|
||||||
|
t.Fatal("get emtpy strings error")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,14 +211,18 @@ func (c *ConfigContainer) DefaultString(key string, defaultval string) string {
|
|||||||
|
|
||||||
// Strings returns the []string value for a given key.
|
// Strings returns the []string value for a given key.
|
||||||
func (c *ConfigContainer) Strings(key string) []string {
|
func (c *ConfigContainer) Strings(key string) []string {
|
||||||
return strings.Split(c.String(key), ";")
|
v := c.String(key)
|
||||||
|
if v == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return strings.Split(v, ";")
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultStrings returns the []string value for a given key.
|
// DefaultStrings returns the []string value for a given key.
|
||||||
// if err != nil return defaltval
|
// if err != nil return defaltval
|
||||||
func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string {
|
func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string {
|
||||||
v := c.Strings(key)
|
v := c.Strings(key)
|
||||||
if len(v) == 0 {
|
if v == nil {
|
||||||
return defaultval
|
return defaultval
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
|
@ -79,4 +79,8 @@ func TestYaml(t *testing.T) {
|
|||||||
if yamlconf.String("name") != "astaxie" {
|
if yamlconf.String("name") != "astaxie" {
|
||||||
t.Fatal("get name error")
|
t.Fatal("get name error")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if yamlconf.Strings("emptystrings") != nil {
|
||||||
|
t.Fatal("get emtpy strings error")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,11 +24,13 @@ 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"
|
||||||
@ -193,6 +195,14 @@ func (w *Response) Write(p []byte) (int, error) {
|
|||||||
return w.ResponseWriter.Write(p)
|
return w.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 (w *Response) WriteHeader(code int) {
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -57,7 +56,7 @@ func (output *BeegoOutput) Header(key, val string) {
|
|||||||
// Body sets response body content.
|
// Body sets response body content.
|
||||||
// if EnableGzip, compress content string.
|
// if EnableGzip, compress content string.
|
||||||
// it sends out response body directly.
|
// it sends out response body directly.
|
||||||
func (output *BeegoOutput) Body(content []byte) {
|
func (output *BeegoOutput) Body(content []byte) error {
|
||||||
var encoding string
|
var encoding string
|
||||||
var buf = &bytes.Buffer{}
|
var buf = &bytes.Buffer{}
|
||||||
if output.EnableGzip {
|
if output.EnableGzip {
|
||||||
@ -75,7 +74,8 @@ func (output *BeegoOutput) Body(content []byte) {
|
|||||||
output.Status = 0
|
output.Status = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
io.Copy(output.Context.ResponseWriter, buf)
|
_, err := output.Context.ResponseWriter.Copy(buf)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cookie sets cookie value via given key.
|
// Cookie sets cookie value via given key.
|
||||||
@ -97,9 +97,10 @@ func (output *BeegoOutput) Cookie(name string, value string, others ...interface
|
|||||||
maxAge = v
|
maxAge = v
|
||||||
}
|
}
|
||||||
|
|
||||||
if maxAge > 0 {
|
switch {
|
||||||
|
case maxAge > 0:
|
||||||
fmt.Fprintf(&b, "; Expires=%s; Max-Age=%d", time.Now().Add(time.Duration(maxAge)*time.Second).UTC().Format(time.RFC1123), maxAge)
|
fmt.Fprintf(&b, "; Expires=%s; Max-Age=%d", time.Now().Add(time.Duration(maxAge)*time.Second).UTC().Format(time.RFC1123), maxAge)
|
||||||
} else {
|
case maxAge < 0:
|
||||||
fmt.Fprintf(&b, "; Max-Age=0")
|
fmt.Fprintf(&b, "; Max-Age=0")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -186,8 +187,7 @@ func (output *BeegoOutput) JSON(data interface{}, hasIndent bool, coding bool) e
|
|||||||
if coding {
|
if coding {
|
||||||
content = []byte(stringsToJSON(string(content)))
|
content = []byte(stringsToJSON(string(content)))
|
||||||
}
|
}
|
||||||
output.Body(content)
|
return output.Body(content)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSONP writes jsonp to response body.
|
// JSONP writes jsonp to response body.
|
||||||
@ -212,8 +212,7 @@ func (output *BeegoOutput) JSONP(data interface{}, hasIndent bool) error {
|
|||||||
callbackContent.WriteString("(")
|
callbackContent.WriteString("(")
|
||||||
callbackContent.Write(content)
|
callbackContent.Write(content)
|
||||||
callbackContent.WriteString(");\r\n")
|
callbackContent.WriteString(");\r\n")
|
||||||
output.Body(callbackContent.Bytes())
|
return output.Body(callbackContent.Bytes())
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// XML writes xml string to response body.
|
// XML writes xml string to response body.
|
||||||
@ -230,8 +229,7 @@ func (output *BeegoOutput) XML(data interface{}, hasIndent bool) error {
|
|||||||
http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
|
http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
output.Body(content)
|
return output.Body(content)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download forces response for download file.
|
// Download forces response for download file.
|
||||||
|
@ -185,8 +185,7 @@ func (c *Controller) Render() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8")
|
c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8")
|
||||||
c.Ctx.Output.Body(rb)
|
return c.Ctx.Output.Body(rb)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderString returns the rendered template string. Do not send out response.
|
// RenderString returns the rendered template string. Do not send out response.
|
||||||
@ -197,33 +196,9 @@ func (c *Controller) RenderString() (string, error) {
|
|||||||
|
|
||||||
// RenderBytes returns the bytes of rendered template string. Do not send out response.
|
// RenderBytes returns the bytes of rendered template string. Do not send out response.
|
||||||
func (c *Controller) RenderBytes() ([]byte, error) {
|
func (c *Controller) RenderBytes() ([]byte, error) {
|
||||||
//if the controller has set layout, then first get the tplname's content set the content to the layout
|
buf, err := c.renderTemplate()
|
||||||
var buf bytes.Buffer
|
//if the controller has set layout, then first get the tplName's content set the content to the layout
|
||||||
if c.Layout != "" {
|
if err == nil && c.Layout != "" {
|
||||||
if c.TplName == "" {
|
|
||||||
c.TplName = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt
|
|
||||||
}
|
|
||||||
|
|
||||||
if BConfig.RunMode == DEV {
|
|
||||||
buildFiles := []string{c.TplName}
|
|
||||||
if c.LayoutSections != nil {
|
|
||||||
for _, sectionTpl := range c.LayoutSections {
|
|
||||||
if sectionTpl == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
buildFiles = append(buildFiles, sectionTpl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BuildTemplate(BConfig.WebConfig.ViewsPath, buildFiles...)
|
|
||||||
}
|
|
||||||
if _, ok := BeeTemplates[c.TplName]; !ok {
|
|
||||||
panic("can't find templatefile in the path:" + c.TplName)
|
|
||||||
}
|
|
||||||
err := BeeTemplates[c.TplName].ExecuteTemplate(&buf, c.TplName, c.Data)
|
|
||||||
if err != nil {
|
|
||||||
Trace("template Execute err:", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c.Data["LayoutContent"] = template.HTML(buf.String())
|
c.Data["LayoutContent"] = template.HTML(buf.String())
|
||||||
|
|
||||||
if c.LayoutSections != nil {
|
if c.LayoutSections != nil {
|
||||||
@ -232,11 +207,9 @@ func (c *Controller) RenderBytes() ([]byte, error) {
|
|||||||
c.Data[sectionName] = ""
|
c.Data[sectionName] = ""
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
err = BeeTemplates[sectionTpl].ExecuteTemplate(&buf, sectionTpl, c.Data)
|
err = executeTemplate(&buf, sectionTpl, c.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Trace("template Execute err:", err)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.Data[sectionName] = template.HTML(buf.String())
|
c.Data[sectionName] = template.HTML(buf.String())
|
||||||
@ -244,30 +217,29 @@ func (c *Controller) RenderBytes() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
err = BeeTemplates[c.Layout].ExecuteTemplate(&buf, c.Layout, c.Data)
|
executeTemplate(&buf, c.Layout, c.Data)
|
||||||
if err != nil {
|
|
||||||
Trace("template Execute err:", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
}
|
||||||
|
return buf.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) renderTemplate() (bytes.Buffer, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
if c.TplName == "" {
|
if c.TplName == "" {
|
||||||
c.TplName = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt
|
c.TplName = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt
|
||||||
}
|
}
|
||||||
if BConfig.RunMode == DEV {
|
if BConfig.RunMode == DEV {
|
||||||
BuildTemplate(BConfig.WebConfig.ViewsPath, c.TplName)
|
buildFiles := []string{c.TplName}
|
||||||
|
if c.Layout != "" && c.LayoutSections != nil {
|
||||||
|
for _, sectionTpl := range c.LayoutSections {
|
||||||
|
if sectionTpl == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
buildFiles = append(buildFiles, sectionTpl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BuildTemplate(BConfig.WebConfig.ViewsPath, buildFiles...)
|
||||||
}
|
}
|
||||||
if _, ok := BeeTemplates[c.TplName]; !ok {
|
return buf, executeTemplate(&buf, c.TplName, c.Data)
|
||||||
panic("can't find templatefile in the path:" + c.TplName)
|
|
||||||
}
|
|
||||||
buf.Reset()
|
|
||||||
err := BeeTemplates[c.TplName].ExecuteTemplate(&buf, c.TplName, c.Data)
|
|
||||||
if err != nil {
|
|
||||||
Trace("template Execute err:", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect sends the redirection response to url with status code.
|
// Redirect sends the redirection response to url with status code.
|
||||||
|
17
logs/conn.go
17
logs/conn.go
@ -17,7 +17,6 @@ package logs
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -25,7 +24,7 @@ import (
|
|||||||
// connWriter implements LoggerInterface.
|
// connWriter implements LoggerInterface.
|
||||||
// it writes messages in keep-live tcp connection.
|
// it writes messages in keep-live tcp connection.
|
||||||
type connWriter struct {
|
type connWriter struct {
|
||||||
lg *log.Logger
|
lg *logWriter
|
||||||
innerWriter io.WriteCloser
|
innerWriter io.WriteCloser
|
||||||
ReconnectOnMsg bool `json:"reconnectOnMsg"`
|
ReconnectOnMsg bool `json:"reconnectOnMsg"`
|
||||||
Reconnect bool `json:"reconnect"`
|
Reconnect bool `json:"reconnect"`
|
||||||
@ -43,8 +42,8 @@ func NewConn() Logger {
|
|||||||
|
|
||||||
// Init init connection writer with json config.
|
// Init init connection writer with json config.
|
||||||
// json config only need key "level".
|
// json config only need key "level".
|
||||||
func (c *connWriter) Init(jsonconfig string) error {
|
func (c *connWriter) Init(jsonConfig string) error {
|
||||||
return json.Unmarshal([]byte(jsonconfig), c)
|
return json.Unmarshal([]byte(jsonConfig), c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteMsg write message in connection.
|
// WriteMsg write message in connection.
|
||||||
@ -53,7 +52,7 @@ func (c *connWriter) WriteMsg(when time.Time, msg string, level int) error {
|
|||||||
if level > c.Level {
|
if level > c.Level {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if c.neddedConnectOnMsg() {
|
if c.needToConnectOnMsg() {
|
||||||
err := c.connect()
|
err := c.connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -64,9 +63,7 @@ func (c *connWriter) WriteMsg(when time.Time, msg string, level int) error {
|
|||||||
defer c.innerWriter.Close()
|
defer c.innerWriter.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = formatLogTime(when) + msg
|
c.lg.println(when, msg)
|
||||||
|
|
||||||
c.lg.Println(msg)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,11 +95,11 @@ func (c *connWriter) connect() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.innerWriter = conn
|
c.innerWriter = conn
|
||||||
c.lg = log.New(conn, "", 0)
|
c.lg = newLogWriter(conn)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *connWriter) neddedConnectOnMsg() bool {
|
func (c *connWriter) needToConnectOnMsg() bool {
|
||||||
if c.Reconnect {
|
if c.Reconnect {
|
||||||
c.Reconnect = false
|
c.Reconnect = false
|
||||||
return true
|
return true
|
||||||
|
@ -16,7 +16,6 @@ package logs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
@ -47,7 +46,7 @@ var colors = []brush{
|
|||||||
|
|
||||||
// consoleWriter implements LoggerInterface and writes messages to terminal.
|
// consoleWriter implements LoggerInterface and writes messages to terminal.
|
||||||
type consoleWriter struct {
|
type consoleWriter struct {
|
||||||
lg *log.Logger
|
lg *logWriter
|
||||||
Level int `json:"level"`
|
Level int `json:"level"`
|
||||||
Colorful bool `json:"color"` //this filed is useful only when system's terminal supports color
|
Colorful bool `json:"color"` //this filed is useful only when system's terminal supports color
|
||||||
}
|
}
|
||||||
@ -55,7 +54,7 @@ type consoleWriter struct {
|
|||||||
// NewConsole create ConsoleWriter returning as LoggerInterface.
|
// NewConsole create ConsoleWriter returning as LoggerInterface.
|
||||||
func NewConsole() Logger {
|
func NewConsole() Logger {
|
||||||
cw := &consoleWriter{
|
cw := &consoleWriter{
|
||||||
lg: log.New(os.Stdout, "", 0),
|
lg: newLogWriter(os.Stdout),
|
||||||
Level: LevelDebug,
|
Level: LevelDebug,
|
||||||
Colorful: true,
|
Colorful: true,
|
||||||
}
|
}
|
||||||
@ -80,12 +79,10 @@ func (c *consoleWriter) WriteMsg(when time.Time, msg string, level int) error {
|
|||||||
if level > c.Level {
|
if level > c.Level {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
msg = formatLogTime(when) + msg
|
|
||||||
if c.Colorful {
|
if c.Colorful {
|
||||||
c.lg.Println(colors[level](msg))
|
msg = colors[level](msg)
|
||||||
} else {
|
|
||||||
c.lg.Println(msg)
|
|
||||||
}
|
}
|
||||||
|
c.lg.println(when, msg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
33
logs/file.go
33
logs/file.go
@ -53,9 +53,11 @@ type fileLogWriter struct {
|
|||||||
Level int `json:"level"`
|
Level int `json:"level"`
|
||||||
|
|
||||||
Perm os.FileMode `json:"perm"`
|
Perm os.FileMode `json:"perm"`
|
||||||
|
|
||||||
|
fileNameOnly, suffix string // like "project.log", project is fileNameOnly and .log is suffix
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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: "",
|
Filename: "",
|
||||||
@ -89,6 +91,11 @@ func (w *fileLogWriter) Init(jsonConfig string) error {
|
|||||||
if len(w.Filename) == 0 {
|
if len(w.Filename) == 0 {
|
||||||
return errors.New("jsonconfig must have filename")
|
return errors.New("jsonconfig must have filename")
|
||||||
}
|
}
|
||||||
|
w.suffix = filepath.Ext(w.Filename)
|
||||||
|
w.fileNameOnly = strings.TrimSuffix(w.Filename, w.suffix)
|
||||||
|
if w.suffix == "" {
|
||||||
|
w.suffix = ".log"
|
||||||
|
}
|
||||||
err = w.startLogger()
|
err = w.startLogger()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -118,10 +125,9 @@ func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error {
|
|||||||
if level > w.Level {
|
if level > w.Level {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
msg = formatLogTime(when) + msg + "\n"
|
h, d := formatTimeHeader(when)
|
||||||
|
msg = string(h) + msg + "\n"
|
||||||
if w.Rotate {
|
if w.Rotate {
|
||||||
d := when.Day()
|
|
||||||
if w.needRotate(len(msg), d) {
|
if w.needRotate(len(msg), d) {
|
||||||
w.Lock()
|
w.Lock()
|
||||||
if w.needRotate(len(msg), d) {
|
if w.needRotate(len(msg), d) {
|
||||||
@ -196,7 +202,7 @@ func (w *fileLogWriter) lines() (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DoRotate means it need to write file in new file.
|
// DoRotate means it need to write file in new file.
|
||||||
// new file name like xx.2013-01-01.2.log
|
// new file name like xx.2013-01-01.log (daily) or xx.001.log (by line or size)
|
||||||
func (w *fileLogWriter) doRotate(logTime time.Time) error {
|
func (w *fileLogWriter) doRotate(logTime time.Time) error {
|
||||||
_, err := os.Lstat(w.Filename)
|
_, err := os.Lstat(w.Filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -206,13 +212,13 @@ func (w *fileLogWriter) doRotate(logTime time.Time) error {
|
|||||||
// Find the next available number
|
// Find the next available number
|
||||||
num := 1
|
num := 1
|
||||||
fName := ""
|
fName := ""
|
||||||
suffix := filepath.Ext(w.Filename)
|
if w.MaxLines > 0 || w.MaxSize > 0 {
|
||||||
filenameOnly := strings.TrimSuffix(w.Filename, suffix)
|
for ; err == nil && num <= 999; num++ {
|
||||||
if suffix == "" {
|
fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", logTime.Format("2006-01-02"), num, w.suffix)
|
||||||
suffix = ".log"
|
_, err = os.Lstat(fName)
|
||||||
}
|
}
|
||||||
for ; err == nil && num <= 999; num++ {
|
} else {
|
||||||
fName = filenameOnly + fmt.Sprintf(".%s.%03d%s", logTime.Format("2006-01-02"), num, suffix)
|
fName = fmt.Sprintf("%s.%s%s", w.fileNameOnly, logTime.Format("2006-01-02"), w.suffix)
|
||||||
_, err = os.Lstat(fName)
|
_, err = os.Lstat(fName)
|
||||||
}
|
}
|
||||||
// return error if the last file checked still existed
|
// return error if the last file checked still existed
|
||||||
@ -250,7 +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().Unix() < (time.Now().Unix()-60*60*24*w.MaxDays) {
|
||||||
if strings.HasPrefix(filepath.Base(path), filepath.Base(w.Filename)) {
|
if strings.HasPrefix(filepath.Base(path), w.fileNameOnly) &&
|
||||||
|
strings.HasSuffix(filepath.Base(path), w.suffix) {
|
||||||
os.Remove(path)
|
os.Remove(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
42
logs/log.go
42
logs/log.go
@ -412,45 +412,3 @@ func (bl *BeeLogger) flush() {
|
|||||||
l.Flush()
|
l.Flush()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatLogTime(when time.Time) string {
|
|
||||||
y, mo, d := when.Date()
|
|
||||||
h, mi, s := when.Clock()
|
|
||||||
//len(2006/01/02 15:03:04)==19
|
|
||||||
var buf [20]byte
|
|
||||||
t := 3
|
|
||||||
for y >= 10 {
|
|
||||||
p := y / 10
|
|
||||||
buf[t] = byte('0' + y - p*10)
|
|
||||||
y = p
|
|
||||||
t--
|
|
||||||
}
|
|
||||||
buf[0] = byte('0' + y)
|
|
||||||
buf[4] = '/'
|
|
||||||
if mo > 9 {
|
|
||||||
buf[5] = '1'
|
|
||||||
buf[6] = byte('0' + mo - 9)
|
|
||||||
} else {
|
|
||||||
buf[5] = '0'
|
|
||||||
buf[6] = byte('0' + mo)
|
|
||||||
}
|
|
||||||
buf[7] = '/'
|
|
||||||
t = d / 10
|
|
||||||
buf[8] = byte('0' + t)
|
|
||||||
buf[9] = byte('0' + d - t*10)
|
|
||||||
buf[10] = ' '
|
|
||||||
t = h / 10
|
|
||||||
buf[11] = byte('0' + t)
|
|
||||||
buf[12] = byte('0' + h - t*10)
|
|
||||||
buf[13] = ':'
|
|
||||||
t = mi / 10
|
|
||||||
buf[14] = byte('0' + t)
|
|
||||||
buf[15] = byte('0' + mi - t*10)
|
|
||||||
buf[16] = ':'
|
|
||||||
t = s / 10
|
|
||||||
buf[17] = byte('0' + t)
|
|
||||||
buf[18] = byte('0' + s - t*10)
|
|
||||||
buf[19] = ' '
|
|
||||||
|
|
||||||
return string(buf[0:])
|
|
||||||
}
|
|
||||||
|
80
logs/logger.go
Normal file
80
logs/logger.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// Copyright 2014 beego Author. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
package logs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type logWriter struct {
|
||||||
|
sync.Mutex
|
||||||
|
writer io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLogWriter(wr io.Writer) *logWriter {
|
||||||
|
return &logWriter{writer: wr}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lg *logWriter) println(when time.Time, msg string) {
|
||||||
|
lg.Lock()
|
||||||
|
h, _ := formatTimeHeader(when)
|
||||||
|
lg.writer.Write(append(append(h, msg...), '\n'))
|
||||||
|
lg.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatTimeHeader(when time.Time) ([]byte, int) {
|
||||||
|
y, mo, d := when.Date()
|
||||||
|
h, mi, s := when.Clock()
|
||||||
|
//len(2006/01/02 15:03:04)==19
|
||||||
|
var buf [20]byte
|
||||||
|
t := 3
|
||||||
|
for y >= 10 {
|
||||||
|
p := y / 10
|
||||||
|
buf[t] = byte('0' + y - p*10)
|
||||||
|
y = p
|
||||||
|
t--
|
||||||
|
}
|
||||||
|
buf[0] = byte('0' + y)
|
||||||
|
buf[4] = '/'
|
||||||
|
if mo > 9 {
|
||||||
|
buf[5] = '1'
|
||||||
|
buf[6] = byte('0' + mo - 9)
|
||||||
|
} else {
|
||||||
|
buf[5] = '0'
|
||||||
|
buf[6] = byte('0' + mo)
|
||||||
|
}
|
||||||
|
buf[7] = '/'
|
||||||
|
t = d / 10
|
||||||
|
buf[8] = byte('0' + t)
|
||||||
|
buf[9] = byte('0' + d - t*10)
|
||||||
|
buf[10] = ' '
|
||||||
|
t = h / 10
|
||||||
|
buf[11] = byte('0' + t)
|
||||||
|
buf[12] = byte('0' + h - t*10)
|
||||||
|
buf[13] = ':'
|
||||||
|
t = mi / 10
|
||||||
|
buf[14] = byte('0' + t)
|
||||||
|
buf[15] = byte('0' + mi - t*10)
|
||||||
|
buf[16] = ':'
|
||||||
|
t = s / 10
|
||||||
|
buf[17] = byte('0' + t)
|
||||||
|
buf[18] = byte('0' + s - t*10)
|
||||||
|
buf[19] = ' '
|
||||||
|
|
||||||
|
return buf[0:], d
|
||||||
|
}
|
116
logs/mulitfile.go
Normal file
116
logs/mulitfile.go
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
// Copyright 2014 beego Author. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package logs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A filesLogWriter manages several fileLogWriter
|
||||||
|
// filesLogWriter will write logs to the file in json configuration and write the same level log to correspond file
|
||||||
|
// means if the file name in configuration is project.log filesLogWriter will create project.error.log/project.debug.log
|
||||||
|
// and write the error-level logs to project.error.log and write the debug-level logs to project.debug.log
|
||||||
|
// the rotate attribute also acts like fileLogWriter
|
||||||
|
type mulitFileLogWriter struct {
|
||||||
|
writers [LevelDebug + 1 + 1]*fileLogWriter // the last one for fullLogWriter
|
||||||
|
fullLogWriter *fileLogWriter
|
||||||
|
Separate []string `json:"separate"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var levelNames = [...]string{"emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"}
|
||||||
|
|
||||||
|
// Init file logger with json config.
|
||||||
|
// jsonConfig like:
|
||||||
|
// {
|
||||||
|
// "filename":"logs/beego.log",
|
||||||
|
// "maxLines":0,
|
||||||
|
// "maxsize":0,
|
||||||
|
// "daily":true,
|
||||||
|
// "maxDays":15,
|
||||||
|
// "rotate":true,
|
||||||
|
// "perm":0600,
|
||||||
|
// "separate":["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"],
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (f *mulitFileLogWriter) Init(config string) error {
|
||||||
|
writer := newFileWriter().(*fileLogWriter)
|
||||||
|
err := writer.Init(config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.fullLogWriter = writer
|
||||||
|
f.writers[LevelDebug+1] = writer
|
||||||
|
|
||||||
|
//unmarshal "separate" field to f.Separate
|
||||||
|
json.Unmarshal([]byte(config), f)
|
||||||
|
|
||||||
|
jsonMap := map[string]interface{}{}
|
||||||
|
json.Unmarshal([]byte(config), &jsonMap)
|
||||||
|
|
||||||
|
for i := LevelEmergency; i < LevelDebug+1; i++ {
|
||||||
|
for _, v := range f.Separate {
|
||||||
|
if v == levelNames[i] {
|
||||||
|
jsonMap["filename"] = f.fullLogWriter.fileNameOnly + "." + levelNames[i] + f.fullLogWriter.suffix
|
||||||
|
jsonMap["level"] = i
|
||||||
|
bs, _ := json.Marshal(jsonMap)
|
||||||
|
writer = newFileWriter().(*fileLogWriter)
|
||||||
|
writer.Init(string(bs))
|
||||||
|
f.writers[i] = writer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *mulitFileLogWriter) Destroy() {
|
||||||
|
for i := 0; i < len(f.writers); i++ {
|
||||||
|
if f.writers[i] != nil {
|
||||||
|
f.writers[i].Destroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *mulitFileLogWriter) WriteMsg(when time.Time, msg string, level int) error {
|
||||||
|
if f.fullLogWriter != nil {
|
||||||
|
f.fullLogWriter.WriteMsg(when, msg, level)
|
||||||
|
}
|
||||||
|
for i := 0; i < len(f.writers)-1; i++ {
|
||||||
|
if f.writers[i] != nil {
|
||||||
|
if level == f.writers[i].Level {
|
||||||
|
f.writers[i].WriteMsg(when, msg, level)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *mulitFileLogWriter) Flush() {
|
||||||
|
for i := 0; i < len(f.writers); i++ {
|
||||||
|
if f.writers[i] != nil {
|
||||||
|
f.writers[i].Flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// newFilesWriter create a FileLogWriter returning as LoggerInterface.
|
||||||
|
func newFilesWriter() Logger {
|
||||||
|
return &mulitFileLogWriter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Register("mulitfile", newFilesWriter)
|
||||||
|
}
|
78
logs/mulitfile_test.go
Normal file
78
logs/mulitfile_test.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// Copyright 2014 beego Author. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package logs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFiles_1(t *testing.T) {
|
||||||
|
log := NewLogger(10000)
|
||||||
|
log.SetLogger("mulitfile", `{"filename":"test.log","separate":["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"]}`)
|
||||||
|
log.Debug("debug")
|
||||||
|
log.Informational("info")
|
||||||
|
log.Notice("notice")
|
||||||
|
log.Warning("warning")
|
||||||
|
log.Error("error")
|
||||||
|
log.Alert("alert")
|
||||||
|
log.Critical("critical")
|
||||||
|
log.Emergency("emergency")
|
||||||
|
fns := []string{""}
|
||||||
|
fns = append(fns, levelNames[0:]...)
|
||||||
|
name := "test"
|
||||||
|
suffix := ".log"
|
||||||
|
for _, fn := range fns {
|
||||||
|
|
||||||
|
file := name + suffix
|
||||||
|
if fn != "" {
|
||||||
|
file = name + "." + fn + suffix
|
||||||
|
}
|
||||||
|
f, err := os.Open(file)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
b := bufio.NewReader(f)
|
||||||
|
lineNum := 0
|
||||||
|
lastLine := ""
|
||||||
|
for {
|
||||||
|
line, _, err := b.ReadLine()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if len(line) > 0 {
|
||||||
|
lastLine = string(line)
|
||||||
|
lineNum++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var expected = 1
|
||||||
|
if fn == "" {
|
||||||
|
expected = LevelDebug + 1
|
||||||
|
}
|
||||||
|
if lineNum != expected {
|
||||||
|
t.Fatal(file, "has", lineNum, "lines not "+strconv.Itoa(expected)+" lines")
|
||||||
|
}
|
||||||
|
if lineNum == 1 {
|
||||||
|
if !strings.Contains(lastLine, fn) {
|
||||||
|
t.Fatal(file + " " + lastLine + " not contains the log msg " + fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os.Remove(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -65,6 +65,11 @@ func (tc *TestController) GetManyRouter() {
|
|||||||
tc.Ctx.WriteString(tc.Ctx.Input.Query(":id") + tc.Ctx.Input.Query(":page"))
|
tc.Ctx.WriteString(tc.Ctx.Input.Query(":id") + tc.Ctx.Input.Query(":page"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tc *TestController) GetEmptyBody() {
|
||||||
|
var res []byte
|
||||||
|
tc.Ctx.Output.Body(res)
|
||||||
|
}
|
||||||
|
|
||||||
type ResStatus struct {
|
type ResStatus struct {
|
||||||
Code int
|
Code int
|
||||||
Msg string
|
Msg string
|
||||||
@ -239,6 +244,21 @@ func TestManyRoute(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test for issue #1669
|
||||||
|
func TestEmptyResponse(t *testing.T) {
|
||||||
|
|
||||||
|
r, _ := http.NewRequest("GET", "/beego-empty.html", nil)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
handler := NewControllerRegister()
|
||||||
|
handler.Add("/beego-empty.html", &TestController{}, "get:GetEmptyBody")
|
||||||
|
handler.ServeHTTP(w, r)
|
||||||
|
|
||||||
|
if body := w.Body.String(); body != "" {
|
||||||
|
t.Error("want empty body")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNotFound(t *testing.T) {
|
func TestNotFound(t *testing.T) {
|
||||||
r, _ := http.NewRequest("GET", "/", nil)
|
r, _ := http.NewRequest("GET", "/", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
@ -102,7 +102,7 @@ func (pder *MemProvider) SessionRead(sid string) (Store, error) {
|
|||||||
pder.lock.RUnlock()
|
pder.lock.RUnlock()
|
||||||
pder.lock.Lock()
|
pder.lock.Lock()
|
||||||
newsess := &MemSessionStore{sid: sid, timeAccessed: time.Now(), value: make(map[interface{}]interface{})}
|
newsess := &MemSessionStore{sid: sid, timeAccessed: time.Now(), value: make(map[interface{}]interface{})}
|
||||||
element := pder.list.PushBack(newsess)
|
element := pder.list.PushFront(newsess)
|
||||||
pder.sessions[sid] = element
|
pder.sessions[sid] = element
|
||||||
pder.lock.Unlock()
|
pder.lock.Unlock()
|
||||||
return newsess, nil
|
return newsess, nil
|
||||||
@ -134,7 +134,7 @@ func (pder *MemProvider) SessionRegenerate(oldsid, sid string) (Store, error) {
|
|||||||
pder.lock.RUnlock()
|
pder.lock.RUnlock()
|
||||||
pder.lock.Lock()
|
pder.lock.Lock()
|
||||||
newsess := &MemSessionStore{sid: sid, timeAccessed: time.Now(), value: make(map[interface{}]interface{})}
|
newsess := &MemSessionStore{sid: sid, timeAccessed: time.Now(), value: make(map[interface{}]interface{})}
|
||||||
element := pder.list.PushBack(newsess)
|
element := pder.list.PushFront(newsess)
|
||||||
pder.sessions[sid] = element
|
pder.sessions[sid] = element
|
||||||
pder.lock.Unlock()
|
pder.lock.Unlock()
|
||||||
return newsess, nil
|
return newsess, nil
|
||||||
|
@ -201,7 +201,9 @@ func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err != nil || cookie.Value == "" {
|
if err != nil || cookie.Value == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
manager.provider.SessionDestroy(cookie.Value)
|
|
||||||
|
sid, _ := url.QueryUnescape(cookie.Value)
|
||||||
|
manager.provider.SessionDestroy(sid)
|
||||||
if manager.config.EnableSetCookie {
|
if manager.config.EnableSetCookie {
|
||||||
expiration := time.Now()
|
expiration := time.Now()
|
||||||
cookie = &http.Cookie{Name: manager.config.CookieName,
|
cookie = &http.Cookie{Name: manager.config.CookieName,
|
||||||
|
@ -93,12 +93,14 @@ type serveContentHolder struct {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
staticFileMap = make(map[string]*serveContentHolder)
|
staticFileMap = make(map[string]*serveContentHolder)
|
||||||
mapLock sync.Mutex
|
mapLock sync.RWMutex
|
||||||
)
|
)
|
||||||
|
|
||||||
func openFile(filePath string, fi os.FileInfo, acceptEncoding string) (bool, string, *serveContentHolder, error) {
|
func openFile(filePath string, fi os.FileInfo, acceptEncoding string) (bool, string, *serveContentHolder, error) {
|
||||||
mapKey := acceptEncoding + ":" + filePath
|
mapKey := acceptEncoding + ":" + filePath
|
||||||
|
mapLock.RLock()
|
||||||
mapFile, _ := staticFileMap[mapKey]
|
mapFile, _ := staticFileMap[mapKey]
|
||||||
|
mapLock.RUnlock()
|
||||||
if isOk(mapFile, fi) {
|
if isOk(mapFile, fi) {
|
||||||
return mapFile.encoding != "", mapFile.encoding, mapFile, nil
|
return mapFile.encoding != "", mapFile.encoding, mapFile, nil
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var currentWorkDir, _ = os.Getwd()
|
var currentWorkDir, _ = os.Getwd()
|
||||||
|
35
template.go
35
template.go
@ -18,6 +18,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -30,13 +31,28 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
beegoTplFuncMap = make(template.FuncMap)
|
beegoTplFuncMap = make(template.FuncMap)
|
||||||
// BeeTemplates caching map and supported template file extensions.
|
// beeTemplates caching map and supported template file extensions.
|
||||||
BeeTemplates = make(map[string]*template.Template)
|
beeTemplates = make(map[string]*template.Template)
|
||||||
templatesLock sync.Mutex
|
templatesLock sync.RWMutex
|
||||||
// BeeTemplateExt stores the template extension which will build
|
// beeTemplateExt stores the template extension which will build
|
||||||
BeeTemplateExt = []string{"tpl", "html"}
|
beeTemplateExt = []string{"tpl", "html"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func executeTemplate(wr io.Writer, name string, data interface{}) error {
|
||||||
|
if BConfig.RunMode == DEV {
|
||||||
|
templatesLock.RLock()
|
||||||
|
defer templatesLock.RUnlock()
|
||||||
|
}
|
||||||
|
if t, ok := beeTemplates[name]; ok {
|
||||||
|
err := t.ExecuteTemplate(wr, name, data)
|
||||||
|
if err != nil {
|
||||||
|
Trace("template Execute err:", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
panic("can't find templatefile in the path:" + name)
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
beegoTplFuncMap["dateformat"] = DateFormat
|
beegoTplFuncMap["dateformat"] = DateFormat
|
||||||
beegoTplFuncMap["date"] = Date
|
beegoTplFuncMap["date"] = Date
|
||||||
@ -55,7 +71,6 @@ func init() {
|
|||||||
beegoTplFuncMap["config"] = GetConfig
|
beegoTplFuncMap["config"] = GetConfig
|
||||||
beegoTplFuncMap["map_get"] = MapGet
|
beegoTplFuncMap["map_get"] = MapGet
|
||||||
|
|
||||||
// go1.2 added template funcs
|
|
||||||
// Comparisons
|
// Comparisons
|
||||||
beegoTplFuncMap["eq"] = eq // ==
|
beegoTplFuncMap["eq"] = eq // ==
|
||||||
beegoTplFuncMap["ge"] = ge // >=
|
beegoTplFuncMap["ge"] = ge // >=
|
||||||
@ -103,7 +118,7 @@ func (tf *templateFile) visit(paths string, f os.FileInfo, err error) error {
|
|||||||
|
|
||||||
// HasTemplateExt return this path contains supported template extension of beego or not.
|
// HasTemplateExt return this path contains supported template extension of beego or not.
|
||||||
func HasTemplateExt(paths string) bool {
|
func HasTemplateExt(paths string) bool {
|
||||||
for _, v := range BeeTemplateExt {
|
for _, v := range beeTemplateExt {
|
||||||
if strings.HasSuffix(paths, "."+v) {
|
if strings.HasSuffix(paths, "."+v) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -113,12 +128,12 @@ func HasTemplateExt(paths string) bool {
|
|||||||
|
|
||||||
// AddTemplateExt add new extension for template.
|
// AddTemplateExt add new extension for template.
|
||||||
func AddTemplateExt(ext string) {
|
func AddTemplateExt(ext string) {
|
||||||
for _, v := range BeeTemplateExt {
|
for _, v := range beeTemplateExt {
|
||||||
if v == ext {
|
if v == ext {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BeeTemplateExt = append(BeeTemplateExt, ext)
|
beeTemplateExt = append(beeTemplateExt, ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildTemplate will build all template files in a directory.
|
// BuildTemplate will build all template files in a directory.
|
||||||
@ -149,7 +164,7 @@ func BuildTemplate(dir string, files ...string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
Trace("parse template err:", file, err)
|
Trace("parse template err:", file, err)
|
||||||
} else {
|
} else {
|
||||||
BeeTemplates[file] = t
|
beeTemplates[file] = t
|
||||||
}
|
}
|
||||||
templatesLock.Unlock()
|
templatesLock.Unlock()
|
||||||
}
|
}
|
||||||
|
@ -70,10 +70,10 @@ func TestTemplate(t *testing.T) {
|
|||||||
if err := BuildTemplate(dir); err != nil {
|
if err := BuildTemplate(dir); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if len(BeeTemplates) != 3 {
|
if len(beeTemplates) != 3 {
|
||||||
t.Fatalf("should be 3 but got %v", len(BeeTemplates))
|
t.Fatalf("should be 3 but got %v", len(beeTemplates))
|
||||||
}
|
}
|
||||||
if err := BeeTemplates["index.tpl"].ExecuteTemplate(os.Stdout, "index.tpl", nil); err != nil {
|
if err := beeTemplates["index.tpl"].ExecuteTemplate(os.Stdout, "index.tpl", nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
for _, name := range files {
|
for _, name := range files {
|
||||||
@ -126,7 +126,7 @@ func TestRelativeTemplate(t *testing.T) {
|
|||||||
if err := BuildTemplate(dir, files[1]); err != nil {
|
if err := BuildTemplate(dir, files[1]); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := BeeTemplates["easyui/rbac/user.tpl"].ExecuteTemplate(os.Stdout, "easyui/rbac/user.tpl", nil); err != nil {
|
if err := beeTemplates["easyui/rbac/user.tpl"].ExecuteTemplate(os.Stdout, "easyui/rbac/user.tpl", nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
for _, name := range files {
|
for _, name := range files {
|
||||||
|
@ -588,7 +588,7 @@ func (b Base64) GetLimitValue() interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// just for chinese mobile phone number
|
// just for chinese mobile phone number
|
||||||
var mobilePattern = regexp.MustCompile("^((\\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][0679]|[4][579]))\\d{8}$")
|
var mobilePattern = regexp.MustCompile("^((\\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][06789]|[4][579]))\\d{8}$")
|
||||||
|
|
||||||
// Mobile check struct
|
// Mobile check struct
|
||||||
type Mobile struct {
|
type Mobile struct {
|
||||||
|
Loading…
Reference in New Issue
Block a user