-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
123 lines (105 loc) · 3.55 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
// SPDX-FileCopyrightText: Amolith <[email protected]>
//
// SPDX-License-Identifier: BSD-2-Clause
package main
import (
"html/template"
"log/slog"
"net/http"
"os"
"path/filepath"
"strings"
"time"
flag "github.com/spf13/pflag"
)
type ring struct {
handle string
discordUserId string
url string
}
type model struct {
ring []ring
index *template.Template
notFoundHtml *string
notFoundModTime time.Time
ringModTime time.Time
indexModTime time.Time
}
// Pre-define all of our flags
var (
flagListen *string = flag.StringP("listen", "l", "127.0.0.1:2857", "Host and port go-webring will listen on")
flagMembers *string = flag.StringP("members", "m", "list.txt", "Path to list of webring members")
flagIndex *string = flag.StringP("index", "i", "index.html", "Path to home page template")
flag404 *string = flag.StringP("404", "4", "404.html", "Path to HTML file to serve on 404")
flagContactString *string = flag.StringP("contact", "c", "contact the admin and let them know what's up", "Contact instructions for errors")
flagValidationLog *string = flag.StringP("validationlog", "v", "validation.log", "Path to validation log, see docs for requirements")
flagHost *string = flag.StringP("host", "H", "", "Host this webring runs on, primarily used for validation")
flagDiscordUrlFile *string = flag.StringP("discord-url-file", "d", "discord-webhook-url.txt", "Path to file containing Discord webhook URL")
gDiscordUrl *string = nil // Will be read from flagDiscordUrlFile
)
func main() {
logger := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo})
slog.SetDefault(slog.New(logger))
m := model{}
m.init()
mux := http.NewServeMux()
// Ensure log file exists and if not, create it
if _, err := os.Stat(*flagValidationLog); os.IsNotExist(err) {
slog.Info("Validation log file does not exist; creating it")
f, err := os.Create(*flagValidationLog)
if err != nil {
slog.Error("Error creating validation log file", "error", err)
os.Exit(1)
}
f.Close()
}
// Spin off a goroutine to validate list members once a day
go func() {
for {
m.validateMembers()
time.Sleep(24 * time.Hour)
}
}()
httpServer := &http.Server{
Addr: *flagListen,
Handler: mux,
}
mux.HandleFunc("/", m.root)
mux.HandleFunc("/next", m.next)
mux.HandleFunc("/previous", m.previous)
mux.HandleFunc("/random", m.random)
mux.HandleFunc("/"+filepath.Base(*flagValidationLog), m.validationLog)
fileHandler := http.StripPrefix("/static/", http.FileServer(http.Dir("static")))
mux.Handle("/static/", fileHandler)
if err := httpServer.ListenAndServe(); err == http.ErrServerClosed {
slog.Info("Web server closed")
} else {
slog.Error("Web server error", "error", err)
}
}
func loadDiscordUrl() {
discordUrlBytes, err := os.ReadFile(*flagDiscordUrlFile)
if err != nil {
slog.Error("Failed to read URL from file", "error", err)
os.Exit(1)
}
discordUrlString := strings.TrimSpace(string(discordUrlBytes))
gDiscordUrl = &discordUrlString
}
func (m *model) init() {
flag.Parse()
if *flagHost == "" {
slog.Error("Host flag is required")
os.Exit(1)
}
slog.Info("Listening", "address", *flagListen)
slog.Info("Loading Discord webhook URL", "file", *flagDiscordUrlFile)
loadDiscordUrl()
slog.Info("Loading members", "file", *flagMembers)
m.parseList()
slog.Info("Loaded members", "member_count", len(m.ring))
slog.Info("Building homepage", "file", *flagIndex)
m.parseIndex()
slog.Info("Reading 404 template", "file", *flag404)
m.parse404()
}