Fix link targets
[bloat] / main.go
1 package main
2
3 import (
4         "errors"
5         "fmt"
6         "log"
7         "net"
8         "net/http"
9         "os"
10         "path/filepath"
11         "strings"
12         "time"
13
14         "bloat/config"
15         "bloat/kv"
16         "bloat/renderer"
17         "bloat/repo"
18         "bloat/service"
19         "bloat/util"
20 )
21
22 var (
23         configFile = "/etc/bloat.conf"
24 )
25
26 func errExit(err error) {
27         fmt.Fprintln(os.Stderr, err.Error())
28         os.Exit(1)
29 }
30
31 func setupHttp() {
32         tr := http.DefaultTransport.(*http.Transport)
33         tr.MaxIdleConnsPerHost = 30
34         tr.MaxIdleConns = 300
35         tr.ForceAttemptHTTP2 = false
36         tr.DialContext = (&net.Dialer{
37                 Timeout:   30 * time.Second,
38                 KeepAlive: 3 * time.Minute,
39                 DualStack: true,
40         }).DialContext
41         client := http.DefaultClient
42         client.Transport = tr
43 }
44
45 func main() {
46         opts, _, err := util.Getopts(os.Args, "f:")
47         if err != nil {
48                 errExit(err)
49         }
50
51         for _, opt := range opts {
52                 switch opt.Option {
53                 case 'f':
54                         configFile = opt.Value
55                 }
56         }
57
58         config, err := config.ParseFile(configFile)
59         if err != nil {
60                 errExit(err)
61         }
62
63         if !config.IsValid() {
64                 errExit(errors.New("invalid config"))
65         }
66
67         templatesGlobPattern := filepath.Join(config.TemplatesPath, "*")
68         renderer, err := renderer.NewRenderer(templatesGlobPattern)
69         if err != nil {
70                 errExit(err)
71         }
72
73         err = os.Mkdir(config.DatabasePath, 0755)
74         if err != nil && !os.IsExist(err) {
75                 errExit(err)
76         }
77
78         sessionDBPath := filepath.Join(config.DatabasePath, "session")
79         sessionDB, err := kv.NewDatabse(sessionDBPath)
80         if err != nil {
81                 errExit(err)
82         }
83
84         appDBPath := filepath.Join(config.DatabasePath, "app")
85         appDB, err := kv.NewDatabse(appDBPath)
86         if err != nil {
87                 errExit(err)
88         }
89
90         sessionRepo := repo.NewSessionRepo(sessionDB)
91         appRepo := repo.NewAppRepo(appDB)
92
93         customCSS := config.CustomCSS
94         if len(customCSS) > 0 && !strings.HasPrefix(customCSS, "http://") &&
95                 !strings.HasPrefix(customCSS, "https://") {
96                 customCSS = "/static/" + customCSS
97         }
98
99         var logger *log.Logger
100         if len(config.LogFile) < 1 {
101                 logger = log.New(os.Stdout, "", log.LstdFlags)
102         } else {
103                 lf, err := os.OpenFile(config.LogFile,
104                         os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
105                 if err != nil {
106                         errExit(err)
107                 }
108                 defer lf.Close()
109                 logger = log.New(lf, "", log.LstdFlags)
110         }
111
112         setupHttp()
113
114         s := service.NewService(config.ClientName, config.ClientScope,
115                 config.ClientWebsite, customCSS, config.PostFormats, renderer,
116                 sessionRepo, appRepo, config.SingleInstance)
117         s = service.NewAuthService(sessionRepo, appRepo, s)
118         s = service.NewLoggingService(logger, s)
119         handler := service.NewHandler(s, config.StaticDirectory)
120
121         logger.Println("listening on", config.ListenAddress)
122         err = http.ListenAndServe(config.ListenAddress, handler)
123         if err != nil {
124                 errExit(err)
125         }
126 }