├── log └── .gitignore ├── gate ├── external.go ├── router.go └── internal │ └── module.go ├── data ├── test.go └── table.go ├── game ├── external.go └── internal │ ├── playermanager.go │ ├── module.go │ ├── uidbuilder.go │ ├── handler.go │ ├── chanrpc.go │ ├── timermanager.go │ └── player.go ├── login ├── external.go └── internal │ ├── module.go │ └── handler.go ├── README.md ├── conf ├── server.json ├── conf.go └── json.go ├── oss ├── syslog_linux.go ├── syslog_bsd.go ├── syslog_windows.go ├── def.go └── bill.go ├── gamedata └── reader.go ├── base ├── skeleton.go └── db.go ├── main.go ├── msg ├── msg.go └── processor │ └── json.go ├── leaf.go └── db └── mongodb.go /log/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /gate/external.go: -------------------------------------------------------------------------------- 1 | package gate 2 | 3 | import ( 4 | "leaf_server/gate/internal" 5 | ) 6 | 7 | var ( 8 | Module = new(internal.Module) 9 | ) 10 | -------------------------------------------------------------------------------- /data/test.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | type Test struct { 4 | ID int 5 | Desc string 6 | } 7 | 8 | func (t Test) GetID() interface{} { 9 | return t.ID 10 | } -------------------------------------------------------------------------------- /game/external.go: -------------------------------------------------------------------------------- 1 | package game 2 | 3 | import ( 4 | "leaf_server/game/internal" 5 | ) 6 | 7 | var ( 8 | Module = new(internal.Module) 9 | ChanRPC = internal.ChanRPC 10 | ) 11 | -------------------------------------------------------------------------------- /login/external.go: -------------------------------------------------------------------------------- 1 | package login 2 | 3 | import ( 4 | "leaf_server/login/internal" 5 | ) 6 | 7 | var ( 8 | Module = new(internal.Module) 9 | ChanRPC = internal.ChanRPC 10 | ) 11 | -------------------------------------------------------------------------------- /gate/router.go: -------------------------------------------------------------------------------- 1 | package gate 2 | 3 | import ( 4 | "leaf_server/game" 5 | "leaf_server/login" 6 | "leaf_server/msg" 7 | ) 8 | 9 | func init() { 10 | msg.Processor.SetRouter(&msg.LoginMsg{}, login.ChanRPC) 11 | msg.Processor.SetRouter(&msg.GameMsg{}, game.ChanRPC) 12 | } 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # leaf_server 2 | 基于leaf搭建的完善的游戏服务器框架,开发者可以直接用这套框架上手开发游戏逻辑。 3 | 4 | 在leaf框架的基础上,做了如下修改: 5 | 6 | 1.编码了完整的登陆流程 7 | 8 | 2.封装了多协程DB操作 9 | 10 | 3.封装定时器 11 | 12 | 4.封装路由模块,减少消息的注册等重复体力劳动,通过反射直接调用player的对应函数,提升logic coder的开发效率 13 | 14 | 5.基于syslog的运营日志模块 15 | 16 | 6.游戏数据表的读取封装 17 | 18 | -------------------------------------------------------------------------------- /conf/server.json: -------------------------------------------------------------------------------- 1 | { 2 | "LogLevel": "debug", 3 | "LogPath": "", 4 | "WSAddr": "172.16.4.29:8082", 5 | "MaxConnNum": 20000, 6 | "ConsolePort":10000, 7 | "ConfPath": "../../bin/xls/", 8 | "MgodbAddr":"mongodb://127.0.0.1:27017", 9 | "GameMgoConnNum":100, 10 | "LoginMgoConnNum":20 11 | } 12 | -------------------------------------------------------------------------------- /oss/syslog_linux.go: -------------------------------------------------------------------------------- 1 | package oss 2 | 3 | import ( 4 | "log/syslog" 5 | ) 6 | 7 | func New(flag Priority, tag string) (writer, error) { 8 | return syslog.New(syslog.Priority(flag), tag) 9 | } 10 | 11 | func Dial(net, addr string, flag Priority, tag string) (writer, error) { 12 | return syslog.Dial(net, addr, syslog.Priority(flag), tag) 13 | } 14 | 15 | -------------------------------------------------------------------------------- /oss/syslog_bsd.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package oss 4 | 5 | import ( 6 | "log/syslog" 7 | ) 8 | 9 | func New(flag Priority, tag string) (writer, error) { 10 | return syslog.New(syslog.Priority(flag), tag) 11 | } 12 | 13 | func Dial(net, addr string, flag Priority, tag string) (writer, error) { 14 | return syslog.Dial(net, addr, syslog.Priority(flag), tag) 15 | } 16 | 17 | -------------------------------------------------------------------------------- /oss/syslog_windows.go: -------------------------------------------------------------------------------- 1 | package oss 2 | 3 | type windowsW struct { 4 | } 5 | 6 | func (w *windowsW) Info(m string) error { 7 | return nil 8 | } 9 | 10 | func (w *windowsW) Close() error { 11 | return nil 12 | } 13 | 14 | func New(flag Priority, tag string) (writer, error) { 15 | return new(windowsW), nil 16 | } 17 | 18 | func Dial(net, addr string, flag Priority, tag string) (writer, error) { 19 | return new(windowsW), nil 20 | } -------------------------------------------------------------------------------- /gamedata/reader.go: -------------------------------------------------------------------------------- 1 | package gamedata 2 | 3 | import ( 4 | "github.com/name5566/leaf/log" 5 | "github.com/name5566/leaf/recordfile" 6 | "reflect" 7 | ) 8 | 9 | func readRf(st interface{}) *recordfile.RecordFile { 10 | rf, err := recordfile.New(st) 11 | if err != nil { 12 | log.Fatal("%v", err) 13 | } 14 | fn := reflect.TypeOf(st).Name() + ".txt" 15 | err = rf.Read("gamedata/" + fn) 16 | if err != nil { 17 | log.Fatal("%v: %v", fn, err) 18 | } 19 | 20 | return rf 21 | } 22 | -------------------------------------------------------------------------------- /base/skeleton.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | import ( 4 | "leaf_server/conf" 5 | 6 | "github.com/name5566/leaf/chanrpc" 7 | "github.com/name5566/leaf/module" 8 | ) 9 | 10 | func NewSkeleton() *module.Skeleton { 11 | skeleton := &module.Skeleton{ 12 | GoLen: conf.GoLen, 13 | TimerDispatcherLen: conf.TimerDispatcherLen, 14 | AsynCallLen: conf.AsynCallLen, 15 | ChanRPCServer: chanrpc.NewServer(conf.ChanRPCLen), 16 | } 17 | skeleton.Init() 18 | return skeleton 19 | } 20 | -------------------------------------------------------------------------------- /conf/conf.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "log" 5 | "time" 6 | ) 7 | 8 | var ( 9 | // log conf 10 | LogFlag = log.LstdFlags 11 | 12 | // gate conf 13 | PendingWriteNum = 2000 14 | MaxMsgLen uint32 = 8192 15 | HTTPTimeout = 10 * time.Second 16 | LenMsgLen = 2 17 | LittleEndian = false 18 | 19 | // skeleton conf 20 | GoLen = 10000 21 | TimerDispatcherLen = 10000 22 | AsynCallLen = 10000 23 | ChanRPCLen = 10000 24 | ) 25 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "leaf_server/conf" 5 | "leaf_server/game" 6 | "leaf_server/gate" 7 | "leaf_server/login" 8 | 9 | lconf "github.com/name5566/leaf/conf" 10 | ) 11 | 12 | 13 | func main() { 14 | lconf.LogLevel = conf.Server.LogLevel 15 | lconf.LogPath = conf.Server.LogPath 16 | lconf.LogFlag = conf.LogFlag 17 | lconf.ConsolePort = conf.Server.ConsolePort 18 | lconf.ProfilePath = conf.Server.ProfilePath 19 | lconf.OssLogAddr = conf.Server.OssLogAddr 20 | 21 | Run( 22 | gate.Module, 23 | game.Module, 24 | login.Module, 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /conf/json.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/name5566/leaf/log" 6 | "io/ioutil" 7 | ) 8 | 9 | var Server struct { 10 | LogLevel string 11 | LogPath string 12 | WSAddr string 13 | CertFile string 14 | KeyFile string 15 | TCPAddr string 16 | MaxConnNum int 17 | ConsolePort int 18 | ProfilePath string 19 | ConfPath string 20 | MgodbAddr string 21 | GameMgoConnNum int 22 | LoginMgoConnNum int 23 | OssLogAddr string 24 | } 25 | 26 | func init() { 27 | data, err := ioutil.ReadFile("conf/server.json") 28 | if err != nil { 29 | log.Fatal("%v", err) 30 | } 31 | err = json.Unmarshal(data, &Server) 32 | if err != nil { 33 | log.Fatal("%v", err) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /game/internal/playermanager.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | type playerManger struct { 4 | PlayerMap map[string]*Player 5 | } 6 | 7 | func NewPlayerManager() *playerManger { 8 | mgr := new(playerManger) 9 | mgr.Init() 10 | return mgr 11 | } 12 | 13 | func (self *playerManger) Init() { 14 | self.PlayerMap = make(map[string]*Player) 15 | } 16 | 17 | func (self *playerManger) Get(id string) *Player { 18 | return self.PlayerMap[id] 19 | } 20 | 21 | func (self *playerManger) AddPlayer(player *Player) { 22 | self.PlayerMap[player.objid] = player 23 | } 24 | 25 | func (self *playerManger) DelPlayer(objid string) { 26 | delete(self.PlayerMap, objid) 27 | } 28 | 29 | func (self *playerManger) Close() { 30 | for _, player := range self.PlayerMap { 31 | player.SaveSync() 32 | } 33 | } -------------------------------------------------------------------------------- /gate/internal/module.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "leaf_server/conf" 5 | "leaf_server/game" 6 | "leaf_server/msg" 7 | 8 | "github.com/name5566/leaf/gate" 9 | ) 10 | 11 | type Module struct { 12 | *gate.Gate 13 | } 14 | 15 | func (m *Module) OnInit() { 16 | m.Gate = &gate.Gate{ 17 | MaxConnNum: conf.Server.MaxConnNum, 18 | PendingWriteNum: conf.PendingWriteNum, 19 | MaxMsgLen: conf.MaxMsgLen, 20 | WSAddr: conf.Server.WSAddr, 21 | HTTPTimeout: conf.HTTPTimeout, 22 | CertFile: conf.Server.CertFile, 23 | KeyFile: conf.Server.KeyFile, 24 | TCPAddr: conf.Server.TCPAddr, 25 | LenMsgLen: conf.LenMsgLen, 26 | LittleEndian: conf.LittleEndian, 27 | Processor: msg.Processor, 28 | AgentChanRPC: game.ChanRPC, 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /login/internal/module.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "leaf_server/base" 5 | "leaf_server/db" 6 | "leaf_server/conf" 7 | 8 | "github.com/name5566/leaf/module" 9 | "github.com/name5566/leaf/log" 10 | ) 11 | 12 | var ( 13 | skeleton = base.NewSkeleton() 14 | ChanRPC = skeleton.ChanRPCServer 15 | mgodb = new(db.Mongodb) 16 | ) 17 | 18 | type Module struct { 19 | *module.Skeleton 20 | } 21 | 22 | func (m *Module) OnInit() { 23 | m.Skeleton = skeleton 24 | var err error 25 | mgodb, err = db.Dial(conf.Server.MgodbAddr, conf.Server.LoginMgoConnNum, skeleton) 26 | if nil == mgodb { 27 | log.Error("dial mongodb failed:", conf.Server.MgodbAddr, " ", err.Error()) 28 | } 29 | 30 | mgodb.EnsureUniqueIndex(base.DBNAME, base.ACCOUNTSET, []string{"account"}) 31 | } 32 | 33 | func (m *Module) OnDestroy() { 34 | mgodb.Close() 35 | } 36 | -------------------------------------------------------------------------------- /msg/msg.go: -------------------------------------------------------------------------------- 1 | package msg 2 | 3 | import ( 4 | "leaf_server/msg/processor" 5 | ) 6 | 7 | var Processor = processor.NewProcessor() 8 | 9 | func init() { 10 | Processor.Register(&LoginMsg{}) 11 | Processor.Register(&GameMsg{}) 12 | Processor.Register(&RetMsg{}) 13 | } 14 | 15 | type LoginMsg struct { 16 | Cmd string `json:"cmd"` 17 | Req interface{} `json:"req"` 18 | } 19 | 20 | type GameMsg struct { 21 | Cmd string `json:"cmd"` 22 | Req interface{} `json:"req"` 23 | } 24 | 25 | type RetMsg struct { 26 | Code int `json:"code"` 27 | ErrorMsg string `json:"errormsg"` 28 | Cmd string `json:"cmd"` 29 | Ans interface{} `json:"data"` 30 | } 31 | 32 | type LoginReq struct { 33 | Account string `json:"account"` 34 | Password string `json:"password"` 35 | } 36 | 37 | type LoginAns struct { 38 | UserCheck string `json:"usercheck"` 39 | } 40 | 41 | type TestReq struct { 42 | } 43 | 44 | type TestAns struct { 45 | } -------------------------------------------------------------------------------- /oss/def.go: -------------------------------------------------------------------------------- 1 | package oss 2 | 3 | type Priority int 4 | 5 | const ( 6 | LOG_EMERG Priority = iota 7 | LOG_ALERT 8 | LOG_CRIT 9 | LOG_ERR 10 | LOG_WARNING 11 | LOG_NOTICE 12 | LOG_INFO 13 | LOG_DEBUG 14 | ) 15 | 16 | const ( 17 | // Facility. 18 | 19 | // From /usr/include/sys/syslog.h. 20 | // These are the same up to LOG_FTP on Linux, BSD, and OS X. 21 | LOG_KERN Priority = iota << 3 22 | LOG_USER 23 | LOG_MAIL 24 | LOG_DAEMON 25 | LOG_AUTH 26 | LOG_SYSLOG 27 | LOG_LPR 28 | LOG_NEWS 29 | LOG_UUCP 30 | LOG_CRON 31 | LOG_AUTHPRIV 32 | LOG_FTP 33 | _ // unused 34 | _ // unused 35 | _ // unused 36 | _ // unused 37 | LOG_LOCAL0 38 | LOG_LOCAL1 39 | LOG_LOCAL2 40 | LOG_LOCAL3 41 | LOG_LOCAL4 42 | LOG_LOCAL5 43 | LOG_LOCAL6 44 | LOG_LOCAL7 45 | ) 46 | 47 | type writer interface { 48 | Info(string) error 49 | Close() error 50 | } 51 | 52 | const ( 53 | BILLID_RES = 1 //资源账单日志 54 | BILLID_REGISTER = 2 //注册 55 | BILLID_LOGIN = 3 //登陆 56 | ) 57 | 58 | -------------------------------------------------------------------------------- /base/db.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | import "gopkg.in/mgo.v2/bson" 4 | 5 | const ( 6 | DBNAME = "Test" 7 | 8 | ACCOUNTSET = "AccountSet" //账号集合 9 | PLAYERSET = "PlayerSet" //玩家集合 10 | INCREMENTSET = "Increment" //增量集合 11 | ) 12 | 13 | type DBTask struct { 14 | ObjID string 15 | DB string 16 | Collection string 17 | Key string 18 | KeyV interface{} 19 | Ret interface{} 20 | Cb func(interface{}, error) 21 | } 22 | 23 | type DBSearch struct { 24 | ObjID string 25 | DB string 26 | Collection string 27 | M bson.M 28 | Limit int 29 | Skip int 30 | Ret interface{} 31 | Cb func(interface{}, error) 32 | } 33 | 34 | //账号信息 35 | type AccountInfo struct { 36 | Account string 37 | Password string 38 | ObjID string 39 | } 40 | 41 | //转换一个Bson 42 | func BsonObjectID(s string) bson.ObjectId { 43 | if s == "" { 44 | return bson.NewObjectId() 45 | } 46 | 47 | if bson.IsObjectIdHex(s) { 48 | return bson.ObjectIdHex(s) 49 | } 50 | 51 | return bson.ObjectId(s) 52 | } 53 | -------------------------------------------------------------------------------- /game/internal/module.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "leaf_server/base" 5 | "leaf_server/db" 6 | "leaf_server/conf" 7 | 8 | "github.com/name5566/leaf/log" 9 | "github.com/name5566/leaf/module" 10 | ) 11 | 12 | var ( 13 | skeleton = base.NewSkeleton() 14 | ChanRPC = skeleton.ChanRPCServer 15 | mgodb = new(db.Mongodb) 16 | PlayerManager = NewPlayerManager() 17 | TimerManager = NewTimerManager() 18 | uidbuilder = new(UidBuilder) 19 | ) 20 | 21 | type Module struct { 22 | *module.Skeleton 23 | } 24 | 25 | func (m *Module) OnInit() { 26 | m.Skeleton = skeleton 27 | var err error 28 | mgodb, err = db.Dial(conf.Server.MgodbAddr, conf.Server.GameMgoConnNum, skeleton) 29 | if nil == mgodb { 30 | log.Error("dial mongodb failed:", conf.Server.MgodbAddr, " ", err.Error()) 31 | return 32 | } 33 | 34 | mgodb.EnsureUniqueIndex(base.DBNAME, base.PLAYERSET, []string{"uid"}) 35 | 36 | uidbuilder.Init() 37 | } 38 | 39 | func (m *Module) OnDestroy() { 40 | PlayerManager.Close() 41 | mgodb.Close() 42 | log.Release("closed") 43 | } 44 | -------------------------------------------------------------------------------- /game/internal/uidbuilder.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "leaf_server/base" 5 | "gopkg.in/mgo.v2" 6 | "github.com/name5566/leaf/log" 7 | ) 8 | 9 | type UidBuilder struct { 10 | Seq int64 11 | } 12 | 13 | func (builder *UidBuilder) Init() { 14 | err := mgodb.GetSync(base.DBNAME, base.INCREMENTSET, "_id", "uid", builder) 15 | if mgo.ErrNotFound == err { 16 | mgodb.EnsureCounter(base.DBNAME, base.INCREMENTSET, "uid") 17 | } else if nil != err { 18 | log.Error("load uid seq failed:", err.Error()) 19 | return 20 | } 21 | 22 | playercount := int64(mgodb.GetTableCountSync(base.DBNAME, base.PLAYERSET)) 23 | if builder.Seq <= playercount { 24 | builder.Seq = playercount + 1 25 | mgodb.SetSync(base.DBNAME, base.INCREMENTSET, "_id", "uid", builder) 26 | } 27 | } 28 | 29 | func (builder *UidBuilder) GenerateUID() int64 { 30 | mgodb.IncreSeq(base.DBNAME, base.INCREMENTSET, "uid", func(i interface{}, err error) { 31 | if nil != err { 32 | log.Error("Increment uid failed:", err.Error()) 33 | } 34 | }) 35 | 36 | builder.Seq ++ 37 | return 10000 + builder.Seq 38 | } 39 | -------------------------------------------------------------------------------- /leaf.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/name5566/leaf/cluster" 5 | "github.com/name5566/leaf/conf" 6 | "github.com/name5566/leaf/console" 7 | "github.com/name5566/leaf/log" 8 | "github.com/name5566/leaf/module" 9 | "os" 10 | "os/signal" 11 | "leaf_server/oss" 12 | ) 13 | 14 | func Run(mods ...module.Module) { 15 | // logger 16 | if conf.LogLevel != "" { 17 | logger, err := log.New(conf.LogLevel, conf.LogPath, conf.LogFlag) 18 | if err != nil { 19 | panic(err) 20 | } 21 | log.Export(logger) 22 | defer logger.Close() 23 | } 24 | 25 | osslogger, err := oss.NewLogger("udp", conf.OssLogAddr, "test") 26 | if nil != err { 27 | log.Error("init oss logger failed:", err.Error()) 28 | return 29 | } 30 | oss.Export(osslogger) 31 | defer oss.Close() 32 | 33 | 34 | log.Release("starting up") 35 | 36 | // module 37 | for i := 0; i < len(mods); i++ { 38 | module.Register(mods[i]) 39 | } 40 | module.Init() 41 | 42 | // cluster 43 | cluster.Init() 44 | 45 | // console 46 | console.Init() 47 | 48 | // close 49 | c := make(chan os.Signal, 1) 50 | signal.Notify(c, os.Interrupt, os.Kill) 51 | sig := <-c 52 | log.Release("closing down (signal: %v)", sig) 53 | console.Destroy() 54 | cluster.Destroy() 55 | module.Destroy() 56 | } 57 | -------------------------------------------------------------------------------- /oss/bill.go: -------------------------------------------------------------------------------- 1 | package oss 2 | 3 | import ( 4 | "time" 5 | "fmt" 6 | ) 7 | 8 | type Logger struct { 9 | writer 10 | } 11 | 12 | var gLogger *Logger 13 | 14 | func NewLogger(network, addr, tag string) (*Logger, error) { 15 | var w writer 16 | var err error 17 | if "" == addr { 18 | w, err = New(LOG_INFO|LOG_USER, tag) 19 | } else { 20 | w, err = Dial(network, addr, LOG_INFO|LOG_USER, tag) 21 | } 22 | if nil != err { 23 | return nil, err 24 | } 25 | return &Logger{w}, err 26 | } 27 | 28 | func Export(logger *Logger) { 29 | if nil != logger { 30 | gLogger = logger 31 | } 32 | } 33 | 34 | func (logger *Logger) WriteLog(objid string, uid int64, billid int, param string) { 35 | now := time.Now() 36 | tm := fmt.Sprintf("%d%02d%02d_%02d%02d%02d", 37 | now.Year(), 38 | now.Month(), 39 | now.Day(), 40 | now.Hour(), 41 | now.Minute(), 42 | now.Second()) 43 | 44 | gLogger.Info(fmt.Sprintf("%d^%s^%s^%d^%s", uid, tm, objid, billid, param)) 45 | } 46 | 47 | func Close() { 48 | gLogger.Close() 49 | } 50 | 51 | //资源日志 52 | func ResLog(objid string, uid int64, restyp, id, count, remaincount, reason int) { 53 | gLogger.WriteLog(objid, uid, BILLID_RES, fmt.Sprintf("%d|%d|%d|%d|%d", restyp, id, count, remaincount, reason)) 54 | } 55 | 56 | //行为日志 57 | func ActionLog(objid string, uid int64, actionid int, param interface{}) { 58 | str := "" 59 | if nil != param { 60 | str = fmt.Sprintf("%+v", param) 61 | } 62 | gLogger.WriteLog(objid, uid, actionid, str) 63 | } -------------------------------------------------------------------------------- /game/internal/handler.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "runtime/debug" 5 | "reflect" 6 | 7 | "leaf_server/base" 8 | "leaf_server/msg" 9 | 10 | "github.com/goinggo/mapstructure" 11 | "github.com/name5566/leaf/gate" 12 | "github.com/name5566/leaf/log" 13 | ) 14 | 15 | func init() { 16 | handler(&msg.GameMsg{}, onClientMsg) 17 | } 18 | 19 | func handler(m interface{}, h interface{}) { 20 | skeleton.RegisterChanRPC(reflect.TypeOf(m), h) 21 | } 22 | 23 | func onClientMsg(args []interface{}) { 24 | defer func() { 25 | if r := recover(); r != nil { 26 | log.Error("", r) 27 | debug.PrintStack() 28 | } 29 | }() 30 | 31 | m := args[0].(*msg.GameMsg) 32 | a := args[1].(gate.Agent) 33 | 34 | udata := a.UserData() 35 | if nil == udata { 36 | log.Error("please login first") 37 | return 38 | } 39 | 40 | account := udata.(*base.AccountInfo) 41 | player := PlayerManager.Get(account.ObjID) 42 | if nil == player { 43 | log.Error("player isn't online:", account.Account, " ", account.ObjID) 44 | return 45 | } 46 | 47 | vplayer := reflect.ValueOf(player) 48 | method := vplayer.MethodByName(m.Cmd) 49 | if !method.IsValid() { 50 | log.Error("invailed player function:", m.Cmd, " ", account.ObjID) 51 | return 52 | } 53 | 54 | param := reflect.New(method.Type().In(0).Elem()).Interface() 55 | err := mapstructure.Decode(m.Req, param) 56 | if nil != err { 57 | log.Error("decode player func inparam failed:", m.Cmd, " ", account.ObjID) 58 | return 59 | } 60 | 61 | params := make([]reflect.Value, 1) 62 | params[0] = reflect.ValueOf(param) 63 | method.Call(params) 64 | } 65 | -------------------------------------------------------------------------------- /data/table.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "reflect" 7 | "leaf_server/conf" 8 | 9 | "github.com/name5566/leaf/log" 10 | ) 11 | 12 | const ( 13 | TABLENAME_BASIC = "test.json" 14 | ) 15 | 16 | var CFG_PATH string 17 | 18 | type TABLE_ITEM interface { 19 | GetID() interface{} 20 | } 21 | 22 | type TABLE map[interface{}]TABLE_ITEM 23 | 24 | var DataMap map[string]TABLE 25 | 26 | func init() { 27 | CFG_PATH = conf.Server.ConfPath 28 | DataMap = make(map[string]TABLE) 29 | 30 | readcfg(TABLENAME_BASIC, &[]Test{}) 31 | } 32 | 33 | func GetTable(name string) TABLE { 34 | return DataMap[name] 35 | } 36 | 37 | func GetTableItem(name string, key interface{}) TABLE_ITEM { 38 | table, ok := DataMap[name] 39 | if !ok { 40 | return nil 41 | } 42 | 43 | return table[key] 44 | } 45 | 46 | func readcfg(name string, array interface{}) error { 47 | arrayv := reflect.ValueOf(array) 48 | if arrayv.Kind() != reflect.Ptr || arrayv.Elem().Kind() != reflect.Slice { 49 | log.Error("readfile: output isn't ptr and kind isn't slice ", name) 50 | return nil 51 | } 52 | 53 | data, err := ioutil.ReadFile(CFG_PATH + name) 54 | if nil != err { 55 | log.Error("read file failed:", name, " err:", err.Error()) 56 | return err 57 | } 58 | 59 | err = json.Unmarshal(data, array) 60 | if nil != err { 61 | log.Error("json unmarshal failed:", name, " err:", err.Error()) 62 | return err 63 | } 64 | 65 | table := make(map[interface{}]TABLE_ITEM) 66 | arraye := arrayv.Elem() 67 | for i := 0; i < arraye.Len(); i++ { 68 | v := arraye.Index(i).Interface() 69 | item := v.(TABLE_ITEM) 70 | table[item.GetID()] = item 71 | } 72 | DataMap[name] = table 73 | return nil 74 | } 75 | -------------------------------------------------------------------------------- /game/internal/chanrpc.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "leaf_server/oss" 5 | "leaf_server/base" 6 | "leaf_server/msg" 7 | 8 | "github.com/name5566/leaf/gate" 9 | "github.com/name5566/leaf/log" 10 | ) 11 | 12 | func init() { 13 | skeleton.RegisterChanRPC("NewAgent", rpcNewAgent) 14 | skeleton.RegisterChanRPC("CloseAgent", rpcCloseAgent) 15 | skeleton.RegisterChanRPC("LoginSuccess", rpcLoginSuccess) 16 | } 17 | 18 | func rpcNewAgent(args []interface{}) { 19 | a := args[0].(gate.Agent) 20 | log.Debug("new agent") 21 | _ = a 22 | } 23 | 24 | func rpcCloseAgent(args []interface{}) { 25 | a := args[0].(gate.Agent) 26 | log.Debug("close agent") 27 | 28 | userdata := a.UserData() 29 | if nil == userdata { 30 | return 31 | } 32 | 33 | info := userdata.(*base.AccountInfo) 34 | player := PlayerManager.Get(info.ObjID) 35 | if nil != player { 36 | player.OnLogout() 37 | } 38 | PlayerManager.DelPlayer(info.ObjID) 39 | } 40 | 41 | func rpcLoginSuccess(args []interface{}) { 42 | a := args[0].(gate.Agent) 43 | userdata := a.UserData() 44 | info := userdata.(*base.AccountInfo) 45 | 46 | //判断玩家重复登陆 47 | player := PlayerManager.Get(info.ObjID) 48 | if nil != player { 49 | player.agent.Close() 50 | player.agent = a 51 | return 52 | } 53 | 54 | mgodb.Get(base.DBTask{info.ObjID, base.DBNAME, base.PLAYERSET, "_id", base.BsonObjectID(info.ObjID), CreatePlayer(), func(param interface{}, err error) { 55 | player := param.(*Player) 56 | player.objid = info.ObjID 57 | player.agent = a 58 | if player.Account == "" { //保存新玩家数据 59 | player.InitData(info.Account) 60 | player.Save() 61 | oss.ActionLog(player.objid, player.UID, oss.BILLID_REGISTER, nil) 62 | } 63 | 64 | player.OnLogin() 65 | PlayerManager.AddPlayer(player) 66 | 67 | player.CallClientFunc(0, "login", &msg.LoginAns{info.ObjID}) 68 | oss.ActionLog(player.objid, player.UID, oss.BILLID_LOGIN, nil) 69 | } }) 70 | } 71 | -------------------------------------------------------------------------------- /game/internal/timermanager.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "time" 5 | "github.com/name5566/leaf/log" 6 | ) 7 | 8 | type Timer struct { 9 | key string 10 | cb func() 11 | interval int 12 | loop bool 13 | } 14 | 15 | type timerManager struct { 16 | timerMap map[interface{}][]*Timer 17 | } 18 | 19 | func NewTimerManager() *timerManager { 20 | return &timerManager{make(map[interface{}][]*Timer)} 21 | } 22 | 23 | func (m *timerManager) addTimer(obj interface{}, key string, cb func(), interval int, loop bool) { 24 | skeleton.AfterFunc(time.Millisecond * time.Duration(interval), func() { 25 | if !m.timerVaild(obj, key) { 26 | return 27 | } 28 | if !loop { 29 | m.RmvTimer(obj, key) 30 | } 31 | 32 | cb() 33 | if loop { 34 | m.addTimer(obj, key, cb, interval, loop) 35 | } 36 | }) 37 | } 38 | 39 | func (m *timerManager) getTimerIndex(l []*Timer, key string) int { 40 | for i, timer := range l { 41 | if timer.key == key { 42 | return i 43 | } 44 | } 45 | return -1 46 | } 47 | 48 | func (m *timerManager) timerVaild(obj interface{}, key string) bool { 49 | l, ok := m.timerMap[obj] 50 | if !ok { 51 | return false 52 | } 53 | 54 | return m.getTimerIndex(l, key) >= 0 55 | } 56 | 57 | func (m *timerManager) AddTimer(obj interface{}, key string, interval int, loop bool, cb func()) { 58 | l, _ := m.timerMap[obj] 59 | if m.getTimerIndex(l, key) >= 0 { 60 | log.Error("add repeated timer:", key) 61 | return 62 | } 63 | 64 | l = append(l, &Timer{key, cb, interval, loop}) 65 | m.timerMap[obj] = l 66 | m.addTimer(obj, key, cb, interval, loop) 67 | } 68 | 69 | func (m *timerManager) RmvTimer(obj interface{}, key string) { 70 | l, ok := m.timerMap[obj] 71 | if !ok { 72 | return 73 | } 74 | 75 | index := m.getTimerIndex(l, key) 76 | if index >= 0 { 77 | l = append(l[:index], l[index+1:]...) 78 | } 79 | m.timerMap[obj] = l 80 | } 81 | 82 | func (m *timerManager) RmvAllTimer(obj interface{}) { 83 | delete(m.timerMap, obj) 84 | } -------------------------------------------------------------------------------- /game/internal/player.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "github.com/name5566/leaf/util" 5 | "leaf_server/base" 6 | "leaf_server/msg" 7 | 8 | "github.com/name5566/leaf/gate" 9 | "github.com/name5566/leaf/log" 10 | ) 11 | 12 | const ( 13 | INTATTR_COIN = 0 //金币 14 | INTATTR_POWER = 1 //体力 15 | 16 | INTATTR_MAX = 10 17 | ) 18 | 19 | const ( 20 | STRATTR_NICK = 0 //昵称 21 | STRATTR_ICON = 1 //头像 22 | 23 | STRATTR_MAX = 2 24 | ) 25 | 26 | 27 | type Player struct { 28 | objid string 29 | agent gate.Agent 30 | UID int64 31 | Account string 32 | IntAttr []int //整型属性 33 | StrAttr []string //字符串属性 34 | } 35 | 36 | func CreatePlayer() *Player { 37 | player := new(Player) 38 | player.IntAttr = make([]int, INTATTR_MAX) 39 | player.StrAttr = make([]string, STRATTR_MAX) 40 | return player 41 | } 42 | 43 | func (self *Player) GetIntAttr(index int) int { 44 | if index < 0 || index >= INTATTR_MAX { 45 | return 0 46 | } 47 | return self.IntAttr[index] 48 | } 49 | 50 | func (self *Player) SetIntAttr(index, val int) { 51 | if index < 0 || index >= INTATTR_MAX { 52 | return 53 | } 54 | 55 | self.IntAttr[index] = val 56 | } 57 | 58 | func (self *Player) GetStrAttr(index int) string { 59 | if index < 0 || index >= STRATTR_MAX { 60 | return "" 61 | } 62 | return self.StrAttr[index] 63 | } 64 | 65 | func (self *Player) SetStrAttr(index int, val string) { 66 | if index < 0 || index >= STRATTR_MAX { 67 | return 68 | } 69 | 70 | self.StrAttr[index] = val 71 | } 72 | 73 | func (self *Player) InitData(account string) { 74 | self.Account = account 75 | self.UID = uidbuilder.GenerateUID() 76 | } 77 | 78 | func (self *Player) CallClientFunc(ret int, cmd string, ans interface{}) { 79 | errmsg := "" 80 | 81 | message := &msg.RetMsg{ret, errmsg, cmd, ans} 82 | self.agent.WriteMsg(message) 83 | } 84 | 85 | func (self *Player) Test(req *msg.TestReq) { 86 | 87 | } 88 | 89 | //登陆 90 | func (self *Player) OnLogin() { 91 | } 92 | 93 | func (self *Player) OnLogout() { 94 | self.Save() 95 | 96 | TimerManager.RmvAllTimer(self) 97 | } 98 | 99 | //保存玩家数据 100 | func (self *Player) Save() { 101 | mgodb.Set(base.DBTask{self.objid, base.DBNAME, base.PLAYERSET, "_id", base.BsonObjectID(self.objid), util.DeepClone(self), func(param interface{}, err error) { 102 | if nil != err { 103 | log.Error("save playerdata failed:", self.objid) 104 | } 105 | } }) 106 | } 107 | 108 | //同步保存玩家数据 109 | func (self *Player) SaveSync() { 110 | if nil != mgodb.SetSync(base.DBNAME, base.PLAYERSET, "_id", base.BsonObjectID(self.objid), self) { 111 | log.Error("save playerdata failed:", self.objid) 112 | } 113 | } -------------------------------------------------------------------------------- /login/internal/handler.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "reflect" 5 | "leaf_server/base" 6 | "leaf_server/game" 7 | "leaf_server/msg" 8 | 9 | "github.com/goinggo/mapstructure" 10 | "github.com/name5566/leaf/gate" 11 | "github.com/name5566/leaf/log" 12 | "gopkg.in/mgo.v2/bson" 13 | ) 14 | 15 | type clientFunc func(interface{}, gate.Agent) int 16 | 17 | type clientFS struct { 18 | clientFunc 19 | req interface{} 20 | } 21 | 22 | var handleMap map[string]clientFS 23 | 24 | func handleMsg(m interface{}, h interface{}) { 25 | skeleton.RegisterChanRPC(reflect.TypeOf(m), h) 26 | } 27 | 28 | func init() { 29 | handleMap = make(map[string]clientFS) 30 | handleMsg(&msg.LoginMsg{}, onClientMsg) 31 | 32 | registerFunc("login", login, msg.LoginReq{}) 33 | } 34 | 35 | func registerFunc(cmd string, fun clientFunc, req interface{}) { 36 | _, ok := handleMap[cmd] 37 | if ok { 38 | log.Error("login handle register repeated function:", cmd) 39 | return 40 | } 41 | 42 | handleMap[cmd] = clientFS{fun, req} 43 | } 44 | 45 | func done(agent gate.Agent, message *msg.RetMsg) { 46 | /*data, err := json.Marshal(message) 47 | if nil != err { 48 | log.Error("login module json marshal failed:", err.Error()) 49 | return 50 | }*/ 51 | 52 | agent.WriteMsg(message) 53 | } 54 | 55 | func onClientMsg(args []interface{}) { 56 | m := args[0].(*msg.LoginMsg) 57 | a := args[1].(gate.Agent) 58 | 59 | fs, ok := handleMap[m.Cmd] 60 | if !ok { 61 | log.Error("login function not found:", m.Cmd) 62 | return 63 | } 64 | 65 | i := reflect.New(reflect.TypeOf(fs.req)).Interface() 66 | err := mapstructure.Decode(m.Req, i) 67 | if nil != err { 68 | log.Error("login function decode req failed:", m.Cmd) 69 | } 70 | 71 | ret := fs.clientFunc(i, a) 72 | if 0 != ret { 73 | log.Error("login function execute error:", m.Cmd, " ", ret) 74 | return 75 | } 76 | 77 | /* 78 | message := new(msg.RetMsg) 79 | message.Ret = ret 80 | message.Cmd = m.Cmd 81 | message.Error = errmsg 82 | message.Ans = ans 83 | 84 | data, err := json.Marshal(message) 85 | if nil != err { 86 | log.Error("login module json marshal failed:", m.Cmd, " ", err.Error()) 87 | return 88 | } 89 | a.WriteMsg(data)*/ 90 | } 91 | 92 | func login(message interface{}, agent gate.Agent) int { 93 | req := message.(*msg.LoginReq) 94 | mgodb.Get(base.DBTask{req.Account, base.DBNAME, base.ACCOUNTSET, "account", req.Account, &base.AccountInfo{}, func(param interface{}, err error) { 95 | info := param.(*base.AccountInfo) 96 | if info.Account == "" { 97 | info.Account = req.Account 98 | info.Password = req.Password 99 | info.ObjID = bson.NewObjectId().Hex() 100 | mgodb.Set(base.DBTask{info.Account, base.DBNAME, base.ACCOUNTSET, "account", req.Account, info, nil}) 101 | } 102 | 103 | if info.Password != req.Password { 104 | done(agent, &msg.RetMsg{1, "", "login", nil}) 105 | return 106 | } 107 | 108 | agent.SetUserData(info) 109 | skeleton.AsynCall(game.ChanRPC, "LoginSuccess", agent, func(err error) { 110 | if nil != err { 111 | log.Error("login failed:", info.ObjID, " ", err.Error()) 112 | done(agent, &msg.RetMsg{-1, "", "login", nil}) 113 | return 114 | } 115 | //done(agent, &msg.RetMsg{0, "", "login", &msg.LoginAns{info.ObjID}}) 116 | }) 117 | } }) 118 | return 0 119 | } 120 | -------------------------------------------------------------------------------- /msg/processor/json.go: -------------------------------------------------------------------------------- 1 | package processor 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "reflect" 8 | 9 | "github.com/name5566/leaf/chanrpc" 10 | "github.com/name5566/leaf/log" 11 | ) 12 | 13 | type Processor struct { 14 | msgInfo map[string]*MsgInfo 15 | } 16 | 17 | type MsgInfo struct { 18 | msgType reflect.Type 19 | msgRouter *chanrpc.Server 20 | msgHandler MsgHandler 21 | msgRawHandler MsgHandler 22 | } 23 | 24 | type MsgHandler func([]interface{}) 25 | 26 | type MsgRaw struct { 27 | msgID string 28 | msgRawData json.RawMessage 29 | } 30 | 31 | func NewProcessor() *Processor { 32 | p := new(Processor) 33 | p.msgInfo = make(map[string]*MsgInfo) 34 | return p 35 | } 36 | 37 | // It's dangerous to call the method on routing or marshaling (unmarshaling) 38 | func (p *Processor) Register(msg interface{}) string { 39 | msgType := reflect.TypeOf(msg) 40 | if msgType == nil || msgType.Kind() != reflect.Ptr { 41 | log.Fatal("json message pointer required") 42 | } 43 | msgID := msgType.Elem().Name() 44 | if msgID == "" { 45 | log.Fatal("unnamed json message") 46 | } 47 | if _, ok := p.msgInfo[msgID]; ok { 48 | log.Fatal("message %v is already registered", msgID) 49 | } 50 | 51 | i := new(MsgInfo) 52 | i.msgType = msgType 53 | p.msgInfo[msgID] = i 54 | return msgID 55 | } 56 | 57 | // It's dangerous to call the method on routing or marshaling (unmarshaling) 58 | func (p *Processor) SetRouter(msg interface{}, msgRouter *chanrpc.Server) { 59 | msgType := reflect.TypeOf(msg) 60 | if msgType == nil || msgType.Kind() != reflect.Ptr { 61 | log.Fatal("json message pointer required") 62 | } 63 | msgID := msgType.Elem().Name() 64 | i, ok := p.msgInfo[msgID] 65 | if !ok { 66 | log.Fatal("message %v not registered", msgID) 67 | } 68 | 69 | i.msgRouter = msgRouter 70 | } 71 | 72 | // It's dangerous to call the method on routing or marshaling (unmarshaling) 73 | func (p *Processor) SetHandler(msg interface{}, msgHandler MsgHandler) { 74 | msgType := reflect.TypeOf(msg) 75 | if msgType == nil || msgType.Kind() != reflect.Ptr { 76 | log.Fatal("json message pointer required") 77 | } 78 | msgID := msgType.Elem().Name() 79 | i, ok := p.msgInfo[msgID] 80 | if !ok { 81 | log.Fatal("message %v not registered", msgID) 82 | } 83 | 84 | i.msgHandler = msgHandler 85 | } 86 | 87 | // It's dangerous to call the method on routing or marshaling (unmarshaling) 88 | func (p *Processor) SetRawHandler(msgID string, msgRawHandler MsgHandler) { 89 | i, ok := p.msgInfo[msgID] 90 | if !ok { 91 | log.Fatal("message %v not registered", msgID) 92 | } 93 | 94 | i.msgRawHandler = msgRawHandler 95 | } 96 | 97 | // goroutine safe 98 | func (p *Processor) Route(msg interface{}, userData interface{}) error { 99 | // raw 100 | if msgRaw, ok := msg.(MsgRaw); ok { 101 | i, ok := p.msgInfo[msgRaw.msgID] 102 | if !ok { 103 | return fmt.Errorf("message %v not registered", msgRaw.msgID) 104 | } 105 | if i.msgRawHandler != nil { 106 | i.msgRawHandler([]interface{}{msgRaw.msgID, msgRaw.msgRawData, userData}) 107 | } 108 | return nil 109 | } 110 | 111 | // json 112 | msgType := reflect.TypeOf(msg) 113 | if msgType == nil || msgType.Kind() != reflect.Ptr { 114 | return errors.New("json message pointer required") 115 | } 116 | msgID := msgType.Elem().Name() 117 | i, ok := p.msgInfo[msgID] 118 | if !ok { 119 | return fmt.Errorf("message %v not registered", msgID) 120 | } 121 | if i.msgHandler != nil { 122 | i.msgHandler([]interface{}{msg, userData}) 123 | } 124 | if i.msgRouter != nil { 125 | i.msgRouter.Go(msgType, msg, userData) 126 | } 127 | return nil 128 | } 129 | 130 | // goroutine safe 131 | func (p *Processor) Unmarshal(data []byte) (interface{}, error) { 132 | var m map[string]json.RawMessage 133 | err := json.Unmarshal(data, &m) 134 | if err != nil { 135 | return nil, err 136 | } 137 | if len(m) != 1 { 138 | return nil, errors.New("invalid json data") 139 | } 140 | 141 | for msgID, data := range m { 142 | i, ok := p.msgInfo[msgID] 143 | if !ok { 144 | return nil, fmt.Errorf("message %v not registered", msgID) 145 | } 146 | 147 | // msg 148 | if i.msgRawHandler != nil { 149 | return MsgRaw{msgID, data}, nil 150 | } else { 151 | msg := reflect.New(i.msgType.Elem()).Interface() 152 | return msg, json.Unmarshal(data, msg) 153 | } 154 | } 155 | 156 | panic("bug") 157 | } 158 | 159 | // goroutine safe 160 | func (p *Processor) Marshal(msg interface{}) ([][]byte, error) { 161 | msgType := reflect.TypeOf(msg) 162 | if msgType == nil || msgType.Kind() != reflect.Ptr { 163 | return nil, errors.New("json message pointer required") 164 | } 165 | 166 | data, err := json.Marshal(msg) 167 | return [][]byte{data}, err 168 | } 169 | -------------------------------------------------------------------------------- /db/mongodb.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "gopkg.in/mgo.v2" 5 | "gopkg.in/mgo.v2/bson" 6 | "github.com/name5566/leaf/go" 7 | "github.com/name5566/leaf/db/mongodb" 8 | "github.com/name5566/leaf/log" 9 | "github.com/name5566/leaf/module" 10 | 11 | "leaf_server/base" 12 | ) 13 | 14 | type Mongodb struct { 15 | *mongodb.DialContext 16 | linearWorkers []*g.LinearContext 17 | } 18 | 19 | func Dial(url string, sessionNum int, skeleton *module.Skeleton) (*Mongodb, error) { 20 | c, err := mongodb.Dial(url, sessionNum) 21 | if nil != err { 22 | log.Error("dial mongodb failed:", url, " ", err.Error()) 23 | return nil, err 24 | } 25 | if nil == skeleton { 26 | return &Mongodb{c, nil}, err 27 | } 28 | 29 | workers := make([]*g.LinearContext, 0) 30 | for i := 0; i < sessionNum>>1; i ++ { 31 | workers = append(workers, skeleton.NewLinearContext()) 32 | } 33 | return &Mongodb{c, workers}, err 34 | } 35 | 36 | func hash(str string) int { 37 | h := uint(1315423911) 38 | for i := 0; i < len(str); i ++ { 39 | h ^= ((uint(str[i]) << 5) + uint(str[i]) + (h >> 2)) 40 | } 41 | return int(h & 0x7fffffff) 42 | } 43 | 44 | func (db *Mongodb) worker(objid string) *g.LinearContext { 45 | index := hash(objid) % len(db.linearWorkers) 46 | return db.linearWorkers[index] 47 | } 48 | 49 | func (db *Mongodb) Get(task base.DBTask) { 50 | w := db.worker(task.ObjID) 51 | var err error 52 | w.Go(func() { 53 | s := db.Ref() 54 | defer db.UnRef(s) 55 | 56 | err = s.DB(task.DB).C(task.Collection).Find(bson.M{task.Key: task.KeyV}).One(task.Ret) 57 | if nil != err && mgo.ErrNotFound != err { 58 | log.Error("db get failed:", task.DB, " collection:", task.Collection, " key:", task.Key, " error:", err.Error()) 59 | } 60 | }, func() { 61 | if nil != task.Cb { 62 | task.Cb(task.Ret, err) 63 | } 64 | }) 65 | } 66 | 67 | func (db *Mongodb) GetAll(task base.DBTask) { 68 | w := db.worker(task.ObjID) 69 | var err error 70 | w.Go(func() { 71 | s := db.Ref() 72 | defer db.UnRef(s) 73 | 74 | err = s.DB(task.DB).C(task.Collection).Find(bson.M{task.Key: task.KeyV}).All(task.Ret) 75 | if nil != err && mgo.ErrNotFound != err { 76 | log.Error("db get failed:", task.DB, " collection:", task.Collection, " key:", task.Key, " error:", err.Error()) 77 | } 78 | }, func() { 79 | if nil != task.Cb { 80 | task.Cb(task.Ret, err) 81 | } 82 | }) 83 | } 84 | 85 | func (db *Mongodb) Set(task base.DBTask) { 86 | w := db.worker(task.ObjID) 87 | var err error 88 | w.Go(func() { 89 | s := db.Ref() 90 | defer db.UnRef(s) 91 | 92 | _, err = s.DB(task.DB).C(task.Collection).Upsert(bson.M{task.Key: task.KeyV}, task.Ret) 93 | if nil != err { 94 | log.Error("db set failed:", task.DB, " collection:", task.Collection, " key:", task.Key, " error:", err.Error()) 95 | } 96 | }, func() { 97 | if nil != task.Cb { 98 | task.Cb(task.Ret, err) 99 | } 100 | }) 101 | } 102 | 103 | func (db *Mongodb) IncreSeq(dbname, collection, id string, cb func(interface{}, error)) { 104 | w := db.worker(id) 105 | var res struct { Seq int64 } 106 | var err error 107 | w.Go(func() { 108 | s := db.Ref() 109 | defer db.UnRef(s) 110 | 111 | _, err = s.DB(dbname).C(collection).FindId(id).Apply(mgo.Change{ 112 | Update: bson.M{"$inc": bson.M{"seq": 1}}, 113 | ReturnNew: true, 114 | }, &res) 115 | }, func() { 116 | if nil != cb { 117 | cb(res.Seq, err) 118 | } 119 | }) 120 | } 121 | 122 | func (db *Mongodb) GetTableCount(objid, dbname, collection string, cb func(interface{}, error)) { 123 | w := db.worker(objid) 124 | count := 0 125 | var err error 126 | w.Go(func() { 127 | s := db.Ref() 128 | defer db.UnRef(s) 129 | 130 | count, err = s.DB(dbname).C(collection).Count() 131 | }, func() { 132 | if nil != cb { 133 | cb(count, err) 134 | } 135 | }) 136 | } 137 | 138 | func (db *Mongodb) Search(task base.DBSearch) { 139 | w := db.worker(task.ObjID) 140 | var err error 141 | w.Go(func() { 142 | s := db.Ref() 143 | defer db.UnRef(s) 144 | 145 | err = s.DB(task.DB).C(task.Collection).Find(task.M).Limit(task.Limit).Skip(task.Skip).All(task.Ret) 146 | if nil != err && mgo.ErrNotFound != err { 147 | log.Error("db search failed:", task.DB, " collection:", task.Collection, " error:", err.Error()) 148 | } 149 | }, func() { 150 | if nil != task.Cb { 151 | task.Cb(task.Ret, err) 152 | } 153 | }) 154 | } 155 | 156 | func (db *Mongodb) GetSync(dbname, collection, key string, keyv, ret interface{}) error { 157 | s := db.Ref() 158 | defer db.UnRef(s) 159 | 160 | err := s.DB(dbname).C(collection).Find(bson.M{key: keyv}).One(ret) 161 | if nil != err && mgo.ErrNotFound != err { 162 | log.Error("db get failed:", dbname, " collection:", collection, " key:", key, " error:", err.Error()) 163 | } 164 | return err 165 | } 166 | 167 | func (db *Mongodb) SetSync(dbname, collection, key string, keyv, v interface{}) error { 168 | s := db.Ref() 169 | defer db.UnRef(s) 170 | 171 | _, err := s.DB(dbname).C(collection).Upsert(bson.M{key: keyv}, v) 172 | if nil != err { 173 | log.Error("db set failed:", dbname, " collection:", collection, " key:", key, " error:", err.Error()) 174 | } 175 | return err 176 | } 177 | 178 | func (db *Mongodb) GetTableCountSync(dbname, collection string) int { 179 | s := db.Ref() 180 | defer db.UnRef(s) 181 | count, err := s.DB(dbname).C(collection).Count() 182 | if err != nil { 183 | return 0 184 | } 185 | return count 186 | } 187 | 188 | func (db *Mongodb) SearchSync(dbname, collection string, m bson.M, ret interface{}, limit, skip int) error { 189 | s := db.Ref() 190 | defer db.UnRef(s) 191 | 192 | err := s.DB(dbname).C(collection).Find(m).Limit(limit).Skip(skip).All(ret) 193 | if nil != err && mgo.ErrNotFound != err { 194 | log.Error("db search failed:", dbname, " collection:", collection, " error:", err.Error()) 195 | } 196 | return err 197 | } --------------------------------------------------------------------------------