-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
129 lines (117 loc) · 3 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// License: AGPL-3.0-only
// (c) 2024 Dakota Walsh <kota@nilsu.org>
package main
import (
"flag"
"fmt"
"log"
"net/http"
"os"
"runtime/debug"
"time"
"git.sr.ht/~kota/kudoer/application"
"git.sr.ht/~kota/kudoer/application/mail"
"git.sr.ht/~kota/kudoer/application/media"
"git.sr.ht/~kota/kudoer/db"
"git.sr.ht/~kota/kudoer/db/models"
"git.sr.ht/~kota/kudoer/ui"
"git.sr.ht/~kota/zqlsession"
"github.com/alexedwards/scs/v2"
"github.com/throttled/throttled/v2"
throttledstore "github.com/throttled/throttled/v2/store/memstore"
)
func main() {
addr := flag.String("addr", ":2024", "HTTP Network Address")
dsn := flag.String("dsn", "kudoer.db", "SQLite data source name")
msn := flag.String("media", "media_store", "Media source name")
mailHost := flag.String("mail-host", "", "Mail server host")
mailPort := flag.Int("mail-port", 25, "Mail server port")
mailUsername := flag.String("mail-username", "", "Mail server username")
mailPassword := flag.String("mail-password", "", "Mail server password")
mailSender := flag.String("mail-sender", "Kudoer <no-reply@kudoer.com>", "Mail server sender")
flag.Parse()
infoLog := log.New(os.Stdout, "INFO ", log.Ldate|log.Ltime)
errLog := log.New(os.Stdout, "ERROR ", log.Ldate|log.Ltime|log.Lshortfile)
infoLog.Println("opening database:", *dsn)
db, err := db.Open(*dsn)
if err != nil {
errLog.Fatal(err)
}
defer func() {
if err := db.Close(); err != nil {
errLog.Fatal(err)
}
}()
mailer := mail.New(
*mailHost,
*mailPort,
*mailUsername,
*mailPassword,
*mailSender,
)
mediaStore, err := media.Open(*msn)
if err != nil {
errLog.Fatal(err)
}
templates, err := ui.Templates()
if err != nil {
errLog.Fatal(err)
}
// Setup session storage.
sessionManager := scs.New()
sessionManager.Store = zqlsession.New(db)
sessionManager.Lifetime = 12 * time.Hour
sessionManager.ErrorFunc = func(
w http.ResponseWriter,
r *http.Request,
err error,
) {
trace := fmt.Sprintf("%s\n%s", err.Error(), debug.Stack())
_ = errLog.Output(2, trace) // Ignore failed error logging.
http.Error(
w,
http.StatusText(http.StatusInternalServerError),
http.StatusInternalServerError,
)
}
// Set up HTTP request throttling.
tstore, err := throttledstore.NewCtx(65536)
if err != nil {
errLog.Fatal(err)
}
quota := throttled.RateQuota{
MaxRate: throttled.PerMin(20),
MaxBurst: 5,
}
throttler, err := throttled.NewGCRARateLimiterCtx(tstore, quota)
if err != nil {
errLog.Fatal(err)
}
rateLimiter := &throttled.HTTPRateLimiterCtx{
RateLimiter: throttler,
VaryBy: &throttled.VaryBy{
Path: true,
Method: true,
Headers: []string{"X-Forwarded-For"},
},
}
app := application.New(
infoLog,
errLog,
templates,
sessionManager,
rateLimiter,
mediaStore,
mailer,
&models.UserModel{DB: db},
&models.ItemModel{DB: db},
&models.KudoModel{DB: db},
&models.SearchModel{DB: db},
&models.PWResetModel{DB: db},
&models.ProfilePictureModel{DB: db},
)
err = app.Serve(*addr)
if err != nil {
errLog.Fatalln(err)
}
}