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) }