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
package main

import (
	"context"
	"fmt"
	"go.uber.org/fx"
	"net/http"
	"os"
	"rss_parrot/dal"
	"rss_parrot/logic"
	"rss_parrot/server"
	"rss_parrot/shared"
	"rss_parrot/texts"
)

type initErrorHandler struct {
}

func (*initErrorHandler) HandleError(err error) {
	fmt.Fprintf(os.Stderr, "Failed to initialize dependency injection\n%v", err)
}

var logger *shared.Logger

func main() {

	cfg := shared.LoadConfig()
	provideConfig := func() *shared.Config {
		return cfg
	}

	logger = initLogger(cfg)
	provideLogger := func() shared.ILogger {
		return logger
	}

	app := fx.New(
		fx.NopLogger,
		fx.Provide(
			provideConfig,
			provideLogger,
			shared.NewUserAgent,
			server.NewHTTPServer,
			fx.Annotate(server.NewMux, fx.ParamTags(`group:"handler_group"`)),
			logic.NewKeyStore,
			logic.NewBlockedFeeds,
			logic.NewMetrics,
			logic.NewFeedFollower,
			logic.NewUserDirectory,
			logic.NewActivitySender,
			logic.NewHttpSigChecker,
			logic.NewUserRetriever,
			logic.NewMessenger,
			logic.NewInbox,
			logic.NewProfiler,
			texts.NewTexts,
			dal.NewRepo,
			asHandlerGroupDef(server.NewApubHandlerGroup),
			asHandlerGroupDef(server.NewApiHandlerGroup),
			asHandlerGroupDef(server.NewWebHandlerGroup),
			asHandlerGroupDef(server.NewMetricsHandlerGroup),
		),
		fx.Invoke(
			registerHooks,
			func(repo dal.IRepo) { repo.InitUpdateDb() },
			func(prof logic.IProfiler) {}, // Needed so profiler gets instantiated
			func(*http.Server) {},         // Needed so server gets instantiated
			test,
		),
		fx.ErrorHook(&initErrorHandler{}),
	)
	app.Run()
}

func asHandlerGroupDef(f any) any {
	return fx.Annotate(
		f,
		fx.As(new(server.IHandlerGroup)),
		fx.ResultTags(`group:"handler_group"`),
	)
}

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

func registerHooks(lc fx.Lifecycle, metrics logic.IMetrics) {
	lc.Append(
		fx.Hook{
			OnStart: func(context.Context) error {
				logger.Printf("Application starting up")
				metrics.ServiceStarted()
				return nil
			},
			OnStop: func(context.Context) error {
				logger.Printf("Application shutting down")
				return nil
			},
		},
	)
}

func test(ff logic.IFeedFollower, repo dal.IRepo) {
	// Used on an ad-hoc basis; keeping here for convenience
}