Skip to content

Commit 1abd702

Browse files
committed
- Logs are now stored in local file and every 1K register we upload to the database
- Maximum threads elevated to 10 - Passing user as cookie after login - Separate gorm models from regular models - Log model created - Better feedback
1 parent d4a762d commit 1abd702

File tree

8 files changed

+156
-25
lines changed

8 files changed

+156
-25
lines changed

controllers/controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ func Login(c *gin.Context) {
8484

8585
// Set token as a cookie
8686
c.SetCookie("token", token, 60*60, "/", "", false, true)
87+
c.SetCookie("user", user.Email, 60*60, "/", "", false, true)
8788

8889
// Return success response
8990
c.JSON(http.StatusOK, gin.H{"Message": "Login successful"})

database/db.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ func connectDB() *gorm.DB {
8282
return nil
8383
}
8484

85+
//create table log
86+
err = db.AutoMigrate(&models.Log{})
87+
if err != nil {
88+
fmt.Printf("Error on gorm auto migrate to database : error=%v\n", err)
89+
return nil
90+
}
91+
8592
return db
8693
}
8794

log/log.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package log
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
database2 "github.com/Darklabel91/API_Names/database"
7+
"github.com/Darklabel91/API_Names/models"
8+
"github.com/gin-gonic/gin"
9+
"gorm.io/gorm"
10+
"io"
11+
"os"
12+
"sync"
13+
)
14+
15+
//user, err := c.Cookie("user")
16+
//if err != nil {
17+
// c.AbortWithStatus(http.StatusUnauthorized)
18+
// return
19+
//}
20+
21+
const logBufferSize = 1000
22+
23+
type databaseWriter struct {
24+
buffer bytes.Buffer
25+
db *gorm.DB
26+
mutex sync.Mutex
27+
logCount int
28+
}
29+
30+
func (w *databaseWriter) Write(p []byte) (n int, err error) {
31+
w.mutex.Lock()
32+
defer w.mutex.Unlock()
33+
34+
n, err = w.buffer.Write(p)
35+
if err != nil {
36+
return
37+
}
38+
39+
// Count the number of logs written to the buffer
40+
w.logCount += bytes.Count(p, []byte{'\n'})
41+
42+
// If the buffer is full, flush it to the database
43+
if w.logCount >= logBufferSize {
44+
err = w.flush()
45+
if err != nil {
46+
return
47+
}
48+
}
49+
50+
return
51+
}
52+
53+
func (w *databaseWriter) flush() error {
54+
// Split the buffer into individual log messages
55+
logs := bytes.Split(w.buffer.Bytes(), []byte{'\n'})
56+
for _, log := range logs {
57+
// Skip empty log messages
58+
if len(log) == 0 {
59+
continue
60+
}
61+
62+
// Insert the log into the database
63+
err := w.db.Create(&models.Log{Message: string(log)}).Error
64+
if err != nil {
65+
return err
66+
}
67+
}
68+
69+
// Reset the buffer and log count
70+
w.buffer.Reset()
71+
w.logCount = 0
72+
73+
return nil
74+
}
75+
76+
func LocalLog() gin.HandlerFunc {
77+
// Create the file writer and database writer
78+
file, err := os.Create("log/gin.txt")
79+
if err != nil {
80+
fmt.Println("Log not created")
81+
return nil
82+
}
83+
database := &databaseWriter{db: database2.InitDb()}
84+
85+
// Use a multi-writer to write to both the file and database writers
86+
writer := io.MultiWriter(file, database)
87+
88+
// Create the gin logger with the custom writer
89+
logger := gin.LoggerWithWriter(writer)
90+
91+
return func(c *gin.Context) {
92+
// Call the logger middleware
93+
logger(c)
94+
95+
// Flush the logs to the database if necessary
96+
if database.logCount >= logBufferSize {
97+
err = database.flush()
98+
if err != nil {
99+
fmt.Println(err)
100+
return
101+
}
102+
}
103+
}
104+
}

main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ func main() {
1212
return
1313
}
1414

15-
fmt.Println("- live")
15+
fmt.Println("- Listening and serving")
1616
routes.HandleRequests()
1717
}

middleware/requireAuth.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
"time"
1313
)
1414

