mirror of
https://github.com/astaxie/beego.git
synced 2024-11-22 19:00:54 +00:00
Merge branch 'develop' of https://github.com/astaxie/beego into develop
This commit is contained in:
commit
b235b48de4
25
cache/file.go
vendored
25
cache/file.go
vendored
@ -22,6 +22,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -222,33 +223,13 @@ func exists(path string) (bool, error) {
|
|||||||
// FileGetContents Get bytes to file.
|
// FileGetContents Get bytes to file.
|
||||||
// if non-exist, create this file.
|
// if non-exist, create this file.
|
||||||
func FileGetContents(filename string) (data []byte, e error) {
|
func FileGetContents(filename string) (data []byte, e error) {
|
||||||
f, e := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm)
|
return ioutil.ReadFile(filename)
|
||||||
if e != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
stat, e := f.Stat()
|
|
||||||
if e != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data = make([]byte, stat.Size())
|
|
||||||
result, e := f.Read(data)
|
|
||||||
if e != nil || int64(result) != stat.Size() {
|
|
||||||
return nil, e
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilePutContents Put bytes to file.
|
// FilePutContents Put bytes to file.
|
||||||
// if non-exist, create this file.
|
// if non-exist, create this file.
|
||||||
func FilePutContents(filename string, content []byte) error {
|
func FilePutContents(filename string, content []byte) error {
|
||||||
fp, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm)
|
return ioutil.WriteFile(filename, content, os.ModePerm)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer fp.Close()
|
|
||||||
_, err = fp.Write(content)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GobEncode Gob encodes file cache item.
|
// GobEncode Gob encodes file cache item.
|
||||||
|
@ -41,6 +41,7 @@ type Config struct {
|
|||||||
EnableGzip bool
|
EnableGzip bool
|
||||||
MaxMemory int64
|
MaxMemory int64
|
||||||
EnableErrorsShow bool
|
EnableErrorsShow bool
|
||||||
|
EnableErrorsRender bool
|
||||||
Listen Listen
|
Listen Listen
|
||||||
WebConfig WebConfig
|
WebConfig WebConfig
|
||||||
Log LogConfig
|
Log LogConfig
|
||||||
@ -171,7 +172,7 @@ func recoverPanic(ctx *context.Context) {
|
|||||||
logs.Critical(fmt.Sprintf("%s:%d", file, line))
|
logs.Critical(fmt.Sprintf("%s:%d", file, line))
|
||||||
stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
|
stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
|
||||||
}
|
}
|
||||||
if BConfig.RunMode == DEV {
|
if BConfig.RunMode == DEV && BConfig.EnableErrorsRender {
|
||||||
showErr(err, ctx, stack)
|
showErr(err, ctx, stack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,6 +190,7 @@ func newBConfig() *Config {
|
|||||||
EnableGzip: false,
|
EnableGzip: false,
|
||||||
MaxMemory: 1 << 26, //64MB
|
MaxMemory: 1 << 26, //64MB
|
||||||
EnableErrorsShow: true,
|
EnableErrorsShow: true,
|
||||||
|
EnableErrorsRender: true,
|
||||||
Listen: Listen{
|
Listen: Listen{
|
||||||
Graceful: false,
|
Graceful: false,
|
||||||
ServerTimeOut: 0,
|
ServerTimeOut: 0,
|
||||||
|
85
config/env/env.go
vendored
Normal file
85
config/env/env.go
vendored
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// Copyright 2014 beego Author. All Rights Reserved.
|
||||||
|
// Copyright 2017 Faissal Elamraoui. 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 env
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/astaxie/beego/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
var env *utils.BeeMap
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
env = utils.NewBeeMap()
|
||||||
|
for _, e := range os.Environ() {
|
||||||
|
splits := strings.Split(e, "=")
|
||||||
|
env.Set(splits[0], os.Getenv(splits[0]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a value by key.
|
||||||
|
// If the key does not exist, the default value will be returned.
|
||||||
|
func Get(key string, defVal string) string {
|
||||||
|
if val := env.Get(key); val != nil {
|
||||||
|
return val.(string)
|
||||||
|
}
|
||||||
|
return defVal
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustGet returns a value by key.
|
||||||
|
// If the key does not exist, it will return an error.
|
||||||
|
func MustGet(key string) (string, error) {
|
||||||
|
if val := env.Get(key); val != nil {
|
||||||
|
return val.(string), nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("no env variable with %s", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets a value in the ENV copy.
|
||||||
|
// This does not affect the child process environment.
|
||||||
|
func Set(key string, value string) {
|
||||||
|
env.Set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustSet sets a value in the ENV copy and the child process environment.
|
||||||
|
// It returns an error in case the set operation failed.
|
||||||
|
func MustSet(key string, value string) error {
|
||||||
|
err := os.Setenv(key, value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
env.Set(key, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAll returns all keys/values in the current child process environment.
|
||||||
|
func GetAll() map[string]string {
|
||||||
|
items := env.Items()
|
||||||
|
envs := make(map[string]string, env.Count())
|
||||||
|
|
||||||
|
for key, val := range items {
|
||||||
|
switch key := key.(type) {
|
||||||
|
case string:
|
||||||
|
switch val := val.(type) {
|
||||||
|
case string:
|
||||||
|
envs[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return envs
|
||||||
|
}
|
75
config/env/env_test.go
vendored
Normal file
75
config/env/env_test.go
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// Copyright 2014 beego Author. All Rights Reserved.
|
||||||
|
// Copyright 2017 Faissal Elamraoui. 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 env
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEnvGet(t *testing.T) {
|
||||||
|
gopath := Get("GOPATH", "")
|
||||||
|
if gopath != os.Getenv("GOPATH") {
|
||||||
|
t.Error("expected GOPATH not empty.")
|
||||||
|
}
|
||||||
|
|
||||||
|
noExistVar := Get("NOEXISTVAR", "foo")
|
||||||
|
if noExistVar != "foo" {
|
||||||
|
t.Errorf("expected NOEXISTVAR to equal foo, got %s.", noExistVar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnvMustGet(t *testing.T) {
|
||||||
|
gopath, err := MustGet("GOPATH")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if gopath != os.Getenv("GOPATH") {
|
||||||
|
t.Errorf("expected GOPATH to be the same, got %s.", gopath)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = MustGet("NOEXISTVAR")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error to be non-nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnvSet(t *testing.T) {
|
||||||
|
Set("MYVAR", "foo")
|
||||||
|
myVar := Get("MYVAR", "bar")
|
||||||
|
if myVar != "foo" {
|
||||||
|
t.Errorf("expected MYVAR to equal foo, got %s.", myVar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnvMustSet(t *testing.T) {
|
||||||
|
err := MustSet("FOO", "bar")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fooVar := os.Getenv("FOO")
|
||||||
|
if fooVar != "bar" {
|
||||||
|
t.Errorf("expected FOO variable to equal bar, got %s.", fooVar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnvGetAll(t *testing.T) {
|
||||||
|
envMap := GetAll()
|
||||||
|
if len(envMap) == 0 {
|
||||||
|
t.Error("expected environment not empty.")
|
||||||
|
}
|
||||||
|
}
|
@ -18,16 +18,13 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -52,24 +49,26 @@ func (ini *IniConfig) Parse(name string) (Configer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) {
|
func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) {
|
||||||
file, err := os.Open(name)
|
data, err := ioutil.ReadFile(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ini.parseData(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ini *IniConfig) parseData(data []byte) (*IniConfigContainer, error) {
|
||||||
cfg := &IniConfigContainer{
|
cfg := &IniConfigContainer{
|
||||||
file.Name(),
|
data: make(map[string]map[string]string),
|
||||||
make(map[string]map[string]string),
|
sectionComment: make(map[string]string),
|
||||||
make(map[string]string),
|
keyComment: make(map[string]string),
|
||||||
make(map[string]string),
|
RWMutex: sync.RWMutex{},
|
||||||
sync.RWMutex{},
|
|
||||||
}
|
}
|
||||||
cfg.Lock()
|
cfg.Lock()
|
||||||
defer cfg.Unlock()
|
defer cfg.Unlock()
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
var comment bytes.Buffer
|
var comment bytes.Buffer
|
||||||
buf := bufio.NewReader(file)
|
buf := bufio.NewReader(bytes.NewBuffer(data))
|
||||||
// check the BOM
|
// check the BOM
|
||||||
head, err := buf.Peek(3)
|
head, err := buf.Peek(3)
|
||||||
if err == nil && head[0] == 239 && head[1] == 187 && head[2] == 191 {
|
if err == nil && head[0] == 239 && head[1] == 187 && head[2] == 191 {
|
||||||
@ -130,16 +129,24 @@ func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) {
|
|||||||
|
|
||||||
// handle include "other.conf"
|
// handle include "other.conf"
|
||||||
if len(keyValue) == 1 && strings.HasPrefix(key, "include") {
|
if len(keyValue) == 1 && strings.HasPrefix(key, "include") {
|
||||||
|
|
||||||
includefiles := strings.Fields(key)
|
includefiles := strings.Fields(key)
|
||||||
if includefiles[0] == "include" && len(includefiles) == 2 {
|
if includefiles[0] == "include" && len(includefiles) == 2 {
|
||||||
|
|
||||||
otherfile := strings.Trim(includefiles[1], "\"")
|
otherfile := strings.Trim(includefiles[1], "\"")
|
||||||
if !filepath.IsAbs(otherfile) {
|
if !filepath.IsAbs(otherfile) {
|
||||||
otherfile = filepath.Join(filepath.Dir(name), otherfile)
|
dir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
otherfile = filepath.Join(dir, otherfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
i, err := ini.parseFile(otherfile)
|
i, err := ini.parseFile(otherfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for sec, dt := range i.data {
|
for sec, dt := range i.data {
|
||||||
if _, ok := cfg.data[sec]; !ok {
|
if _, ok := cfg.data[sec]; !ok {
|
||||||
cfg.data[sec] = make(map[string]string)
|
cfg.data[sec] = make(map[string]string)
|
||||||
@ -148,12 +155,15 @@ func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) {
|
|||||||
cfg.data[sec][k] = v
|
cfg.data[sec][k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for sec, comm := range i.sectionComment {
|
for sec, comm := range i.sectionComment {
|
||||||
cfg.sectionComment[sec] = comm
|
cfg.sectionComment[sec] = comm
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, comm := range i.keyComment {
|
for k, comm := range i.keyComment {
|
||||||
cfg.keyComment[k] = comm
|
cfg.keyComment[k] = comm
|
||||||
}
|
}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,19 +188,12 @@ func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) {
|
|||||||
|
|
||||||
// ParseData parse ini the data
|
// ParseData parse ini the data
|
||||||
func (ini *IniConfig) ParseData(data []byte) (Configer, error) {
|
func (ini *IniConfig) ParseData(data []byte) (Configer, error) {
|
||||||
// Save memory data to temporary file
|
return ini.parseData(data)
|
||||||
tmpName := path.Join(os.TempDir(), "beego", fmt.Sprintf("%d", time.Now().Nanosecond()))
|
|
||||||
os.MkdirAll(path.Dir(tmpName), os.ModePerm)
|
|
||||||
if err := ioutil.WriteFile(tmpName, data, 0655); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ini.Parse(tmpName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IniConfigContainer A Config represents the ini configuration.
|
// IniConfigContainer A Config represents the ini configuration.
|
||||||
// When set and get value, support key as section:name type.
|
// When set and get value, support key as section:name type.
|
||||||
type IniConfigContainer struct {
|
type IniConfigContainer struct {
|
||||||
filename string
|
|
||||||
data map[string]map[string]string // section=> key:val
|
data map[string]map[string]string // section=> key:val
|
||||||
sectionComment map[string]string // section : comment
|
sectionComment map[string]string // section : comment
|
||||||
keyComment map[string]string // id: []{comment, key...}; id 1 is for main comment.
|
keyComment map[string]string // id: []{comment, key...}; id 1 is for main comment.
|
||||||
|
@ -35,11 +35,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/astaxie/beego/config"
|
"github.com/astaxie/beego/config"
|
||||||
"github.com/beego/x2j"
|
"github.com/beego/x2j"
|
||||||
@ -52,36 +50,26 @@ type Config struct{}
|
|||||||
|
|
||||||
// Parse returns a ConfigContainer with parsed xml config map.
|
// Parse returns a ConfigContainer with parsed xml config map.
|
||||||
func (xc *Config) Parse(filename string) (config.Configer, error) {
|
func (xc *Config) Parse(filename string) (config.Configer, error) {
|
||||||
file, err := os.Open(filename)
|
context, err := ioutil.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
|
return xc.ParseData(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseData xml data
|
||||||
|
func (xc *Config) ParseData(data []byte) (config.Configer, error) {
|
||||||
x := &ConfigContainer{data: make(map[string]interface{})}
|
x := &ConfigContainer{data: make(map[string]interface{})}
|
||||||
content, err := ioutil.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
d, err := x2j.DocToMap(string(content))
|
d, err := x2j.DocToMap(string(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
x.data = config.ExpandValueEnvForMap(d["config"].(map[string]interface{}))
|
x.data = config.ExpandValueEnvForMap(d["config"].(map[string]interface{}))
|
||||||
return x, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseData xml data
|
return x, nil
|
||||||
func (xc *Config) ParseData(data []byte) (config.Configer, error) {
|
|
||||||
// Save memory data to temporary file
|
|
||||||
tmpName := path.Join(os.TempDir(), "beego", fmt.Sprintf("%d", time.Now().Nanosecond()))
|
|
||||||
os.MkdirAll(path.Dir(tmpName), os.ModePerm)
|
|
||||||
if err := ioutil.WriteFile(tmpName, data, 0655); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return xc.Parse(tmpName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigContainer A Config represents the xml configuration.
|
// ConfigContainer A Config represents the xml configuration.
|
||||||
|
@ -37,10 +37,8 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/astaxie/beego/config"
|
"github.com/astaxie/beego/config"
|
||||||
"github.com/beego/goyaml2"
|
"github.com/beego/goyaml2"
|
||||||
@ -63,26 +61,30 @@ func (yaml *Config) Parse(filename string) (y config.Configer, err error) {
|
|||||||
|
|
||||||
// ParseData parse yaml data
|
// ParseData parse yaml data
|
||||||
func (yaml *Config) ParseData(data []byte) (config.Configer, error) {
|
func (yaml *Config) ParseData(data []byte) (config.Configer, error) {
|
||||||
// Save memory data to temporary file
|
cnf, err := parseYML(data)
|
||||||
tmpName := path.Join(os.TempDir(), "beego", fmt.Sprintf("%d", time.Now().Nanosecond()))
|
if err != nil {
|
||||||
os.MkdirAll(path.Dir(tmpName), os.ModePerm)
|
|
||||||
if err := ioutil.WriteFile(tmpName, data, 0655); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return yaml.Parse(tmpName)
|
|
||||||
|
return &ConfigContainer{
|
||||||
|
data: cnf,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadYmlReader Read yaml file to map.
|
// ReadYmlReader Read yaml file to map.
|
||||||
// if json like, use json package, unless goyaml2 package.
|
// if json like, use json package, unless goyaml2 package.
|
||||||
func ReadYmlReader(path string) (cnf map[string]interface{}, err error) {
|
func ReadYmlReader(path string) (cnf map[string]interface{}, err error) {
|
||||||
f, err := os.Open(path)
|
buf, err := ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
buf, err := ioutil.ReadAll(f)
|
return parseYML(buf)
|
||||||
if err != nil || len(buf) < 3 {
|
}
|
||||||
|
|
||||||
|
// parseYML parse yaml formatted []byte to map.
|
||||||
|
func parseYML(buf []byte) (cnf map[string]interface{}, err error) {
|
||||||
|
if len(buf) < 3 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,16 +331,17 @@ func (output *BeegoOutput) IsServerError() bool {
|
|||||||
|
|
||||||
func stringsToJSON(str string) string {
|
func stringsToJSON(str string) string {
|
||||||
rs := []rune(str)
|
rs := []rune(str)
|
||||||
jsons := ""
|
var jsons bytes.Buffer
|
||||||
for _, r := range rs {
|
for _, r := range rs {
|
||||||
rint := int(r)
|
rint := int(r)
|
||||||
if rint < 128 {
|
if rint < 128 {
|
||||||
jsons += string(r)
|
jsons.WriteRune(r)
|
||||||
} else {
|
} else {
|
||||||
jsons += "\\u" + strconv.FormatInt(int64(rint), 16) // json
|
jsons.WriteString("\\u")
|
||||||
|
jsons.WriteString(strconv.FormatInt(int64(rint), 16))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return jsons
|
return jsons.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Session sets session item value with given key.
|
// Session sets session item value with given key.
|
||||||
|
@ -69,6 +69,7 @@ type Controller struct {
|
|||||||
|
|
||||||
// template data
|
// template data
|
||||||
TplName string
|
TplName string
|
||||||
|
ViewPath string
|
||||||
Layout string
|
Layout string
|
||||||
LayoutSections map[string]string // the key is the section name and the value is the template name
|
LayoutSections map[string]string // the key is the section name and the value is the template name
|
||||||
TplPrefix string
|
TplPrefix string
|
||||||
@ -213,7 +214,7 @@ func (c *Controller) RenderBytes() ([]byte, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
err = ExecuteTemplate(&buf, sectionTpl, c.Data)
|
err = ExecuteViewPathTemplate(&buf, sectionTpl, c.viewPath(), c.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -222,7 +223,7 @@ func (c *Controller) RenderBytes() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
ExecuteTemplate(&buf, c.Layout, c.Data)
|
ExecuteViewPathTemplate(&buf, c.Layout, c.viewPath() ,c.Data)
|
||||||
}
|
}
|
||||||
return buf.Bytes(), err
|
return buf.Bytes(), err
|
||||||
}
|
}
|
||||||
@ -248,9 +249,16 @@ func (c *Controller) renderTemplate() (bytes.Buffer, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BuildTemplate(BConfig.WebConfig.ViewsPath, buildFiles...)
|
BuildTemplate(c.viewPath() , buildFiles...)
|
||||||
}
|
}
|
||||||
return buf, ExecuteTemplate(&buf, c.TplName, c.Data)
|
return buf, ExecuteViewPathTemplate(&buf, c.TplName, c.viewPath(), c.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) viewPath() string {
|
||||||
|
if c.ViewPath == "" {
|
||||||
|
return BConfig.WebConfig.ViewsPath
|
||||||
|
}
|
||||||
|
return c.ViewPath
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect sends the redirection response to url with status code.
|
// Redirect sends the redirection response to url with status code.
|
||||||
|
@ -20,6 +20,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/astaxie/beego/context"
|
"github.com/astaxie/beego/context"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetInt(t *testing.T) {
|
func TestGetInt(t *testing.T) {
|
||||||
@ -121,3 +123,59 @@ func TestGetUint64(t *testing.T) {
|
|||||||
t.Errorf("TestGetUint64 expect %v,get %T,%v", uint64(math.MaxUint64), val, val)
|
t.Errorf("TestGetUint64 expect %v,get %T,%v", uint64(math.MaxUint64), val, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAdditionalViewPaths(t *testing.T) {
|
||||||
|
dir1 := "_beeTmp"
|
||||||
|
dir2 := "_beeTmp2"
|
||||||
|
defer os.RemoveAll(dir1)
|
||||||
|
defer os.RemoveAll(dir2)
|
||||||
|
|
||||||
|
dir1file := "file1.tpl"
|
||||||
|
dir2file := "file2.tpl"
|
||||||
|
|
||||||
|
genFile := func(dir string, name string, content string) {
|
||||||
|
os.MkdirAll(filepath.Dir(filepath.Join(dir, name)), 0777)
|
||||||
|
if f, err := os.Create(filepath.Join(dir, name)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else {
|
||||||
|
defer f.Close()
|
||||||
|
f.WriteString(content)
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
genFile(dir1, dir1file, `<div>{{.Content}}</div>`)
|
||||||
|
genFile(dir2, dir2file, `<html>{{.Content}}</html>`)
|
||||||
|
|
||||||
|
AddViewPath(dir1)
|
||||||
|
AddViewPath(dir2)
|
||||||
|
|
||||||
|
ctrl := Controller{
|
||||||
|
TplName: "file1.tpl",
|
||||||
|
ViewPath: dir1,
|
||||||
|
}
|
||||||
|
ctrl.Data = map[interface{}]interface{}{
|
||||||
|
"Content": "value2",
|
||||||
|
}
|
||||||
|
if result, err := ctrl.RenderString(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else {
|
||||||
|
if result != "<div>value2</div>" {
|
||||||
|
t.Fatalf("TestAdditionalViewPaths expect %s got %s", "<div>value2</div>", result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func() {
|
||||||
|
ctrl.TplName = "file2.tpl"
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r == nil {
|
||||||
|
t.Fatal("TestAdditionalViewPaths expected error")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
ctrl.RenderString();
|
||||||
|
}()
|
||||||
|
|
||||||
|
ctrl.TplName = "file2.tpl"
|
||||||
|
ctrl.ViewPath = dir2
|
||||||
|
ctrl.RenderString();
|
||||||
|
}
|
||||||
|
3
hooks.go
3
hooks.go
@ -72,7 +72,8 @@ func registerSession() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func registerTemplate() error {
|
func registerTemplate() error {
|
||||||
if err := BuildTemplate(BConfig.WebConfig.ViewsPath); err != nil {
|
defer lockViewPaths()
|
||||||
|
if err := AddViewPath(BConfig.WebConfig.ViewsPath); err != nil {
|
||||||
if BConfig.RunMode == DEV {
|
if BConfig.RunMode == DEV {
|
||||||
logs.Warn(err)
|
logs.Warn(err)
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ var (
|
|||||||
"lte": true,
|
"lte": true,
|
||||||
"eq": true,
|
"eq": true,
|
||||||
"nq": true,
|
"nq": true,
|
||||||
|
"ne": true,
|
||||||
"startswith": true,
|
"startswith": true,
|
||||||
"endswith": true,
|
"endswith": true,
|
||||||
"istartswith": true,
|
"istartswith": true,
|
||||||
|
@ -153,6 +153,11 @@ func (o querySet) SetCond(cond *Condition) QuerySeter {
|
|||||||
return &o
|
return &o
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get condition from QuerySeter
|
||||||
|
func (o querySet) GetCond() *Condition {
|
||||||
|
return o.cond
|
||||||
|
}
|
||||||
|
|
||||||
// return QuerySeter execution result number
|
// return QuerySeter execution result number
|
||||||
func (o *querySet) Count() (int64, error) {
|
func (o *querySet) Count() (int64, error) {
|
||||||
return o.orm.alias.DbBaser.Count(o.orm.db, o, o.mi, o.cond, o.orm.alias.TZ)
|
return o.orm.alias.DbBaser.Count(o.orm.db, o, o.mi, o.cond, o.orm.alias.TZ)
|
||||||
|
10
orm/types.go
10
orm/types.go
@ -145,6 +145,16 @@ type QuerySeter interface {
|
|||||||
// //sql-> WHERE T0.`profile_id` IS NOT NULL AND NOT T0.`Status` IN (?) OR T1.`age` > 2000
|
// //sql-> WHERE T0.`profile_id` IS NOT NULL AND NOT T0.`Status` IN (?) OR T1.`age` > 2000
|
||||||
// num, err := qs.SetCond(cond1).Count()
|
// num, err := qs.SetCond(cond1).Count()
|
||||||
SetCond(*Condition) QuerySeter
|
SetCond(*Condition) QuerySeter
|
||||||
|
// get condition from QuerySeter.
|
||||||
|
// sql's where condition
|
||||||
|
// cond := orm.NewCondition()
|
||||||
|
// cond = cond.And("profile__isnull", false).AndNot("status__in", 1)
|
||||||
|
// qs = qs.SetCond(cond)
|
||||||
|
// cond = qs.GetCond()
|
||||||
|
// cond := cond.Or("profile__age__gt", 2000)
|
||||||
|
// //sql-> WHERE T0.`profile_id` IS NOT NULL AND NOT T0.`Status` IN (?) OR T1.`age` > 2000
|
||||||
|
// num, err := qs.SetCond(cond).Count()
|
||||||
|
GetCond() *Condition
|
||||||
// add LIMIT value.
|
// add LIMIT value.
|
||||||
// args[0] means offset, e.g. LIMIT num,offset.
|
// args[0] means offset, e.g. LIMIT num,offset.
|
||||||
// if Limit <= 0 then Limit will be set to default limit ,eg 1000
|
// if Limit <= 0 then Limit will be set to default limit ,eg 1000
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
package apiauth
|
package apiauth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
@ -128,53 +129,32 @@ func APISecretAuth(f AppIDToAppSecret, timeout int) beego.FilterFunc {
|
|||||||
|
|
||||||
// Signature used to generate signature with the appsecret/method/params/RequestURI
|
// Signature used to generate signature with the appsecret/method/params/RequestURI
|
||||||
func Signature(appsecret, method string, params url.Values, RequestURL string) (result string) {
|
func Signature(appsecret, method string, params url.Values, RequestURL string) (result string) {
|
||||||
var query string
|
var b bytes.Buffer
|
||||||
|
keys := make([]string, len(params))
|
||||||
pa := make(map[string]string)
|
pa := make(map[string]string)
|
||||||
for k, v := range params {
|
for k, v := range params {
|
||||||
pa[k] = v[0]
|
pa[k] = v[0]
|
||||||
|
keys = append(keys, k)
|
||||||
}
|
}
|
||||||
vs := mapSorter(pa)
|
|
||||||
vs.Sort()
|
sort.Strings(keys)
|
||||||
for i := 0; i < vs.Len(); i++ {
|
|
||||||
if vs.Keys[i] == "signature" {
|
for _, key := range keys {
|
||||||
|
if key == "signature" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if vs.Keys[i] != "" && vs.Vals[i] != "" {
|
|
||||||
query = fmt.Sprintf("%v%v%v", query, vs.Keys[i], vs.Vals[i])
|
val := pa[key]
|
||||||
|
if key != "" && val != "" {
|
||||||
|
b.WriteString(key)
|
||||||
|
b.WriteString(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stringToSign := fmt.Sprintf("%v\n%v\n%v\n", method, query, RequestURL)
|
|
||||||
|
stringToSign := fmt.Sprintf("%v\n%v\n%v\n", method, b.String(), RequestURL)
|
||||||
|
|
||||||
sha256 := sha256.New
|
sha256 := sha256.New
|
||||||
hash := hmac.New(sha256, []byte(appsecret))
|
hash := hmac.New(sha256, []byte(appsecret))
|
||||||
hash.Write([]byte(stringToSign))
|
hash.Write([]byte(stringToSign))
|
||||||
return base64.StdEncoding.EncodeToString(hash.Sum(nil))
|
return base64.StdEncoding.EncodeToString(hash.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
type valSorter struct {
|
|
||||||
Keys []string
|
|
||||||
Vals []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func mapSorter(m map[string]string) *valSorter {
|
|
||||||
vs := &valSorter{
|
|
||||||
Keys: make([]string, 0, len(m)),
|
|
||||||
Vals: make([]string, 0, len(m)),
|
|
||||||
}
|
|
||||||
for k, v := range m {
|
|
||||||
vs.Keys = append(vs.Keys, k)
|
|
||||||
vs.Vals = append(vs.Vals, v)
|
|
||||||
}
|
|
||||||
return vs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vs *valSorter) Sort() {
|
|
||||||
sort.Sort(vs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vs *valSorter) Len() int { return len(vs.Keys) }
|
|
||||||
func (vs *valSorter) Less(i, j int) bool { return vs.Keys[i] < vs.Keys[j] }
|
|
||||||
func (vs *valSorter) Swap(i, j int) {
|
|
||||||
vs.Vals[i], vs.Vals[j] = vs.Vals[j], vs.Vals[i]
|
|
||||||
vs.Keys[i], vs.Keys[j] = vs.Keys[j], vs.Keys[i]
|
|
||||||
}
|
|
||||||
|
20
plugins/apiauth/apiauth_test.go
Normal file
20
plugins/apiauth/apiauth_test.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package apiauth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSignature(t *testing.T) {
|
||||||
|
appsecret := "beego secret"
|
||||||
|
method := "GET"
|
||||||
|
RequestURL := "http://localhost/test/url"
|
||||||
|
params := make(url.Values)
|
||||||
|
params.Add("arg1", "hello")
|
||||||
|
params.Add("arg2", "beego")
|
||||||
|
|
||||||
|
signature := "mFdpvLh48ca4mDVEItE9++AKKQ/IVca7O/ZyyB8hR58="
|
||||||
|
if Signature(appsecret, method, params, RequestURL) != signature {
|
||||||
|
t.Error("Signature error")
|
||||||
|
}
|
||||||
|
}
|
25
router.go
25
router.go
@ -51,15 +51,22 @@ const (
|
|||||||
var (
|
var (
|
||||||
// HTTPMETHOD list the supported http methods.
|
// HTTPMETHOD list the supported http methods.
|
||||||
HTTPMETHOD = map[string]string{
|
HTTPMETHOD = map[string]string{
|
||||||
"GET": "GET",
|
"GET": "GET",
|
||||||
"POST": "POST",
|
"POST": "POST",
|
||||||
"PUT": "PUT",
|
"PUT": "PUT",
|
||||||
"DELETE": "DELETE",
|
"DELETE": "DELETE",
|
||||||
"PATCH": "PATCH",
|
"PATCH": "PATCH",
|
||||||
"OPTIONS": "OPTIONS",
|
"OPTIONS": "OPTIONS",
|
||||||
"HEAD": "HEAD",
|
"HEAD": "HEAD",
|
||||||
"TRACE": "TRACE",
|
"TRACE": "TRACE",
|
||||||
"CONNECT": "CONNECT",
|
"CONNECT": "CONNECT",
|
||||||
|
"MKCOL": "MKCOL",
|
||||||
|
"COPY": "COPY",
|
||||||
|
"MOVE": "MOVE",
|
||||||
|
"PROPFIND": "PROPFIND",
|
||||||
|
"PROPPATCH": "PROPPATCH",
|
||||||
|
"LOCK": "LOCK",
|
||||||
|
"UNLOCK": "UNLOCK",
|
||||||
}
|
}
|
||||||
// these beego.Controller's methods shouldn't reflect to AutoRouter
|
// these beego.Controller's methods shouldn't reflect to AutoRouter
|
||||||
exceptMethod = []string{"Init", "Prepare", "Finish", "Render", "RenderString",
|
exceptMethod = []string{"Init", "Prepare", "Finish", "Render", "RenderString",
|
||||||
|
@ -143,6 +143,7 @@ func (mp *Provider) SessionInit(maxlifetime int64, savePath string) error {
|
|||||||
// SessionRead get mysql session by sid
|
// SessionRead get mysql session by sid
|
||||||
func (mp *Provider) SessionRead(sid string) (session.Store, error) {
|
func (mp *Provider) SessionRead(sid string) (session.Store, error) {
|
||||||
c := mp.connectInit()
|
c := mp.connectInit()
|
||||||
|
defer c.Close()
|
||||||
row := c.QueryRow("select session_data from "+TableName+" where session_key=?", sid)
|
row := c.QueryRow("select session_data from "+TableName+" where session_key=?", sid)
|
||||||
var sessiondata []byte
|
var sessiondata []byte
|
||||||
err := row.Scan(&sessiondata)
|
err := row.Scan(&sessiondata)
|
||||||
@ -179,6 +180,7 @@ func (mp *Provider) SessionExist(sid string) bool {
|
|||||||
// SessionRegenerate generate new sid for mysql session
|
// SessionRegenerate generate new sid for mysql session
|
||||||
func (mp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) {
|
func (mp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) {
|
||||||
c := mp.connectInit()
|
c := mp.connectInit()
|
||||||
|
defer c.Close()
|
||||||
row := c.QueryRow("select session_data from "+TableName+" where session_key=?", oldsid)
|
row := c.QueryRow("select session_data from "+TableName+" where session_key=?", oldsid)
|
||||||
var sessiondata []byte
|
var sessiondata []byte
|
||||||
err := row.Scan(&sessiondata)
|
err := row.Scan(&sessiondata)
|
||||||
|
@ -15,8 +15,7 @@
|
|||||||
package session
|
package session
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -135,6 +134,9 @@ func (fp *FileProvider) SessionRead(sid string) (Store, error) {
|
|||||||
} else {
|
} else {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
os.Chtimes(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), time.Now(), time.Now())
|
os.Chtimes(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), time.Now(), time.Now())
|
||||||
var kv map[interface{}]interface{}
|
var kv map[interface{}]interface{}
|
||||||
b, err := ioutil.ReadAll(f)
|
b, err := ioutil.ReadAll(f)
|
||||||
@ -149,7 +151,7 @@ func (fp *FileProvider) SessionRead(sid string) (Store, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.Close()
|
|
||||||
ss := &FileSessionStore{sid: sid, values: kv}
|
ss := &FileSessionStore{sid: sid, values: kv}
|
||||||
return ss, nil
|
return ss, nil
|
||||||
}
|
}
|
||||||
@ -204,49 +206,58 @@ func (fp *FileProvider) SessionRegenerate(oldsid, sid string) (Store, error) {
|
|||||||
filepder.lock.Lock()
|
filepder.lock.Lock()
|
||||||
defer filepder.lock.Unlock()
|
defer filepder.lock.Unlock()
|
||||||
|
|
||||||
err := os.MkdirAll(path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1])), 0777)
|
oldPath := path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1]))
|
||||||
if err != nil {
|
oldSidFile := path.Join(oldPath, oldsid)
|
||||||
SLogger.Println(err.Error())
|
newPath := path.Join(fp.savePath, string(sid[0]), string(sid[1]))
|
||||||
}
|
newSidFile := path.Join(newPath, sid)
|
||||||
err = os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777)
|
|
||||||
if err != nil {
|
// new sid file is exist
|
||||||
SLogger.Println(err.Error())
|
_, err := os.Stat(newSidFile)
|
||||||
}
|
|
||||||
_, err = os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
|
|
||||||
var newf *os.File
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil, errors.New("newsid exist")
|
return nil, fmt.Errorf("newsid %s exist", newSidFile)
|
||||||
} else if os.IsNotExist(err) {
|
|
||||||
newf, err = os.Create(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = os.Stat(path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1]), oldsid))
|
err = os.MkdirAll(newPath, 0777)
|
||||||
var f *os.File
|
|
||||||
if err == nil {
|
|
||||||
f, err = os.OpenFile(path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1]), oldsid), os.O_RDWR, 0777)
|
|
||||||
io.Copy(newf, f)
|
|
||||||
} else if os.IsNotExist(err) {
|
|
||||||
newf, err = os.Create(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
|
|
||||||
} else {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
f.Close()
|
|
||||||
os.Remove(path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1])))
|
|
||||||
os.Chtimes(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), time.Now(), time.Now())
|
|
||||||
var kv map[interface{}]interface{}
|
|
||||||
b, err := ioutil.ReadAll(newf)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
SLogger.Println(err.Error())
|
||||||
}
|
}
|
||||||
if len(b) == 0 {
|
|
||||||
kv = make(map[interface{}]interface{})
|
// if old sid file exist
|
||||||
} else {
|
// 1.read and parse file content
|
||||||
kv, err = DecodeGob(b)
|
// 2.write content to new sid file
|
||||||
|
// 3.remove old sid file, change new sid file atime and ctime
|
||||||
|
// 4.return FileSessionStore
|
||||||
|
_, err = os.Stat(oldSidFile)
|
||||||
|
if err == nil {
|
||||||
|
b, err := ioutil.ReadFile(oldSidFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var kv map[interface{}]interface{}
|
||||||
|
if len(b) == 0 {
|
||||||
|
kv = make(map[interface{}]interface{})
|
||||||
|
} else {
|
||||||
|
kv, err = DecodeGob(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ioutil.WriteFile(newSidFile, b, 0777)
|
||||||
|
os.Remove(oldSidFile)
|
||||||
|
os.Chtimes(newSidFile, time.Now(), time.Now())
|
||||||
|
ss := &FileSessionStore{sid: sid, values: kv}
|
||||||
|
return ss, nil
|
||||||
}
|
}
|
||||||
ss := &FileSessionStore{sid: sid, values: kv}
|
|
||||||
|
// if old sid file not exist, just create new sid file and return
|
||||||
|
newf, err := os.Create(newSidFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newf.Close()
|
||||||
|
ss := &FileSessionStore{sid: sid, values: make(map[interface{}]interface{})}
|
||||||
return ss, nil
|
return ss, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
58
template.go
58
template.go
@ -32,8 +32,9 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
beegoTplFuncMap = make(template.FuncMap)
|
beegoTplFuncMap = make(template.FuncMap)
|
||||||
// beeTemplates caching map and supported template file extensions.
|
beeViewPathTemplateLocked = false
|
||||||
beeTemplates = make(map[string]*template.Template)
|
// beeViewPathTemplates caching map and supported template file extensions per view
|
||||||
|
beeViewPathTemplates = make(map[string]map[string]*template.Template)
|
||||||
templatesLock sync.RWMutex
|
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"}
|
||||||
@ -45,23 +46,33 @@ var (
|
|||||||
// writing the output to wr.
|
// writing the output to wr.
|
||||||
// A template will be executed safely in parallel.
|
// A template will be executed safely in parallel.
|
||||||
func ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
|
func ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
|
||||||
|
return ExecuteViewPathTemplate(wr,name, BConfig.WebConfig.ViewsPath, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecuteViewPathTemplate applies the template with name and from specific viewPath to the specified data object,
|
||||||
|
// writing the output to wr.
|
||||||
|
// A template will be executed safely in parallel.
|
||||||
|
func ExecuteViewPathTemplate(wr io.Writer, name string, viewPath string, data interface{}) error {
|
||||||
if BConfig.RunMode == DEV {
|
if BConfig.RunMode == DEV {
|
||||||
templatesLock.RLock()
|
templatesLock.RLock()
|
||||||
defer templatesLock.RUnlock()
|
defer templatesLock.RUnlock()
|
||||||
}
|
}
|
||||||
if t, ok := beeTemplates[name]; ok {
|
if beeTemplates,ok := beeViewPathTemplates[viewPath]; ok {
|
||||||
var err error
|
if t, ok := beeTemplates[name]; ok {
|
||||||
if t.Lookup(name) != nil {
|
var err error
|
||||||
err = t.ExecuteTemplate(wr, name, data)
|
if t.Lookup(name) != nil {
|
||||||
} else {
|
err = t.ExecuteTemplate(wr, name, data)
|
||||||
err = t.Execute(wr, data)
|
} else {
|
||||||
|
err = t.Execute(wr, data)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
logs.Trace("template Execute err:", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
if err != nil {
|
panic("can't find templatefile in the path:" + viewPath + "/" + name)
|
||||||
logs.Trace("template Execute err:", err)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
panic("can't find templatefile in the path:" + name)
|
panic("Uknown view path:" + viewPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -149,6 +160,21 @@ func AddTemplateExt(ext string) {
|
|||||||
beeTemplateExt = append(beeTemplateExt, ext)
|
beeTemplateExt = append(beeTemplateExt, ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddViewPath adds a new path to the supported view paths.
|
||||||
|
//Can later be used by setting a controller ViewPath to this folder
|
||||||
|
//will panic if called after beego.Run()
|
||||||
|
func AddViewPath(viewPath string) error {
|
||||||
|
if beeViewPathTemplateLocked {
|
||||||
|
panic("Can not add new view paths after beego.Run()")
|
||||||
|
}
|
||||||
|
beeViewPathTemplates[viewPath] = make(map[string]*template.Template)
|
||||||
|
return BuildTemplate(viewPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func lockViewPaths() {
|
||||||
|
beeViewPathTemplateLocked = true
|
||||||
|
}
|
||||||
|
|
||||||
// BuildTemplate will build all template files in a directory.
|
// BuildTemplate will build all template files in a directory.
|
||||||
// it makes beego can render any template file in view directory.
|
// it makes beego can render any template file in view directory.
|
||||||
func BuildTemplate(dir string, files ...string) error {
|
func BuildTemplate(dir string, files ...string) error {
|
||||||
@ -158,6 +184,10 @@ func BuildTemplate(dir string, files ...string) error {
|
|||||||
}
|
}
|
||||||
return errors.New("dir open err")
|
return errors.New("dir open err")
|
||||||
}
|
}
|
||||||
|
beeTemplates,ok := beeViewPathTemplates[dir];
|
||||||
|
if !ok {
|
||||||
|
panic("Unknown view path: " + dir)
|
||||||
|
}
|
||||||
self := &templateFile{
|
self := &templateFile{
|
||||||
root: dir,
|
root: dir,
|
||||||
files: make(map[string][]string),
|
files: make(map[string][]string),
|
||||||
@ -224,7 +254,7 @@ func getTplDeep(root, file, parent string, t *template.Template) (*template.Temp
|
|||||||
if !HasTemplateExt(m[1]) {
|
if !HasTemplateExt(m[1]) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
t, _, err = getTplDeep(root, m[1], file, t)
|
_, _, err = getTplDeep(root, m[1], file, t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, [][]string{}, err
|
return nil, [][]string{}, err
|
||||||
}
|
}
|
||||||
|
@ -67,9 +67,10 @@ func TestTemplate(t *testing.T) {
|
|||||||
f.Close()
|
f.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := BuildTemplate(dir); err != nil {
|
if err := AddViewPath(dir); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
beeTemplates := beeViewPathTemplates[dir]
|
||||||
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))
|
||||||
}
|
}
|
||||||
@ -103,6 +104,12 @@ var user = `<!DOCTYPE html>
|
|||||||
|
|
||||||
func TestRelativeTemplate(t *testing.T) {
|
func TestRelativeTemplate(t *testing.T) {
|
||||||
dir := "_beeTmp"
|
dir := "_beeTmp"
|
||||||
|
|
||||||
|
//Just add dir to known viewPaths
|
||||||
|
if err := AddViewPath(dir); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
files := []string{
|
files := []string{
|
||||||
"easyui/public/menu.tpl",
|
"easyui/public/menu.tpl",
|
||||||
"easyui/rbac/user.tpl",
|
"easyui/rbac/user.tpl",
|
||||||
@ -126,6 +133,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)
|
||||||
}
|
}
|
||||||
|
beeTemplates := beeViewPathTemplates[dir]
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user