Skip to content

Commit 07dbb0c

Browse files
committed
feat: 用户操作日志
1 parent 599fea3 commit 07dbb0c

5 files changed

Lines changed: 165 additions & 30 deletions

File tree

ServiceV2/client_log.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package ServiceV2
2+
3+
import (
4+
"code/Hahachitchat/dataLayer"
5+
"code/Hahachitchat/definition"
6+
"github.com/gin-gonic/gin"
7+
"github.com/gorilla/websocket"
8+
"net/http"
9+
)
10+
11+
func InitClientLog() {
12+
definition.ClientLogChan = make(chan string, 500)
13+
definition.WsLogConnChan = make(chan struct{}, 1)
14+
}
15+
16+
func LogWebSocketConnect(c *gin.Context) {
17+
select {
18+
case definition.WsLogConnChan <- struct{}{}:
19+
default: // 只允许一个连接
20+
c.JSON(http.StatusOK, definition.CommonResponse{
21+
State: definition.ServerError,
22+
StateMessage: "服务器繁忙",
23+
})
24+
return
25+
}
26+
defer func() {
27+
<-definition.WsLogConnChan // 释放连接
28+
}()
29+
30+
upGrader := websocket.Upgrader{
31+
CheckOrigin: func(r *http.Request) bool {
32+
return true
33+
},
34+
}
35+
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
36+
defer ws.Close()
37+
if err != nil {
38+
dataLayer.Serverlog.Println("[WebSocketConnect] err: ", err)
39+
return
40+
}
41+
42+
for {
43+
log := <-definition.ClientLogChan
44+
err := ws.WriteMessage(websocket.TextMessage, []byte(log))
45+
if err != nil {
46+
dataLayer.Serverlog.Println("[LogWebSocketConnect] err: ", err)
47+
break
48+
}
49+
}
50+
}

ServiceV2/middleWare.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package ServiceV2
22

