first commit

This commit is contained in:
ytc1012
2025-11-18 18:08:48 +08:00
commit de90ad79ea
162 changed files with 28098 additions and 0 deletions

View File

@@ -0,0 +1,204 @@
package controller
import (
"github.com/mitchellh/mapstructure"
"log/slog"
"slgserver/constant"
"slgserver/middleware"
"slgserver/net"
"slgserver/server/chatserver/logic"
"slgserver/server/chatserver/proto"
"slgserver/util"
"sync"
)
var DefaultChat = Chat{
worldGroup: logic.NewGroup(),
unionGroups: make(map[int]*logic.Group),
ridToUnionGroups: make(map[int]int),
}
type Chat struct {
unionMutex sync.RWMutex
worldGroup *logic.Group //世界频道
unionGroups map[int]*logic.Group //联盟频道
ridToUnionGroups map[int]int //rid对应的联盟频道
}
func (this*Chat) InitRouter(r *net.Router) {
g := r.Group("chat").Use(middleware.ElapsedTime(), middleware.Log())
g.AddRouter("login", this.login)
g.AddRouter("logout", this.logout, middleware.CheckRId())
g.AddRouter("chat", this.chat, middleware.CheckRId())
g.AddRouter("history", this.history, middleware.CheckRId())
g.AddRouter("join", this.join, middleware.CheckRId())
g.AddRouter("exit", this.exit, middleware.CheckRId())
}
func (this*Chat) login(req *net.WsMsgReq, rsp *net.WsMsgRsp) {
reqObj := &proto.LoginReq{}
rspObj := &proto.LoginRsp{}
rsp.Body.Code = constant.OK
rsp.Body.Msg = rspObj
mapstructure.Decode(req.Body.Msg, reqObj)
rspObj.RId = reqObj.RId
rspObj.NickName = reqObj.NickName
sess, err := util.ParseSession(reqObj.Token)
if err != nil{
rsp.Body.Code = constant.InvalidParam
return
}
if sess.IsValid() == false || sess.Id != reqObj.RId{
rsp.Body.Code = constant.InvalidParam
return
}
net.ConnMgr.RoleEnter(req.Conn, reqObj.RId)
this.worldGroup.Enter(logic.NewUser(reqObj.RId, reqObj.NickName))
}
func (this*Chat) logout(req *net.WsMsgReq, rsp *net.WsMsgRsp) {
reqObj := &proto.LogoutReq{}
rspObj := &proto.LogoutRsp{}
rsp.Body.Code = constant.OK
rsp.Body.Msg = rspObj
mapstructure.Decode(req.Body.Msg, reqObj)
rspObj.RId = reqObj.RId
net.ConnMgr.UserLogout(req.Conn)
this.worldGroup.Exit(reqObj.RId)
}
func (this*Chat) chat(req *net.WsMsgReq, rsp *net.WsMsgRsp) {
reqObj := &proto.ChatReq{}
rspObj := &proto.ChatMsg{}
rsp.Body.Code = constant.OK
rsp.Body.Msg = rspObj
mapstructure.Decode(req.Body.Msg, reqObj)
p, _ := req.Conn.GetProperty("rid")
rid := p.(int)
if reqObj.Type == 0 {
//世界聊天
rsp.Body.Msg = this.worldGroup.PutMsg(reqObj.Msg, rid, 0)
}else if reqObj.Type == 1{
//联盟聊天
this.unionMutex.RLock()
id, ok := this.ridToUnionGroups[rid]
if ok {
g, ok := this.unionGroups[id]
if ok {
g.PutMsg(reqObj.Msg, rid, 1)
}else{
slog.Warn("chat not found rid in unionGroups", "rid", rid)
}
}else{
slog.Warn("chat not found rid in ridToUnionGroups", "rid", rid)
}
this.unionMutex.RUnlock()
}
}
//历史记录
func (this*Chat) history(req *net.WsMsgReq, rsp *net.WsMsgRsp) {
reqObj := &proto.HistoryReq{}
rspObj := &proto.HistoryRsp{}
rsp.Body.Code = constant.OK
mapstructure.Decode(req.Body.Msg, reqObj)
rspObj.Msgs = []proto.ChatMsg{}
p, _ := req.Conn.GetProperty("rid")
rid := p.(int)
if reqObj.Type == 0 {
r := this.worldGroup.History()
rspObj.Msgs = r
}else if reqObj.Type == 1 {
this.unionMutex.RLock()
id, ok := this.ridToUnionGroups[rid]
if ok {
g, ok := this.unionGroups[id]
if ok {
rspObj.Msgs = g.History()
}
}
this.unionMutex.RUnlock()
}
rspObj.Type = reqObj.Type
rsp.Body.Msg = rspObj
}
func (this*Chat) join(req *net.WsMsgReq, rsp *net.WsMsgRsp) {
reqObj := &proto.JoinReq{}
rspObj := &proto.JoinRsp{}
rsp.Body.Code = constant.OK
rsp.Body.Msg = rspObj
rspObj.Type = reqObj.Type
mapstructure.Decode(req.Body.Msg, reqObj)
p, _ := req.Conn.GetProperty("rid")
rid := p.(int)
if reqObj.Type == 1 {
u := this.worldGroup.GetUser(rid)
if u == nil {
rsp.Body.Code = constant.InvalidParam
return
}
this.unionMutex.Lock()
gId, ok := this.ridToUnionGroups[rid]
if ok {
if gId != reqObj.Id {
//联盟聊天只能有一个,顶掉旧的
if g,ok := this.unionGroups[gId]; ok {
g.Exit(rid)
}
_, ok = this.unionGroups[reqObj.Id]
if ok == false {
this.unionGroups[reqObj.Id] = logic.NewGroup()
}
this.ridToUnionGroups[rid] = reqObj.Id
this.unionGroups[reqObj.Id].Enter(u)
}
}else{
//新加入
_, ok = this.unionGroups[reqObj.Id]
if ok == false {
this.unionGroups[reqObj.Id] = logic.NewGroup()
}
this.ridToUnionGroups[rid] = reqObj.Id
this.unionGroups[reqObj.Id].Enter(u)
}
this.unionMutex.Unlock()
}
}
func (this*Chat) exit(req *net.WsMsgReq, rsp *net.WsMsgRsp) {
reqObj := &proto.ExitReq{}
rspObj := &proto.ExitRsp{}
rsp.Body.Code = constant.OK
rsp.Body.Msg = rspObj
rspObj.Type = reqObj.Type
mapstructure.Decode(req.Body.Msg, reqObj)
p, _ := req.Conn.GetProperty("rid")
rid := p.(int)
if reqObj.Type == 1 {
this.unionMutex.Lock()
id, ok := this.ridToUnionGroups[rid]
if ok {
g, ok := this.unionGroups[id]
if ok {
g.Exit(rid)
}
}
delete(this.ridToUnionGroups, rid)
this.unionMutex.Unlock()
}
}