15-
const MaxThreadsByToken = 5
15+
const MaxThreadsByToken = 10
1616

1717
// RequireAuth returns a Gin middleware function that checks for a valid JWT token in the request header or cookie, and limits the rate of requests to prevent DDoS attacks.
1818
// - The rate limit is enforced using a token bucket algorithm.

models/models.go

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,18 @@ import (
55
"time"
66
)
77

8-
//NameType main struct
9-
type NameType struct {
10-
gorm.Model
11-
Name string `gorm:"unique" json:"Name,omitempty"`
12-
Classification string `json:"Classification,omitempty"`
13-
Metaphone string `json:"Metaphone,omitempty"`
14-
NameVariations string `json:"NameVariations,omitempty"`
15-
}
16-
17-
//User is the struct of API users
18-
type User struct {
19-
gorm.Model
20-
Email string `gorm:"unique"`
21-
Password string
22-
}
23-
248
//NameLevenshtein struct for organizing name variations by Levenshtein
259
type NameLevenshtein struct {
2610
Name string
2711
Levenshtein float32
2812
}
2913

14+
//InputBody struct for validation middleware
15+
type InputBody struct {
16+
Email string `json:"Email,omitempty"`
17+
Password string `json:"Password,omitempty"`
18+
}
19+
3020
//MetaphoneR only use for SearchSimilarNames return
3121
type MetaphoneR struct {
3222
ID uint `json:"ID,omitempty"`
@@ -38,9 +28,3 @@ type MetaphoneR struct {
3828
Metaphone string `json:"Metaphone,omitempty"`
3929
NameVariations []string `json:"NameVariations,omitempty"`
4030
}
41-
42-
//InputBody struct for validation middleware
43-
type InputBody struct {
44-
Email string `json:"Email,omitempty"`
45-
Password string `json:"Password,omitempty"`
46-
}

models/modelsGrom.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package models
2+
3+
import (
4+
"gorm.io/gorm"
5+
)
6+
7+
//NameType main struct
8+
type NameType struct {
9+
gorm.Model
10+
Name string `gorm:"unique" json:"Name,omitempty"`
11+
Classification string `json:"Classification,omitempty"`
12+
Metaphone string `json:"Metaphone,omitempty"`
13+
NameVariations string `json:"NameVariations,omitempty"`
14+
}
15+
16+
//User is the struct of API users
17+
type User struct {
18+
gorm.Model
19+
Email string `gorm:"unique"`
20+
Password string
21+
}
22+
23+
//Log is the struct used to register the log file
24+
type Log struct {
25+
gorm.Model
26+
user string
27+
Message string
28+
}

routes/routes.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package routes
33
import (
44
"github.com/Darklabel91/API_Names/controllers"
55
"github.com/Darklabel91/API_Names/database"
6+
"github.com/Darklabel91/API_Names/log"
67
"github.com/Darklabel91/API_Names/middleware"
78
"github.com/Darklabel91/API_Names/models"
89
"github.com/gin-gonic/gin"
@@ -16,13 +17,17 @@ var allowedIPs = []string{"127.0.0.1", "::1"} // List of allowed IP addresses
1617
func HandleRequests() {
1718
gin.SetMode(gin.ReleaseMode)
1819
r := gin.Default()
20+
r.Use(log.LocalLog())
1921

20-
// Use the OnlyAllowIPs middleware on all routes
22+
//use the OnlyAllowIPs middleware on all routes
2123
err := r.SetTrustedProxies(allowedIPs)
2224
if err != nil {
2325
return
2426
}
2527

28+
//export every log to a local file and upload to the database on every 1000k request's
29+
//r.Use(log.Testando)
30+
2631
//set up routes
2732
r.POST("/signup", controllers.Signup)
2833
r.POST("/login", controllers.Login)
@@ -38,6 +43,8 @@ func HandleRequests() {
3843
r.GET("/name/:name", middleware.ValidateNameParam(), waitGroupName)
3944
r.GET("/metaphone/:name", middleware.ValidateNameParam(), preloadNameTypes(), middleware.ValidateNameParam(), waitGroupMetaphone)
4045

46+
gin.Logger()
47+
4148
// run
4249
err = r.Run(door)
4350
if err != nil {

0 commit comments

Comments
 (0)