config.go 13.4 KB
Newer Older
A
astaxie 已提交
1
// Copyright 2014 beego Author. All Rights Reserved.
A
astaxie 已提交
2
//
A
astaxie 已提交
3 4 5
// 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
A
astaxie 已提交
6
//
A
astaxie 已提交
7
//      http://www.apache.org/licenses/LICENSE-2.0
A
astaxie 已提交
8
//
A
astaxie 已提交
9 10 11 12 13 14
// 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.

15 16 17
package beego

import (
Y
youngsterxyf 已提交
18
	"fmt"
19
	"os"
20
	"path/filepath"
J
JessonChan 已提交
21
	"reflect"
A
astaxie 已提交
22
	"runtime"
23
	"strings"
P
Pengfei Xue 已提交
24 25

	"github.com/astaxie/beego/config"
A
astaxie 已提交
26
	"github.com/astaxie/beego/context"
27
	"github.com/astaxie/beego/logs"
P
Pengfei Xue 已提交
28
	"github.com/astaxie/beego/session"
29
	"github.com/astaxie/beego/utils"
30 31
)

A
astaxie 已提交
32
// Config is the main struct for BConfig
A
astaxie 已提交
33
type Config struct {
A
astaxie 已提交
34 35
	AppName             string //Application name
	RunMode             string //Running Mode: dev | prod
36
	RouterCaseSensitive bool
A
astaxie 已提交
37 38
	ServerName          string
	RecoverPanic        bool
A
astaxie 已提交
39
	RecoverFunc         func(*context.Context)
A
astaxie 已提交
40 41 42 43
	CopyRequestBody     bool
	EnableGzip          bool
	MaxMemory           int64
	EnableErrorsShow    bool
X
xhzhang 已提交
44
	EnableErrorsRender  bool
A
astaxie 已提交
45 46 47
	Listen              Listen
	WebConfig           WebConfig
	Log                 LogConfig
A
astaxie 已提交
48 49
}

A
astaxie 已提交
50
// Listen holds for http and https related config
A
astaxie 已提交
51
type Listen struct {
L
lotus 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
	Graceful          bool // Graceful means use graceful module to start the server
	ServerTimeOut     int64
	ListenTCP4        bool
	EnableHTTP        bool
	HTTPAddr          string
	HTTPPort          int
	EnableHTTPS       bool
	EnableMutualHTTPS bool
	HTTPSAddr         string
	HTTPSPort         int
	HTTPSCertFile     string
	HTTPSKeyFile      string
	TrustCaFile       string
	EnableAdmin       bool
	AdminAddr         string
	AdminPort         int
	EnableFcgi        bool
	EnableStdIo       bool // EnableStdIo works with EnableFcgi Use FCGI via standard I/O
A
astaxie 已提交
70 71
}

A
astaxie 已提交
72
// WebConfig holds web related config
A
astaxie 已提交
73 74 75 76
type WebConfig struct {
	AutoRender             bool
	EnableDocs             bool
	FlashName              string
J
JessonChan 已提交
77
	FlashSeparator         string
A
astaxie 已提交
78 79 80 81 82 83 84
	DirectoryIndex         bool
	StaticDir              map[string]string
	StaticExtensionsToGzip []string
	TemplateLeft           string
	TemplateRight          string
	ViewsPath              string
	EnableXSRF             bool
J
JessonChan 已提交
85
	XSRFKey                string
A
astaxie 已提交
86 87
	XSRFExpire             int
	Session                SessionConfig
A
astaxie 已提交
88 89
}

A
astaxie 已提交
90
// SessionConfig holds session related config
A
astaxie 已提交
91
type SessionConfig struct {
G
GrimTheReaper 已提交
92 93 94 95 96 97 98 99 100 101 102 103
	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
A
astaxie 已提交
104 105
}

