-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathmain.go
177 lines (148 loc) · 4.44 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package main
import (
"context"
"log"
"net/http"
"os"
"os/exec"
"os/signal"
"stockbackend/middleware"
"stockbackend/routes"
"stockbackend/services"
"strconv"
"syscall"
"time"
"github.com/getsentry/sentry-go"
sentrygin "github.com/getsentry/sentry-go/gin"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// Peer represents the data of a peer stock
type Peer struct {
Name string
PE float64
MarketCap float64
DividendYield float64
ROCE float64
QuarterlySales float64
QuarterlyProfit float64
}
// QuarterlyData holds historical data for a stock
type QuarterlyData struct {
NetProfit float64
Sales float64
TotalLiabilities float64
ROCE float64
}
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
origin := c.Request.Header.Get("Origin")
if origin != "" {
c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
}
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With, trell-auth-token, trell-app-version-int, creator-space-auth-token")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
// GracefulShutdown handles graceful shutdown of the server and ticker
func GracefulShutdown(server *http.Server, ticker, rankUpdater *time.Ticker) {
stopper := make(chan os.Signal, 1)
// Listen for interrupt and SIGTERM signals
signal.Notify(stopper, os.Interrupt, syscall.SIGTERM)
go func() {
<-stopper
zap.L().Info("Shutting down gracefully...")
// Stop the ticker
ticker.Stop()
rankUpdater.Stop()
// Create a context with a timeout for shutdown
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Shut down the server
if err := server.Shutdown(ctx); err != nil {
zap.L().Error("Server shutdown failed", zap.Error(err))
return
}
zap.L().Info("Server exited gracefully")
}()
}
func setupSentry() {
tracesSampleRate, err := strconv.ParseFloat(os.Getenv("SENTRY_SAMPLE_RATE"), 64)
if err != nil {
tracesSampleRate = 1.0
}
if err := sentry.Init(sentry.ClientOptions{
Dsn: os.Getenv("SENTRY_DSN"),
Environment: os.Getenv("ENVIRONMENT"),
EnableTracing: true,
Debug: true,
// Set TracesSampleRate to 1.0 to capture 100%
// of transactions for tracing.
// Sentry recommend adjusting this value in production,
TracesSampleRate: tracesSampleRate, // 1.0 by default if ENV SENTRY_SAMPLE_RATE not set
}); err != nil {
zap.L().Error("Sentry initialization failed: ", zap.Any("error", err.Error()))
}
}
func main() {
config := zap.NewProductionConfig()
config.Level = zap.NewAtomicLevelAt(zap.ErrorLevel)
logger, _ := config.Build()
zap.ReplaceGlobals(logger)
setupSentry()
router := gin.New()
router.Use(middleware.RecoveryMiddleware())
router.Use(sentrygin.New(sentrygin.Options{}))
router.Use(CORSMiddleware())
ticker := startTicker()
rankUpdater := startRankUpdater()
routes.Routes(router)
port := os.Getenv("PORT")
if port == "" {
port = "4000"
}
// Create a server instance using gin engine as handler
server := &http.Server{
Addr: ":" + port,
Handler: router,
}
// Call GracefulShutdown with the server and ticker
GracefulShutdown(server, ticker, rankUpdater)
// Start the server
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("Error starting server: %v", err)
}
}
func startTicker() *time.Ticker {
ticker := time.NewTicker(48 * time.Second)
go func() {
for t := range ticker.C {
zap.L().Info("Tick at: ", zap.String("time", t.String()))
cmd := exec.Command("curl", "https://free-fokat.onrender.com/api/keepServerRunning")
output, err := cmd.CombinedOutput()
if err != nil {
zap.L().Error("Error running curl: ", zap.Any("error", err.Error()))
return
}
zap.L().Info("Curl output: ", zap.String("output", string(output)))
}
}()
return ticker
}
func startRankUpdater() *time.Ticker {
ticker := time.NewTicker(30 * time.Hour * 24)
go func() {
for t := range ticker.C {
//write a function that is called every 30 days
zap.L().Info("Rank updater tick at: ", zap.String("time", t.String()))
services.UpdateRating()
}
}()
return ticker
}