conf.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  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 conf
  5. import (
  6. "fmt"
  7. "net/mail"
  8. "net/url"
  9. "os"
  10. "path"
  11. "path/filepath"
  12. "strconv"
  13. "strings"
  14. "time"
  15. _ "github.com/go-macaron/cache/memcache"
  16. _ "github.com/go-macaron/cache/redis"
  17. "github.com/go-macaron/session"
  18. _ "github.com/go-macaron/session/redis"
  19. "github.com/mcuadros/go-version"
  20. "github.com/pkg/errors"
  21. "gopkg.in/ini.v1"
  22. log "unknwon.dev/clog/v2"
  23. "github.com/gogs/go-libravatar"
  24. "gogs.io/gogs/internal/assets/conf"
  25. "gogs.io/gogs/internal/osutil"
  26. )
  27. func init() {
  28. // Initialize the primary logger until logging service is up.
  29. err := log.NewConsole()
  30. if err != nil {
  31. panic("init console logger: " + err.Error())
  32. }
  33. }
  34. // Asset is a wrapper for getting conf assets.
  35. func Asset(name string) ([]byte, error) {
  36. return conf.Asset(name)
  37. }
  38. // AssetDir is a wrapper for getting conf assets.
  39. func AssetDir(name string) ([]string, error) {
  40. return conf.AssetDir(name)
  41. }
  42. // MustAsset is a wrapper for getting conf assets.
  43. func MustAsset(name string) []byte {
  44. return conf.MustAsset(name)
  45. }
  46. // File is the configuration object.
  47. var File *ini.File
  48. // Init initializes configuration from conf assets and given custom configuration file.
  49. // If `customConf` is empty, it falls back to default location, i.e. "<WORK DIR>/custom".
  50. // It is safe to call this function multiple times with desired `customConf`, but it is
  51. // not concurrent safe.
  52. //
  53. // NOTE: The order of loading configuration sections matters as one may depend on another.
  54. //
  55. // ⚠️ WARNING: Do not print anything in this function other than wanrings.
  56. func Init(customConf string) error {
  57. var err error
  58. File, err = ini.LoadSources(ini.LoadOptions{
  59. IgnoreInlineComment: true,
  60. }, conf.MustAsset("conf/app.ini"))
  61. if err != nil {
  62. return errors.Wrap(err, "parse 'conf/app.ini'")
  63. }
  64. File.NameMapper = ini.SnackCase
  65. if customConf == "" {
  66. customConf = filepath.Join(CustomDir(), "conf", "app.ini")
  67. } else {
  68. customConf, err = filepath.Abs(customConf)
  69. if err != nil {
  70. return errors.Wrap(err, "get absolute path")
  71. }
  72. }
  73. CustomConf = customConf
  74. if osutil.IsFile(customConf) {
  75. if err = File.Append(customConf); err != nil {
  76. return errors.Wrapf(err, "append %q", customConf)
  77. }
  78. } else {
  79. log.Warn("Custom config %q not found. Ignore this warning if you're running for the first time", customConf)
  80. }
  81. if err = File.Section(ini.DefaultSection).MapTo(&App); err != nil {
  82. return errors.Wrap(err, "mapping default section")
  83. }
  84. // ***************************
  85. // ----- Server settings -----
  86. // ***************************
  87. if err = File.Section("server").MapTo(&Server); err != nil {
  88. return errors.Wrap(err, "mapping [server] section")
  89. }
  90. Server.AppDataPath = ensureAbs(Server.AppDataPath)
  91. if !strings.HasSuffix(Server.ExternalURL, "/") {
  92. Server.ExternalURL += "/"
  93. }
  94. Server.URL, err = url.Parse(Server.ExternalURL)
  95. if err != nil {
  96. return errors.Wrapf(err, "parse '[server] EXTERNAL_URL' %q", err)
  97. }
  98. // Subpath should start with '/' and end without '/', i.e. '/{subpath}'.
  99. Server.Subpath = strings.TrimRight(Server.URL.Path, "/")
  100. Server.SubpathDepth = strings.Count(Server.Subpath, "/")
  101. unixSocketMode, err := strconv.ParseUint(Server.UnixSocketPermission, 8, 32)
  102. if err != nil {
  103. return errors.Wrapf(err, "parse '[server] UNIX_SOCKET_PERMISSION' %q", Server.UnixSocketPermission)
  104. }
  105. if unixSocketMode > 0777 {
  106. unixSocketMode = 0666
  107. }
  108. Server.UnixSocketMode = os.FileMode(unixSocketMode)
  109. // ************************
  110. // ----- SSH settings -----
  111. // ************************
  112. SSH.RootPath = filepath.Join(HomeDir(), ".ssh")
  113. SSH.KeyTestPath = os.TempDir()
  114. if err = File.Section("server").MapTo(&SSH); err != nil {
  115. return errors.Wrap(err, "mapping SSH settings from [server] section")
  116. }
  117. SSH.RootPath = ensureAbs(SSH.RootPath)
  118. SSH.KeyTestPath = ensureAbs(SSH.KeyTestPath)
  119. if !SSH.Disabled {
  120. if !SSH.StartBuiltinServer {
  121. if err := os.MkdirAll(SSH.RootPath, 0700); err != nil {
  122. return errors.Wrap(err, "create SSH root directory")
  123. } else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil {
  124. return errors.Wrap(err, "create SSH key test directory")
  125. }
  126. } else {
  127. SSH.RewriteAuthorizedKeysAtStart = false
  128. }
  129. // Check if server is eligible for minimum key size check when user choose to enable.
  130. // Windows server and OpenSSH version lower than 5.1 are forced to be disabled because
  131. // the "ssh-keygen" in Windows does not print key type.
  132. // See https://github.com/gogs/gogs/issues/4507.
  133. if SSH.MinimumKeySizeCheck {
  134. sshVersion, err := openSSHVersion()
  135. if err != nil {
  136. return errors.Wrap(err, "get OpenSSH version")
  137. }
  138. if IsWindowsRuntime() || version.Compare(sshVersion, "5.1", "<") {
  139. log.Warn(`SSH minimum key size check is forced to be disabled because server is not eligible:
  140. 1. Windows server
  141. 2. OpenSSH version is lower than 5.1`)
  142. } else {
  143. SSH.MinimumKeySizes = map[string]int{}
  144. for _, key := range File.Section("ssh.minimum_key_sizes").Keys() {
  145. if key.MustInt() != -1 {
  146. SSH.MinimumKeySizes[strings.ToLower(key.Name())] = key.MustInt()
  147. }
  148. }
  149. }
  150. }
  151. }
  152. // *******************************
  153. // ----- Repository settings -----
  154. // *******************************
  155. Repository.Root = filepath.Join(HomeDir(), "gogs-repositories")
  156. if err = File.Section("repository").MapTo(&Repository); err != nil {
  157. return errors.Wrap(err, "mapping [repository] section")
  158. }
  159. Repository.Root = ensureAbs(Repository.Root)
  160. Repository.Upload.TempPath = ensureAbs(Repository.Upload.TempPath)
  161. // *******************************
  162. // ----- Database settings -----
  163. // *******************************
  164. if err = File.Section("database").MapTo(&Database); err != nil {
  165. return errors.Wrap(err, "mapping [database] section")
  166. }
  167. Database.Path = ensureAbs(Database.Path)
  168. // *******************************
  169. // ----- Security settings -----
  170. // *******************************
  171. if err = File.Section("security").MapTo(&Security); err != nil {
  172. return errors.Wrap(err, "mapping [security] section")
  173. }
  174. // Check run user when the install is locked.
  175. if Security.InstallLock {
  176. currentUser, match := CheckRunUser(App.RunUser)
  177. if !match {
  178. return fmt.Errorf("user configured to run Gogs is %q, but the current user is %q", App.RunUser, currentUser)
  179. }
  180. }
  181. // **************************
  182. // ----- Email settings -----
  183. // **************************
  184. if err = File.Section("email").MapTo(&Email); err != nil {
  185. return errors.Wrap(err, "mapping [email] section")
  186. }
  187. // LEGACY [0.13]: In case there are values with old section name.
  188. if err = File.Section("mailer").MapTo(&Email); err != nil {
  189. return errors.Wrap(err, "mapping [mailer] section")
  190. }
  191. if Email.Enabled {
  192. if Email.From == "" {
  193. Email.From = Email.User
  194. }
  195. parsed, err := mail.ParseAddress(Email.From)
  196. if err != nil {
  197. return errors.Wrapf(err, "parse mail address %q", Email.From)
  198. }
  199. Email.FromEmail = parsed.Address
  200. }
  201. // ***********************************
  202. // ----- Authentication settings -----
  203. // ***********************************
  204. if err = File.Section("auth").MapTo(&Auth); err != nil {
  205. return errors.Wrap(err, "mapping [auth] section")
  206. }
  207. // LEGACY [0.13]: In case there are values with old section name.
  208. if err = File.Section("service").MapTo(&Auth); err != nil {
  209. return errors.Wrap(err, "mapping [service] section")
  210. }
  211. // ***********************************
  212. // ----- User settings -----
  213. // ***********************************
  214. if err = File.Section("user").MapTo(&User); err != nil {
  215. return errors.Wrap(err, "mapping [user] section")
  216. }
  217. handleDeprecated()
  218. // TODO
  219. sec := File.Section("attachment")
  220. AttachmentPath = sec.Key("PATH").MustString(filepath.Join(Server.AppDataPath, "attachments"))
  221. if !filepath.IsAbs(AttachmentPath) {
  222. AttachmentPath = path.Join(workDir, AttachmentPath)
  223. }
  224. AttachmentAllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png"), "|", ",", -1)
  225. AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(4)
  226. AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(5)
  227. AttachmentEnabled = sec.Key("ENABLED").MustBool(true)
  228. TimeFormat = map[string]string{
  229. "ANSIC": time.ANSIC,
  230. "UnixDate": time.UnixDate,
  231. "RubyDate": time.RubyDate,
  232. "RFC822": time.RFC822,
  233. "RFC822Z": time.RFC822Z,
  234. "RFC850": time.RFC850,
  235. "RFC1123": time.RFC1123,
  236. "RFC1123Z": time.RFC1123Z,
  237. "RFC3339": time.RFC3339,
  238. "RFC3339Nano": time.RFC3339Nano,
  239. "Kitchen": time.Kitchen,
  240. "Stamp": time.Stamp,
  241. "StampMilli": time.StampMilli,
  242. "StampMicro": time.StampMicro,
  243. "StampNano": time.StampNano,
  244. }[File.Section("time").Key("FORMAT").MustString("RFC1123")]
  245. sec = File.Section("picture")
  246. AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString(filepath.Join(Server.AppDataPath, "avatars"))
  247. if !filepath.IsAbs(AvatarUploadPath) {
  248. AvatarUploadPath = path.Join(workDir, AvatarUploadPath)
  249. }
  250. RepositoryAvatarUploadPath = sec.Key("REPOSITORY_AVATAR_UPLOAD_PATH").MustString(filepath.Join(Server.AppDataPath, "repo-avatars"))
  251. if !filepath.IsAbs(RepositoryAvatarUploadPath) {
  252. RepositoryAvatarUploadPath = path.Join(workDir, RepositoryAvatarUploadPath)
  253. }
  254. switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source {
  255. case "duoshuo":
  256. GravatarSource = "http://gravatar.duoshuo.com/avatar/"
  257. case "gravatar":
  258. GravatarSource = "https://secure.gravatar.com/avatar/"
  259. case "libravatar":
  260. GravatarSource = "https://seccdn.libravatar.org/avatar/"
  261. default:
  262. GravatarSource = source
  263. }
  264. DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool()
  265. EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(true)
  266. if Server.OfflineMode {
  267. DisableGravatar = true
  268. EnableFederatedAvatar = false
  269. }
  270. if DisableGravatar {
  271. EnableFederatedAvatar = false
  272. }
  273. if EnableFederatedAvatar {
  274. LibravatarService = libravatar.New()
  275. parts := strings.Split(GravatarSource, "/")
  276. if len(parts) >= 3 {
  277. if parts[0] == "https:" {
  278. LibravatarService.SetUseHTTPS(true)
  279. LibravatarService.SetSecureFallbackHost(parts[2])
  280. } else {
  281. LibravatarService.SetUseHTTPS(false)
  282. LibravatarService.SetFallbackHost(parts[2])
  283. }
  284. }
  285. }
  286. if err = File.Section("http").MapTo(&HTTP); err != nil {
  287. log.Fatal("Failed to map HTTP settings: %v", err)
  288. } else if err = File.Section("webhook").MapTo(&Webhook); err != nil {
  289. log.Fatal("Failed to map Webhook settings: %v", err)
  290. } else if err = File.Section("release.attachment").MapTo(&Release.Attachment); err != nil {
  291. log.Fatal("Failed to map Release.Attachment settings: %v", err)
  292. } else if err = File.Section("markdown").MapTo(&Markdown); err != nil {
  293. log.Fatal("Failed to map Markdown settings: %v", err)
  294. } else if err = File.Section("smartypants").MapTo(&Smartypants); err != nil {
  295. log.Fatal("Failed to map Smartypants settings: %v", err)
  296. } else if err = File.Section("admin").MapTo(&Admin); err != nil {
  297. log.Fatal("Failed to map Admin settings: %v", err)
  298. } else if err = File.Section("cron").MapTo(&Cron); err != nil {
  299. log.Fatal("Failed to map Cron settings: %v", err)
  300. } else if err = File.Section("git").MapTo(&Git); err != nil {
  301. log.Fatal("Failed to map Git settings: %v", err)
  302. } else if err = File.Section("mirror").MapTo(&Mirror); err != nil {
  303. log.Fatal("Failed to map Mirror settings: %v", err)
  304. } else if err = File.Section("api").MapTo(&API); err != nil {
  305. log.Fatal("Failed to map API settings: %v", err)
  306. } else if err = File.Section("ui").MapTo(&UI); err != nil {
  307. log.Fatal("Failed to map UI settings: %v", err)
  308. } else if err = File.Section("prometheus").MapTo(&Prometheus); err != nil {
  309. log.Fatal("Failed to map Prometheus settings: %v", err)
  310. }
  311. if Mirror.DefaultInterval <= 0 {
  312. Mirror.DefaultInterval = 24
  313. }
  314. Langs = File.Section("i18n").Key("LANGS").Strings(",")
  315. Names = File.Section("i18n").Key("NAMES").Strings(",")
  316. dateLangs = File.Section("i18n.datelang").KeysHash()
  317. ShowFooterBranding = File.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool()
  318. ShowFooterTemplateLoadTime = File.Section("other").Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool()
  319. HasRobotsTxt = osutil.IsFile(path.Join(CustomDir(), "robots.txt"))
  320. return nil
  321. }
  322. // MustInit panics if configuration initialization failed.
  323. func MustInit(customConf string) {
  324. err := Init(customConf)
  325. if err != nil {
  326. panic(err)
  327. }
  328. }
  329. // TODO
  330. var (
  331. HTTP struct {
  332. AccessControlAllowOrigin string
  333. }
  334. // Database settings
  335. UseSQLite3 bool
  336. UseMySQL bool
  337. UsePostgreSQL bool
  338. UseMSSQL bool
  339. // Webhook settings
  340. Webhook struct {
  341. Types []string
  342. QueueLength int
  343. DeliverTimeout int
  344. SkipTLSVerify bool `ini:"SKIP_TLS_VERIFY"`
  345. PagingNum int
  346. }
  347. // Release settigns
  348. Release struct {
  349. Attachment struct {
  350. Enabled bool
  351. TempPath string
  352. AllowedTypes []string `delim:"|"`
  353. MaxSize int64
  354. MaxFiles int
  355. } `ini:"-"`
  356. }
  357. // Markdown sttings
  358. Markdown struct {
  359. EnableHardLineBreak bool
  360. CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"`
  361. FileExtensions []string
  362. }
  363. // Smartypants settings
  364. Smartypants struct {
  365. Enabled bool
  366. Fractions bool
  367. Dashes bool
  368. LatexDashes bool
  369. AngledQuotes bool
  370. }
  371. // Admin settings
  372. Admin struct {
  373. DisableRegularOrgCreation bool
  374. }
  375. // Picture settings
  376. AvatarUploadPath string
  377. RepositoryAvatarUploadPath string
  378. GravatarSource string
  379. DisableGravatar bool
  380. EnableFederatedAvatar bool
  381. LibravatarService *libravatar.Libravatar
  382. // Log settings
  383. LogRootPath string
  384. LogModes []string
  385. LogConfigs []interface{}
  386. // Attachment settings
  387. AttachmentPath string
  388. AttachmentAllowedTypes string
  389. AttachmentMaxSize int64
  390. AttachmentMaxFiles int
  391. AttachmentEnabled bool
  392. // Time settings
  393. TimeFormat string
  394. // Cache settings
  395. CacheAdapter string
  396. CacheInterval int
  397. CacheConn string
  398. // Session settings
  399. SessionConfig session.Options
  400. CSRFCookieName string
  401. // Cron tasks
  402. Cron struct {
  403. UpdateMirror struct {
  404. Enabled bool
  405. RunAtStart bool
  406. Schedule string
  407. } `ini:"cron.update_mirrors"`
  408. RepoHealthCheck struct {
  409. Enabled bool
  410. RunAtStart bool
  411. Schedule string
  412. Timeout time.Duration
  413. Args []string `delim:" "`
  414. } `ini:"cron.repo_health_check"`
  415. CheckRepoStats struct {
  416. Enabled bool
  417. RunAtStart bool
  418. Schedule string
  419. } `ini:"cron.check_repo_stats"`
  420. RepoArchiveCleanup struct {
  421. Enabled bool
  422. RunAtStart bool
  423. Schedule string
  424. OlderThan time.Duration
  425. } `ini:"cron.repo_archive_cleanup"`
  426. }
  427. // Git settings
  428. Git struct {
  429. Version string `ini:"-"`
  430. DisableDiffHighlight bool
  431. MaxGitDiffLines int
  432. MaxGitDiffLineCharacters int
  433. MaxGitDiffFiles int
  434. GCArgs []string `ini:"GC_ARGS" delim:" "`
  435. Timeout struct {
  436. Migrate int
  437. Mirror int
  438. Clone int
  439. Pull int
  440. GC int `ini:"GC"`
  441. } `ini:"git.timeout"`
  442. }
  443. // Mirror settings
  444. Mirror struct {
  445. DefaultInterval int
  446. }
  447. // API settings
  448. API struct {
  449. MaxResponseItems int
  450. }
  451. // UI settings
  452. UI struct {
  453. ExplorePagingNum int
  454. IssuePagingNum int
  455. FeedMaxCommitNum int
  456. ThemeColorMetaTag string
  457. MaxDisplayFileSize int64
  458. Admin struct {
  459. UserPagingNum int
  460. RepoPagingNum int
  461. NoticePagingNum int
  462. OrgPagingNum int
  463. } `ini:"ui.admin"`
  464. User struct {
  465. RepoPagingNum int
  466. NewsFeedPagingNum int
  467. CommitsPagingNum int
  468. } `ini:"ui.user"`
  469. }
  470. // Prometheus settings
  471. Prometheus struct {
  472. Enabled bool
  473. EnableBasicAuth bool
  474. BasicAuthUsername string
  475. BasicAuthPassword string
  476. }
  477. // I18n settings
  478. Langs []string
  479. Names []string
  480. dateLangs map[string]string
  481. // Highlight settings are loaded in modules/template/hightlight.go
  482. // Other settings
  483. ShowFooterBranding bool
  484. ShowFooterTemplateLoadTime bool
  485. // Global setting objects
  486. HasRobotsTxt bool
  487. )
  488. // DateLang transforms standard language locale name to corresponding value in datetime plugin.
  489. func DateLang(lang string) string {
  490. name, ok := dateLangs[lang]
  491. if ok {
  492. return name
  493. }
  494. return "en"
  495. }
  496. // InitLogging initializes the logging service of the application.
  497. func InitLogging() {
  498. LogRootPath = File.Section("log").Key("ROOT_PATH").MustString(filepath.Join(WorkDir(), "log"))
  499. // Because we always create a console logger as the primary logger at init time,
  500. // we need to remove it in case the user doesn't configure to use it after the
  501. // logging service is initalized.
  502. hasConsole := false
  503. // Iterate over [log.*] sections to initialize individual logger.
  504. LogModes = strings.Split(File.Section("log").Key("MODE").MustString("console"), ",")
  505. LogConfigs = make([]interface{}, len(LogModes))
  506. levelMappings := map[string]log.Level{
  507. "trace": log.LevelTrace,
  508. "info": log.LevelInfo,
  509. "warn": log.LevelWarn,
  510. "error": log.LevelError,
  511. "fatal": log.LevelFatal,
  512. }
  513. type config struct {
  514. Buffer int64
  515. Config interface{}
  516. }
  517. for i, mode := range LogModes {
  518. mode = strings.ToLower(strings.TrimSpace(mode))
  519. secName := "log." + mode
  520. sec, err := File.GetSection(secName)
  521. if err != nil {
  522. log.Fatal("Missing configuration section [%s] for %q logger", secName, mode)
  523. return
  524. }
  525. level := levelMappings[strings.ToLower(sec.Key("LEVEL").MustString("trace"))]
  526. buffer := sec.Key("BUFFER_LEN").MustInt64(100)
  527. c := new(config)
  528. switch mode {
  529. case log.DefaultConsoleName:
  530. hasConsole = true
  531. c = &config{
  532. Buffer: buffer,
  533. Config: log.ConsoleConfig{
  534. Level: level,
  535. },
  536. }
  537. err = log.NewConsole(c.Buffer, c.Config)
  538. case log.DefaultFileName:
  539. logPath := filepath.Join(LogRootPath, "gogs.log")
  540. logDir := filepath.Dir(logPath)
  541. err = os.MkdirAll(logDir, os.ModePerm)
  542. if err != nil {
  543. log.Fatal("Failed to create log directory %q: %v", logDir, err)
  544. return
  545. }
  546. c = &config{
  547. Buffer: buffer,
  548. Config: log.FileConfig{
  549. Level: level,
  550. Filename: logPath,
  551. FileRotationConfig: log.FileRotationConfig{
  552. Rotate: sec.Key("LOG_ROTATE").MustBool(true),
  553. Daily: sec.Key("DAILY_ROTATE").MustBool(true),
  554. MaxSize: 1 << uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)),
  555. MaxLines: sec.Key("MAX_LINES").MustInt64(1000000),
  556. MaxDays: sec.Key("MAX_DAYS").MustInt64(7),
  557. },
  558. },
  559. }
  560. err = log.NewFile(c.Buffer, c.Config)
  561. case log.DefaultSlackName:
  562. c = &config{
  563. Buffer: buffer,
  564. Config: log.SlackConfig{
  565. Level: level,
  566. URL: sec.Key("URL").String(),
  567. },
  568. }
  569. err = log.NewSlack(c.Buffer, c.Config)
  570. case log.DefaultDiscordName:
  571. c = &config{
  572. Buffer: buffer,
  573. Config: log.DiscordConfig{
  574. Level: level,
  575. URL: sec.Key("URL").String(),
  576. Username: sec.Key("USERNAME").String(),
  577. },
  578. }
  579. default:
  580. continue
  581. }
  582. if err != nil {
  583. log.Fatal("Failed to init %s logger: %v", mode, err)
  584. return
  585. }
  586. LogConfigs[i] = c
  587. log.Trace("Log mode: %s (%s)", strings.Title(mode), strings.Title(strings.ToLower(level.String())))
  588. }
  589. if !hasConsole {
  590. log.Remove(log.DefaultConsoleName)
  591. }
  592. }
  593. func newCacheService() {
  594. CacheAdapter = File.Section("cache").Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"})
  595. switch CacheAdapter {
  596. case "memory":
  597. CacheInterval = File.Section("cache").Key("INTERVAL").MustInt(60)
  598. case "redis", "memcache":
  599. CacheConn = strings.Trim(File.Section("cache").Key("HOST").String(), "\" ")
  600. default:
  601. log.Fatal("Unrecognized cache adapter %q", CacheAdapter)
  602. return
  603. }
  604. log.Trace("Cache service is enabled")
  605. }
  606. func newSessionService() {
  607. SessionConfig.Provider = File.Section("session").Key("PROVIDER").In("memory",
  608. []string{"memory", "file", "redis", "mysql"})
  609. SessionConfig.ProviderConfig = strings.Trim(File.Section("session").Key("PROVIDER_CONFIG").String(), "\" ")
  610. SessionConfig.CookieName = File.Section("session").Key("COOKIE_NAME").MustString("i_like_gogs")
  611. SessionConfig.CookiePath = Server.Subpath
  612. SessionConfig.Secure = File.Section("session").Key("COOKIE_SECURE").MustBool()
  613. SessionConfig.Gclifetime = File.Section("session").Key("GC_INTERVAL_TIME").MustInt64(3600)
  614. SessionConfig.Maxlifetime = File.Section("session").Key("SESSION_LIFE_TIME").MustInt64(86400)
  615. CSRFCookieName = File.Section("session").Key("CSRF_COOKIE_NAME").MustString("_csrf")
  616. log.Trace("Session service is enabled")
  617. }
  618. func NewServices() {
  619. newCacheService()
  620. newSessionService()
  621. }
  622. // HookMode indicates whether program starts as Git server-side hook callback.
  623. // All operations should be done synchronously to prevent program exits before finishing.
  624. var HookMode bool