setting.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package setting
  5. import (
  6. "fmt"
  7. "net/url"
  8. "os"
  9. "os/exec"
  10. "path"
  11. "path/filepath"
  12. "runtime"
  13. "strings"
  14. "time"
  15. "github.com/Unknwon/com"
  16. _ "github.com/go-macaron/cache/memcache"
  17. _ "github.com/go-macaron/cache/redis"
  18. "github.com/go-macaron/session"
  19. _ "github.com/go-macaron/session/redis"
  20. "github.com/strk/go-libravatar"
  21. "gopkg.in/ini.v1"
  22. "github.com/gogits/gogs/modules/bindata"
  23. "github.com/gogits/gogs/modules/log"
  24. "github.com/gogits/gogs/modules/user"
  25. )
  26. type Scheme string
  27. const (
  28. HTTP Scheme = "http"
  29. HTTPS Scheme = "https"
  30. FCGI Scheme = "fcgi"
  31. )
  32. type LandingPage string
  33. const (
  34. LANDING_PAGE_HOME LandingPage = "/"
  35. LANDING_PAGE_EXPLORE LandingPage = "/explore"
  36. )
  37. var (
  38. // Build information
  39. BuildTime string
  40. BuildGitHash string
  41. // App settings
  42. AppVer string
  43. AppName string
  44. AppUrl string
  45. AppSubUrl string
  46. AppSubUrlDepth int // Number of slashes
  47. AppPath string
  48. AppDataPath string
  49. // Server settings
  50. Protocol Scheme
  51. Domain string
  52. HttpAddr, HttpPort string
  53. LocalURL string
  54. OfflineMode bool
  55. DisableRouterLog bool
  56. CertFile, KeyFile string
  57. StaticRootPath string
  58. EnableGzip bool
  59. LandingPageUrl LandingPage
  60. SSH struct {
  61. Disabled bool `ini:"DISABLE_SSH"`
  62. StartBuiltinServer bool `ini:"START_SSH_SERVER"`
  63. Domain string `ini:"SSH_DOMAIN"`
  64. Port int `ini:"SSH_PORT"`
  65. ListenPort int `ini:"SSH_LISTEN_PORT"`
  66. RootPath string `ini:"SSH_ROOT_PATH"`
  67. KeyTestPath string `ini:"SSH_KEY_TEST_PATH"`
  68. KeygenPath string `ini:"SSH_KEYGEN_PATH"`
  69. MinimumKeySizeCheck bool `ini:"-"`
  70. MinimumKeySizes map[string]int `ini:"-"`
  71. }
  72. // Security settings
  73. InstallLock bool
  74. SecretKey string
  75. LogInRememberDays int
  76. CookieUserName string
  77. CookieRememberName string
  78. ReverseProxyAuthUser string
  79. // Database settings
  80. UseSQLite3 bool
  81. UseMySQL bool
  82. UsePostgreSQL bool
  83. UseTiDB bool
  84. // Webhook settings
  85. Webhook struct {
  86. QueueLength int
  87. DeliverTimeout int
  88. SkipTLSVerify bool
  89. Types []string
  90. PagingNum int
  91. }
  92. // Repository settings
  93. Repository struct {
  94. AnsiCharset string
  95. ForcePrivate bool
  96. MaxCreationLimit int
  97. PullRequestQueueLength int
  98. }
  99. RepoRootPath string
  100. ScriptType string
  101. // UI settings
  102. UI struct {
  103. ExplorePagingNum int
  104. IssuePagingNum int
  105. FeedMaxCommitNum int
  106. ThemeColorMetaTag string
  107. MaxDisplayFileSize int64
  108. Admin struct {
  109. UserPagingNum int
  110. RepoPagingNum int
  111. NoticePagingNum int
  112. OrgPagingNum int
  113. } `ini:"ui.admin"`
  114. User struct {
  115. RepoPagingNum int
  116. } `ini:"ui.user"`
  117. }
  118. // Markdown sttings
  119. Markdown struct {
  120. EnableHardLineBreak bool
  121. CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"`
  122. }
  123. // Picture settings
  124. AvatarUploadPath string
  125. GravatarSource string
  126. DisableGravatar bool
  127. EnableFederatedAvatar bool
  128. LibravatarService *libravatar.Libravatar
  129. // Log settings
  130. LogRootPath string
  131. LogModes []string
  132. LogConfigs []string
  133. // Attachment settings
  134. AttachmentPath string
  135. AttachmentAllowedTypes string
  136. AttachmentMaxSize int64
  137. AttachmentMaxFiles int
  138. AttachmentEnabled bool
  139. // Time settings
  140. TimeFormat string
  141. // Cache settings
  142. CacheAdapter string
  143. CacheInternal int
  144. CacheConn string
  145. // Session settings
  146. SessionConfig session.Options
  147. CSRFCookieName = "_csrf"
  148. // Cron tasks
  149. Cron struct {
  150. UpdateMirror struct {
  151. Enabled bool
  152. RunAtStart bool
  153. Schedule string
  154. } `ini:"cron.update_mirrors"`
  155. RepoHealthCheck struct {
  156. Enabled bool
  157. RunAtStart bool
  158. Schedule string
  159. Timeout time.Duration
  160. Args []string `delim:" "`
  161. } `ini:"cron.repo_health_check"`
  162. CheckRepoStats struct {
  163. Enabled bool
  164. RunAtStart bool
  165. Schedule string
  166. } `ini:"cron.check_repo_stats"`
  167. }
  168. // Git settings
  169. Git struct {
  170. DisableDiffHighlight bool
  171. MaxGitDiffLines int
  172. MaxGitDiffLineCharacters int
  173. MaxGitDiffFiles int
  174. GcArgs []string `delim:" "`
  175. Timeout struct {
  176. Migrate int
  177. Mirror int
  178. Clone int
  179. Pull int
  180. } `ini:"git.timeout"`
  181. }
  182. // API settings
  183. API struct {
  184. MaxResponseItems int
  185. }
  186. // I18n settings
  187. Langs, Names []string
  188. dateLangs map[string]string
  189. // Highlight settings are loaded in modules/template/hightlight.go
  190. // Other settings
  191. ShowFooterBranding bool
  192. ShowFooterVersion bool
  193. SupportMiniWinService bool
  194. // Global setting objects
  195. Cfg *ini.File
  196. CustomPath string // Custom directory path
  197. CustomConf string
  198. ProdMode bool
  199. RunUser string
  200. IsWindows bool
  201. HasRobotsTxt bool
  202. )
  203. func DateLang(lang string) string {
  204. name, ok := dateLangs[lang]
  205. if ok {
  206. return name
  207. }
  208. return "en"
  209. }
  210. // execPath returns the executable path.
  211. func execPath() (string, error) {
  212. file, err := exec.LookPath(os.Args[0])
  213. if err != nil {
  214. return "", err
  215. }
  216. return filepath.Abs(file)
  217. }
  218. func init() {
  219. IsWindows = runtime.GOOS == "windows"
  220. log.NewLogger(0, "console", `{"level": 0}`)
  221. var err error
  222. if AppPath, err = execPath(); err != nil {
  223. log.Fatal(4, "fail to get app path: %v\n", err)
  224. }
  225. // Note: we don't use path.Dir here because it does not handle case
  226. // which path starts with two "/" in Windows: "//psf/Home/..."
  227. AppPath = strings.Replace(AppPath, "\\", "/", -1)
  228. }
  229. // WorkDir returns absolute path of work directory.
  230. func WorkDir() (string, error) {
  231. wd := os.Getenv("GOGS_WORK_DIR")
  232. if len(wd) > 0 {
  233. return wd, nil
  234. }
  235. i := strings.LastIndex(AppPath, "/")
  236. if i == -1 {
  237. return AppPath, nil
  238. }
  239. return AppPath[:i], nil
  240. }
  241. func forcePathSeparator(path string) {
  242. if strings.Contains(path, "\\") {
  243. log.Fatal(4, "Do not use '\\' or '\\\\' in paths, instead, please use '/' in all places")
  244. }
  245. }
  246. // NewContext initializes configuration context.
  247. // NOTE: do not print any log except error.
  248. func NewContext() {
  249. workDir, err := WorkDir()
  250. if err != nil {
  251. log.Fatal(4, "Fail to get work directory: %v", err)
  252. }
  253. Cfg, err = ini.Load(bindata.MustAsset("conf/app.ini"))
  254. if err != nil {
  255. log.Fatal(4, "Fail to parse 'conf/app.ini': %v", err)
  256. }
  257. CustomPath = os.Getenv("GOGS_CUSTOM")
  258. if len(CustomPath) == 0 {
  259. CustomPath = workDir + "/custom"
  260. }
  261. if len(CustomConf) == 0 {
  262. CustomConf = CustomPath + "/conf/app.ini"
  263. }
  264. if com.IsFile(CustomConf) {
  265. if err = Cfg.Append(CustomConf); err != nil {
  266. log.Fatal(4, "Fail to load custom conf '%s': %v", CustomConf, err)
  267. }
  268. } else {
  269. log.Warn("Custom config '%s' not found, ignore this if you're running first time", CustomConf)
  270. }
  271. Cfg.NameMapper = ini.AllCapsUnderscore
  272. homeDir, err := com.HomeDir()
  273. if err != nil {
  274. log.Fatal(4, "Fail to get home directory: %v", err)
  275. }
  276. homeDir = strings.Replace(homeDir, "\\", "/", -1)
  277. LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(workDir, "log"))
  278. forcePathSeparator(LogRootPath)
  279. sec := Cfg.Section("server")
  280. AppName = Cfg.Section("").Key("APP_NAME").MustString("Gogs: Go Git Service")
  281. AppUrl = sec.Key("ROOT_URL").MustString("http://localhost:3000/")
  282. if AppUrl[len(AppUrl)-1] != '/' {
  283. AppUrl += "/"
  284. }
  285. // Check if has app suburl.
  286. url, err := url.Parse(AppUrl)
  287. if err != nil {
  288. log.Fatal(4, "Invalid ROOT_URL '%s': %s", AppUrl, err)
  289. }
  290. // Suburl should start with '/' and end without '/', such as '/{subpath}'.
  291. // This value is empty if site does not have sub-url.
  292. AppSubUrl = strings.TrimSuffix(url.Path, "/")
  293. AppSubUrlDepth = strings.Count(AppSubUrl, "/")
  294. Protocol = HTTP
  295. if sec.Key("PROTOCOL").String() == "https" {
  296. Protocol = HTTPS
  297. CertFile = sec.Key("CERT_FILE").String()
  298. KeyFile = sec.Key("KEY_FILE").String()
  299. } else if sec.Key("PROTOCOL").String() == "fcgi" {
  300. Protocol = FCGI
  301. }
  302. Domain = sec.Key("DOMAIN").MustString("localhost")
  303. HttpAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0")
  304. HttpPort = sec.Key("HTTP_PORT").MustString("3000")
  305. LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(string(Protocol) + "://localhost:" + HttpPort + "/")
  306. OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
  307. DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool()
  308. StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(workDir)
  309. AppDataPath = sec.Key("APP_DATA_PATH").MustString("data")
  310. EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
  311. switch sec.Key("LANDING_PAGE").MustString("home") {
  312. case "explore":
  313. LandingPageUrl = LANDING_PAGE_EXPLORE
  314. default:
  315. LandingPageUrl = LANDING_PAGE_HOME
  316. }
  317. SSH.RootPath = path.Join(homeDir, ".ssh")
  318. SSH.KeyTestPath = os.TempDir()
  319. if err = Cfg.Section("server").MapTo(&SSH); err != nil {
  320. log.Fatal(4, "Fail to map SSH settings: %v", err)
  321. }
  322. // When disable SSH, start builtin server value is ignored.
  323. if SSH.Disabled {
  324. SSH.StartBuiltinServer = false
  325. }
  326. if !SSH.Disabled && !SSH.StartBuiltinServer {
  327. if err := os.MkdirAll(SSH.RootPath, 0700); err != nil {
  328. log.Fatal(4, "Fail to create '%s': %v", SSH.RootPath, err)
  329. } else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil {
  330. log.Fatal(4, "Fail to create '%s': %v", SSH.KeyTestPath, err)
  331. }
  332. }
  333. SSH.MinimumKeySizeCheck = sec.Key("MINIMUM_KEY_SIZE_CHECK").MustBool()
  334. SSH.MinimumKeySizes = map[string]int{}
  335. minimumKeySizes := Cfg.Section("ssh.minimum_key_sizes").Keys()
  336. for _, key := range minimumKeySizes {
  337. if key.MustInt() != -1 {
  338. SSH.MinimumKeySizes[strings.ToLower(key.Name())] = key.MustInt()
  339. }
  340. }
  341. sec = Cfg.Section("security")
  342. InstallLock = sec.Key("INSTALL_LOCK").MustBool()
  343. SecretKey = sec.Key("SECRET_KEY").String()
  344. LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt()
  345. CookieUserName = sec.Key("COOKIE_USERNAME").String()
  346. CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").String()
  347. ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
  348. sec = Cfg.Section("attachment")
  349. AttachmentPath = sec.Key("PATH").MustString(path.Join(AppDataPath, "attachments"))
  350. if !filepath.IsAbs(AttachmentPath) {
  351. AttachmentPath = path.Join(workDir, AttachmentPath)
  352. }
  353. AttachmentAllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png"), "|", ",", -1)
  354. AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(4)
  355. AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(5)
  356. AttachmentEnabled = sec.Key("ENABLE").MustBool(true)
  357. TimeFormat = map[string]string{
  358. "ANSIC": time.ANSIC,
  359. "UnixDate": time.UnixDate,
  360. "RubyDate": time.RubyDate,
  361. "RFC822": time.RFC822,
  362. "RFC822Z": time.RFC822Z,
  363. "RFC850": time.RFC850,
  364. "RFC1123": time.RFC1123,
  365. "RFC1123Z": time.RFC1123Z,
  366. "RFC3339": time.RFC3339,
  367. "RFC3339Nano": time.RFC3339Nano,
  368. "Kitchen": time.Kitchen,
  369. "Stamp": time.Stamp,
  370. "StampMilli": time.StampMilli,
  371. "StampMicro": time.StampMicro,
  372. "StampNano": time.StampNano,
  373. }[Cfg.Section("time").Key("FORMAT").MustString("RFC1123")]
  374. RunUser = Cfg.Section("").Key("RUN_USER").String()
  375. curUser := user.CurrentUsername()
  376. // Does not check run user when the install lock is off.
  377. if InstallLock && RunUser != curUser {
  378. log.Fatal(4, "Expect user(%s) but current user is: %s", RunUser, curUser)
  379. }
  380. // Determine and create root git repository path.
  381. sec = Cfg.Section("repository")
  382. RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gogs-repositories"))
  383. forcePathSeparator(RepoRootPath)
  384. if !filepath.IsAbs(RepoRootPath) {
  385. RepoRootPath = path.Join(workDir, RepoRootPath)
  386. } else {
  387. RepoRootPath = path.Clean(RepoRootPath)
  388. }
  389. ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash")
  390. if err = Cfg.Section("repository").MapTo(&Repository); err != nil {
  391. log.Fatal(4, "Fail to map Repository settings: %v", err)
  392. }
  393. sec = Cfg.Section("picture")
  394. AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString(path.Join(AppDataPath, "avatars"))
  395. forcePathSeparator(AvatarUploadPath)
  396. if !filepath.IsAbs(AvatarUploadPath) {
  397. AvatarUploadPath = path.Join(workDir, AvatarUploadPath)
  398. }
  399. switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source {
  400. case "duoshuo":
  401. GravatarSource = "http://gravatar.duoshuo.com/avatar/"
  402. case "gravatar":
  403. GravatarSource = "https://secure.gravatar.com/avatar/"
  404. default:
  405. GravatarSource = source
  406. }
  407. DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool()
  408. EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool()
  409. if OfflineMode {
  410. DisableGravatar = true
  411. EnableFederatedAvatar = false
  412. }
  413. if DisableGravatar {
  414. EnableFederatedAvatar = false
  415. }
  416. if EnableFederatedAvatar {
  417. LibravatarService = libravatar.New()
  418. parts := strings.Split(GravatarSource, "/")
  419. if len(parts) >= 3 {
  420. if parts[0] == "https:" {
  421. LibravatarService.SetUseHTTPS(true)
  422. LibravatarService.SetSecureFallbackHost(parts[2])
  423. } else {
  424. LibravatarService.SetUseHTTPS(false)
  425. LibravatarService.SetFallbackHost(parts[2])
  426. }
  427. }
  428. }
  429. if err = Cfg.Section("ui").MapTo(&UI); err != nil {
  430. log.Fatal(4, "Fail to map UI settings: %v", err)
  431. } else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil {
  432. log.Fatal(4, "Fail to map Markdown settings: %v", err)
  433. } else if err = Cfg.Section("cron").MapTo(&Cron); err != nil {
  434. log.Fatal(4, "Fail to map Cron settings: %v", err)
  435. } else if err = Cfg.Section("git").MapTo(&Git); err != nil {
  436. log.Fatal(4, "Fail to map Git settings: %v", err)
  437. } else if err = Cfg.Section("api").MapTo(&API); err != nil {
  438. log.Fatal(4, "Fail to map API settings: %v", err)
  439. }
  440. Langs = Cfg.Section("i18n").Key("LANGS").Strings(",")
  441. Names = Cfg.Section("i18n").Key("NAMES").Strings(",")
  442. dateLangs = Cfg.Section("i18n.datelang").KeysHash()
  443. ShowFooterBranding = Cfg.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool()
  444. ShowFooterVersion = Cfg.Section("other").Key("SHOW_FOOTER_VERSION").MustBool()
  445. HasRobotsTxt = com.IsFile(path.Join(CustomPath, "robots.txt"))
  446. }
  447. var Service struct {
  448. ActiveCodeLives int
  449. ResetPwdCodeLives int
  450. RegisterEmailConfirm bool
  451. DisableRegistration bool
  452. ShowRegistrationButton bool
  453. RequireSignInView bool
  454. EnableNotifyMail bool
  455. EnableReverseProxyAuth bool
  456. EnableReverseProxyAutoRegister bool
  457. EnableCaptcha bool
  458. }
  459. func newService() {
  460. sec := Cfg.Section("service")
  461. Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180)
  462. Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180)
  463. Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool()
  464. Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!Service.DisableRegistration)
  465. Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
  466. Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool()
  467. Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool()
  468. Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool()
  469. }
  470. var logLevels = map[string]string{
  471. "Trace": "0",
  472. "Debug": "1",
  473. "Info": "2",
  474. "Warn": "3",
  475. "Error": "4",
  476. "Critical": "5",
  477. }
  478. func newLogService() {
  479. log.Info("%s %s", AppName, AppVer)
  480. if len(BuildTime) > 0 {
  481. log.Info("Build Time: %s", BuildTime)
  482. log.Info("Build Git Hash: %s", BuildGitHash)
  483. }
  484. // Get and check log mode.
  485. LogModes = strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",")
  486. LogConfigs = make([]string, len(LogModes))
  487. for i, mode := range LogModes {
  488. mode = strings.TrimSpace(mode)
  489. sec, err := Cfg.GetSection("log." + mode)
  490. if err != nil {
  491. log.Fatal(4, "Unknown log mode: %s", mode)
  492. }
  493. validLevels := []string{"Trace", "Debug", "Info", "Warn", "Error", "Critical"}
  494. // Log level.
  495. levelName := Cfg.Section("log."+mode).Key("LEVEL").In(
  496. Cfg.Section("log").Key("LEVEL").In("Trace", validLevels),
  497. validLevels)
  498. level, ok := logLevels[levelName]
  499. if !ok {
  500. log.Fatal(4, "Unknown log level: %s", levelName)
  501. }
  502. // Generate log configuration.
  503. switch mode {
  504. case "console":
  505. LogConfigs[i] = fmt.Sprintf(`{"level":%s}`, level)
  506. case "file":
  507. logPath := sec.Key("FILE_NAME").MustString(path.Join(LogRootPath, "gogs.log"))
  508. if err = os.MkdirAll(path.Dir(logPath), os.ModePerm); err != nil {
  509. panic(err.Error())
  510. }
  511. LogConfigs[i] = fmt.Sprintf(
  512. `{"level":%s,"filename":"%s","rotate":%v,"maxlines":%d,"maxsize":%d,"daily":%v,"maxdays":%d}`, level,
  513. logPath,
  514. sec.Key("LOG_ROTATE").MustBool(true),
  515. sec.Key("MAX_LINES").MustInt(1000000),
  516. 1<<uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)),
  517. sec.Key("DAILY_ROTATE").MustBool(true),
  518. sec.Key("MAX_DAYS").MustInt(7))
  519. case "conn":
  520. LogConfigs[i] = fmt.Sprintf(`{"level":%s,"reconnectOnMsg":%v,"reconnect":%v,"net":"%s","addr":"%s"}`, level,
  521. sec.Key("RECONNECT_ON_MSG").MustBool(),
  522. sec.Key("RECONNECT").MustBool(),
  523. sec.Key("PROTOCOL").In("tcp", []string{"tcp", "unix", "udp"}),
  524. sec.Key("ADDR").MustString(":7020"))
  525. case "smtp":
  526. LogConfigs[i] = fmt.Sprintf(`{"level":%s,"username":"%s","password":"%s","host":"%s","sendTos":"%s","subject":"%s"}`, level,
  527. sec.Key("USER").MustString("example@example.com"),
  528. sec.Key("PASSWD").MustString("******"),
  529. sec.Key("HOST").MustString("127.0.0.1:25"),
  530. sec.Key("RECEIVERS").MustString("[]"),
  531. sec.Key("SUBJECT").MustString("Diagnostic message from serve"))
  532. case "database":
  533. LogConfigs[i] = fmt.Sprintf(`{"level":%s,"driver":"%s","conn":"%s"}`, level,
  534. sec.Key("DRIVER").String(),
  535. sec.Key("CONN").String())
  536. }
  537. log.NewLogger(Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000), mode, LogConfigs[i])
  538. log.Info("Log Mode: %s(%s)", strings.Title(mode), levelName)
  539. }
  540. }
  541. func newCacheService() {
  542. CacheAdapter = Cfg.Section("cache").Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"})
  543. switch CacheAdapter {
  544. case "memory":
  545. CacheInternal = Cfg.Section("cache").Key("INTERVAL").MustInt(60)
  546. case "redis", "memcache":
  547. CacheConn = strings.Trim(Cfg.Section("cache").Key("HOST").String(), "\" ")
  548. default:
  549. log.Fatal(4, "Unknown cache adapter: %s", CacheAdapter)
  550. }
  551. log.Info("Cache Service Enabled")
  552. }
  553. func newSessionService() {
  554. SessionConfig.Provider = Cfg.Section("session").Key("PROVIDER").In("memory",
  555. []string{"memory", "file", "redis", "mysql"})
  556. SessionConfig.ProviderConfig = strings.Trim(Cfg.Section("session").Key("PROVIDER_CONFIG").String(), "\" ")
  557. SessionConfig.CookieName = Cfg.Section("session").Key("COOKIE_NAME").MustString("i_like_gogits")
  558. SessionConfig.CookiePath = AppSubUrl
  559. SessionConfig.Secure = Cfg.Section("session").Key("COOKIE_SECURE").MustBool()
  560. SessionConfig.Gclifetime = Cfg.Section("session").Key("GC_INTERVAL_TIME").MustInt64(86400)
  561. SessionConfig.Maxlifetime = Cfg.Section("session").Key("SESSION_LIFE_TIME").MustInt64(86400)
  562. log.Info("Session Service Enabled")
  563. }
  564. // Mailer represents mail service.
  565. type Mailer struct {
  566. QueueLength int
  567. Name string
  568. Host string
  569. From string
  570. User, Passwd string
  571. DisableHelo bool
  572. HeloHostname string
  573. SkipVerify bool
  574. UseCertificate bool
  575. CertFile, KeyFile string
  576. EnableHTMLAlternative bool
  577. }
  578. var (
  579. MailService *Mailer
  580. )
  581. func newMailService() {
  582. sec := Cfg.Section("mailer")
  583. // Check mailer setting.
  584. if !sec.Key("ENABLED").MustBool() {
  585. return
  586. }
  587. MailService = &Mailer{
  588. QueueLength: sec.Key("SEND_BUFFER_LEN").MustInt(100),
  589. Name: sec.Key("NAME").MustString(AppName),
  590. Host: sec.Key("HOST").String(),
  591. User: sec.Key("USER").String(),
  592. Passwd: sec.Key("PASSWD").String(),
  593. DisableHelo: sec.Key("DISABLE_HELO").MustBool(),
  594. HeloHostname: sec.Key("HELO_HOSTNAME").String(),
  595. SkipVerify: sec.Key("SKIP_VERIFY").MustBool(),
  596. UseCertificate: sec.Key("USE_CERTIFICATE").MustBool(),
  597. CertFile: sec.Key("CERT_FILE").String(),
  598. KeyFile: sec.Key("KEY_FILE").String(),
  599. EnableHTMLAlternative: sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(),
  600. }
  601. MailService.From = sec.Key("FROM").MustString(MailService.User)
  602. log.Info("Mail Service Enabled")
  603. }
  604. func newRegisterMailService() {
  605. if !Cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() {
  606. return
  607. } else if MailService == nil {
  608. log.Warn("Register Mail Service: Mail Service is not enabled")
  609. return
  610. }
  611. Service.RegisterEmailConfirm = true
  612. log.Info("Register Mail Service Enabled")
  613. }
  614. func newNotifyMailService() {
  615. if !Cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() {
  616. return
  617. } else if MailService == nil {
  618. log.Warn("Notify Mail Service: Mail Service is not enabled")
  619. return
  620. }
  621. Service.EnableNotifyMail = true
  622. log.Info("Notify Mail Service Enabled")
  623. }
  624. func newWebhookService() {
  625. sec := Cfg.Section("webhook")
  626. Webhook.QueueLength = sec.Key("QUEUE_LENGTH").MustInt(1000)
  627. Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5)
  628. Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool()
  629. Webhook.Types = []string{"gogs", "slack"}
  630. Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10)
  631. }
  632. func NewServices() {
  633. newService()
  634. newLogService()
  635. newCacheService()
  636. newSessionService()
  637. newMailService()
  638. newRegisterMailService()
  639. newNotifyMailService()
  640. newWebhookService()
  641. }