A
astaxie 已提交
106
// LogConfig holds Log related config
A
astaxie 已提交
107
type LogConfig struct {
A
astaxie 已提交
108 109 110 111
	AccessLogs       bool
	AccessLogsFormat string //access log format: JSON_FORMAT, APACHE_FORMAT or empty string
	FileLineNum      bool
	Outputs          map[string]string // Store Adaptor : config
A
astaxie 已提交
112 113
}

A
astaxie 已提交
114 115
var (
	// BConfig is the default config for Application
A
astaxie 已提交
116
	BConfig *Config
A
astaxie 已提交
117 118
	// AppConfig is the instance of Config, store the config information from file
	AppConfig *beegoAppConfig
C
coseyo 已提交
119 120
	// AppPath is the absolute path to the app
	AppPath string
A
astaxie 已提交
121 122
	// GlobalSessions is the instance for the session manager
	GlobalSessions *session.Manager
Y
youngsterxyf 已提交
123

124 125 126 127
	// appConfigPath is the path to the config files
	appConfigPath string
	// appConfigProvider is the provider for the config, default is ini
	appConfigProvider = "ini"
A
astaxie 已提交
128
)
A
astaxie 已提交
129

A
astaxie 已提交
130
func init() {
J
JessonChan 已提交
131 132 133 134 135 136 137 138 139
	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)
	}
A
Abel 已提交
140 141 142 143
	var filename = "app.conf"
	if os.Getenv("BEEGO_MODE") != "" {
		filename = os.Getenv("BEEGO_MODE") + ".app.conf"
	}
A
Abel 已提交
144
	appConfigPath = filepath.Join(workPath, "conf", filename)
J
JessonChan 已提交
145
	if !utils.FileExists(appConfigPath) {
A
Abel 已提交
146
		appConfigPath = filepath.Join(AppPath, "conf", filename)
J
JessonChan 已提交
147 148 149 150 151 152 153 154 155
		if !utils.FileExists(appConfigPath) {
			AppConfig = &beegoAppConfig{innerConfig: config.NewFakeConfig()}
			return
		}
	}
	if err = parseConfig(appConfigPath); err != nil {
		panic(err)
	}
}
Y
youngsterxyf 已提交
156

A
astaxie 已提交
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
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))
		}
X
xhzhang 已提交
182
		if BConfig.RunMode == DEV && BConfig.EnableErrorsRender {
A
astaxie 已提交
183 184 185 186 187
			showErr(err, ctx, stack)
		}
	}
}

J
JessonChan 已提交
188 189
func newBConfig() *Config {
	return &Config{
A
astaxie 已提交
190
		AppName:             "beego",
191
		RunMode:             DEV,
A
astaxie 已提交
192 193 194
		RouterCaseSensitive: true,
		ServerName:          "beegoServer:" + VERSION,
		RecoverPanic:        true,
A
astaxie 已提交
195
		RecoverFunc:         recoverPanic,
A
astaxie 已提交
196 197 198 199
		CopyRequestBody:     false,
		EnableGzip:          false,
		MaxMemory:           1 << 26, //64MB
		EnableErrorsShow:    true,
X
xhzhang 已提交
200
		EnableErrorsRender:  true,
A
astaxie 已提交
201 202 203 204
		Listen: Listen{
			Graceful:      false,
			ServerTimeOut: 0,
			ListenTCP4:    false,
A
astaxie 已提交
205
			EnableHTTP:    true,
A
astaxie 已提交
206 207
			HTTPAddr:      "",
			HTTPPort:      8080,
A
astaxie 已提交
208
			EnableHTTPS:   false,
A
astaxie 已提交
209 210 211 212
			HTTPSAddr:     "",
			HTTPSPort:     10443,
			HTTPSCertFile: "",
			HTTPSKeyFile:  "",
A
astaxie 已提交
213
			EnableAdmin:   false,
A
astaxie 已提交
214 215 216 217 218 219 220 221 222
			AdminAddr:     "",
			AdminPort:     8088,
			EnableFcgi:    false,
			EnableStdIo:   false,
		},
		WebConfig: WebConfig{
			AutoRender:             true,
			EnableDocs:             false,
			FlashName:              "BEEGO_FLASH",
J
JessonChan 已提交
223
			FlashSeparator:         "BEEGOFLASH",
A
astaxie 已提交
224 225 226 227 228 229 230
			DirectoryIndex:         false,
			StaticDir:              map[string]string{"/static": "static"},
			StaticExtensionsToGzip: []string{".css", ".js"},
			TemplateLeft:           "{{",
			TemplateRight:          "}}",
			ViewsPath:              "views",
			EnableXSRF:             false,
J
JessonChan 已提交
231
			XSRFKey:                "beegoxsrf",
A
astaxie 已提交
232 233
			XSRFExpire:             0,
			Session: SessionConfig{
G
GrimTheReaper 已提交
234 235 236 237 238 239 240 241 242 243 244 245
				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
A
astaxie 已提交
246 247 248
			},
		},
		Log: LogConfig{
A
astaxie 已提交
249 250 251 252
			AccessLogs:       false,
			AccessLogsFormat: "APACHE_FORMAT",
			FileLineNum:      true,
			Outputs:          map[string]string{"console": ""},
A
astaxie 已提交
253
		},
A
astaxie 已提交
254
	}
Y
youngsterxyf 已提交
255 256
}

