This repository has been archived by the owner on Oct 3, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 74
/
config.go
354 lines (304 loc) · 9.39 KB
/
config.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
//go:generate ffjson --nodecoder --force-regenerate $GOFILE
// Package config stores and exports the configuration for server-side use and
// the public availability JSON struct, which includes a small subset of the
// server configuration.
package config
import (
"encoding/json"
"sort"
"sync"
"time"
"github.com/bakape/meguca/util"
)
var (
// Ensures no reads happen, while the configuration is reloading
globalMu, boardMu sync.RWMutex
// Contains currently loaded global server configuration
global *Configs
// Map of board IDs to their configuration structs
boardConfigs = map[string]BoardConfContainer{}
// AllBoardConfigs stores board-specific configurations for the /all/
// metaboard. Constant.
AllBoardConfigs = BoardConfContainer{
BoardConfigs: BoardConfigs{
ID: "all",
BoardPublic: BoardPublic{
PostParseConfigs: PostParseConfigs{
HashCommands: true,
},
CodeTags: true,
Spoiler: "default.jpg",
Title: "Aggregator metaboard",
Banners: []string{},
},
},
Hash: "0",
}
// JSON of client-accessible configuration
clientJSON []byte
// Hash of the global configs. Used for live reloading configuration on the
// client.
hash string
// Defaults contains the default server configuration values
Defaults = Configs{
ThreadExpiry: 14,
BoardExpiry: 7,
JPEGQuality: 80,
MaxSize: 5,
MaxHeight: 6000,
MaxWidth: 6000,
SessionExpiry: 30,
Salt: "LALALALALALALALALALALALALALALALALALALALA",
FeedbackEmail: "admin@email.com",
RootURL: "http://localhost",
FAQ: defaultFAQ,
Public: Public{
DefaultCSS: "moe",
DefaultLang: "en_GB",
Links: map[string]string{"4chan": "http://www.4chan.org/"},
},
}
// EightballDefaults contains the default eightball answer set
EightballDefaults = []string{
"Yes",
"No",
"Maybe",
"It can't be helped",
"Hell yeah, motherfucker!",
"Anta baka?",
}
)
// Default string for the FAQ panel
const defaultFAQ = `Supported upload file types are JPEG, PNG, APNG, WEBM, MP3, MP4, OGG, PDF, ZIP, 7Z, TAR.GZ and TAR.XZ.
Encase words in ** to spoiler them. Spoilers reset on newline.
<hr>Hash commands:
#d100 #2d100 - Roll dice
#flip - Coin flip
#8ball - An 8ball
All hash commands need to be input on their own line`
// Configs stores the global server configuration
type Configs struct {
Public
PruneThreads bool `json:"pruneThreads" gorethink:"pruneThreads"`
PruneBoards bool `json:"pruneBoards" gorethink:"pruneBoards"`
Pyu bool `json:"pyu" gorethink:"pyu"`
JPEGQuality uint8
MaxWidth uint16 `json:"maxWidth" gorethink:"maxWidth"`
MaxHeight uint16 `json:"maxHeight" gorethink:"maxHeight"`
ThreadExpiry uint `json:"threadExpiry" gorethink:"threadExpiry"`
BoardExpiry uint `json:"boardExpiry" gorethink:"boardExpiry"`
MaxSize uint `json:"maxSize" gorethink:"maxSize"`
SessionExpiry uint `json:"sessionExpiry" gorethink:"sessionExpiry"`
RootURL string `json:"rootURL" gorethink:"rootURL"`
Salt string `json:"salt" gorethink:"salt"`
FeedbackEmail string `json:"feedbackEmail" gorethink:"feedbackEmail"`
CaptchaPrivateKey string `json:"captchaPrivateKey" gorethink:"captchaPrivateKey"`
FAQ string
}
// Public contains configurations exposeable through public availability APIs
type Public struct {
Captcha bool `json:"captcha" gorethink:"captcha"`
Mature bool `json:"mature" gorethink:"mature"`
DefaultLang string `json:"defaultLang" gorethink:"defaultLang"`
DefaultCSS string `json:"defaultCSS" gorethink:"defaultCSS"`
CaptchaPublicKey string `json:"captchaPublicKey" gorethink:"captchaPublicKey"`
Links map[string]string `json:"links" gorethink:"links"`
}
// BoardConfigs stores board-specific configuration
type BoardConfigs struct {
BoardPublic
ID string `json:"id" gorethink:"id"`
Eightball []string `json:"eightball" gorethink:"eightball"`
Staff map[string][]string `json:"staff" gorethink:"staff"`
}
// BoardPublic contains publically accessible board-specific configurations
type BoardPublic struct {
PostParseConfigs
CodeTags bool `json:"codeTags" gorethink:"codeTags"`
Spoiler string `json:"spoiler" gorethink:"spoiler"`
Title string `json:"title" gorethink:"title"`
Notice string `json:"notice" gorethink:"notice"`
Rules string `json:"rules" gorethink:"rules"`
Banners []string `json:"banners" gorethink:"banners"`
}
// BoardConfContainer contains configurations for an individual board as well
// as pregenerated public JSON and it's hash
type BoardConfContainer struct {
BoardConfigs
JSON []byte
Hash string
}
// DatabaseBoardConfigs contains extra fields not exposed on database reads
type DatabaseBoardConfigs struct {
BoardConfigs
Created time.Time `gorethink:"created"`
}
// PostParseConfigs contains board-specific flags for post text parsing
type PostParseConfigs struct {
ReadOnly bool `json:"readOnly" gorethink:"readOnly"`
TextOnly bool `json:"textOnly" gorethink:"textOnly"`
ForcedAnon bool `json:"forcedAnon" gorethink:"forcedAnon"`
HashCommands bool `json:"hashCommands" gorethink:"hashCommands"`
}
// BoardTitle contains a board's ID and title
type BoardTitle struct {
ID string `json:"id"`
Title string `json:"title"`
}
// BoardTitles implements sort.Interface
type BoardTitles []BoardTitle
// Generate /all/ board configs
func init() {
var err error
AllBoardConfigs.JSON, err = json.Marshal(AllBoardConfigs.BoardPublic)
if err != nil {
panic(err)
}
}
func (b BoardTitles) Len() int {
return len(b)
}
func (b BoardTitles) Less(i, j int) bool {
return b[i].ID < b[j].ID
}
func (b BoardTitles) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}
// Get returns a pointer to the current server configuration struct. Callers
// should not modify this struct.
func Get() *Configs {
globalMu.RLock()
defer globalMu.RUnlock()
return global
}
// Set sets the internal configuration struct
func Set(c Configs) error {
client, err := json.Marshal(c.Public)
if err != nil {
return err
}
h := util.HashBuffer(client)
globalMu.Lock()
clientJSON = client
global = &c
hash = h
globalMu.Unlock()
return nil
}
// GetClient returns public availability configuration JSON and a truncated
// configuration MD5 hash
func GetClient() ([]byte, string) {
globalMu.RLock()
defer globalMu.RUnlock()
return clientJSON, hash
}
// SetClient sets the client configuration JSON and hash. To be used only in
// tests.
func SetClient(json []byte, cHash string) {
globalMu.Lock()
clientJSON = json
hash = cHash
globalMu.Unlock()
}
// GetBoardConfigs returns board-specific configurations for a board combined
// with pregenerated public JSON of these configurations and their hash. Do
// not modify the retrieved struct.
func GetBoardConfigs(b string) BoardConfContainer {
if b == "all" {
return AllBoardConfigs
}
boardMu.RLock()
defer boardMu.RUnlock()
return boardConfigs[b]
}
// GetAllBoardConfigs returns board-specific configurations for all boards. Do
// not modify the retrieved structs.
func GetAllBoardConfigs() []BoardConfContainer {
boardMu.RLock()
defer boardMu.RUnlock()
conf := make([]BoardConfContainer, 0, len(boardConfigs))
for _, c := range boardConfigs {
conf = append(conf, c)
}
return conf
}
// GetBoardTitles returns a slice of all existing boards and their titles
func GetBoardTitles() BoardTitles {
boardMu.RLock()
defer boardMu.RUnlock()
bt := make(BoardTitles, 0, len(boardConfigs))
for id, conf := range boardConfigs {
bt = append(bt, BoardTitle{
ID: id,
Title: conf.Title,
})
}
sort.Sort(bt)
return bt
}
// GetBoards returns an array of currently existing boards
func GetBoards() []string {
boardMu.RLock()
defer boardMu.RUnlock()
boards := make([]string, 0, len(boardConfigs))
for b := range boardConfigs {
boards = append(boards, b)
}
sort.Strings(boards)
return boards
}
// IsBoard returns whether the passed string is a currently existing board
func IsBoard(b string) bool {
boardMu.RLock()
defer boardMu.RUnlock()
_, ok := boardConfigs[b]
return ok
}
// SetBoardConfigs sets configurations for a specific board as well as
// pregenerates their public JSON and hash. Returns if any changes were made to
// the configs in result.
func SetBoardConfigs(conf BoardConfigs) (bool, error) {
cont := BoardConfContainer{
BoardConfigs: conf,
}
var err error
cont.JSON, err = json.Marshal(conf.BoardPublic)
if err != nil {
return false, err
}
cont.Hash = util.HashBuffer(cont.JSON)
boardMu.Lock()
defer boardMu.Unlock()
// Nothing changed
if boardConfigs[conf.ID].Hash == cont.Hash {
return false, nil
}
// Swap config
boardConfigs[conf.ID] = cont
return true, nil
}
// RemoveBoard removes a board from the exiting board list and deletes its
// configurations. To be called, when a board is deleted.
func RemoveBoard(b string) {
boardMu.Lock()
defer boardMu.Unlock()
delete(boardConfigs, b)
}
// Clear resets package state. Only use in tests.
func Clear() {
boardMu.Lock()
defer boardMu.Unlock()
globalMu.RLock()
defer globalMu.RUnlock()
global = &Configs{}
boardConfigs = map[string]BoardConfContainer{}
clientJSON = nil
hash = ""
}
// ClearBoards clears any existing board configuration entries. Only use in
// tests.
func ClearBoards() {
boardMu.Lock()
defer boardMu.Unlock()
boardConfigs = map[string]BoardConfContainer{}
}