20
server/chatserver/init.go Normal file
View File

@@ -0,0 +1,20 @@
package chatserver
import (
"slgserver/db"
"slgserver/net"
"slgserver/server/chatserver/controller"
)
var MyRouter = &net.Router{}
func Init() {
db.TestDB()
//全部初始化完才注册路由,防止服务器还没启动就绪收到请求
initRouter()
}
func initRouter() {
controller.DefaultChat.InitRouter(MyRouter)
}

View File

@@ -0,0 +1,22 @@
package logic
import "time"
type User struct {
rid int
nickName string
}
func NewUser(rid int, nickName string) *User {
return &User{
rid: rid,
nickName: nickName,
}
}
type Msg struct {
RId int `json:"rid"`
NickName string `json:"nickName"`
Msg string `json:"msg"`
Time time.Time `json:"time"`
}

View File

@@ -0,0 +1,79 @@
package logic
import (
"slgserver/net"
"slgserver/server/chatserver/proto"
"sync"
"time"
)
type Group struct {
userMutex sync.RWMutex
msgMutex sync.RWMutex
users map[int]*User
msgs ItemQueue
}
func NewGroup() *Group {
return &Group{users: map[int]*User{}}
}
func (this*Group) Enter(u *User) {
this.userMutex.Lock()
defer this.userMutex.Unlock()
this.users[u.rid] = u
}
func (this*Group) Exit(rid int) {
this.userMutex.Lock()
defer this.userMutex.Unlock()
delete(this.users, rid)
}
func (this*Group) GetUser(rid int) *User {
this.userMutex.Lock()
defer this.userMutex.Unlock()
return this.users[rid]
}
func (this*Group) PutMsg(text string, rid int, t int8) *proto.ChatMsg {
this.userMutex.RLock()
u, ok := this.users[rid]
this.userMutex.RUnlock()
if ok == false{
return nil
}
msg := &Msg{Msg: text, RId: rid, Time: time.Now(), NickName: u.nickName}
this.msgMutex.Lock()
size := this.msgs.Size()
if size > 100 {
this.msgs.Dequeue()
}
this.msgs.Enqueue(msg)
this.msgMutex.Unlock()
//广播
this.userMutex.RLock()
c := &proto.ChatMsg{RId: msg.RId, NickName: msg.NickName, Time: msg.Time.Unix(), Msg: msg.Msg, Type: t}
for _, user := range this.users {
net.ConnMgr.PushByRoleId(user.rid, "chat.push", c)
}
this.userMutex.RUnlock()
return c
}
func (this*Group) History() []proto.ChatMsg {
r := make([]proto.ChatMsg, 0)
this.msgMutex.RLock()
items := this.msgs.items
for _, item := range items {
msg := item.(*Msg)
c := proto.ChatMsg{RId: msg.RId, NickName: msg.NickName, Time: msg.Time.Unix(), Msg: msg.Msg}
r = append(r, c)
}
this.msgMutex.RUnlock()
return r
}