A
astaxie 已提交
257
// now only support ini, next will support json.
Y
youngsterxyf 已提交
258
func parseConfig(appConfigPath string) (err error) {
259
	AppConfig, err = newAppConfig(appConfigProvider, appConfigPath)
A
astaxie 已提交
260 261 262
	if err != nil {
		return err
	}
J
JessonChan 已提交
263 264 265 266
	return assignConfig(AppConfig)
}

func assignConfig(ac config.Configer) error {
A
astaxie 已提交
267
	for _, i := range []interface{}{BConfig, &BConfig.Listen, &BConfig.WebConfig, &BConfig.Log, &BConfig.WebConfig.Session} {
A
astaxie 已提交
268 269
		assignSingleConfig(i, ac)
	}
270
	// set the run mode first
F
fuxiaohei 已提交
271
	if envRunMode := os.Getenv("BEEGO_RUNMODE"); envRunMode != "" {
A
astaxie 已提交
272
		BConfig.RunMode = envRunMode
J
JessonChan 已提交
273
	} else if runMode := ac.String("RunMode"); runMode != "" {
274
		BConfig.RunMode = runMode
A
astaxie 已提交
275
	}
276

J
JessonChan 已提交
277 278
	if sd := ac.String("StaticDir"); sd != "" {
		BConfig.WebConfig.StaticDir = map[string]string{}
A
astaxie 已提交
279 280 281
		sds := strings.Fields(sd)
		for _, v := range sds {
			if url2fsmap := strings.SplitN(v, ":", 2); len(url2fsmap) == 2 {
282
				BConfig.WebConfig.StaticDir["/"+strings.Trim(url2fsmap[0], "/")] = url2fsmap[1]
A
astaxie 已提交
283
			} else {
284
				BConfig.WebConfig.StaticDir["/"+strings.Trim(url2fsmap[0], "/")] = url2fsmap[0]
285 286
			}
		}
A
astaxie 已提交
287
	}
288

J
JessonChan 已提交
289
	if sgz := ac.String("StaticExtensionsToGzip"); sgz != "" {
A
astaxie 已提交
290
		extensions := strings.Split(sgz, ",")
J
JessonChan 已提交
291
		fileExts := []string{}
J
JessonChan 已提交
292 293 294 295
		for _, ext := range extensions {
			ext = strings.TrimSpace(ext)
			if ext == "" {
				continue
F
Francois 已提交
296
			}
J
JessonChan 已提交
297 298 299
			if !strings.HasPrefix(ext, ".") {
				ext = "." + ext
			}
J
JessonChan 已提交
300 301 302
			fileExts = append(fileExts, ext)
		}
		if len(fileExts) > 0 {
A
astaxie 已提交
303
			BConfig.WebConfig.StaticExtensionsToGzip = fileExts
F
Francois 已提交
304
		}
A
astaxie 已提交
305
	}
Y
youngsterxyf 已提交
306

J
JessonChan 已提交
307
	if lo := ac.String("LogOutputs"); lo != "" {
B
Back 已提交
308 309 310 311
		// 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)
Y
youngsterxyf 已提交
312 313 314 315 316 317 318 319 320 321 322
		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
323
	logs.Reset()
Y
youngsterxyf 已提交
324
	for adaptor, config := range BConfig.Log.Outputs {
J
JessonChan 已提交
325
		err := logs.SetLogger(adaptor, config)
Y
youngsterxyf 已提交
326
		if err != nil {
Y
ysqi 已提交
327
			fmt.Fprintln(os.Stderr, fmt.Sprintf("%s with the config %q got err:%s", adaptor, config, err.Error()))
Y
youngsterxyf 已提交
328 329
		}
	}
330
	logs.SetLogFuncCall(BConfig.Log.FileLineNum)
Y
youngsterxyf 已提交
331

A
astaxie 已提交
332
	return nil
333
}
A
astaxie 已提交
334

J
JessonChan 已提交
335
func assignSingleConfig(p interface{}, ac config.Configer) {
J
JessonChan 已提交
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
	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:
S
Sergey Lanzman 已提交
356
			pf.SetInt(ac.DefaultInt64(name, pf.Int()))
J
JessonChan 已提交
357 358 359 360
		case reflect.Bool:
			pf.SetBool(ac.DefaultBool(name, pf.Bool()))
		case reflect.Struct:
		default:
J
JessonChan 已提交
361
			//do nothing here
J
JessonChan 已提交
362 363 364 365 366
		}
	}

}

