pet_home_server/src/server/game/ServerMod.go
2025-02-21 10:10:43 +08:00

180 lines
4.0 KiB
Go

package game
import (
"context"
"database/sql"
"fmt"
"server/GoUtil"
"server/db"
"server/game/mod/msg"
"server/pkg/github.com/name5566/leaf/log"
"server/pkg/github.com/name5566/leaf/timer"
"sync"
"time"
)
const (
FRIEND_MGR_KEY = "FRIEND_MGR"
RANK_MGR_KEY = "RANK_MGR"
MAIL_MGR_KEY = "MAIL_MGR"
VAR_MGR_KEY = "VAR_MGR"
CHAMPSHIP_MGR_KEY = "CHAMPSHIP_MGR"
PER_SAVE_TIME = 60
)
type ServerMod struct {
mDispatr *timer.Dispatcher
lock sync.Mutex
msgChan chan *msg.Msg
key string
handler map[int]interface{}
timeout time.Duration
update bool
data interface{}
}
// 初始化
func (s *ServerMod) init() {
s.msgChan = make(chan *msg.Msg, 10)
s.mDispatr = timer.NewDispatcher(10)
s.timeout = time.Duration(time.Second * 10)
s.handler = make(map[int]interface{})
s.update = false
s.LoadData()
s.mDispatr.AfterFunc(time.Duration(PER_SAVE_TIME)*time.Second, func() {
go s.SaveData()
})
go func() {
defer func() {
if r := recover(); r != nil {
log.Debug("%s panic: %s", s.key, r)
s.lock.Unlock()
}
}()
for {
select {
case msg := <-s.msgChan:
s.lock.Lock()
s.Handle(msg)
s.lock.Unlock()
case Cb := <-s.mDispatr.ChanTimer:
s.lock.Lock()
Cb.Cb()
s.lock.Unlock()
}
}
}()
}
// 处理消息
func (s *ServerMod) Handle(m *msg.Msg) (interface{}, error) {
if fun, ok := s.handler[m.Type]; ok {
return fun.(func(*msg.Msg) (interface{}, error))(m)
}
log.Debug("server mod key:%s handle not exist handle type:%d", s.key, m.Type)
return nil, fmt.Errorf("server mod handler err")
}
// 注册处理器
func (s *ServerMod) RegisterHandler(HandlerType int, fun interface{}) {
switch fun.(type) {
case func(*msg.Msg) (interface{}, error):
default:
log.Debug("RegisterHandler fun type err, key:%s, handler type :%d", s.key, HandlerType)
}
s.handler[HandlerType] = fun
}
// 发送消息队列
func (s *ServerMod) Send(msg *msg.Msg) {
s.msgChan <- msg
}
// 同步请求
func (s *ServerMod) Call(m *msg.Msg) (interface{}, error) {
responseChan := make(chan interface{})
errorChan := make(chan error)
go func() {
defer func() {
if r := recover(); r != nil {
errorChan <- fmt.Errorf("panic: %v", r)
}
}()
s.lock.Lock()
defer s.lock.Unlock()
result, err := s.Handle(m)
if err != nil {
errorChan <- err
return
}
responseChan <- result
}()
select {
case res := <-responseChan:
return res, nil
case err := <-errorChan:
log.Debug("handle call err. %v", err)
return nil, err
case <-time.After(s.timeout):
log.Debug("handle call timeout")
return nil, fmt.Errorf("timeout after %v", s.timeout)
}
}
// mysql 保存消息
func (s *ServerMod) SaveData() {
s.mDispatr.AfterFunc(time.Duration(PER_SAVE_TIME+GoUtil.RandNum(5, 10))*time.Second, func() {
go s.SaveData()
})
DbData := db.SqlServerModStruct{}
DbData.Key = s.key
DbData.UpdataTime = GoUtil.Now()
var err error
DbData.ModData, err = GoUtil.GobMarshal(s.data)
if err != nil {
log.Debug("SaveData Marshal failed,Mod Key: %s err:%v", s.key, err)
}
// log.Debug("SaveData Marshal success,Mod Key: %s", s.key)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
txOptions := &sql.TxOptions{}
tx, err := db.SqlDb.BeginTx(ctx, txOptions)
if err != nil {
log.Debug("SaveData sql begin tx failed,Mod Key: %s err:%v", s.key, err)
return
}
err = db.SaveServerData(&DbData)
if err != nil {
tx.Rollback()
log.Debug("SaveData sql exec ,Mod Key: %s err:%v", s.key, err)
return
}
tx.Commit()
}
func (s *ServerMod) LoadData() {
DbData := db.SqlServerModStruct{}
err := db.GetServerData(&DbData, s.key)
if err != nil {
DbData.Key = s.key
DbData.UpdataTime = GoUtil.Now()
err = db.InsertServerData(&DbData)
if err != nil {
log.Debug("LoadData sql exec ,Mod Key: %s err:%v", s.key, err)
}
return
}
if len(DbData.ModData) == 0 {
return
}
err = GoUtil.GobUnmarshal(DbData.ModData, s.data)
if err != nil {
log.Debug("LoadData Unmarshal failed,Mod Key: %s err:%v", s.key, err)
return
}
}