- 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>
134 lines
2.9 KiB
Go
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...)
|
|
} |