Y
youngsterxyf 已提交
367
// LoadAppConfig allow developer to apply a config file
368
func LoadAppConfig(adapterName, configPath string) error {
Y
youngsterxyf 已提交
369 370 371 372
	absConfigPath, err := filepath.Abs(configPath)
	if err != nil {
		return err
	}
Y
youngsterxyf 已提交
373 374

	if !utils.FileExists(absConfigPath) {
A
astaxie 已提交
375
		return fmt.Errorf("the target config file: %s don't exist", configPath)
Y
youngsterxyf 已提交
376 377
	}

378 379
	appConfigPath = absConfigPath
	appConfigProvider = adapterName
Y
youngsterxyf 已提交
380

381
	return parseConfig(appConfigPath)
Y
youngsterxyf 已提交
382 383
}

A
astaxie 已提交
384 385 386 387
type beegoAppConfig struct {
	innerConfig config.Configer
}

388 389
func newAppConfig(appConfigProvider, appConfigPath string) (*beegoAppConfig, error) {
	ac, err := config.NewConfig(appConfigProvider, appConfigPath)
A
astaxie 已提交
390 391 392
	if err != nil {
		return nil, err
	}
F
fuxiaohei 已提交
393
	return &beegoAppConfig{ac}, nil
A
astaxie 已提交
394 395 396
}

func (b *beegoAppConfig) Set(key, val string) error {
F
fuxiaohei 已提交
397
	if err := b.innerConfig.Set(BConfig.RunMode+"::"+key, val); err != nil {
A
astaxie 已提交
398 399 400 401 402 403
		return err
	}
	return b.innerConfig.Set(key, val)
}

func (b *beegoAppConfig) String(key string) string {
F
fuxiaohei 已提交
404 405
	if v := b.innerConfig.String(BConfig.RunMode + "::" + key); v != "" {
		return v
A
astaxie 已提交
406
	}
F
fuxiaohei 已提交
407
	return b.innerConfig.String(key)
A
astaxie 已提交
408 409 410
}

