Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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