config.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. // Copyright 2014 beego Author. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package beego
  15. import (
  16. "fmt"
  17. "os"
  18. "path/filepath"
  19. "reflect"
  20. "runtime"
  21. "strings"
  22. "github.com/astaxie/beego/config"
  23. "github.com/astaxie/beego/context"
  24. "github.com/astaxie/beego/logs"
  25. "github.com/astaxie/beego/session"
  26. "github.com/astaxie/beego/utils"
  27. )
  28. // Config is the main struct for BConfig
  29. type Config struct {
  30. AppName string //Application name
  31. RunMode string //Running Mode: dev | prod
  32. RouterCaseSensitive bool
  33. ServerName string
  34. RecoverPanic bool
  35. RecoverFunc func(*context.Context)
  36. CopyRequestBody bool
  37. EnableGzip bool
  38. MaxMemory int64
  39. EnableErrorsShow bool
  40. EnableErrorsRender bool
  41. Listen Listen
  42. WebConfig WebConfig
  43. Log LogConfig
  44. }
  45. // Listen holds for http and https related config
  46. type Listen struct {
  47. Graceful bool // Graceful means use graceful module to start the server
  48. ServerTimeOut int64
  49. ListenTCP4 bool
  50. EnableHTTP bool
  51. HTTPAddr string
  52. HTTPPort int
  53. EnableHTTPS bool
  54. HTTPSAddr string
  55. HTTPSPort int
  56. HTTPSCertFile string
  57. HTTPSKeyFile string
  58. EnableAdmin bool
  59. AdminAddr string
  60. AdminPort int
  61. EnableFcgi bool
  62. EnableStdIo bool // EnableStdIo works with EnableFcgi Use FCGI via standard I/O
  63. }
  64. // WebConfig holds web related config
  65. type WebConfig struct {
  66. AutoRender bool
  67. EnableDocs bool
  68. FlashName string
  69. FlashSeparator string
  70. DirectoryIndex bool
  71. StaticDir map[string]string
  72. StaticExtensionsToGzip []string
  73. TemplateLeft string
  74. TemplateRight string
  75. ViewsPath string
  76. EnableXSRF bool
  77. XSRFKey string
  78. XSRFExpire int
  79. Session SessionConfig
  80. }
  81. // SessionConfig holds session related config
  82. type SessionConfig struct {
  83. SessionOn bool
  84. SessionProvider string
  85. SessionName string
  86. SessionGCMaxLifetime int64
  87. SessionProviderConfig string
  88. SessionCookieLifeTime int
  89. SessionAutoSetCookie bool
  90. SessionDomain string
  91. SessionDisableHTTPOnly bool // used to allow for cross domain cookies/javascript cookies.
  92. SessionEnableSidInHTTPHeader bool // enable store/get the sessionId into/from http headers
  93. SessionNameInHTTPHeader string
  94. SessionEnableSidInURLQuery bool // enable get the sessionId from Url Query params
  95. }
  96. // LogConfig holds Log related config
  97. type LogConfig struct {
  98. AccessLogs bool
  99. FileLineNum bool
  100. Outputs map[string]string // Store Adaptor : config
  101. }
  102. var (
  103. // BConfig is the default config for Application
  104. BConfig *Config
  105. // AppConfig is the instance of Config, store the config information from file
  106. AppConfig *beegoAppConfig
  107. // AppPath is the absolute path to the app
  108. AppPath string
  109. // GlobalSessions is the instance for the session manager
  110. GlobalSessions *session.Manager
  111. // appConfigPath is the path to the config files
  112. appConfigPath string
  113. // appConfigProvider is the provider for the config, default is ini
  114. appConfigProvider = "ini"
  115. )
  116. func init() {
  117. BConfig = newBConfig()
  118. var err error
  119. if AppPath, err = filepath.Abs(filepath.Dir(os.Args[0])); err != nil {
  120. panic(err)
  121. }
  122. workPath, err := os.Getwd()
  123. if err != nil {
  124. panic(err)
  125. }
  126. appConfigPath = filepath.Join(workPath, "conf", "app.conf")
  127. if !utils.FileExists(appConfigPath) {
  128. appConfigPath = filepath.Join(AppPath, "conf", "app.conf")
  129. if !utils.FileExists(appConfigPath) {
  130. AppConfig = &beegoAppConfig{innerConfig: config.NewFakeConfig()}
  131. return
  132. }
  133. }
  134. if err = parseConfig(appConfigPath); err != nil {
  135. panic(err)
  136. }
  137. }
  138. func recoverPanic(ctx *context.Context) {
  139. if err := recover(); err != nil {
  140. if err == ErrAbort {
  141. return
  142. }
  143. if !BConfig.RecoverPanic {
  144. panic(err)
  145. }
  146. if BConfig.EnableErrorsShow {
  147. if _, ok := ErrorMaps[fmt.Sprint(err)]; ok {
  148. exception(fmt.Sprint(err), ctx)
  149. return
  150. }
  151. }
  152. var stack string
  153. logs.Critical("the request url is ", ctx.Input.URL())
  154. logs.Critical("Handler crashed with error", err)
  155. for i := 1; ; i++ {
  156. _, file, line, ok := runtime.Caller(i)
  157. if !ok {
  158. break
  159. }
  160. logs.Critical(fmt.Sprintf("%s:%d", file, line))
  161. stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
  162. }
  163. if BConfig.RunMode == DEV && BConfig.EnableErrorsRender {
  164. showErr(err, ctx, stack)
  165. }
  166. }
  167. }
  168. func newBConfig() *Config {
  169. return &Config{
  170. AppName: "beego",
  171. RunMode: DEV,
  172. RouterCaseSensitive: true,
  173. ServerName: "beegoServer:" + VERSION,
  174. RecoverPanic: true,
  175. RecoverFunc: recoverPanic,
  176. CopyRequestBody: false,
  177. EnableGzip: false,
  178. MaxMemory: 1 << 26, //64MB
  179. EnableErrorsShow: true,
  180. EnableErrorsRender: true,
  181. Listen: Listen{
  182. Graceful: false,
  183. ServerTimeOut: 0,
  184. ListenTCP4: false,
  185. EnableHTTP: true,
  186. HTTPAddr: "",
  187. HTTPPort: 8080,
  188. EnableHTTPS: false,
  189. HTTPSAddr: "",
  190. HTTPSPort: 10443,
  191. HTTPSCertFile: "",
  192. HTTPSKeyFile: "",
  193. EnableAdmin: false,
  194. AdminAddr: "",
  195. AdminPort: 8088,
  196. EnableFcgi: false,
  197. EnableStdIo: false,
  198. },
  199. WebConfig: WebConfig{
  200. AutoRender: true,
  201. EnableDocs: false,
  202. FlashName: "BEEGO_FLASH",
  203. FlashSeparator: "BEEGOFLASH",
  204. DirectoryIndex: false,
  205. StaticDir: map[string]string{"/static": "static"},
  206. StaticExtensionsToGzip: []string{".css", ".js"},
  207. TemplateLeft: "{{",
  208. TemplateRight: "}}",
  209. ViewsPath: "views",
  210. EnableXSRF: false,
  211. XSRFKey: "beegoxsrf",
  212. XSRFExpire: 0,
  213. Session: SessionConfig{
  214. SessionOn: false,
  215. SessionProvider: "memory",
  216. SessionName: "beegosessionID",
  217. SessionGCMaxLifetime: 3600,
  218. SessionProviderConfig: "",
  219. SessionDisableHTTPOnly: false,
  220. SessionCookieLifeTime: 0, //set cookie default is the browser life
  221. SessionAutoSetCookie: true,
  222. SessionDomain: "",
  223. SessionEnableSidInHTTPHeader: false, // enable store/get the sessionId into/from http headers
  224. SessionNameInHTTPHeader: "Beegosessionid",
  225. SessionEnableSidInURLQuery: false, // enable get the sessionId from Url Query params
  226. },
  227. },
  228. Log: LogConfig{
  229. AccessLogs: false,
  230. FileLineNum: true,
  231. Outputs: map[string]string{"console": ""},
  232. },
  233. }
  234. }
  235. // now only support ini, next will support json.
  236. func parseConfig(appConfigPath string) (err error) {
  237. AppConfig, err = newAppConfig(appConfigProvider, appConfigPath)
  238. if err != nil {
  239. return err
  240. }
  241. return assignConfig(AppConfig)
  242. }
  243. func assignConfig(ac config.Configer) error {
  244. for _, i := range []interface{}{BConfig, &BConfig.Listen, &BConfig.WebConfig, &BConfig.Log, &BConfig.WebConfig.Session} {
  245. assignSingleConfig(i, ac)
  246. }
  247. // set the run mode first
  248. if envRunMode := os.Getenv("BEEGO_RUNMODE"); envRunMode != "" {
  249. BConfig.RunMode = envRunMode
  250. } else if runMode := ac.String("RunMode"); runMode != "" {
  251. BConfig.RunMode = runMode
  252. }
  253. if sd := ac.String("StaticDir"); sd != "" {
  254. BConfig.WebConfig.StaticDir = map[string]string{}
  255. sds := strings.Fields(sd)
  256. for _, v := range sds {
  257. if url2fsmap := strings.SplitN(v, ":", 2); len(url2fsmap) == 2 {
  258. BConfig.WebConfig.StaticDir["/"+strings.Trim(url2fsmap[0], "/")] = url2fsmap[1]
  259. } else {
  260. BConfig.WebConfig.StaticDir["/"+strings.Trim(url2fsmap[0], "/")] = url2fsmap[0]
  261. }
  262. }
  263. }
  264. if sgz := ac.String("StaticExtensionsToGzip"); sgz != "" {
  265. extensions := strings.Split(sgz, ",")
  266. fileExts := []string{}
  267. for _, ext := range extensions {
  268. ext = strings.TrimSpace(ext)
  269. if ext == "" {
  270. continue
  271. }
  272. if !strings.HasPrefix(ext, ".") {
  273. ext = "." + ext
  274. }
  275. fileExts = append(fileExts, ext)
  276. }
  277. if len(fileExts) > 0 {
  278. BConfig.WebConfig.StaticExtensionsToGzip = fileExts
  279. }
  280. }
  281. if lo := ac.String("LogOutputs"); lo != "" {
  282. // if lo is not nil or empty
  283. // means user has set his own LogOutputs
  284. // clear the default setting to BConfig.Log.Outputs
  285. BConfig.Log.Outputs = make(map[string]string)
  286. los := strings.Split(lo, ";")
  287. for _, v := range los {
  288. if logType2Config := strings.SplitN(v, ",", 2); len(logType2Config) == 2 {
  289. BConfig.Log.Outputs[logType2Config[0]] = logType2Config[1]
  290. } else {
  291. continue
  292. }
  293. }
  294. }
  295. //init log
  296. logs.Reset()
  297. for adaptor, config := range BConfig.Log.Outputs {
  298. err := logs.SetLogger(adaptor, config)
  299. if err != nil {
  300. fmt.Fprintln(os.Stderr, fmt.Sprintf("%s with the config %q got err:%s", adaptor, config, err.Error()))
  301. }
  302. }
  303. logs.SetLogFuncCall(BConfig.Log.FileLineNum)
  304. return nil
  305. }
  306. func assignSingleConfig(p interface{}, ac config.Configer) {
  307. pt := reflect.TypeOf(p)
  308. if pt.Kind() != reflect.Ptr {
  309. return
  310. }
  311. pt = pt.Elem()
  312. if pt.Kind() != reflect.Struct {
  313. return
  314. }
  315. pv := reflect.ValueOf(p).Elem()
  316. for i := 0; i < pt.NumField(); i++ {
  317. pf := pv.Field(i)
  318. if !pf.CanSet() {
  319. continue
  320. }
  321. name := pt.Field(i).Name
  322. switch pf.Kind() {
  323. case reflect.String:
  324. pf.SetString(ac.DefaultString(name, pf.String()))
  325. case reflect.Int, reflect.Int64:
  326. pf.SetInt(int64(ac.DefaultInt64(name, pf.Int())))
  327. case reflect.Bool:
  328. pf.SetBool(ac.DefaultBool(name, pf.Bool()))
  329. case reflect.Struct:
  330. default:
  331. //do nothing here
  332. }
  333. }
  334. }
  335. // LoadAppConfig allow developer to apply a config file
  336. func LoadAppConfig(adapterName, configPath string) error {
  337. absConfigPath, err := filepath.Abs(configPath)
  338. if err != nil {
  339. return err
  340. }
  341. if !utils.FileExists(absConfigPath) {
  342. return fmt.Errorf("the target config file: %s don't exist", configPath)
  343. }
  344. appConfigPath = absConfigPath
  345. appConfigProvider = adapterName
  346. return parseConfig(appConfigPath)
  347. }
  348. type beegoAppConfig struct {
  349. innerConfig config.Configer
  350. }
  351. func newAppConfig(appConfigProvider, appConfigPath string) (*beegoAppConfig, error) {
  352. ac, err := config.NewConfig(appConfigProvider, appConfigPath)
  353. if err != nil {
  354. return nil, err
  355. }
  356. return &beegoAppConfig{ac}, nil
  357. }
  358. func (b *beegoAppConfig) Set(key, val string) error {
  359. if err := b.innerConfig.Set(BConfig.RunMode+"::"+key, val); err != nil {
  360. return err
  361. }
  362. return b.innerConfig.Set(key, val)
  363. }
  364. func (b *beegoAppConfig) String(key string) string {
  365. if v := b.innerConfig.String(BConfig.RunMode + "::" + key); v != "" {
  366. return v
  367. }
  368. return b.innerConfig.String(key)
  369. }
  370. func (b *beegoAppConfig) Strings(key string) []string {
  371. if v := b.innerConfig.Strings(BConfig.RunMode + "::" + key); len(v) > 0 {
  372. return v
  373. }
  374. return b.innerConfig.Strings(key)
  375. }
  376. func (b *beegoAppConfig) Int(key string) (int, error) {
  377. if v, err := b.innerConfig.Int(BConfig.RunMode + "::" + key); err == nil {
  378. return v, nil
  379. }
  380. return b.innerConfig.Int(key)
  381. }
  382. func (b *beegoAppConfig) Int64(key string) (int64, error) {
  383. if v, err := b.innerConfig.Int64(BConfig.RunMode + "::" + key); err == nil {
  384. return v, nil
  385. }
  386. return b.innerConfig.Int64(key)
  387. }
  388. func (b *beegoAppConfig) Bool(key string) (bool, error) {
  389. if v, err := b.innerConfig.Bool(BConfig.RunMode + "::" + key); err == nil {
  390. return v, nil
  391. }
  392. return b.innerConfig.Bool(key)
  393. }
  394. func (b *beegoAppConfig) Float(key string) (float64, error) {
  395. if v, err := b.innerConfig.Float(BConfig.RunMode + "::" + key); err == nil {
  396. return v, nil
  397. }
  398. return b.innerConfig.Float(key)
  399. }
  400. func (b *beegoAppConfig) DefaultString(key string, defaultVal string) string {
  401. if v := b.String(key); v != "" {
  402. return v
  403. }
  404. return defaultVal
  405. }
  406. func (b *beegoAppConfig) DefaultStrings(key string, defaultVal []string) []string {
  407. if v := b.Strings(key); len(v) != 0 {
  408. return v
  409. }
  410. return defaultVal
  411. }
  412. func (b *beegoAppConfig) DefaultInt(key string, defaultVal int) int {
  413. if v, err := b.Int(key); err == nil {
  414. return v
  415. }
  416. return defaultVal
  417. }
  418. func (b *beegoAppConfig) DefaultInt64(key string, defaultVal int64) int64 {
  419. if v, err := b.Int64(key); err == nil {
  420. return v
  421. }
  422. return defaultVal
  423. }
  424. func (b *beegoAppConfig) DefaultBool(key string, defaultVal bool) bool {
  425. if v, err := b.Bool(key); err == nil {
  426. return v
  427. }
  428. return defaultVal
  429. }
  430. func (b *beegoAppConfig) DefaultFloat(key string, defaultVal float64) float64 {
  431. if v, err := b.Float(key); err == nil {
  432. return v
  433. }
  434. return defaultVal
  435. }
  436. func (b *beegoAppConfig) DIY(key string) (interface{}, error) {
  437. return b.innerConfig.DIY(key)
  438. }
  439. func (b *beegoAppConfig) GetSection(section string) (map[string]string, error) {
  440. return b.innerConfig.GetSection(section)
  441. }
  442. func (b *beegoAppConfig) SaveConfigFile(filename string) error {
  443. return b.innerConfig.SaveConfigFile(filename)
  444. }