180 lines
4.0 KiB
Go
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
|
|
}
|
|
}
|