go语言实现的GM邮件功能:全服邮件和多人邮件的发送

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)
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值