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
|
package main
import (
"context"
"fmt"
"net"
"os"
"os/signal"
"rss-kakapo/dal"
"rss-kakapo/logic"
"rss-kakapo/server"
"rss-kakapo/shared"
"rss-kakapo/texts"
"syscall"
"time"
)
// shutdownTimeout is how long open requests get to finish once the service is
// asked to stop.
const shutdownTimeout = 15 * time.Second
func main() {
if len(os.Args) > 1 {
os.Exit(runCli(os.Args[1:], os.Stdout, os.Stderr))
}
cfg := shared.LoadConfig()
logger := initLogger(cfg)
// The database is migrated before anything else uses it: the feed
// follower and the messenger start their loops as soon as they exist.
repo := dal.NewRepo(cfg, logger)
repo.InitUpdateDb()
userAgent := shared.NewUserAgent(cfg)
prof := logic.NewProfiler(cfg, logger)
txt := texts.NewTexts()
keyStore := logic.NewKeyStore(cfg, repo)
blockedFeeds := logic.NewBlockedFeeds(repo)
sender := logic.NewActivitySender(cfg, logger, userAgent)
userRetriever := logic.NewUserRetriever(cfg, userAgent, keyStore)
sigChecker := logic.NewHttpSigChecker(logger, userRetriever)
messenger := logic.NewMessenger(cfg, logger, repo, keyStore, sender)
feedFollower := logic.NewFeedFollower(cfg, logger, userAgent, repo, blockedFeeds,
messenger, txt, keyStore)
userDir := logic.NewUserDirectory(cfg, logger, repo, keyStore, sender, txt)
inbox := logic.NewInbox(cfg, logger, repo, txt, userDir, keyStore,
sender, messenger, feedFollower)
groups := []server.IHandlerGroup{
server.NewApubHandlerGroup(cfg, logger, sender, sigChecker, userDir, inbox),
server.NewApiHandlerGroup(cfg, logger, feedFollower, repo, prof),
server.NewWebHandlerGroup(cfg, logger, repo, txt),
}
srv := server.NewHTTPServer(cfg, server.NewMux(groups, logger))
logger.Printf("Application starting up")
listener, err := net.Listen("tcp", srv.Addr)
if err != nil {
fmt.Fprintf(os.Stderr, "rss-kakapo: %v\n", err)
os.Exit(1)
}
logger.Printf("Starting HTTP server at %v", srv.Addr)
go srv.Serve(listener)
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
<-ctx.Done()
stop()
logger.Printf("Shutting down HTTP server")
shutdownCtx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
defer cancel()
if err := srv.Shutdown(shutdownCtx); err != nil {
logger.Errorf("Shutting down HTTP server: %v", err)
}
logger.Printf("Application shutting down")
}
// initLogger builds the process logger. Logs always go to stderr, which under
// systemd is captured by the journal. The log_file config field is ignored.
func initLogger(cfg *shared.Config) *shared.Logger {
return shared.NewLogger(os.Stderr, cfg.LogLevel)
}
|