setting.go 21 KB

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