Files
CatsOfMastodonGo/cmd/CatsOfMastodonBotGo/main.go
Mohammad Mahdi f136ae58b3 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>
2025-09-16 11:41:01 +03:30

134 lines
2.9 KiB
Go

package main
import (
"context"
"time"
"CatsOfMastodonBotGo/internal/auth"
"CatsOfMastodonBotGo/internal/config"
"CatsOfMastodonBotGo/internal/database"
"CatsOfMastodonBotGo/internal/server"
"CatsOfMastodonBotGo/internal/services"
"CatsOfMastodonBotGo/internal/web/handlers"
"go.uber.org/fx"
"go.uber.org/zap"
)
func main() {
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...)
}