setting.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  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. CacheInterval 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. GC int `ini:"GC"`
  181. } `ini:"git.timeout"`
  182. }
  183. // Mirror settings
  184. Mirror struct {
  185. DefaultInterval int
  186. }
  187. // API settings
  188. API struct {
  189. MaxResponseItems int
  190. }
  191. // I18n settings
  192. Langs, Names []string
  193. dateLangs map[string]string
  194. // Highlight settings are loaded in modules/template/hightlight.go
  195. // Other settings
  196. ShowFooterBranding bool
  197. ShowFooterVersion bool
  198. SupportMiniWinService bool
  199. // Global setting objects
  200. Cfg *ini.File
  201. CustomPath string // Custom directory path
  202. CustomConf string
  203. ProdMode bool
  204. RunUser string
  205. IsWindows bool
  206. HasRobotsTxt bool
  207. )
  208. func DateLang(lang string) string {
  209. name, ok := dateLangs[lang]
  210. if ok {
  211. return name
  212. }
  213. return "en"
  214. }
  215. // execPath returns the executable path.
  216. func execPath() (string, error) {
  217. file, err := exec.LookPath(os.Args[0])
  218. if err != nil {
  219. return "", err
  220. }
  221. return filepath.Abs(file)
  222. }
  223. func init() {
  224. IsWindows = runtime.GOOS == "windows"
  225. log.NewLogger(0, "console", `{"level": 0}`)
  226. var err error
  227. if AppPath, err = execPath(); err != nil {
  228. log.Fatal(4, "fail to get app path: %v\n", err)
  229. }
  230. // Note: we don't use path.Dir here because it does not handle case
  231. // which path starts with two "/" in Windows: "//psf/Home/..."
  232. AppPath = strings.Replace(AppPath, "\\", "/", -1)
  233. }
  234. // WorkDir returns absolute path of work directory.
  235. func WorkDir() (string, error) {
  236. wd := os.Getenv("GOGS_WORK_DIR")
  237. if len(wd) > 0 {
  238. return wd, nil
  239. }
  240. i := strings.LastIndex(AppPath, "/")
  241. if i == -1 {
  242. return AppPath, nil
  243. }
  244. return AppPath[:i], nil
  245. }
  246. func forcePathSeparator(path string) {
  247. if strings.Contains(path, "\\") {
  248. log.Fatal(4, "Do not use '\\' or '\\\\' in paths, instead, please use '/' in all places")
  249. }
  250. }
  251. // IsRunUserMatchCurrentUser returns false if configured run user does not match
  252. // actual user that runs the app. The first return value is the actual user name.
  253. // This check is ignored under Windows since SSH remote login is not the main
  254. // method to login on Windows.
  255. func IsRunUserMatchCurrentUser(runUser string) (string, bool) {
  256. if IsWindows {
  257. return "", true
  258. }
  259. currentUser := user.CurrentUsername()
  260. return currentUser, runUser == currentUser
  261. }
  262. // NewContext initializes configuration context.
  263. // NOTE: do not print any log except error.
  264. func NewContext() {
  265. workDir, err := WorkDir()
  266. if err != nil {
  267. log.Fatal(4, "Fail to get work directory: %v", err)
  268. }
  269. Cfg, err = ini.Load(bindata.MustAsset("conf/app.ini"))
  270. if err != nil {
  271. log.Fatal(4, "Fail to parse 'conf/app.ini': %v", err)
  272. }
  273. CustomPath = os.Getenv("GOGS_CUSTOM")
  274. if len(CustomPath) == 0 {
  275. CustomPath = workDir + "/custom"
  276. }
  277. if len(CustomConf) == 0 {
  278. CustomConf = CustomPath + "/conf/app.ini"
  279. }
  280. if com.IsFile(CustomConf) {
  281. if err = Cfg.Append(CustomConf); err != nil {
  282. log.Fatal(4, "Fail to load custom conf '%s': %v", CustomConf, err)
  283. }
  284. } else {
  285. log.Warn("Custom config '%s' not found, ignore this if you're running first time", CustomConf)
  286. }
  287. Cfg.NameMapper = ini.AllCapsUnderscore
  288. homeDir, err := com.HomeDir()
  289. if err != nil {
  290. log.Fatal(4, "Fail to get home directory: %v", err)
  291. }
  292. homeDir = strings.Replace(homeDir, "\\", "/", -1)
  293. LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(workDir, "log"))
  294. forcePathSeparator(LogRootPath)
  295. sec := Cfg.Section("server")
  296. AppName = Cfg.Section("").Key("APP_NAME").MustString("Gogs: Go Git Service")
  297. AppUrl = sec.Key("ROOT_URL").MustString("http://localhost:3000/")
  298. if AppUrl[len(AppUrl)-1] != '/' {
  299. AppUrl += "/"
  300. }
  301. // Check if has app suburl.
  302. url, err := url.Parse(AppUrl)
  303. if err != nil {
  304. log.Fatal(4, "Invalid ROOT_URL '%s': %s", AppUrl, err)
  305. }
  306. // Suburl should start with '/' and end without '/', such as '/{subpath}'.
  307. // This value is empty if site does not have sub-url.
  308. AppSubUrl = strings.TrimSuffix(url.Path, "/")
  309. AppSubUrlDepth = strings.Count(AppSubUrl, "/")
  310. Protocol = HTTP
  311. if sec.Key("PROTOCOL").String() == "https" {
  312. Protocol = HTTPS
  313. CertFile = sec.Key("CERT_FILE").String()
  314. KeyFile = sec.Key("KEY_FILE").String()
  315. } else if sec.Key("PROTOCOL").String() == "fcgi" {
  316. Protocol = FCGI
  317. }
  318. Domain = sec.Key("DOMAIN").MustString("localhost")
  319. HttpAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0")
  320. HttpPort = sec.Key("HTTP_PORT").MustString("3000")
  321. LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(string(Protocol) + "://localhost:" + HttpPort + "/")
  322. OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
  323. DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool()
  324. StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(workDir)
  325. AppDataPath = sec.Key("APP_DATA_PATH").MustString("data")
  326. EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
  327. switch sec.Key("LANDING_PAGE").MustString("home") {
  328. case "explore":
  329. LandingPageUrl = LANDING_PAGE_EXPLORE
  330. default:
  331. LandingPageUrl = LANDING_PAGE_HOME
  332. }
  333. SSH.RootPath = path.Join(homeDir, ".ssh")
  334. SSH.KeyTestPath = os.TempDir()
  335. if err = Cfg.Section("server").MapTo(&SSH); err != nil {
  336. log.Fatal(4, "Fail to map SSH settings: %v", err)
  337. }
  338. // When disable SSH, start builtin server value is ignored.
  339. if SSH.Disabled {
  340. SSH.StartBuiltinServer = false
  341. }
  342. if !SSH.Disabled && !SSH.StartBuiltinServer {
  343. if err := os.MkdirAll(SSH.RootPath, 0700); err != nil {
  344. log.Fatal(4, "Fail to create '%s': %v", SSH.RootPath, err)
  345. } else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil {
  346. log.Fatal(4, "Fail to create '%s': %v", SSH.KeyTestPath, err)
  347. }
  348. }
  349. SSH.MinimumKeySizeCheck = sec.Key("MINIMUM_KEY_SIZE_CHECK").MustBool()
  350. SSH.MinimumKeySizes = map[string]int{}
  351. minimumKeySizes := Cfg.Section("ssh.minimum_key_sizes").Keys()
  352. for _, key := range minimumKeySizes {
  353. if key.MustInt() != -1 {
  354. SSH.MinimumKeySizes[strings.ToLower(key.Name())] = key.MustInt()
  355. }
  356. }
  357. sec = Cfg.Section("security")
  358. InstallLock = sec.Key("INSTALL_LOCK").MustBool()
  359. SecretKey = sec.Key("SECRET_KEY").String()
  360. LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt()
  361. CookieUserName = sec.Key("COOKIE_USERNAME").String()
  362. CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").String()
  363. ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
  364. sec = Cfg.Section("attachment")
  365. AttachmentPath = sec.Key("PATH").MustString(path.Join(AppDataPath, "attachments"))
  366. if !filepath.IsAbs(AttachmentPath) {
  367. AttachmentPath = path.Join(workDir, AttachmentPath)
  368. }
  369. AttachmentAllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png"), "|", ",", -1)
  370. AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(4)
  371. AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(5)
  372. AttachmentEnabled = sec.Key("ENABLE").MustBool(true)
  373. TimeFormat = map[string]string{
  374. "ANSIC": time.ANSIC,
  375. "UnixDate": time.UnixDate,
  376. "RubyDate": time.RubyDate,
  377. "RFC822": time.RFC822,
  378. "RFC822Z": time.RFC822Z,
  379. "RFC850": time.RFC850,
  380. "RFC1123": time.RFC1123,
  381. "RFC1123Z": time.RFC1123Z,
  382. "RFC3339": time.RFC3339,
  383. "RFC3339Nano": time.RFC3339Nano,
  384. "Kitchen": time.Kitchen,
  385. "Stamp": time.Stamp,
  386. "StampMilli": time.StampMilli,
  387. "StampMicro": time.StampMicro,
  388. "StampNano": time.StampNano,
  389. }[Cfg.Section("time").Key("FORMAT").MustString("RFC1123")]
  390. RunUser = Cfg.Section("").Key("RUN_USER").String()
  391. // Does not check run user when the install lock is off.
  392. if InstallLock {
  393. currentUser, match := IsRunUserMatchCurrentUser(RunUser)
  394. if !match {
  395. log.Fatal(4, "Expect user '%s' but current user is: %s", RunUser, currentUser)
  396. }
  397. }
  398. // Determine and create root git repository path.
  399. sec = Cfg.Section("repository")
  400. RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gogs-repositories"))
  401. forcePathSeparator(RepoRootPath)
  402. if !filepath.IsAbs(RepoRootPath) {
  403. RepoRootPath = path.Join(workDir, RepoRootPath)
  404. } else {
  405. RepoRootPath = path.Clean(RepoRootPath)
  406. }
  407. ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash")
  408. if err = Cfg.Section("repository").MapTo(&Repository); err != nil {
  409. log.Fatal(4, "Fail to map Repository settings: %v", err)
  410. }
  411. sec = Cfg.Section("picture")
  412. AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString(path.Join(AppDataPath, "avatars"))
  413. forcePathSeparator(AvatarUploadPath)
  414. if !filepath.IsAbs(AvatarUploadPath) {
  415. AvatarUploadPath = path.Join(workDir, AvatarUploadPath)
  416. }
  417. switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source {
  418. case "duoshuo":
  419. GravatarSource = "http://gravatar.duoshuo.com/avatar/"
  420. case "gravatar":
  421. GravatarSource = "https://secure.gravatar.com/avatar/"
  422. default:
  423. GravatarSource = source
  424. }
  425. DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool()
  426. EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool()
  427. if OfflineMode {
  428. DisableGravatar = true
  429. EnableFederatedAvatar = false
  430. }
  431. if DisableGravatar {
  432. EnableFederatedAvatar = false
  433. }
  434. if EnableFederatedAvatar {
  435. LibravatarService = libravatar.New()
  436. parts := strings.Split(GravatarSource, "/")
  437. if len(parts) >= 3 {
  438. if parts[0] == "https:" {
  439. LibravatarService.SetUseHTTPS(true)
  440. LibravatarService.SetSecureFallbackHost(parts[2])
  441. } else {
  442. LibravatarService.SetUseHTTPS(false)
  443. LibravatarService.SetFallbackHost(parts[2])
  444. }
  445. }
  446. }
  447. if err = Cfg.Section("ui").MapTo(&UI); err != nil {
  448. log.Fatal(4, "Fail to map UI settings: %v", err)
  449. } else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil {
  450. log.Fatal(4, "Fail to map Markdown settings: %v", err)
  451. } else if err = Cfg.Section("cron").MapTo(&Cron); err != nil {
  452. log.Fatal(4, "Fail to map Cron settings: %v", err)
  453. } else if err = Cfg.Section("git").MapTo(&Git); err != nil {
  454. log.Fatal(4, "Fail to map Git settings: %v", err)
  455. } else if err = Cfg.Section("mirror").MapTo(&Mirror); err != nil {
  456. log.Fatal(4, "Fail to map API settings: %v", err)
  457. } else if err = Cfg.Section("api").MapTo(&API); err != nil {
  458. log.Fatal(4, "Fail to map API settings: %v", err)
  459. }
  460. if Mirror.DefaultInterval <= 0 {
  461. Mirror.DefaultInterval = 24
  462. }
  463. Langs = Cfg.Section("i18n").Key("LANGS").Strings(",")
  464. Names = Cfg.Section("i18n").Key("NAMES").Strings(",")
  465. dateLangs = Cfg.Section("i18n.datelang").KeysHash()
  466. ShowFooterBranding = Cfg.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool()
  467. ShowFooterVersion = Cfg.Section("other").Key("SHOW_FOOTER_VERSION").MustBool()
  468. HasRobotsTxt = com.IsFile(path.Join(CustomPath, "robots.txt"))
  469. }
  470. var Service struct {
  471. ActiveCodeLives int
  472. ResetPwdCodeLives int
  473. RegisterEmailConfirm bool
  474. DisableRegistration bool
  475. ShowRegistrationButton bool
  476. RequireSignInView bool
  477. EnableNotifyMail bool
  478. EnableReverseProxyAuth bool
  479. EnableReverseProxyAutoRegister bool
  480. EnableCaptcha bool
  481. }
  482. func newService() {
  483. sec := Cfg.Section("service")
  484. Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180)
  485. Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180)
  486. Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool()
  487. Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!Service.DisableRegistration)
  488. Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
  489. Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool()
  490. Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool()
  491. Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool()
  492. }
  493. var logLevels = map[string]string{
  494. "Trace": "0",
  495. "Debug": "1",
  496. "Info": "2",
  497. "Warn": "3",
  498. "Error": "4",
  499. "Critical": "5",
  500. }
  501. func newLogService() {
  502. log.Info("%s %s", AppName, AppVer)
  503. if len(BuildTime) > 0 {
  504. log.Info("Build Time: %s", BuildTime)
  505. log.Info("Build Git Hash: %s", BuildGitHash)
  506. }
  507. // Get and check log mode.
  508. LogModes = strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",")
  509. LogConfigs = make([]string, len(LogModes))
  510. for i, mode := range LogModes {
  511. mode = strings.TrimSpace(mode)
  512. sec, err := Cfg.GetSection("log." + mode)
  513. if err != nil {
  514. log.Fatal(4, "Unknown log mode: %s", mode)
  515. }
  516. validLevels := []string{"Trace", "Debug", "Info", "Warn", "Error", "Critical"}
  517. // Log level.
  518. levelName := Cfg.Section("log."+mode).Key("LEVEL").In(
  519. Cfg.Section("log").Key("LEVEL").In("Trace", validLevels),
  520. validLevels)
  521. level, ok := logLevels[levelName]
  522. if !ok {
  523. log.Fatal(4, "Unknown log level: %s", levelName)
  524. }
  525. // Generate log configuration.
  526. switch mode {
  527. case "console":
  528. LogConfigs[i] = fmt.Sprintf(`{"level":%s}`, level)
  529. case "file":
  530. logPath := sec.Key("FILE_NAME").MustString(path.Join(LogRootPath, "gogs.log"))
  531. if err = os.MkdirAll(path.Dir(logPath), os.ModePerm); err != nil {
  532. panic(err.Error())
  533. }
  534. LogConfigs[i] = fmt.Sprintf(
  535. `{"level":%s,"filename":"%s","rotate":%v,"maxlines":%d,"maxsize":%d,"daily":%v,"maxdays":%d}`, level,
  536. logPath,
  537. sec.Key("LOG_ROTATE").MustBool(true),
  538. sec.Key("MAX_LINES").MustInt(1000000),
  539. 1<<uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)),
  540. sec.Key("DAILY_ROTATE").MustBool(true),
  541. sec.Key("MAX_DAYS").MustInt(7))
  542. case "conn":
  543. LogConfigs[i] = fmt.Sprintf(`{"level":%s,"reconnectOnMsg":%v,"reconnect":%v,"net":"%s","addr":"%s"}`, level,
  544. sec.Key("RECONNECT_ON_MSG").MustBool(),
  545. sec.Key("RECONNECT").MustBool(),
  546. sec.Key("PROTOCOL").In("tcp", []string{"tcp", "unix", "udp"}),
  547. sec.Key("ADDR").MustString(":7020"))
  548. case "smtp":
  549. LogConfigs[i] = fmt.Sprintf(`{"level":%s,"username":"%s","password":"%s","host":"%s","sendTos":"%s","subject":"%s"}`, level,
  550. sec.Key("USER").MustString("example@example.com"),
  551. sec.Key("PASSWD").MustString("******"),
  552. sec.Key("HOST").MustString("127.0.0.1:25"),
  553. sec.Key("RECEIVERS").MustString("[]"),
  554. sec.Key("SUBJECT").MustString("Diagnostic message from serve"))
  555. case "database":
  556. LogConfigs[i] = fmt.Sprintf(`{"level":%s,"driver":"%s","conn":"%s"}`, level,
  557. sec.Key("DRIVER").String(),
  558. sec.Key("CONN").String())
  559. }
  560. log.NewLogger(Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000), mode, LogConfigs[i])
  561. log.Info("Log Mode: %s(%s)", strings.Title(mode), levelName)
  562. }
  563. }
  564. func newCacheService() {
  565. CacheAdapter = Cfg.Section("cache").Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"})
  566. switch CacheAdapter {
  567. case "memory":
  568. CacheInterval = Cfg.Section("cache").Key("INTERVAL").MustInt(60)
  569. case "redis", "memcache":
  570. CacheConn = strings.Trim(Cfg.Section("cache").Key("HOST").String(), "\" ")
  571. default:
  572. log.Fatal(4, "Unknown cache adapter: %s", CacheAdapter)
  573. }
  574. log.Info("Cache Service Enabled")
  575. }
  576. func newSessionService() {
  577. SessionConfig.Provider = Cfg.Section("session").Key("PROVIDER").In("memory",
  578. []string{"memory", "file", "redis", "mysql"})
  579. SessionConfig.ProviderConfig = strings.Trim(Cfg.Section("session").Key("PROVIDER_CONFIG").String(), "\" ")
  580. SessionConfig.CookieName = Cfg.Section("session").Key("COOKIE_NAME").MustString("i_like_gogits")
  581. SessionConfig.CookiePath = AppSubUrl
  582. SessionConfig.Secure = Cfg.Section("session").Key("COOKIE_SECURE").MustBool()
  583. SessionConfig.Gclifetime = Cfg.Section("session").Key("GC_INTERVAL_TIME").MustInt64(86400)
  584. SessionConfig.Maxlifetime = Cfg.Section("session").Key("SESSION_LIFE_TIME").MustInt64(86400)
  585. log.Info("Session Service Enabled")
  586. }
  587. // Mailer represents mail service.
  588. type Mailer struct {
  589. QueueLength int
  590. Name string
  591. Host string
  592. From string
  593. User, Passwd string
  594. DisableHelo bool
  595. HeloHostname string
  596. SkipVerify bool
  597. UseCertificate bool
  598. CertFile, KeyFile string
  599. EnableHTMLAlternative bool
  600. }
  601. var (
  602. MailService *Mailer
  603. )
  604. func newMailService() {
  605. sec := Cfg.Section("mailer")
  606. // Check mailer setting.
  607. if !sec.Key("ENABLED").MustBool() {
  608. return
  609. }
  610. MailService = &Mailer{
  611. QueueLength: sec.Key("SEND_BUFFER_LEN").MustInt(100),
  612. Name: sec.Key("NAME").MustString(AppName),
  613. Host: sec.Key("HOST").String(),
  614. User: sec.Key("USER").String(),
  615. Passwd: sec.Key("PASSWD").String(),
  616. DisableHelo: sec.Key("DISABLE_HELO").MustBool(),
  617. HeloHostname: sec.Key("HELO_HOSTNAME").String(),
  618. SkipVerify: sec.Key("SKIP_VERIFY").MustBool(),
  619. UseCertificate: sec.Key("USE_CERTIFICATE").MustBool(),
  620. CertFile: sec.Key("CERT_FILE").String(),
  621. KeyFile: sec.Key("KEY_FILE").String(),
  622. EnableHTMLAlternative: sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(),
  623. }
  624. MailService.From = sec.Key("FROM").MustString(MailService.User)
  625. log.Info("Mail Service Enabled")
  626. }
  627. func newRegisterMailService() {
  628. if !Cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() {
  629. return
  630. } else if MailService == nil {
  631. log.Warn("Register Mail Service: Mail Service is not enabled")
  632. return
  633. }
  634. Service.RegisterEmailConfirm = true
  635. log.Info("Register Mail Service Enabled")
  636. }
  637. func newNotifyMailService() {
  638. if !Cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() {
  639. return
  640. } else if MailService == nil {
  641. log.Warn("Notify Mail Service: Mail Service is not enabled")
  642. return
  643. }
  644. Service.EnableNotifyMail = true
  645. log.Info("Notify Mail Service Enabled")
  646. }
  647. func newWebhookService() {
  648. sec := Cfg.Section("webhook")
  649. Webhook.QueueLength = sec.Key("QUEUE_LENGTH").MustInt(1000)
  650. Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5)
  651. Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool()
  652. Webhook.Types = []string{"gogs", "slack"}
  653. Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10)
  654. }
  655. func NewServices() {
  656. newService()
  657. newLogService()
  658. newCacheService()
  659. newSessionService()
  660. newMailService()
  661. newRegisterMailService()
  662. newNotifyMailService()
  663. newWebhookService()
  664. }