package main import ( "context" "fmt" "log" "os" "time" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/logger" "github.com/gooseek/backend/internal/finance" ) func main() { heatmapSvc := finance.NewHeatmapService(finance.HeatmapConfig{ CacheTTL: 5 * time.Minute, RefreshInterval: time.Minute, }) app := fiber.New(fiber.Config{ ReadTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second, }) app.Use(logger.New()) app.Use(cors.New()) app.Get("/health", func(c *fiber.Ctx) error { return c.JSON(fiber.Map{"status": "ok"}) }) app.Get("/api/v1/heatmap/:market", func(c *fiber.Ctx) error { market := c.Params("market") timeRange := c.Query("range", "1d") ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() heatmap, err := heatmapSvc.GetMarketHeatmap(ctx, market, timeRange) if err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(heatmap) }) app.Get("/api/v1/heatmap/:market/treemap", func(c *fiber.Ctx) error { market := c.Params("market") timeRange := c.Query("range", "1d") ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() heatmap, err := heatmapSvc.GetMarketHeatmap(ctx, market, timeRange) if err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } treemapData := heatmapSvc.GenerateTreemapData(heatmap) return c.JSON(treemapData) }) app.Get("/api/v1/heatmap/:market/grid", func(c *fiber.Ctx) error { market := c.Params("market") timeRange := c.Query("range", "1d") rows := c.QueryInt("rows", 5) cols := c.QueryInt("cols", 10) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() heatmap, err := heatmapSvc.GetMarketHeatmap(ctx, market, timeRange) if err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } gridData := heatmapSvc.GenerateGridData(heatmap, rows, cols) return c.JSON(fiber.Map{"grid": gridData, "rows": rows, "cols": cols}) }) app.Get("/api/v1/heatmap/:market/sector/:sector", func(c *fiber.Ctx) error { market := c.Params("market") sector := c.Params("sector") timeRange := c.Query("range", "1d") ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() heatmap, err := heatmapSvc.GetSectorHeatmap(ctx, market, sector, timeRange) if err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(heatmap) }) app.Get("/api/v1/movers/:market", func(c *fiber.Ctx) error { market := c.Params("market") count := c.QueryInt("count", 10) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() movers, err := heatmapSvc.GetTopMovers(ctx, market, count) if err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(movers) }) app.Get("/api/v1/markets", func(c *fiber.Ctx) error { markets := []map[string]interface{}{ {"id": "sp500", "name": "S&P 500", "region": "us"}, {"id": "nasdaq", "name": "NASDAQ", "region": "us"}, {"id": "dow", "name": "Dow Jones", "region": "us"}, {"id": "moex", "name": "MOEX", "region": "ru"}, {"id": "crypto", "name": "Cryptocurrency", "region": "global"}, {"id": "forex", "name": "Forex", "region": "global"}, } return c.JSON(fiber.Map{"markets": markets}) }) port := getEnvInt("PORT", 3033) log.Printf("finance-heatmap-svc listening on :%d", port) log.Fatal(app.Listen(fmt.Sprintf(":%d", port))) } func getEnvInt(key string, defaultValue int) int { if val := os.Getenv(key); val != "" { var result int if _, err := fmt.Sscanf(val, "%d", &result); err == nil { return result } } return defaultValue }