mirror of
https://github.com/astaxie/beego.git
synced 2024-11-16 12:10:55 +00:00
e90f4bee1a
The application path is incorrect on Windows with the command line "go run". AppPath is assigned to the temp directory instead the folder project
489 lines
13 KiB
Go
489 lines
13 KiB
Go
// 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 beego
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/astaxie/beego/config"
|
|
"github.com/astaxie/beego/context"
|
|
"github.com/astaxie/beego/logs"
|
|
"github.com/astaxie/beego/session"
|
|
"github.com/astaxie/beego/utils"
|
|
)
|
|
|
|
// Config is the main struct for BConfig
|
|
type Config struct {
|
|
AppName string //Application name
|
|
RunMode string //Running Mode: dev | prod
|
|
RouterCaseSensitive bool
|
|
ServerName string
|
|
RecoverPanic bool
|
|
RecoverFunc func(*context.Context)
|
|
CopyRequestBody bool
|
|
EnableGzip bool
|
|
MaxMemory int64
|
|
EnableErrorsShow bool
|
|
Listen Listen
|
|
WebConfig WebConfig
|
|
Log LogConfig
|
|
}
|
|
|
|
// Listen holds for http and https related config
|
|
type Listen struct {
|
|
Graceful bool // Graceful means use graceful module to start the server
|
|
ServerTimeOut int64
|
|
ListenTCP4 bool
|
|
EnableHTTP bool
|
|
HTTPAddr string
|
|
HTTPPort int
|
|
EnableHTTPS bool
|
|
HTTPSAddr string
|
|
HTTPSPort int
|
|
HTTPSCertFile string
|
|
HTTPSKeyFile string
|
|
EnableAdmin bool
|
|
AdminAddr string
|
|
AdminPort int
|
|
EnableFcgi bool
|
|
EnableStdIo bool // EnableStdIo works with EnableFcgi Use FCGI via standard I/O
|
|
}
|
|
|
|
// WebConfig holds web related config
|
|
type WebConfig struct {
|
|
AutoRender bool
|
|
EnableDocs bool
|
|
FlashName string
|
|
FlashSeparator string
|
|
DirectoryIndex bool
|
|
StaticDir map[string]string
|
|
StaticExtensionsToGzip []string
|
|
TemplateLeft string
|
|
TemplateRight string
|
|
ViewsPath string
|
|
EnableXSRF bool
|
|
XSRFKey string
|
|
XSRFExpire int
|
|
Session SessionConfig
|
|
}
|
|
|
|
// SessionConfig holds session related config
|
|
type SessionConfig struct {
|
|
SessionOn bool
|
|
SessionProvider string
|
|
SessionName string
|
|
SessionGCMaxLifetime int64
|
|
SessionProviderConfig string
|
|
SessionCookieLifeTime int
|
|
SessionAutoSetCookie bool
|
|
SessionDomain string
|
|
SessionDisableHTTPOnly bool // used to allow for cross domain cookies/javascript cookies.
|
|
SessionEnableSidInHTTPHeader bool // enable store/get the sessionId into/from http headers
|
|
SessionNameInHTTPHeader string
|
|
SessionEnableSidInURLQuery bool // enable get the sessionId from Url Query params
|
|
}
|
|
|
|
// LogConfig holds Log related config
|
|
type LogConfig struct {
|
|
AccessLogs bool
|
|
FileLineNum bool
|
|
Outputs map[string]string // Store Adaptor : config
|
|
}
|
|
|
|
var (
|
|
// BConfig is the default config for Application
|
|
BConfig *Config
|
|
// AppConfig is the instance of Config, store the config information from file
|
|
AppConfig *beegoAppConfig
|
|
// AppPath is the absolute path to the app
|
|
AppPath string
|
|
// GlobalSessions is the instance for the session manager
|
|
GlobalSessions *session.Manager
|
|
|
|
// appConfigPath is the path to the config files
|
|
appConfigPath string
|
|
// appConfigProvider is the provider for the config, default is ini
|
|
appConfigProvider = "ini"
|
|
)
|
|
|
|
func init() {
|
|
BConfig = newBConfig()
|
|
var err error
|
|
if AppPath, err = filepath.Abs(filepath.Dir(os.Args[0])); err != nil {
|
|
panic(err)
|
|
}
|
|
workPath, err := os.Getwd()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
appConfigPath = filepath.Join(workPath, "conf", "app.conf")
|
|
if !utils.FileExists(appConfigPath) {
|
|
appConfigPath = filepath.Join(AppPath, "conf", "app.conf")
|
|
if !utils.FileExists(appConfigPath) {
|
|
AppConfig = &beegoAppConfig{innerConfig: config.NewFakeConfig()}
|
|
return
|
|
}
|
|
}
|
|
if err = parseConfig(appConfigPath); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func recoverPanic(ctx *context.Context) {
|
|
if err := recover(); err != nil {
|
|
if err == ErrAbort {
|
|
return
|
|
}
|
|
if !BConfig.RecoverPanic {
|
|
panic(err)
|
|
}
|
|
if BConfig.EnableErrorsShow {
|
|
if _, ok := ErrorMaps[fmt.Sprint(err)]; ok {
|
|
exception(fmt.Sprint(err), ctx)
|
|
return
|
|
}
|
|
}
|
|
var stack string
|
|
logs.Critical("the request url is ", ctx.Input.URL())
|
|
logs.Critical("Handler crashed with error", err)
|
|
for i := 1; ; i++ {
|
|
_, file, line, ok := runtime.Caller(i)
|
|
if !ok {
|
|
break
|
|
}
|
|
logs.Critical(fmt.Sprintf("%s:%d", file, line))
|
|
stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
|
|
}
|
|
if BConfig.RunMode == DEV {
|
|
showErr(err, ctx, stack)
|
|
}
|
|
}
|
|
}
|
|
|
|
func newBConfig() *Config {
|
|
return &Config{
|
|
AppName: "beego",
|
|
RunMode: DEV,
|
|
RouterCaseSensitive: true,
|
|
ServerName: "beegoServer:" + VERSION,
|
|
RecoverPanic: true,
|
|
RecoverFunc: recoverPanic,
|
|
CopyRequestBody: false,
|
|
EnableGzip: false,
|
|
MaxMemory: 1 << 26, //64MB
|
|
EnableErrorsShow: true,
|
|
Listen: Listen{
|
|
Graceful: false,
|
|
ServerTimeOut: 0,
|
|
ListenTCP4: false,
|
|
EnableHTTP: true,
|
|
HTTPAddr: "",
|
|
HTTPPort: 8080,
|
|
EnableHTTPS: false,
|
|
HTTPSAddr: "",
|
|
HTTPSPort: 10443,
|
|
HTTPSCertFile: "",
|
|
HTTPSKeyFile: "",
|
|
EnableAdmin: false,
|
|
AdminAddr: "",
|
|
AdminPort: 8088,
|
|
EnableFcgi: false,
|
|
EnableStdIo: false,
|
|
},
|
|
WebConfig: WebConfig{
|
|
AutoRender: true,
|
|
EnableDocs: false,
|
|
FlashName: "BEEGO_FLASH",
|
|
FlashSeparator: "BEEGOFLASH",
|
|
DirectoryIndex: false,
|
|
StaticDir: map[string]string{"/static": "static"},
|
|
StaticExtensionsToGzip: []string{".css", ".js"},
|
|
TemplateLeft: "{{",
|
|
TemplateRight: "}}",
|
|
ViewsPath: "views",
|
|
EnableXSRF: false,
|
|
XSRFKey: "beegoxsrf",
|
|
XSRFExpire: 0,
|
|
Session: SessionConfig{
|
|
SessionOn: false,
|
|
SessionProvider: "memory",
|
|
SessionName: "beegosessionID",
|
|
SessionGCMaxLifetime: 3600,
|
|
SessionProviderConfig: "",
|
|
SessionDisableHTTPOnly: false,
|
|
SessionCookieLifeTime: 0, //set cookie default is the browser life
|
|
SessionAutoSetCookie: true,
|
|
SessionDomain: "",
|
|
SessionEnableSidInHTTPHeader: false, // enable store/get the sessionId into/from http headers
|
|
SessionNameInHTTPHeader: "Beegosessionid",
|
|
SessionEnableSidInURLQuery: false, // enable get the sessionId from Url Query params
|
|
},
|
|
},
|
|
Log: LogConfig{
|
|
AccessLogs: false,
|
|
FileLineNum: true,
|
|
Outputs: map[string]string{"console": ""},
|
|
},
|
|
}
|
|
}
|
|
|
|
// now only support ini, next will support json.
|
|
func parseConfig(appConfigPath string) (err error) {
|
|
AppConfig, err = newAppConfig(appConfigProvider, appConfigPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return assignConfig(AppConfig)
|
|
}
|
|
|
|
func assignConfig(ac config.Configer) error {
|
|
// set the run mode first
|
|
if envRunMode := os.Getenv("BEEGO_RUNMODE"); envRunMode != "" {
|
|
BConfig.RunMode = envRunMode
|
|
} else if runMode := ac.String("RunMode"); runMode != "" {
|
|
BConfig.RunMode = runMode
|
|
}
|
|
|
|
for _, i := range []interface{}{BConfig, &BConfig.Listen, &BConfig.WebConfig, &BConfig.Log, &BConfig.WebConfig.Session} {
|
|
assignSingleConfig(i, ac)
|
|
}
|
|
|
|
if sd := ac.String("StaticDir"); sd != "" {
|
|
BConfig.WebConfig.StaticDir = map[string]string{}
|
|
sds := strings.Fields(sd)
|
|
for _, v := range sds {
|
|
if url2fsmap := strings.SplitN(v, ":", 2); len(url2fsmap) == 2 {
|
|
BConfig.WebConfig.StaticDir["/"+strings.Trim(url2fsmap[0], "/")] = url2fsmap[1]
|
|
} else {
|
|
BConfig.WebConfig.StaticDir["/"+strings.Trim(url2fsmap[0], "/")] = url2fsmap[0]
|
|
}
|
|
}
|
|
}
|
|
|
|
if sgz := ac.String("StaticExtensionsToGzip"); sgz != "" {
|
|
extensions := strings.Split(sgz, ",")
|
|
fileExts := []string{}
|
|
for _, ext := range extensions {
|
|
ext = strings.TrimSpace(ext)
|
|
if ext == "" {
|
|
continue
|
|
}
|
|
if !strings.HasPrefix(ext, ".") {
|
|
ext = "." + ext
|
|
}
|
|
fileExts = append(fileExts, ext)
|
|
}
|
|
if len(fileExts) > 0 {
|
|
BConfig.WebConfig.StaticExtensionsToGzip = fileExts
|
|
}
|
|
}
|
|
|
|
if lo := ac.String("LogOutputs"); lo != "" {
|
|
// if lo is not nil or empty
|
|
// means user has set his own LogOutputs
|
|
// clear the default setting to BConfig.Log.Outputs
|
|
BConfig.Log.Outputs = make(map[string]string)
|
|
los := strings.Split(lo, ";")
|
|
for _, v := range los {
|
|
if logType2Config := strings.SplitN(v, ",", 2); len(logType2Config) == 2 {
|
|
BConfig.Log.Outputs[logType2Config[0]] = logType2Config[1]
|
|
} else {
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
//init log
|
|
logs.Reset()
|
|
for adaptor, config := range BConfig.Log.Outputs {
|
|
err := logs.SetLogger(adaptor, config)
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, fmt.Sprintf("%s with the config %q got err:%s", adaptor, config, err.Error()))
|
|
}
|
|
}
|
|
logs.SetLogFuncCall(BConfig.Log.FileLineNum)
|
|
|
|
return nil
|
|
}
|
|
|
|
func assignSingleConfig(p interface{}, ac config.Configer) {
|
|
pt := reflect.TypeOf(p)
|
|
if pt.Kind() != reflect.Ptr {
|
|
return
|
|
}
|
|
pt = pt.Elem()
|
|
if pt.Kind() != reflect.Struct {
|
|
return
|
|
}
|
|
pv := reflect.ValueOf(p).Elem()
|
|
|
|
for i := 0; i < pt.NumField(); i++ {
|
|
pf := pv.Field(i)
|
|
if !pf.CanSet() {
|
|
continue
|
|
}
|
|
name := pt.Field(i).Name
|
|
switch pf.Kind() {
|
|
case reflect.String:
|
|
pf.SetString(ac.DefaultString(name, pf.String()))
|
|
case reflect.Int, reflect.Int64:
|
|
pf.SetInt(int64(ac.DefaultInt64(name, pf.Int())))
|
|
case reflect.Bool:
|
|
pf.SetBool(ac.DefaultBool(name, pf.Bool()))
|
|
case reflect.Struct:
|
|
default:
|
|
//do nothing here
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// LoadAppConfig allow developer to apply a config file
|
|
func LoadAppConfig(adapterName, configPath string) error {
|
|
absConfigPath, err := filepath.Abs(configPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !utils.FileExists(absConfigPath) {
|
|
return fmt.Errorf("the target config file: %s don't exist", configPath)
|
|
}
|
|
|
|
appConfigPath = absConfigPath
|
|
appConfigProvider = adapterName
|
|
|
|
return parseConfig(appConfigPath)
|
|
}
|
|
|
|
type beegoAppConfig struct {
|
|
innerConfig config.Configer
|
|
}
|
|
|
|
func newAppConfig(appConfigProvider, appConfigPath string) (*beegoAppConfig, error) {
|
|
ac, err := config.NewConfig(appConfigProvider, appConfigPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &beegoAppConfig{ac}, nil
|
|
}
|
|
|
|
func (b *beegoAppConfig) Set(key, val string) error {
|
|
if err := b.innerConfig.Set(BConfig.RunMode+"::"+key, val); err != nil {
|
|
return err
|
|
}
|
|
return b.innerConfig.Set(key, val)
|
|
}
|
|
|
|
func (b *beegoAppConfig) String(key string) string {
|
|
if v := b.innerConfig.String(BConfig.RunMode + "::" + key); v != "" {
|
|
return v
|
|
}
|
|
return b.innerConfig.String(key)
|
|
}
|
|
|
|
func (b *beegoAppConfig) Strings(key string) []string {
|
|
if v := b.innerConfig.Strings(BConfig.RunMode + "::" + key); len(v) > 0 {
|
|
return v
|
|
}
|
|
return b.innerConfig.Strings(key)
|
|
}
|
|
|
|
func (b *beegoAppConfig) Int(key string) (int, error) {
|
|
if v, err := b.innerConfig.Int(BConfig.RunMode + "::" + key); err == nil {
|
|
return v, nil
|
|
}
|
|
return b.innerConfig.Int(key)
|
|
}
|
|
|
|
func (b *beegoAppConfig) Int64(key string) (int64, error) {
|
|
if v, err := b.innerConfig.Int64(BConfig.RunMode + "::" + key); err == nil {
|
|
return v, nil
|
|
}
|
|
return b.innerConfig.Int64(key)
|
|
}
|
|
|
|
func (b *beegoAppConfig) Bool(key string) (bool, error) {
|
|
if v, err := b.innerConfig.Bool(BConfig.RunMode + "::" + key); err == nil {
|
|
return v, nil
|
|
}
|
|
return b.innerConfig.Bool(key)
|
|
}
|
|
|
|
func (b *beegoAppConfig) Float(key string) (float64, error) {
|
|
if v, err := b.innerConfig.Float(BConfig.RunMode + "::" + key); err == nil {
|
|
return v, nil
|
|
}
|
|
return b.innerConfig.Float(key)
|
|
}
|
|
|
|
func (b *beegoAppConfig) DefaultString(key string, defaultVal string) string {
|
|
if v := b.String(key); v != "" {
|
|
return v
|
|
}
|
|
return defaultVal
|
|
}
|
|
|
|
func (b *beegoAppConfig) DefaultStrings(key string, defaultVal []string) []string {
|
|
if v := b.Strings(key); len(v) != 0 {
|
|
return v
|
|
}
|
|
return defaultVal
|
|
}
|
|
|
|
func (b *beegoAppConfig) DefaultInt(key string, defaultVal int) int {
|
|
if v, err := b.Int(key); err == nil {
|
|
return v
|
|
}
|
|
return defaultVal
|
|
}
|
|
|
|
func (b *beegoAppConfig) DefaultInt64(key string, defaultVal int64) int64 {
|
|
if v, err := b.Int64(key); err == nil {
|
|
return v
|
|
}
|
|
return defaultVal
|
|
}
|
|
|
|
func (b *beegoAppConfig) DefaultBool(key string, defaultVal bool) bool {
|
|
if v, err := b.Bool(key); err == nil {
|
|
return v
|
|
}
|
|
return defaultVal
|
|
}
|
|
|
|
func (b *beegoAppConfig) DefaultFloat(key string, defaultVal float64) float64 {
|
|
if v, err := b.Float(key); err == nil {
|
|
return v
|
|
}
|
|
return defaultVal
|
|
}
|
|
|
|
func (b *beegoAppConfig) DIY(key string) (interface{}, error) {
|
|
return b.innerConfig.DIY(key)
|
|
}
|
|
|
|
func (b *beegoAppConfig) GetSection(section string) (map[string]string, error) {
|
|
return b.innerConfig.GetSection(section)
|
|
}
|
|
|
|
func (b *beegoAppConfig) SaveConfigFile(filename string) error {
|
|
return b.innerConfig.SaveConfigFile(filename)
|
|
}
|