go基础语法 菜鸟教程 http://www.runoob.com/go/go-tutorial.html
概述一下需求和游戏功能
需求:
1. 接入第三方平台的http请求,数据格式json
2. 可发送多人邮件和全服邮件
3. 多人邮件包括单人邮件,全服邮件包括单服邮件和多服邮件
游戏功能<服务器>:
1. 邮件信息包括:模板id,主题/标题,内容,发送人/署名,类型,附件,收件人,操作途径,离线是否发送
2. 消息流程:第三方请求–>HttpServer—>GameServer
需要留意的几个地方
1. handleSendMail 处理收到的协议包
2. IsHTTPCenter() 如果是中心服务器,则可以向其它HttpServer转发协议包
3. sendMail2GS中CallGameSer向GameServer发送邮件信息包,MailRspPack向HttpServer回包
4. HFWriteRsp 向第三方回包
5. go func() 并行处理向GameServer发包
6. CallGameSer 和 MailRspPack 发包和回包 是顺序执行的 其中MailRspPack 可先挂起等待 直到GameServer返回消息再执行
7. sendGlobalMail2GS全服邮件每隔1s按批次发送邮件,减少服务器同一时间的压力
8. batchSendMail首次向服务器发送邮件时需GameServer创建一个模板id并返回,其它批次发送是需获得这个邮件模板id并把它发给GameServer,并且其它批次不再需要GameServer回包,这样全服邮件就只需创建一个邮件模板即可。batchSendMail返回值依次为:邮件模板id,函数执行结果,数据库查询行索引。只有函数执行成功即发送成功时,下次发送的行索引才可增加。
代码部分
代码中很少有注释,原因:代码的理解不想依赖于注释,想通过好的命名和代码结构让读代码的人也能够理解。有时候过多的注释会降低对代码质量的要求,总想着代码乱点,多写点注释就行了,而不想着如何去精简和优化代码。错误的注释还不如没有注释。只在关键的地方写上注释即可。当然,下面的代码也还有待提高。
body := []byte… 测试用的json数据
package GM
import (
"encoding/json"
"fmt"
"httpserver/logger"
"httpserver/misc/packet"
"httpserver/myDB"
"httpserver/tylnet"
"io/ioutil"
"net/http"
"time"
)
//MailType
const (
MailTypeSingle = 0
MailTypeMulti = 1
MailTypeServer = 2
)
//MailSenderName
const (
MailSenderNameGM = "GM"
MailSenderNameLD = "官方"
)
//MailSenderId
const (
MailSenderIDGM = 1
MailSenderIDLD = 2
)
//MailAttachsMaxNum ..
const MailAttachsMaxNum = 5
//MailPlayerIdsMaxNum ..
const MailPlayerIdsMaxNum = 50
//SendGlobalMailStep ..
const SendGlobalMailStep = 100
//MailAttachXF struct
type MailAttachXF struct {
TypeID int32 `json:"typeId"`
GoodsID int32 `json:"goodsId"`
Count int32 `json:"count"`
}
//SendMailXF struct
type SendMailXF struct {
ID int `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
Sign string `json:"sign"`
IsGlobal bool `json:"isGlobal"`
PlayerIds []uint64 `json:"playerIds"`
RegDate int64 `json:"regDate"`
Attaches []MailAttachXF `json:"attachment"`
AreaServerIds []int32 `json:"areaServerIds"`
Validity int `json:"validity"`
}
//SQLPlayerPID struct
type SQLPlayerPID struct {
Pid int64 `db:"PID"`
}
//MailDataPack send MailDataPack to GameServer
var MailDataPack *tylnet.SendMailPack
//MailSendOver ..
var MailSendOver bool = true
//batchSendMail send mail in batches
func batchSendMail(bFirstTime bool, mailID uint64, startRow int) (uint64, bool, int) {
if !bFirstTime && mailID == 0 {
return mailID, false, startRow
}
if myDB.GameDB == nil {
logger.ERR("send mail Err: myDB.GameDB not ready!")
return mailID, false, startRow
}
playerPidData := []SQLPlayerPID{}
sql := fmt.Sprintf("SELECT PID FROM player LIMIT %d,%d", startRow, SendGlobalMailStep)
err := myDB.GameDB.Select(&playerPidData, sql)
if err != nil {
logger.ERR("send mail Err: myDB Sql", sql, err.Error())
return mailID, false, startRow
}
if len(playerPidData) == 0 {
logger.INFO("send global mail over! mail id =", mailID)
return mailID, true, -1
}
MailDataPack.PidList = nil
MailDataPack.PidList = make([]uint64, len(playerPidData))
for k, v := range playerPidData {
MailDataPack.PidList[k] = uint64(v.Pid)
//fmt.Println("player id =", v.Pid, "mail id =", mailID)
}
MailDataPack.ID = mailID
if bFirstTime {
ret := tylnet.CallGameSer(packet.Pack(tylnet.Code["sendmail"], MailDataPack, nil), true)
if ret == nil {
logger.ERR("send mail Err: golbal mail _callGameSer return nil")
return mailID, false, startRow
}
retPack := tylnet.MailRspPack{}
ok := packet.UnPackBuf(&retPack, ret)
if !ok {
logger.ERR("send mail Err: UnPackBuf return failure")
return mailID, false, startRow
}
//更新mailID
mailID = retPack.MailID
logger.INFO("send mail success: mail type =", retPack.TypeID, "mail id =", retPack.MailID)
} else {
tylnet.CallGameSer(packet.Pack(tylnet.Code["sendmail"], MailDataPack, nil), false)
}
return mailID, true, startRow
}
func checkGlobalMailSendOver() bool {
return MailSendOver
}
func handleSendMail(w http.ResponseWriter, req *http.Request) {
body, _ := ioutil.ReadAll(req.Body)
//body := []byte(`{"attachment":[{"goodsId":0,"count":100,"typeId":3},{"goodsId":93024,"count":1,"typeId":8},{"goodsId":93025,"count":1,"typeId":8}],"areaServerIds":[102],"isGlobal":true,"sign":"GM","regDate":0,"id":156,"validity":3,"title":"哈哈","playerIds":[1000000000000028],"content":"测试道具"}`)
var mailData SendMailXF
err := json.Unmarshal(body, &mailData)
if err != nil {
logger.ERR(err.Error())
tylnet.HFWriteRsp(w, 1, err.Error())
return
}
selfproc := true
if mailData.IsGlobal && tylnet.IsHTTPCenter() {
selfproc = tylnet.RedirectOthers(w, req, mailData.AreaServerIds)
}
if selfproc {
sendMail2GS(w, &mailData)
}
}
func sendMail2GS(w http.ResponseWriter, mailData *SendMailXF) bool {
if len(mailData.Attaches) > MailAttachsMaxNum {
errStr := "send mail Err: attaches out of max num"
logger.ERR(errStr)
tylnet.HFWriteRsp(w, 1, errStr)
return false
}
if len(mailData.PlayerIds) > MailPlayerIdsMaxNum {
errStr := "send mail Err: player id is out of max num"
logger.ERR(errStr)
tylnet.HFWriteRsp(w, 1, errStr)
return false
}
if !mailData.IsGlobal && len(mailData.PlayerIds) == 0 {
errStr := "send mail Err: this mail need at least one player! "
logger.ERR(errStr)
tylnet.HFWriteRsp(w, 1, errStr)
return false
}
if !checkGlobalMailSendOver() {
errStr := "send mail Err: there are other mails being sent! please try again in a few minutes!"
logger.ERR(errStr)
tylnet.HFWriteRsp(w, 1, errStr)
return false
}
MailDataPack = &tylnet.SendMailPack{}
MailDataPack.ID = 0
MailDataPack.SendOffline = 1
MailDataPack.Method = -1
MailDataPack.Theme = mailData.Title
MailDataPack.Content = mailData.Content
if mailData.IsGlobal {
MailDataPack.TypeID = MailTypeServer
} else {
MailDataPack.TypeID = MailTypeMulti
}
if mailData.Sign == MailSenderNameGM {
MailDataPack.Sender = MailSenderIDGM
} else {
MailDataPack.Sender = MailSenderIDLD
}
MailDataPack.Attaches = make([]tylnet.MailAttach, len(mailData.Attaches))
for k, v := range mailData.Attaches {
MailDataPack.Attaches[k].TypeID = v.TypeID
MailDataPack.Attaches[k].GoodsID = v.GoodsID
MailDataPack.Attaches[k].Count = v.Count
}
MailDataPack.PidList = make([]uint64, len(mailData.PlayerIds))
for k, v := range mailData.PlayerIds {
MailDataPack.PidList[k] = v
}
go func() {
if mailData.IsGlobal {
sendGlobalMail2GS
} else {
sendMultiMail2GS()
}
}()
tylnet.HFWriteRsp(w, 0, "")
return true
}
func sendGlobalMail2GS() {
MailSendOver = false
var mailID uint64
startRow := 0
bSend := true
bFirstTime := true
for true {
if startRow == -1 {
break
}
rowRefer := 0
mailID, bSend, rowRefer = batchSendMail(bFirstTime, mailID, startRow)
if bSend {
if rowRefer == -1 {
startRow = rowRefer
} else {
startRow += SendGlobalMailStep
}
} else {
startRow = rowRefer
}
bFirstTime = false
time.Sleep(time.Second)
}
MailSendOver = true
}
func sendMultiMail2GS() {
ret := tylnet.CallGameSer(packet.Pack(tylnet.Code["sendmail"], MailDataPack, nil), true)
if ret == nil {
logger.ERR("send mail Err: _callGameSer return nil")
return
}
retPack := tylnet.MailRspPack{}
ok := packet.UnPackBuf(&retPack, ret)
if !ok {
logger.ERR("send mail Err: UnPackBuf return failure")
return
}
logger.INFO("send mail success: mail type =", retPack.TypeID, "mail id =", retPack.MailID)
}