all repos

onasty @ 4195af474492cbc311522682e36c5b021211807a

a one-time notes service

onasty/cmd/server/main.go (view raw)

Smirnov Oleksandr Smirnov Oleksandr
ss2316544@gmail.com
feat: mailer service (#55)..., 1 year ago
1
package main
2
3
import (
4
	"context"
5
	"errors"
6
	"fmt"
7
	"log/slog"
8
	"net/http"
9
	"os"
10
	"os/signal"
11
12
	"github.com/gin-gonic/gin"
13
	"github.com/nats-io/nats.go"
14
	"github.com/olexsmir/onasty/internal/config"
15
	"github.com/olexsmir/onasty/internal/events/mailermq"
16
	"github.com/olexsmir/onasty/internal/hasher"
17
	"github.com/olexsmir/onasty/internal/jwtutil"
18
	"github.com/olexsmir/onasty/internal/logger"
19
	"github.com/olexsmir/onasty/internal/metrics"
20
	"github.com/olexsmir/onasty/internal/service/notesrv"
21
	"github.com/olexsmir/onasty/internal/service/usersrv"
22
	"github.com/olexsmir/onasty/internal/store/psql/noterepo"
23
	"github.com/olexsmir/onasty/internal/store/psql/sessionrepo"
24
	"github.com/olexsmir/onasty/internal/store/psql/userepo"
25
	"github.com/olexsmir/onasty/internal/store/psql/vertokrepo"
26
	"github.com/olexsmir/onasty/internal/store/psqlutil"
27
	"github.com/olexsmir/onasty/internal/store/rdb"
28
	"github.com/olexsmir/onasty/internal/store/rdb/usercache"
29
	httptransport "github.com/olexsmir/onasty/internal/transport/http"
30
	"github.com/olexsmir/onasty/internal/transport/http/httpserver"
31
	"github.com/olexsmir/onasty/internal/transport/http/ratelimit"
32
)
33
34
func main() {
35
	if err := run(context.Background()); err != nil {
36
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
37
		os.Exit(1)
38
	}
39
}
40
41
//nolint:err113,funlen
42
func run(ctx context.Context) error {
43
	ctx, cancel := context.WithCancel(ctx)
44
	defer cancel()
45
46
	cfg := config.NewConfig()
47
48
	// logger
49
	logger, err := logger.NewCustomLogger(cfg.LogLevel, cfg.LogFormat, cfg.LogShowLine)
50
	if err != nil {
51
		return err
52
	}
53
54
	slog.SetDefault(logger)
55
56
	// semi dev mode
57
	if !cfg.IsDevMode() {
58
		gin.SetMode(gin.ReleaseMode)
59
	}
60
61
	// app deps
62
	nc, err := nats.Connect(cfg.NatsURL)
63
	if err != nil {
64
		return err
65
	}
66
67
	psqlDB, err := psqlutil.Connect(ctx, cfg.PostgresDSN)
68
	if err != nil {
69
		return err
70
	}
71
72
	redisDB, err := rdb.Connect(ctx, cfg.RedisAddr, cfg.RedisPassword, cfg.RedisDB)
73
	if err != nil {
74
		return err
75
	}
76
77
	userPasswordHasher := hasher.NewSHA256Hasher(cfg.PasswordSalt)
78
	notePasswordHasher := hasher.NewSHA256Hasher(cfg.NotePassowrdSalt)
79
	jwtTokenizer := jwtutil.NewJWTUtil(cfg.JwtSigningKey, cfg.JwtAccessTokenTTL)
80
81
	mailermq := mailermq.New(nc)
82
83
	sessionrepo := sessionrepo.New(psqlDB)
84
	vertokrepo := vertokrepo.New(psqlDB)
85
86
	userepo := userepo.New(psqlDB)
87
	usercache := usercache.New(redisDB, cfg.CacheUsersTTL)
88
	usersrv := usersrv.New(
89
		userepo,
90
		sessionrepo,
91
		vertokrepo,
92
		userPasswordHasher,
93
		jwtTokenizer,
94
		mailermq,
95
		usercache,
96
		cfg.JwtRefreshTokenTTL,
97
		cfg.VerificationTokenTTL,
98
		cfg.AppURL,
99
	)
100
101
	noterepo := noterepo.New(psqlDB)
102
	notesrv := notesrv.New(noterepo, notePasswordHasher)
103
104
	rateLimiterConfig := ratelimit.Config{
105
		RPS:   cfg.RateLimiterRPS,
106
		TTL:   cfg.RateLimiterTTL,
107
		Burst: cfg.RateLimiterBurst,
108
	}
109
110
	handler := httptransport.NewTransport(
111
		usersrv,
112
		notesrv,
113
		rateLimiterConfig,
114
	)
115
116
	// http server
117
	srv := httpserver.NewServer(cfg.ServerPort, handler.Handler())
118
	go func() {
119
		slog.Info("starting http server", "port", cfg.ServerPort)
120
		if err := srv.Start(); !errors.Is(err, http.ErrServerClosed) {
121
			slog.Error("failed to start http server", "error", err)
122
		}
123
	}()
124
125
	// metrics
126
	if cfg.MetricsEnabled {
127
		mSrv := httpserver.NewServer(cfg.MetricsPort, metrics.Handler())
128
		go func() {
129
			slog.Info("starting metrics server", "port", cfg.MetricsPort)
130
			if err := mSrv.Start(); !errors.Is(err, http.ErrServerClosed) {
131
				slog.Error("failed to start metrics server", "error", err)
132
			}
133
		}()
134
	}
135
136
	// graceful shutdown
137
	quit := make(chan os.Signal, 1)
138
	signal.Notify(quit, os.Interrupt)
139
	<-quit
140
141
	if err := srv.Stop(ctx); err != nil {
142
		return errors.Join(errors.New("failed to stop http server"), err)
143
	}
144
145
	if err := psqlDB.Close(); err != nil {
146
		return errors.Join(errors.New("failed to close postgres connection"), err)
147
	}
148
149
	if err := redisDB.Close(); err != nil {
150
		return errors.Join(errors.New("failed to close redis connection"), err)
151
	}
152
153
	return nil
154
}