View File

@@ -0,0 +1,45 @@
package logic
type Item interface {
}
// Item the type of the queue
type ItemQueue struct {
items []Item
}
type ItemQueuer interface {
New() ItemQueue
Enqueue(t Item)
Dequeue() *Item
IsEmpty() bool
Size() int
}
// New creates a new ItemQueue
func (s *ItemQueue) New() *ItemQueue {
s.items = []Item{}
return s
}
// Enqueue adds an Item to the end of the queue
func (s *ItemQueue) Enqueue(t Item) {
s.items = append(s.items, t)
}
// dequeue
func (s *ItemQueue) Dequeue() *Item {
item := s.items[0] // 先进先出
s.items = s.items[1:len(s.items)]
return &item
}
func (s *ItemQueue) IsEmpty() bool {
return len(s.items) == 0
}
// Size returns the number of Items in the queue
func (s *ItemQueue) Size() int {
return len(s.items)
}

View File

@@ -0,0 +1,64 @@
package proto
type LoginReq struct {
RId int `json:"rid"`
NickName string `json:"nickName"`
Token string `json:"token"`
}
type LoginRsp struct {
RId int `json:"rid"`
NickName string `json:"nickName"`
}
type LogoutReq struct {
RId int `json:"RId"`
}
type LogoutRsp struct {
RId int `json:"RId"`
}
type ChatReq struct {
Type int8 `json:"type"` //0世界聊天、1联盟聊天
Msg string `json:"msg"`
}
type ChatMsg struct {
RId int `json:"rid"`
NickName string `json:"nickName"`
Type int8 `json:"type"` //0世界聊天、1联盟聊天
Msg string `json:"msg"`
Time int64 `json:"time"`
}
type HistoryReq struct {
Type int8 `json:"type"` //0世界聊天、1联盟聊天
}
type HistoryRsp struct {
Type int8 `json:"type"` //0世界聊天、1联盟聊天
Msgs []ChatMsg `json:"msgs"`
}
type JoinReq struct {
Type int8 `json:"type"` //0世界聊天、1联盟聊天
Id int `json:"id"`
}
type JoinRsp struct {
Type int8 `json:"type"` //0世界聊天、1联盟聊天
Id int `json:"id"`
}
type ExitReq struct {
Type int8 `json:"type"` //0世界聊天、1联盟聊天
Id int `json:"id"`
}
type ExitRsp struct {
Type int8 `json:"type"` //0世界聊天、1联盟聊天
Id int `json:"id"`
}