func (b *beegoAppConfig) Strings(key string) []string {
J
JessonChan 已提交
411
	if v := b.innerConfig.Strings(BConfig.RunMode + "::" + key); len(v) > 0 {
F
fud 已提交
412
		return v
A
astaxie 已提交
413
	}
F
fuxiaohei 已提交
414
	return b.innerConfig.Strings(key)
A
astaxie 已提交
415 416 417
}

func (b *beegoAppConfig) Int(key string) (int, error) {
F
fuxiaohei 已提交
418 419
	if v, err := b.innerConfig.Int(BConfig.RunMode + "::" + key); err == nil {
		return v, nil
A
astaxie 已提交
420
	}
F
fuxiaohei 已提交
421
	return b.innerConfig.Int(key)
A
astaxie 已提交
422 423 424
}

func (b *beegoAppConfig) Int64(key string) (int64, error) {
F
fuxiaohei 已提交
425 426
	if v, err := b.innerConfig.Int64(BConfig.RunMode + "::" + key); err == nil {
		return v, nil
A
astaxie 已提交
427
	}
F
fuxiaohei 已提交
428
	return b.innerConfig.Int64(key)
A
astaxie 已提交
429 430 431
}

func (b *beegoAppConfig) Bool(key string) (bool, error) {
F
fuxiaohei 已提交
432 433
	if v, err := b.innerConfig.Bool(BConfig.RunMode + "::" + key); err == nil {
		return v, nil
A
astaxie 已提交
434
	}
F
fuxiaohei 已提交
435
	return b.innerConfig.Bool(key)
A
astaxie 已提交
436 437 438
}

func (b *beegoAppConfig) Float(key string) (float64, error) {
F
fuxiaohei 已提交
439 440
	if v, err := b.innerConfig.Float(BConfig.RunMode + "::" + key); err == nil {
		return v, nil
A
astaxie 已提交
441
	}
F
fuxiaohei 已提交
442
	return b.innerConfig.Float(key)
A
astaxie 已提交
443 444
}

445
func (b *beegoAppConfig) DefaultString(key string, defaultVal string) string {
F
fuxiaohei 已提交
446
	if v := b.String(key); v != "" {
A
astaxie 已提交
447 448
		return v
	}
449
	return defaultVal
A
astaxie 已提交
450 451
}

452
func (b *beegoAppConfig) DefaultStrings(key string, defaultVal []string) []string {
F
fuxiaohei 已提交
453
	if v := b.Strings(key); len(v) != 0 {
A
astaxie 已提交
454 455
		return v
	}
456
	return defaultVal
A
astaxie 已提交
457 458
}

459
func (b *beegoAppConfig) DefaultInt(key string, defaultVal int) int {
F
fuxiaohei 已提交
460
	if v, err := b.Int(key); err == nil {
A
astaxie 已提交
461 462
		return v
	}
463
	return defaultVal
A
astaxie 已提交
464 465
}

466
func (b *beegoAppConfig) DefaultInt64(key string, defaultVal int64) int64 {
F
fuxiaohei 已提交
467
	if v, err := b.Int64(key); err == nil {
A
astaxie 已提交
468 469
		return v
	}
470
	return defaultVal
A
astaxie 已提交
471 472
}

473
func (b *beegoAppConfig) DefaultBool(key string, defaultVal bool) bool {
F
fuxiaohei 已提交
474
	if v, err := b.Bool(key); err == nil {
A
astaxie 已提交
475 476
		return v
	}
477
	return defaultVal
A
astaxie 已提交
478 479
}

480
func (b *beegoAppConfig) DefaultFloat(key string, defaultVal float64) float64 {
F
fuxiaohei 已提交
481
	if v, err := b.Float(key); err == nil {
A
astaxie 已提交
482 483
		return v
	}
484
	return defaultVal
A
astaxie 已提交
485 486 487 488 489 490 491 492 493 494 495 496 497
}

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)
}