Refactor: Implement uber-go/fx dependency injection
- Replace global variable pattern with proper dependency injection - Add uber-go/fx for automatic dependency resolution - Refactor all services and handlers to use constructor injection - Eliminate fragile initialization order dependencies - Improve testability and modularity - Add structured logging with zap Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
+123
-64
@@ -1,75 +1,134 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"CatsOfMastodonBotGo/internal/auth"
|
||||
"CatsOfMastodonBotGo/internal/config"
|
||||
"CatsOfMastodonBotGo/internal/database"
|
||||
"CatsOfMastodonBotGo/internal/domain"
|
||||
"CatsOfMastodonBotGo/internal/server"
|
||||
"CatsOfMastodonBotGo/internal/services"
|
||||
"context"
|
||||
"log/slog"
|
||||
"strconv"
|
||||
"time"
|
||||
"CatsOfMastodonBotGo/internal/web/handlers"
|
||||
|
||||
"go.uber.org/fx"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Setup config
|
||||
config.Init()
|
||||
|
||||
// Initialize database
|
||||
database.Init()
|
||||
|
||||
services.InitPostService()
|
||||
|
||||
// Not needed but anyways
|
||||
services.InitImgKitHelper()
|
||||
|
||||
ticker := time.NewTicker(10 * time.Minute)
|
||||
|
||||
runFetchPosts := func() {
|
||||
// Get posts
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
var posts []domain.Post = nil
|
||||
err, posts := services.PostServiceInstance.GetPostsFromApi(ctx, config.Config.Tag, config.Config.Instance)
|
||||
if err != nil {
|
||||
slog.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var existingPostIds = services.PostServiceInstance.GetExistingPostIds()
|
||||
var existingAccountIds = services.PostServiceInstance.GetExistingAccountIds()
|
||||
var newPosts = services.PostServiceInstance.GetNewPosts(existingPostIds, posts)
|
||||
var newAccounts = services.PostServiceInstance.GetNewAccounts(existingAccountIds, newPosts)
|
||||
|
||||
// Save to database
|
||||
slog.Info("Fetched " + strconv.Itoa(len(posts)) + " posts; " + strconv.Itoa(len(existingPostIds)) + " existing posts; " + strconv.Itoa(len(newPosts)) + " new posts and " + strconv.Itoa(len(newAccounts)) + " new accounts\n")
|
||||
// Additional logging
|
||||
if newAccounts != nil {
|
||||
slog.Info("Inserted " + strconv.Itoa(services.PostServiceInstance.InsertNewAccounts(newAccounts)) + " accounts\n")
|
||||
}
|
||||
if newPosts != nil {
|
||||
slog.Info("Inserted " + strconv.Itoa(services.PostServiceInstance.InsertNewPosts(newPosts)) + " posts\n")
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
for range ticker.C {
|
||||
runFetchPosts()
|
||||
}
|
||||
}()
|
||||
|
||||
// Run initial fetch on startup
|
||||
go func() {
|
||||
runFetchPosts()
|
||||
}()
|
||||
|
||||
// https://seefnasrul.medium.com/create-your-first-go-rest-api-with-jwt-authentication-in-gin-framework-dbe5bda72817
|
||||
|
||||
r := server.SetupRouter()
|
||||
err := r.Run(":8080")
|
||||
if err != nil {
|
||||
slog.Error(err.Error())
|
||||
}
|
||||
|
||||
fx.New(
|
||||
fx.Provide(
|
||||
// Configuration
|
||||
config.Load,
|
||||
|
||||
// Database
|
||||
database.Connect,
|
||||
|
||||
// Services
|
||||
services.NewPostService,
|
||||
services.NewImgKitHelper,
|
||||
|
||||
// Auth
|
||||
auth.NewJwtTokenGenerator,
|
||||
auth.NewGiteaOauth2Token,
|
||||
|
||||
// Handlers
|
||||
handlers.NewAdminDashboardHandler,
|
||||
handlers.NewApiEndpointHandler,
|
||||
handlers.NewEmbedCardHandler,
|
||||
handlers.NewOauthLoginHandler,
|
||||
|
||||
// Logger
|
||||
NewLogger,
|
||||
),
|
||||
fx.Invoke(
|
||||
// Start background tasks
|
||||
startBackgroundTasks,
|
||||
|
||||
// Setup and start server
|
||||
server.SetupRouter,
|
||||
),
|
||||
fx.Logger(NewFXLogger()), // Optional custom logger
|
||||
).Run()
|
||||
}
|
||||
|
||||
// Background tasks as a separate function
|
||||
func startBackgroundTasks(
|
||||
lc fx.Lifecycle,
|
||||
postService *services.PostService,
|
||||
cfg *config.Config,
|
||||
logger *zap.Logger,
|
||||
) {
|
||||
lc.Append(fx.Hook{
|
||||
OnStart: func(context.Context) error {
|
||||
ticker := time.NewTicker(10 * time.Minute)
|
||||
|
||||
runFetchPosts := func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
|
||||
posts, err := postService.GetPostsFromApi(ctx, cfg.Tag, cfg.Instance)
|
||||
if err != nil {
|
||||
logger.Error("Failed to fetch posts", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
existingPostIds := postService.GetExistingPostIds()
|
||||
existingAccountIds := postService.GetExistingAccountIds()
|
||||
newPosts := postService.GetNewPosts(existingPostIds, posts)
|
||||
newAccounts := postService.GetNewAccounts(existingAccountIds, newPosts)
|
||||
|
||||
logger.Info("Fetched posts",
|
||||
zap.Int("total", len(posts)),
|
||||
zap.Int("existing", len(existingPostIds)),
|
||||
zap.Int("new", len(newPosts)),
|
||||
zap.Int("new_accounts", len(newAccounts)))
|
||||
|
||||
if len(newAccounts) > 0 {
|
||||
count := postService.InsertNewAccounts(newAccounts)
|
||||
logger.Info("Inserted accounts", zap.Int("count", count))
|
||||
}
|
||||
|
||||
if len(newPosts) > 0 {
|
||||
count := postService.InsertNewPosts(newPosts)
|
||||
logger.Info("Inserted posts", zap.Int("count", count))
|
||||
}
|
||||
}
|
||||
|
||||
// Run initial fetch
|
||||
go runFetchPosts()
|
||||
|
||||
// Start ticker
|
||||
go func() {
|
||||
for range ticker.C {
|
||||
runFetchPosts()
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
},
|
||||
OnStop: func(context.Context) error {
|
||||
// Cleanup if needed
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Logger provider
|
||||
func NewLogger() (*zap.Logger, error) {
|
||||
return zap.NewDevelopment()
|
||||
}
|
||||
|
||||
// Simple logger for fx
|
||||
type FXLogger struct {
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
func NewFXLogger() *FXLogger {
|
||||
logger, _ := zap.NewDevelopment()
|
||||
return &FXLogger{logger: logger}
|
||||
}
|
||||
|
||||
func (l *FXLogger) Printf(str string, args ...interface{}) {
|
||||
l.logger.Sugar().Infof(str, args...)
|
||||
}
|
||||
Reference in New Issue
Block a user