summaryrefslogtreecommitdiff
path: root/main.go
blob: 059d7e7e91b8280d9d3c50bcd465aff899c6a5d9 (plain)
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
package main

import (
	"fmt"
	stdlog "log"
	"net"
	"os"
	"path"
	"time"

	nntpserver "github.com/dustin/go-nntp/server"
	"github.com/go-kit/log"
	"github.com/go-kit/log/level"
	"github.com/go-kit/log/term"

	"tildegit.org/tjp/metanews/iris"
	"tildegit.org/tjp/metanews/slog"
)

func main() {
	logger := setupLogging()

	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		fatal(logger, "network listen failed", err)
	}
	_ = level.Info(logger).Log(
		"msg", "listening",
		"addr", l.Addr().String(),
	)

	writeLocation(l.Addr().String(), logger)

	ib, err := iris.NewBackend(logger, 0)
	if err != nil {
		fatal(logger, "error starting iris backend", err)
	}

	sb, err := slog.NewBackend(logger, 0)
	if err != nil {
		fatal(logger, "error starting slog backend", err)
	}

	backend, err := NewMetaBackend(logger, ib, sb)
	if err != nil {
		fatal(logger, "creating meta backend failed", err)
	}

	server := nntpserver.NewServer(backend)

	c, err := l.Accept()
	if err != nil {
		fatal(logger, "accepting network connection failed", err)
	}
	_ = level.Info(logger).Log(
		"msg", "accepted client connection",
		"remote-addr", c.RemoteAddr().String(),
	)

	server.Process(c)
}

func setupLogging() log.Logger {
	base := term.NewLogger(os.Stdout, log.NewLogfmtLogger, func(keyvals ...any) term.FgBgColor {
		for i := 0; i < len(keyvals)-1; i += 2 {
			if keyvals[i] != "level" {
				continue
			}

			switch keyvals[i+1] {
			case level.DebugValue():
				return term.FgBgColor{Fg: term.Gray}
			case level.InfoValue():
				return term.FgBgColor{Fg: term.Green}
			case level.WarnValue():
				return term.FgBgColor{Fg: term.Yellow}
			case level.ErrorValue():
				return term.FgBgColor{Fg: term.Red}
			}
		}

		return term.FgBgColor{}
	})
	base = log.NewSyncLogger(base)
	base = log.With(base, "ts", func() any {
		return time.Now().UTC().Format(time.DateTime)
	})

	// go-nntp is noisy on the stdlib log pkg
	stdlibLogger := level.Debug(log.With(base, "src", "go-nntp"))
	stdlog.SetOutput(log.NewStdlibAdapter(stdlibLogger))

	return base
}

func writeLocation(location string, logger log.Logger) {
	home, err := os.UserHomeDir()
	if err != nil {
		fatal(logger, "finding user home dir failed", err)
	}

	filepath := path.Join(home, ".metanews-server")
	f, err := os.Create(filepath)
	if err != nil {
		fatal(logger, "creating server location file failed", err)
	}
	defer func() { _ = f.Close() }()

	if _, err := fmt.Fprintln(f, location); err != nil {
		fatal(logger, "failed writing to location file", err)
	}

	_ = level.Info(logger).Log(
		"msg", "wrote address to location file",
		"address", location,
		"file", filepath,
	)
}

func fatal(logger log.Logger, msg string, err error) {
	_ = level.Error(logger).Log("msg", msg, "err", err)
	os.Exit(1)
}