33
import (
4+
"bytes"
45
"code/Hahachitchat/dataLayer"
56
"code/Hahachitchat/definition"
67
"code/Hahachitchat/utils"
8+
"encoding/json"
79
"github.com/gin-gonic/gin"
810
"net/http"
911
)
@@ -98,3 +100,43 @@ func SetSessionMiddleWare() gin.HandlerFunc { // 用户有登录态则写入,
98100
c.Next()
99101
}
100102
}
103+
104+
func ClientLogMiddleWare() gin.HandlerFunc {
105+
return func(c *gin.Context) {
106+
blw := &definition.CustomResponseWriter{Body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
107+
c.Writer = blw
108+
c.Next()
109+
if operateName, exist := definition.URLMapOperateName[c.Request.URL.Path]; exist {
110+
var responseMessage definition.CommonResponse
111+
json.Unmarshal([]byte(blw.Body.String()), &responseMessage)
112+
clientLog := definition.ClientLog{
113+
IP: c.ClientIP(),
114+
Uid: nil,
115+
OperateName: operateName,
116+
HttpStatusCode: c.Writer.Status(),
117+
ResponseMessage: definition.ResponseMessage{
118+
State: responseMessage.State,
119+
StateMessage: responseMessage.StateMessage,
120+
},
121+
}
122+
123+
userId, exists := c.Get("u_id")
124+
uid, ok := userId.(uint64)
125+
if exists && ok {
126+
clientLog.Uid = &uid // 有登录态
127+
}
128+
b, _ := json.Marshal(&clientLog)
129+
select {
130+
case definition.ClientLogChan <- string(b):
131+
default: // 阻塞时先消费 50 个再写入
132+
for i := 0; i < 50; i++ {
133+
select {
134+
case <-definition.ClientLogChan:
135+
default: // 防止消费阻塞
136+
}
137+
}
138+
definition.ClientLogChan <- string(b)
139+
}
140+
}
141+
}
142+
}

ServiceV2/newService.go

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ package ServiceV2
33
import (
44
"code/Hahachitchat/dataLayer"
55
"code/Hahachitchat/definition"
6-
"github.com/chenjiandongx/ginprom"
76
"github.com/gin-gonic/gin"
8-
"github.com/prometheus/client_golang/prometheus/promhttp"
97
"os"
108
)
119

@@ -36,40 +34,36 @@ func StartService(port string) {
3634
ServiceInit()
3735

3836
r := gin.Default()
39-
// use prometheus metrics exporter middleware.
40-
r.Use(ginprom.PromMiddleware(ginprom.NewDefaultOpts()))
4137

42-
// register the `/metrices` route.
38+
r.Use(HearsetMiddleWare())
4339

44-
r.GET("/metrics", ginprom.PromHandler(promhttp.Handler()))
40+
clientRoute := r.Group("", ClientLogMiddleWare(), ForbiddenMiddleWare())
4541

46-
r.Use(HearsetMiddleWare(), ForbiddenMiddleWare())
42+
clientRoute.GET("/", DefaultTest)
43+
clientRoute.GET("/allpostid", AllPostId)
44+
clientRoute.GET("/top-post", GetTopPost)
45+
clientRoute.GET("/allcommentid/:post_id", AllCommentIdByPostId)
46+
clientRoute.GET("/user/:u_id", GetUserById)
47+
clientRoute.GET("/post/:post_id", GetPostById)
48+
clientRoute.GET("/comment/:comment_id", GetCommentById)
49+
clientRoute.GET("/reply/:reply_id", GetReplyById)
50+
clientRoute.GET("/allposthot", AllPostHot)
51+
clientRoute.GET("/getimg/:img_id", GetImg)
52+
clientRoute.GET("/id-by-name/:u_nickname", GetUidByUserNickname)
4753

48-
r.GET("/", DefaultTest)
49-
r.GET("/allpostid", AllPostId)
50-
r.GET("/top-post", GetTopPost)
51-
r.GET("/allcommentid/:post_id", AllCommentIdByPostId)
52-
r.GET("/user/:u_id", GetUserById)
53-
r.GET("/post/:post_id", GetPostById)
54-
r.GET("/comment/:comment_id", GetCommentById)
55-
r.GET("/reply/:reply_id", GetReplyById)
56-
r.GET("/allposthot", AllPostHot)
57-
r.GET("/getimg/:img_id", GetImg)
58-
r.GET("/id-by-name/:u_nickname", GetUidByUserNickname)
59-
60-
r.POST("/register", Register)
61-
r.POST("/login", Login)
54+
clientRoute.POST("/register", Register)
55+
clientRoute.POST("/login", Login)
6256

6357
//可能需要登录态的操作 个人资料(根据用户隐私设置判断是否展示)
64-
profileRoute := r.Group("/profile", SetSessionMiddleWare())
58+
profileRoute := clientRoute.Group("/profile", SetSessionMiddleWare())
6559
profileRoute.GET("/user-saved/:u_id", GetUserSavedPost)
6660
profileRoute.GET("/subscriptions/:u_id", GetSubscriptions)
6761
profileRoute.GET("/allpostid-by-uid/:u_id", GetUserAllPostId)
6862
profileRoute.GET("/allcommentid-by-uid/:u_id", GetUserAllCommentId)
6963
profileRoute.GET("/allreplyid-by-uid/:u_id", GetUserAllReplyId)
7064

7165
// 需要登录态的操作
72-
needSessionRoute := r.Group("", AuthMiddleWare())
66+
needSessionRoute := clientRoute.Group("", AuthMiddleWare())
7367

7468
needSessionRoute.GET("/user_state", GetUserState)
7569
needSessionRoute.GET("/ws-connect", WebSocketConnect)
@@ -100,13 +94,13 @@ func StartService(port string) {
10094
MessageRoute.POST("/ignore", IgnoreMessages)
10195

10296
// ------------V2--------------
103-
routeV2 := r.Group("/v2")
97+
routeV2 := clientRoute.Group("/v2")
10498
routeV2.GET("/zone/:zone", AllPostByZone)
10599
routeV2.GET("/comment/:comment_id", GetCommentByIdV2)
106100
routeV2.POST("/posts", BatchQueryPost)
107101

108102
// 点赞功能
109-
voteRoute := r.Group("/vote")
103+
voteRoute := clientRoute.Group("/vote")
110104
voteRoute.GET("/post/:post_id", GetPostVote)
111105
voteRoute.GET("/comment/:comment_id", GetCommentVote)
112106
voteRoute.POST("/post", AuthMiddleWare(), VotePost)
@@ -117,7 +111,7 @@ func StartService(port string) {
117111
adminRoute.GET("/users", GetAllUser)
118112
adminRoute.GET("/ban-users", GetBanUser)
119113
adminRoute.POST("/add-ban-users", AddBanUser)
120-
adminRoute.POST("/cancel-ban-users",CancelBanUser)
114+
adminRoute.POST("/cancel-ban-users", CancelBanUser)
121115
adminRoute.GET("/ban-ips", GetBanIPs)
122116
adminRoute.POST("/add-ban-ips", AddBanIP)
123117
adminRoute.POST("/cancel-ban-ip", CancelBanIp)
@@ -127,11 +121,11 @@ func StartService(port string) {
127121
adminRoute.POST("/delete-reply", AdminDeleteReplyById)
128122
adminRoute.POST("/set-top-post", SetTopPost)
129123
// 审批功能
130-
adminRoute.POST("/set-approval-user",SetApprovalUser)
131-
adminRoute.GET("/need-approval-post",GetNeedApprovalPost)
132-
adminRoute.POST("/approval-post",ApprovalPost)
124+
adminRoute.POST("/set-approval-user", SetApprovalUser)
125+
adminRoute.GET("/need-approval-post", GetNeedApprovalPost)
126+
adminRoute.POST("/approval-post", ApprovalPost)
133127
//日志功能
134-
128+
adminRoute.GET("/log-ws-connect", LogWebSocketConnect)
135129
// 查看统计图
136130
postStatisticsRoute := adminRoute.Group("/post-statistics")
137131
postStatisticsRoute.GET("/line-chart", PostStatisticsLineChart)

definition/client_log.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package definition
2+
3+
import (
4+
"bytes"
5+
"github.com/gin-gonic/gin"
6+
)
7+
8+
var ClientLogChan chan string
9+
var WsLogConnChan chan struct{}
10+
11+
type CustomResponseWriter struct {
12+
gin.ResponseWriter
13+
Body *bytes.Buffer
14+
}
15+
16+
func (w CustomResponseWriter) Write(b []byte) (int, error) {
17+
w.Body.Write(b)
18+
return w.ResponseWriter.Write(b)
19+
}
20+
21+
func (w CustomResponseWriter) WriteString(s string) (int, error) {
22+
w.Body.WriteString(s)
23+
return w.ResponseWriter.WriteString(s)
24+
}
25+
26+
type ResponseMessage struct {
27+
State int `json:"业务状态码"`
28+
StateMessage string `json:"响应消息"`
29+
}
30+
31+
type ClientLog struct {
32+
IP string `json:"IP地址"`
33+
Uid *uint64 `json:"用户ID(可空)"`
34+
OperateName string `json:"用户操作"`
35+
HttpStatusCode int `json:"HTTP响应"`
36+
ResponseMessage ResponseMessage `json:"操作结果"`
37+
}
38+
39+
var URLMapOperateName = map[string]string{
40+
"/register": "用户注册",
41+
"/login": "用户登录",
42+
"/create-post": "用户发贴",
43+
"/create-comment": "发表评论",
44+
"/create-reply": "发表回复",
45+
"/delete-post": "删除贴子",
46+
"/delete-comment": "删除评论",
47+
"/delete-reply": "删除回复",
48+
"/uploadimg": "更换头像",
49+
}

xixi

6.58 MB
Binary file not shown.

0 commit comments

Comments
 (0)