├── .gitignore ├── LICENSE ├── README.md ├── core ├── admin │ ├── admin.go │ └── config.go ├── basic │ ├── command.go │ ├── command_own.go │ ├── command_term.go │ ├── command_termack.go │ ├── command_termreq.go │ ├── cond.go │ ├── object.go │ ├── object_test.go │ ├── objectlocalstorage.go │ ├── objectmonitor.go │ ├── options.go │ └── sinker.go ├── build.go ├── build_darwin.go ├── build_linux.go ├── build_windows.go ├── buildall.bat ├── builtin │ ├── action │ │ ├── packetslices.go │ │ ├── txctrlcmd.go │ │ ├── txresult.go │ │ └── txstart.go │ ├── filter │ │ ├── authentication.go │ │ ├── blacklist.go │ │ ├── connectionthrottle.go │ │ ├── keepalive.go │ │ └── trace.go │ ├── gen_cpp.bat │ ├── gen_go.bat │ └── protocol │ │ ├── corepacketid.pb.go │ │ ├── corepacketid.proto │ │ ├── keepalive.pb.go │ │ ├── keepalive.proto │ │ ├── sessionauth.pb.go │ │ ├── sessionauth.proto │ │ ├── slices.pb.go │ │ ├── slices.proto │ │ ├── transact.pb.go │ │ └── transact.proto ├── cmdline │ ├── cmdline.go │ ├── cmdline_exit.go │ ├── cmdline_help.go │ ├── command_cmdline.go │ └── config.go ├── config.go ├── container │ ├── doc.go │ ├── queue │ │ ├── queue.go │ │ ├── queue_chan.go │ │ ├── queue_sync.go │ │ └── queue_test.go │ ├── recycler │ │ ├── recycler.go │ │ ├── recycler_bytebuf.go │ │ ├── recycler_mgr.go │ │ ├── recycler_test.go │ │ └── recycler_timer.go │ ├── synchronizedlist.go │ └── synchronizedmap.go ├── ctx.go ├── doc.go ├── i18n │ ├── config.go │ └── i18n.go ├── ids.go ├── loader.go ├── logger │ ├── ilogger.go │ └── log.go ├── module │ ├── config.go │ ├── module.go │ ├── modulemgr.go │ └── preload.go ├── mongo │ └── config.go ├── netlib │ ├── acceptor.go │ ├── action.go │ ├── command_start_ioservice.go │ ├── config.go │ ├── connector.go │ ├── connectormgr.go │ ├── decoder.go │ ├── defaultprotocol.go │ ├── enc-binary.go │ ├── enc-gbp.go │ ├── enc-gob.go │ ├── enc-nill.go │ ├── encoder.go │ ├── encoder_test.go │ ├── encoding.go │ ├── error.go │ ├── errorpackethandler.go │ ├── ioservice.go │ ├── netengine.go │ ├── packetfactory.go │ ├── packethandler.go │ ├── packetpool.go │ ├── recycler_action.go │ ├── recycler_rwbuf.go │ ├── session.go │ ├── sessionfilter.go │ ├── sessionhandler.go │ ├── tcp_acceptor.go │ ├── tcp_connector.go │ ├── tcp_session.go │ ├── tcpkeepalive │ │ ├── LICENSE │ │ ├── README.md │ │ ├── keepalive.go │ │ ├── keepalive_bsd.go │ │ ├── keepalive_darwin.go │ │ ├── keepalive_linux.go │ │ ├── keepalive_solaris.go │ │ └── keepalive_windows.go │ ├── test.go │ ├── udp_acceptor.go │ ├── udp_connector.go │ ├── udp_session.go │ ├── ws_acceptor.go │ ├── ws_connector.go │ └── ws_session.go ├── profile │ ├── config.go │ ├── recycler_watcher.go │ ├── statistics.go │ └── timewatcher.go ├── schedule │ ├── task.go │ └── task_test.go ├── signal │ ├── config.go │ ├── interrupt_handler.go │ ├── kill_handler.go │ └── signal.go ├── task │ ├── command_task_exe.go │ ├── command_task_req.go │ ├── command_task_res.go │ ├── config.go │ ├── executor.go │ ├── task.go │ └── worker.go ├── timer │ ├── command_start_timer.go │ ├── command_stop_timer.go │ ├── command_timeout_timer.go │ ├── config.go │ ├── timer.go │ ├── timer_action.go │ ├── timer_queue.go │ └── timer_queue_test.go ├── transact │ ├── command_trans_resume.go │ ├── command_trans_yield.go │ ├── config.go │ ├── doc.go │ ├── transcommitpolicy.go │ ├── transcommskeleton.go │ ├── transcoordinator.go │ ├── transctx.go │ ├── transfactory.go │ ├── transhandler.go │ ├── transnode.go │ ├── transtimeouthandler.go │ └── transtype.go ├── utils │ ├── atomicidgen.go │ ├── clone.go │ ├── clone_test.go │ ├── debug.go │ ├── debug_test.go │ ├── healthcheck.go │ ├── idgen.go │ ├── panic.go │ ├── profile.go │ ├── profile_test.go │ ├── rand.go │ ├── slices.go │ ├── utils.go │ └── waitor.go └── zk │ ├── zk.go │ └── zk_test.go ├── doc.go ├── examples ├── echoclient │ ├── config.json │ ├── logger.xml │ ├── main.go │ ├── pressure.go │ ├── scpacketponghandler.go │ └── serversessionfilter.go ├── echoserver │ ├── config.json │ ├── logger.xml │ ├── main.go │ └── scpacketponghandler.go ├── gen_go.bat ├── other │ ├── config.json │ ├── logger.xml │ ├── main.go │ ├── task.go │ └── timer.go ├── protocol │ ├── packetid.pb.go │ ├── packetid.proto │ ├── pingpong.pb.go │ ├── pingpong.proto │ ├── txtype.go │ └── txuserdata.go ├── txserver1 │ ├── config.json │ ├── dependent.go │ ├── logger.xml │ ├── main.go │ └── tx_trace.go └── txserver2 │ ├── config.json │ ├── dependent.go │ ├── logger.xml │ ├── main.go │ └── tx_trace.go ├── mmo ├── accountsrv │ ├── config.json │ ├── doc.go │ ├── logger.xml │ └── main.go ├── balancesrv │ ├── clientsessionhandler.go │ ├── config.json │ ├── doc.go │ ├── logger.xml │ └── main.go ├── build.bat ├── clean.bat ├── client │ ├── config.json │ ├── logger.xml │ ├── main.go │ └── packet_scgateinfo.go ├── close.bat ├── clrlogs.bat ├── gamesrv │ ├── config.json │ ├── doc.go │ ├── logger.xml │ └── main.go ├── gatesrv │ ├── broadcasthandler.go │ ├── bundlemgr.go │ ├── clientsessionload.go │ ├── config.json │ ├── doc.go │ ├── dupfilter.go │ ├── logger.xml │ ├── main.go │ ├── multicasthandler.go │ └── packetdispatchhandler.go ├── gen_go.bat ├── imports.go ├── mgrsrv │ ├── config.json │ ├── doc.go │ ├── logger.xml │ └── main.go ├── protocol │ ├── gateinfo.pb.go │ ├── gateinfo.proto │ ├── packetid.pb.go │ ├── packetid.proto │ ├── serverload.pb.go │ └── serverload.proto ├── startup.bat └── worldsrv │ ├── config.json │ ├── doc.go │ ├── logger.xml │ └── main.go └── srvlib ├── action ├── redirecthandler.go └── transithandler.go ├── clientsessionmgr.go ├── const.go ├── gen_go.bat ├── handler.go ├── handler ├── clientsessionregiste.go ├── serverserviceregiste.go └── serversessionregiste.go ├── protocol ├── broadcast.pb.go ├── broadcast.proto ├── multicast.pb.go ├── multicast.proto ├── packetid.pb.go ├── packetid.proto ├── redirect.pb.go ├── redirect.proto ├── serviceinfo.pb.go ├── serviceinfo.proto ├── srvregiste.pb.go ├── srvregiste.proto ├── transit.pb.go └── transit.proto ├── serversessionmgr.go ├── servicemgr.go ├── sessionid.go ├── srvertable.go └── txcommskeleton.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## goserver 2 | 3 | goserver 旨在做一个传统的CS结构的服务器框架 4 | 目前主要用于游戏服务器开发 5 | 框架还在不断努力完善中,如果你对它感兴趣,请关注它的动态或者参与进来 6 | 7 | ## Features 8 | 9 | * 组件通过package的概念统一管理(可以理解为win32下的dll),由config来配置各个组件的特性参数 10 | * goroutine通过Object进行包装以树型结构组织,Object间的通信通过command(内部是chan),主要是为了预防chan滥用、失控,从而造成各种死锁问题 11 | * 提供了时间,任务,事务,计划工作,网络通讯,模块管理的内置组件 12 | * 提供一套传统的游戏服务器架构(制作中...) 13 | 14 | ## 模块说明 15 | * +core 核心模块 16 | * admin : http管理接口,主要提供一种外部可以操控进程的可能 17 | * basic : 基础的线程对象,封装对象间内部通讯;避免chan环锁现象,树形管理object 18 | * bulletin: 框架内建元素,提供通讯层的一些基础过滤器和通讯协议 19 | * cmdline: 自建命令行,给控制台进程提供一种命令模式 20 | * container: 框架用到的一些容器,队列,回收器,线程安全list,线程安全map 21 | * i18n: 国际化配置 22 | * logger: 日志接口 23 | * module: 业务模块管理,提供统一的心跳管理,模块通过注册挂载到管理器 24 | * mongo: mogodb相关配置 25 | * netlib: 通讯模块,支持TCP和WebSocket两种通讯方式 26 | * profile: 性能统计相关,用于辅助查找性能热点 27 | * schedule: 定时任务调度模块,用于周期job处理,如:每日凌晨4:00进行日志清理 28 | * signal: 信号管理模块,hook操作系统的信号进行回调处理,如:kill -2 PID 29 | * task: 线程模块,提供线程池、实名线程和独立线程多种模式 30 | * timer: 定时器,有别于go内置的timer;主要用于确保线程安全问题 31 | * transact: 分布式事务,基于二段提交实现,协调多节点配合完成一件原子性操作 32 | * utils: 工具接口 33 | * zk: zookeeper接口,用于分布式协调 34 | * +srvlib core/netlib的扩展封装,提供常用的客户端session和服务端service管理,以及服务发现;进一步封装,使框架层达到拆箱即用 35 | * action 内置常用的包重定向和中转操作 36 | * handler 提供基本的session和service管理 37 | * protocol 内置协议定义 38 | * +examples 示例程序 39 | * echoclient 回声客户端程序 40 | * echoserver 回声服务端程序 41 | * other timer和task使用示例 42 | * txserver1 分布式事务节点1 43 | * txserver2 分布式事务节点2 44 | * +mmo 提供一套基本的服务器架构模板 -------------------------------------------------------------------------------- /core/admin/config.go: -------------------------------------------------------------------------------- 1 | package admin 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core" 5 | ) 6 | 7 | var Config = Configuration{} 8 | 9 | type Configuration struct { 10 | SupportAdmin bool 11 | AdminHttpAddr string 12 | AdminHttpPort int 13 | WhiteHttpAddr []string 14 | } 15 | 16 | func (c *Configuration) Name() string { 17 | return "admin" 18 | } 19 | 20 | func (c *Configuration) Init() error { 21 | if c.SupportAdmin { 22 | MyAdminApp.Start(c.AdminHttpAddr, c.AdminHttpPort) 23 | } 24 | return nil 25 | } 26 | 27 | func (c *Configuration) Close() error { 28 | return nil 29 | } 30 | 31 | func init() { 32 | core.RegistePackage(&Config) 33 | } 34 | -------------------------------------------------------------------------------- /core/basic/command.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | // Object to process the command. 4 | 5 | type Command interface { 6 | Done(*Object) error 7 | } 8 | 9 | type CommandWrapper func(*Object) error 10 | 11 | func (cw CommandWrapper) Done(o *Object) error { 12 | return cw(o) 13 | } 14 | -------------------------------------------------------------------------------- /core/basic/command_own.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | import "github.com/idealeak/goserver/core/container" 4 | 5 | type ownCommand struct { 6 | c *Object 7 | } 8 | 9 | func (oc *ownCommand) Done(o *Object) error { 10 | 11 | defer o.ProcessSeqnum() 12 | 13 | // If the object is already being shut down, new owned objects are 14 | // immediately asked to terminate. Note that linger is set to zero. 15 | if o.terminating { 16 | o.termAcks++ 17 | SendTerm(oc.c) 18 | return nil 19 | } 20 | 21 | // Store the reference to the owned object. 22 | if o.childs == nil { 23 | o.childs = container.NewSynchronizedMap() 24 | } 25 | o.childs.Set(oc.c.Id, oc.c) 26 | 27 | return nil 28 | } 29 | 30 | func SendOwn(p *Object, c *Object) bool { 31 | return p.SendCommand(&ownCommand{c: c}, true) 32 | } 33 | -------------------------------------------------------------------------------- /core/basic/command_term.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | var termCmd = &termCommand{} 4 | 5 | type termCommand struct { 6 | } 7 | 8 | func (tc *termCommand) Done(o *Object) error { 9 | if o == nil { 10 | return nil 11 | } 12 | 13 | // Double termination should never happen. 14 | o.processTerm() 15 | 16 | return nil 17 | } 18 | 19 | func SendTerm(o *Object) bool { 20 | return o.SendCommand(termCmd, false) 21 | } 22 | -------------------------------------------------------------------------------- /core/basic/command_termack.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | var termAckCmd = &termAckCommand{} 4 | 5 | type termAckCommand struct { 6 | } 7 | 8 | func (tac *termAckCommand) Done(o *Object) error { 9 | if o == nil { 10 | return nil 11 | } 12 | 13 | if o.termAcks > 0 { 14 | o.termAcks-- 15 | 16 | // This may be a last ack we are waiting for before termination... 17 | o.checkTermAcks() 18 | } 19 | 20 | return nil 21 | } 22 | 23 | func SendTermAck(p *Object) bool { 24 | return p.SendCommand(termAckCmd, false) 25 | } 26 | -------------------------------------------------------------------------------- /core/basic/command_termreq.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | type termReqCommand struct { 4 | c *Object 5 | } 6 | 7 | func (trc *termReqCommand) Done(o *Object) error { 8 | if o == nil { 9 | return nil 10 | } 11 | 12 | // When shutting down we can ignore termination requests from owned 13 | // objects. The termination request was already sent to the object. 14 | if o.terminating { 15 | return nil 16 | } 17 | 18 | // If I/O object is well and alive let's ask it to terminate. 19 | if o.childs.IsExist(trc.c.Id) { 20 | o.termAcks++ 21 | // Note that this object is the root of the (partial shutdown) thus, its 22 | // value of linger is used, rather than the value stored by the children. 23 | SendTerm(trc.c) 24 | // Remove child 25 | o.childs.Delete(trc.c.Id) 26 | } 27 | 28 | return nil 29 | } 30 | 31 | func SendTermReq(p *Object, c *Object) bool { 32 | return p.SendCommand(&termReqCommand{c: c}, false) 33 | } 34 | -------------------------------------------------------------------------------- /core/basic/cond.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | import ( 4 | "sync/atomic" 5 | "time" 6 | ) 7 | 8 | type Cond struct { 9 | notify chan struct{} 10 | countor int32 11 | } 12 | 13 | func NewCond(waitor int) *Cond { 14 | return &Cond{notify: make(chan struct{}, waitor)} 15 | } 16 | 17 | func (c *Cond) Wait() { 18 | atomic.AddInt32(&c.countor, 1) 19 | defer atomic.AddInt32(&c.countor, -1) 20 | 21 | select { 22 | case <-c.notify: 23 | } 24 | } 25 | 26 | func (c *Cond) WaitForTimeout(dura time.Duration) bool { 27 | atomic.AddInt32(&c.countor, 1) 28 | defer atomic.AddInt32(&c.countor, -1) 29 | 30 | select { 31 | case <-c.notify: 32 | case <-time.Tick(dura): 33 | return true 34 | } 35 | return false 36 | } 37 | 38 | func (c *Cond) WaitForTick(ticker *time.Ticker) bool { 39 | atomic.AddInt32(&c.countor, 1) 40 | defer atomic.AddInt32(&c.countor, -1) 41 | 42 | select { 43 | case <-c.notify: 44 | case <-ticker.C: 45 | return true 46 | } 47 | return false 48 | } 49 | 50 | func (c *Cond) Signal() { 51 | select { 52 | case c.notify <- struct{}{}: 53 | default: 54 | return 55 | } 56 | } 57 | 58 | func (c *Cond) Drain() { 59 | for { 60 | select { 61 | case <-c.notify: 62 | default: 63 | return 64 | } 65 | } 66 | } 67 | 68 | func (c *Cond) Broadcast() { 69 | for atomic.LoadInt32(&c.countor) > 0 { 70 | c.notify <- struct{}{} 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /core/basic/object_test.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func TestSendCommand(t *testing.T) { 11 | n := 5 12 | opt := Options{ 13 | Interval: time.Second, 14 | MaxDone: n, 15 | } 16 | c := make(chan int) 17 | o := NewObject(1, "test1", opt, nil) 18 | o.Active() 19 | for i := 0; i < n*2; i++ { 20 | go func(tag int) { 21 | o.SendCommand(CommandWrapper(func(*Object) error { 22 | c <- tag 23 | return nil 24 | }), true) 25 | }(i) 26 | } 27 | 28 | go func() { 29 | i := 0 30 | for { 31 | i++ 32 | if i%1000 == 0 { 33 | runtime.Gosched() 34 | } 35 | } 36 | }() 37 | 38 | slice := make([]int, 0, n*2) 39 | for i := 0; i < n*2; i++ { 40 | tag := <-c 41 | slice = append(slice, tag) 42 | } 43 | if len(slice) != n*2 { 44 | t.Fatal("Command be droped") 45 | } 46 | fmt.Println("TestSendCommand", slice) 47 | } 48 | 49 | func TestSendCommandLoop(t *testing.T) { 50 | n := 5 51 | m := n * 2 52 | opt := Options{ 53 | Interval: time.Second, 54 | MaxDone: n, 55 | } 56 | c := make(chan int) 57 | o := NewObject(1, "test1", opt, nil) 58 | o.Active() 59 | for i := 0; i < n; i++ { 60 | go func(tag int) { 61 | o.SendCommand(CommandWrapper(func(oo *Object) error { 62 | for j := 0; j < m; j++ { 63 | func(tag2 int) { 64 | oo.SendCommand(CommandWrapper(func(*Object) error { 65 | c <- tag*1000 + tag2 66 | return nil 67 | }), true) 68 | }(j) 69 | } 70 | return nil 71 | }), true) 72 | }(i) 73 | } 74 | go func() { 75 | i := 0 76 | for { 77 | i++ 78 | if i%1000 == 0 { 79 | runtime.Gosched() 80 | } 81 | } 82 | }() 83 | slice := make([]int, 0, n*m) 84 | for i := 0; i < n*m; i++ { 85 | tag := <-c 86 | slice = append(slice, tag) 87 | } 88 | if len(slice) != n*m { 89 | t.Fatal("Command be droped") 90 | } 91 | fmt.Println("TestSendCommandLoop", slice, len(slice)) 92 | } 93 | -------------------------------------------------------------------------------- /core/basic/objectlocalstorage.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | import ( 4 | "math" 5 | "sync" 6 | 7 | "github.com/idealeak/goserver/core/container" 8 | ) 9 | 10 | // Be similar to (Windows, Thread Local Storage) 11 | 12 | const OLS_MAX_SLOT uint = 64 13 | const OLS_INVALID_SLOT = math.MaxUint32 14 | 15 | type OlsSlotCleanHandler func(interface{}) 16 | 17 | var objSlotFlag uint64 18 | var objSlotLock sync.Mutex 19 | var objSlotCleanHandler [OLS_MAX_SLOT]OlsSlotCleanHandler 20 | var objSlotHolder = container.NewSynchronizedMap() 21 | 22 | func OlsAlloc() uint { 23 | objSlotLock.Lock() 24 | for i := uint(0); i < 64; i++ { 25 | if ((1 << i) & objSlotFlag) == 0 { 26 | objSlotFlag |= (1 << i) 27 | objSlotLock.Unlock() 28 | return i 29 | } 30 | } 31 | objSlotLock.Unlock() 32 | return OLS_INVALID_SLOT 33 | } 34 | 35 | func OlsFree(slot uint) { 36 | objSlotLock.Lock() 37 | defer objSlotLock.Unlock() 38 | if slot < OLS_MAX_SLOT { 39 | handler := objSlotCleanHandler[slot] 40 | flag := objSlotFlag & (1 << slot) 41 | if handler != nil && flag != 0 { 42 | objSlotFlag ^= (1 << slot) 43 | objSlotHolder.Foreach(func(k, v interface{}) { 44 | if o, ok := k.(*Object); ok && o != nil { 45 | v := o.ols[slot] 46 | if v != nil { 47 | o.ols[slot] = nil 48 | handler(v) 49 | } 50 | } 51 | }) 52 | } 53 | } 54 | } 55 | 56 | func OlsInstallSlotCleanHandler(slot uint, handler OlsSlotCleanHandler) { 57 | if slot < OLS_MAX_SLOT { 58 | objSlotCleanHandler[slot] = handler 59 | } 60 | } 61 | 62 | func (o *Object) OlsGetValue(slot uint) interface{} { 63 | if slot < OLS_MAX_SLOT { 64 | return o.ols[slot] 65 | } 66 | return nil 67 | } 68 | 69 | func (o *Object) OlsSetValue(slot uint, val interface{}) { 70 | if slot < OLS_MAX_SLOT { 71 | old := o.ols[slot] 72 | o.ols[slot] = val 73 | if old != nil { 74 | handler := objSlotCleanHandler[slot] 75 | if handler != nil { 76 | handler(old) 77 | } 78 | } 79 | objSlotHolder.Set(o, struct{}{}) 80 | } 81 | } 82 | 83 | func (o *Object) OlsClrValue() { 84 | for i := uint(0); i < OLS_MAX_SLOT; i++ { 85 | v := o.ols[i] 86 | if v != nil { 87 | handler := objSlotCleanHandler[i] 88 | if handler != nil { 89 | handler(v) 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /core/basic/objectmonitor.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | var StatsWatchMgr IStatsWatchMgr 4 | 5 | type ObjectMonitor struct { 6 | } 7 | 8 | func (om *ObjectMonitor) OnStart(o *Object) { 9 | } 10 | 11 | func (om *ObjectMonitor) OnTick(o *Object) { 12 | } 13 | 14 | func (om *ObjectMonitor) OnStop(o *Object) { 15 | } 16 | 17 | type IStatsWatchMgr interface { 18 | WatchStart(name string, elementype int) IStatsWatch 19 | } 20 | 21 | type IStatsWatch interface { 22 | Stop() 23 | } 24 | 25 | type CmdStats struct { 26 | PendingCnt int64 27 | SendCmdCnt int64 28 | RecvCmdCnt int64 29 | } 30 | -------------------------------------------------------------------------------- /core/basic/options.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | const ( 8 | QueueType_List int = iota 9 | QueueType_Chan 10 | ) 11 | 12 | type Options struct { 13 | // HeartBeat interval 14 | Interval time.Duration 15 | // The maximum number of processing each heartbeat 16 | MaxDone int 17 | // 18 | QueueBacklog int 19 | } 20 | -------------------------------------------------------------------------------- /core/basic/sinker.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | type Sinker interface { 4 | OnStart() 5 | OnTick() 6 | OnStop() 7 | } 8 | -------------------------------------------------------------------------------- /core/build.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | func BuildTime() string { 4 | return "" //buildTime() 5 | } 6 | -------------------------------------------------------------------------------- /core/build_darwin.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | /* 4 | const char* build_time(void) 5 | { 6 | static const char* psz_build_time = "["__DATE__ " " __TIME__ "]"; 7 | return psz_build_time; 8 | } 9 | */ 10 | import "C" 11 | 12 | var ( 13 | _linux_buildTime = C.GoString(C.build_time()) 14 | ) 15 | 16 | func buildTime() string { 17 | return _linux_buildTime 18 | } 19 | -------------------------------------------------------------------------------- /core/build_linux.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | /* 4 | const char* build_time(void) 5 | { 6 | static const char* psz_build_time = "["__DATE__ " " __TIME__ "]"; 7 | return psz_build_time; 8 | } 9 | */ 10 | import "C" 11 | 12 | var ( 13 | _linux_buildTime = C.GoString(C.build_time()) 14 | ) 15 | 16 | func buildTime() string { 17 | return _linux_buildTime 18 | } 19 | -------------------------------------------------------------------------------- /core/build_windows.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func buildTime() string { 9 | return fmt.Sprintf("[%s]", time.Now().String()) 10 | } 11 | -------------------------------------------------------------------------------- /core/buildall.bat: -------------------------------------------------------------------------------- 1 | go build 2 | cd admin 3 | go build 4 | cd ../basic 5 | go build 6 | cd ../builtin/action 7 | go build 8 | cd ../filter 9 | go build 10 | cd ../protocol 11 | go build 12 | cd ../../cmdline 13 | go build 14 | cd ../logger 15 | go build 16 | cd ../module 17 | go build 18 | cd ../netlib 19 | go build 20 | cd ../profile 21 | go build 22 | cd ../schedule 23 | go build 24 | cd ../signal 25 | go build 26 | cd ../task 27 | go build 28 | cd ../timer 29 | go build 30 | cd ../transact 31 | go build 32 | cd ../utils 33 | go build 34 | pause 35 | -------------------------------------------------------------------------------- /core/builtin/action/txctrlcmd.go: -------------------------------------------------------------------------------- 1 | package action 2 | 3 | import ( 4 | "errors" 5 | "strconv" 6 | 7 | "code.google.com/p/goprotobuf/proto" 8 | "github.com/idealeak/goserver/core/builtin/protocol" 9 | "github.com/idealeak/goserver/core/netlib" 10 | "github.com/idealeak/goserver/core/transact" 11 | ) 12 | 13 | type TxCtrlCmdPacketFactory struct { 14 | } 15 | 16 | type TxCtrlCmdHandler struct { 17 | } 18 | 19 | func (this *TxCtrlCmdPacketFactory) CreatePacket() interface{} { 20 | pack := &protocol.TransactCtrlCmd{} 21 | return pack 22 | } 23 | 24 | func (this *TxCtrlCmdHandler) Process(session *netlib.Session, packetid int, data interface{}) error { 25 | //logger.Logger.Trace("TxCtrlCmdHandler.Process") 26 | if txcmd, ok := data.(*protocol.TransactCtrlCmd); ok { 27 | if !transact.ProcessTransCmd(transact.TransNodeID(txcmd.GetTId()), transact.TransCmd(txcmd.GetCmd())) { 28 | return errors.New("TxCtrlCmdHandler error, tid=" + strconv.FormatInt(txcmd.GetTId(), 16) + " cmd=" + strconv.Itoa(int(txcmd.GetCmd()))) 29 | } 30 | } 31 | return nil 32 | } 33 | 34 | func init() { 35 | netlib.RegisterHandler(int(protocol.CoreBuiltinPacketID_PACKET_SS_TX_CMD), &TxCtrlCmdHandler{}) 36 | netlib.RegisterFactory(int(protocol.CoreBuiltinPacketID_PACKET_SS_TX_CMD), &TxCtrlCmdPacketFactory{}) 37 | } 38 | 39 | func ConstructTxCmdPacket(tnp *transact.TransNodeParam, cmd transact.TransCmd) proto.Message { 40 | packet := &protocol.TransactCtrlCmd{ 41 | TId: proto.Int64(int64(tnp.TId)), 42 | Cmd: proto.Int32(int32(cmd)), 43 | } 44 | proto.SetDefaults(packet) 45 | return packet 46 | } 47 | -------------------------------------------------------------------------------- /core/builtin/action/txresult.go: -------------------------------------------------------------------------------- 1 | package action 2 | 3 | import ( 4 | "errors" 5 | "strconv" 6 | 7 | "code.google.com/p/goprotobuf/proto" 8 | "github.com/idealeak/goserver/core/builtin/protocol" 9 | "github.com/idealeak/goserver/core/logger" 10 | "github.com/idealeak/goserver/core/netlib" 11 | "github.com/idealeak/goserver/core/transact" 12 | ) 13 | 14 | type TxResultPacketFactory struct { 15 | } 16 | 17 | type TxResultHandler struct { 18 | } 19 | 20 | func (this *TxResultPacketFactory) CreatePacket() interface{} { 21 | pack := &protocol.TransactResult{} 22 | return pack 23 | } 24 | 25 | func (this *TxResultHandler) Process(session *netlib.Session, packetid int, data interface{}) error { 26 | //logger.Logger.Trace("TxResultHandler.Process") 27 | if tr, ok := data.(*protocol.TransactResult); ok { 28 | if !transact.ProcessTransResult(transact.TransNodeID(tr.GetMyTId()), transact.TransNodeID(tr.GetChildTId()), int(tr.GetRetCode()), tr.GetCustomData()) { 29 | return errors.New("TxResultHandler error, tid=" + strconv.FormatInt(tr.GetMyTId(), 16)) 30 | } 31 | } 32 | return nil 33 | } 34 | 35 | func init() { 36 | netlib.RegisterHandler(int(protocol.CoreBuiltinPacketID_PACKET_SS_TX_RESULT), &TxResultHandler{}) 37 | netlib.RegisterFactory(int(protocol.CoreBuiltinPacketID_PACKET_SS_TX_RESULT), &TxResultPacketFactory{}) 38 | } 39 | 40 | func ContructTxResultPacket(parent, me *transact.TransNodeParam, tr *transact.TransResult) proto.Message { 41 | packet := &protocol.TransactResult{ 42 | MyTId: proto.Int64(int64(parent.TId)), 43 | ChildTId: proto.Int64(int64(me.TId)), 44 | RetCode: proto.Int32(int32(tr.RetCode)), 45 | } 46 | if tr.RetFiels != nil { 47 | b, err := netlib.MarshalPacketNoPackId(tr.RetFiels) 48 | if err != nil { 49 | logger.Logger.Warn("ContructTxResultPacket Marshal UserData error:", err) 50 | } else { 51 | packet.CustomData = b 52 | } 53 | } 54 | proto.SetDefaults(packet) 55 | return packet 56 | } 57 | -------------------------------------------------------------------------------- /core/builtin/filter/connectionthrottle.go: -------------------------------------------------------------------------------- 1 | package filter 2 | 3 | import ( 4 | "net" 5 | "time" 6 | 7 | "github.com/idealeak/goserver/core/container" 8 | "github.com/idealeak/goserver/core/netlib" 9 | ) 10 | 11 | var ( 12 | DefaultAllowedInterval = 500 //ms 13 | ConnectionThrottleFilterName = "session-filter-connectionthrottle" 14 | ) 15 | 16 | type ConnectionThrottleFilter struct { 17 | clients *container.SynchronizedMap //need synchronize 18 | AllowedInterval int //ms 19 | } 20 | 21 | func (ctf *ConnectionThrottleFilter) GetName() string { 22 | return ConnectionThrottleFilterName 23 | } 24 | 25 | func (ctf *ConnectionThrottleFilter) GetInterestOps() uint { 26 | return 1 << netlib.InterestOps_Opened 27 | } 28 | 29 | func (ctf *ConnectionThrottleFilter) OnSessionOpened(s *netlib.Session) bool { 30 | if !ctf.isConnectionOk(s) { 31 | s.Close() 32 | return false 33 | } 34 | return true 35 | } 36 | 37 | func (ctf *ConnectionThrottleFilter) OnSessionClosed(s *netlib.Session) bool { 38 | return true 39 | } 40 | 41 | func (ctf *ConnectionThrottleFilter) OnSessionIdle(s *netlib.Session) bool { 42 | return true 43 | } 44 | 45 | func (ctf *ConnectionThrottleFilter) OnPacketReceived(s *netlib.Session, packetid int, logicNo uint32, packet interface{}) bool { 46 | return true 47 | } 48 | 49 | func (ctf *ConnectionThrottleFilter) OnPacketSent(s *netlib.Session, packetid int, logicNo uint32, data []byte) bool { 50 | return true 51 | } 52 | 53 | func (ctf *ConnectionThrottleFilter) isConnectionOk(s *netlib.Session) bool { 54 | host, _, err := net.SplitHostPort(s.RemoteAddr()) 55 | if err != nil { 56 | return false 57 | } 58 | 59 | tNow := time.Now() 60 | value := ctf.clients.Get(host) 61 | if value != nil { 62 | tLast := value.(time.Time) 63 | if tNow.Sub(tLast) < time.Duration(ctf.AllowedInterval)*time.Millisecond { 64 | ctf.clients.Set(host, tNow) 65 | return false 66 | } 67 | } 68 | 69 | ctf.clients.Set(host, tNow) 70 | return true 71 | } 72 | 73 | func init() { 74 | netlib.RegisteSessionFilterCreator(ConnectionThrottleFilterName, func() netlib.SessionFilter { 75 | return &ConnectionThrottleFilter{clients: container.NewSynchronizedMap(), AllowedInterval: DefaultAllowedInterval} 76 | }) 77 | } 78 | -------------------------------------------------------------------------------- /core/builtin/filter/keepalive.go: -------------------------------------------------------------------------------- 1 | package filter 2 | 3 | import ( 4 | "code.google.com/p/goprotobuf/proto" 5 | "github.com/idealeak/goserver/core/builtin/protocol" 6 | "github.com/idealeak/goserver/core/netlib" 7 | ) 8 | 9 | var ( 10 | KeepAliveFilterName = "session-filter-keepalive" 11 | ) 12 | 13 | type KeepAliveFilter struct { 14 | } 15 | 16 | func (kf *KeepAliveFilter) GetName() string { 17 | return KeepAliveFilterName 18 | } 19 | 20 | func (kf *KeepAliveFilter) GetInterestOps() uint { 21 | return 1 << netlib.InterestOps_Idle 22 | } 23 | 24 | func (kf *KeepAliveFilter) OnSessionOpened(s *netlib.Session) bool { 25 | return true 26 | } 27 | 28 | func (kf *KeepAliveFilter) OnSessionClosed(s *netlib.Session) bool { 29 | return true 30 | } 31 | 32 | func (kf *KeepAliveFilter) OnSessionIdle(s *netlib.Session) bool { 33 | p := &protocol.SSPacketKeepAlive{Flag: proto.Int32(0)} 34 | proto.SetDefaults(p) 35 | s.Send(int(protocol.CoreBuiltinPacketID_PACKET_SS_KEEPALIVE), p) 36 | return true 37 | } 38 | 39 | func (kf *KeepAliveFilter) OnPacketReceived(s *netlib.Session, packetid int, logicNo uint32, packet interface{}) bool { 40 | return true 41 | } 42 | 43 | func (kf *KeepAliveFilter) OnPacketSent(s *netlib.Session, packetid int, logicNo uint32, data []byte) bool { 44 | return true 45 | } 46 | 47 | func init() { 48 | netlib.RegisterFactory(int(protocol.CoreBuiltinPacketID_PACKET_SS_KEEPALIVE), netlib.PacketFactoryWrapper(func() interface{} { 49 | return &protocol.SSPacketKeepAlive{} 50 | })) 51 | netlib.RegisteSessionFilterCreator(KeepAliveFilterName, func() netlib.SessionFilter { 52 | return &KeepAliveFilter{} 53 | }) 54 | netlib.RegisterHandler(int(protocol.CoreBuiltinPacketID_PACKET_SS_KEEPALIVE), netlib.HandlerWrapper(func(s *netlib.Session, packetid int, data interface{}) error { 55 | if p, ok := data.(*protocol.SSPacketKeepAlive); ok { 56 | if p.GetFlag() == 0 { 57 | p.Flag = proto.Int32(1) 58 | s.Send(int(protocol.CoreBuiltinPacketID_PACKET_SS_KEEPALIVE), p) 59 | } 60 | } 61 | return nil 62 | })) 63 | } 64 | -------------------------------------------------------------------------------- /core/builtin/gen_cpp.bat: -------------------------------------------------------------------------------- 1 | protoc --cpp_out=. protocol/*.proto 2 | pause -------------------------------------------------------------------------------- /core/builtin/gen_go.bat: -------------------------------------------------------------------------------- 1 | protoc --go_out=. protocol/*.proto 2 | pause -------------------------------------------------------------------------------- /core/builtin/protocol/corepacketid.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: protocol/corepacketid.proto 3 | // DO NOT EDIT! 4 | 5 | package protocol 6 | 7 | import proto "code.google.com/p/goprotobuf/proto" 8 | import json "encoding/json" 9 | import math "math" 10 | 11 | // Reference proto, json, and math imports to suppress error if they are not otherwise used. 12 | var _ = proto.Marshal 13 | var _ = &json.SyntaxError{} 14 | var _ = math.Inf 15 | 16 | type CoreBuiltinPacketID int32 17 | 18 | const ( 19 | CoreBuiltinPacketID_PACKET_SS_TX_START CoreBuiltinPacketID = -1000 20 | CoreBuiltinPacketID_PACKET_SS_TX_CMD CoreBuiltinPacketID = -1001 21 | CoreBuiltinPacketID_PACKET_SS_TX_RESULT CoreBuiltinPacketID = -1002 22 | CoreBuiltinPacketID_PACKET_SS_SLICES CoreBuiltinPacketID = -1003 23 | CoreBuiltinPacketID_PACKET_SS_AUTH CoreBuiltinPacketID = -1004 24 | CoreBuiltinPacketID_PACKET_SS_KEEPALIVE CoreBuiltinPacketID = -1005 25 | CoreBuiltinPacketID_PACKET_SS_AUTH_ACK CoreBuiltinPacketID = -1006 26 | ) 27 | 28 | var CoreBuiltinPacketID_name = map[int32]string{ 29 | -1000: "PACKET_SS_TX_START", 30 | -1001: "PACKET_SS_TX_CMD", 31 | -1002: "PACKET_SS_TX_RESULT", 32 | -1003: "PACKET_SS_SLICES", 33 | -1004: "PACKET_SS_AUTH", 34 | -1005: "PACKET_SS_KEEPALIVE", 35 | -1006: "PACKET_SS_AUTH_ACK", 36 | } 37 | var CoreBuiltinPacketID_value = map[string]int32{ 38 | "PACKET_SS_TX_START": -1000, 39 | "PACKET_SS_TX_CMD": -1001, 40 | "PACKET_SS_TX_RESULT": -1002, 41 | "PACKET_SS_SLICES": -1003, 42 | "PACKET_SS_AUTH": -1004, 43 | "PACKET_SS_KEEPALIVE": -1005, 44 | "PACKET_SS_AUTH_ACK": -1006, 45 | } 46 | 47 | func (x CoreBuiltinPacketID) Enum() *CoreBuiltinPacketID { 48 | p := new(CoreBuiltinPacketID) 49 | *p = x 50 | return p 51 | } 52 | func (x CoreBuiltinPacketID) String() string { 53 | return proto.EnumName(CoreBuiltinPacketID_name, int32(x)) 54 | } 55 | func (x CoreBuiltinPacketID) MarshalJSON() ([]byte, error) { 56 | return json.Marshal(x.String()) 57 | } 58 | func (x *CoreBuiltinPacketID) UnmarshalJSON(data []byte) error { 59 | value, err := proto.UnmarshalJSONEnum(CoreBuiltinPacketID_value, data, "CoreBuiltinPacketID") 60 | if err != nil { 61 | return err 62 | } 63 | *x = CoreBuiltinPacketID(value) 64 | return nil 65 | } 66 | 67 | func init() { 68 | proto.RegisterEnum("protocol.CoreBuiltinPacketID", CoreBuiltinPacketID_name, CoreBuiltinPacketID_value) 69 | } 70 | -------------------------------------------------------------------------------- /core/builtin/protocol/corepacketid.proto: -------------------------------------------------------------------------------- 1 | package protocol; 2 | 3 | enum CoreBuiltinPacketID { 4 | PACKET_SS_TX_START = -1000; 5 | PACKET_SS_TX_CMD = -1001; 6 | PACKET_SS_TX_RESULT = -1002; 7 | PACKET_SS_SLICES = -1003; 8 | PACKET_SS_AUTH = -1004; 9 | PACKET_SS_KEEPALIVE = -1005; 10 | PACKET_SS_AUTH_ACK = -1006; 11 | } -------------------------------------------------------------------------------- /core/builtin/protocol/keepalive.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: protocol/keepalive.proto 3 | // DO NOT EDIT! 4 | 5 | package protocol 6 | 7 | import proto "code.google.com/p/goprotobuf/proto" 8 | import json "encoding/json" 9 | import math "math" 10 | 11 | // Reference proto, json, and math imports to suppress error if they are not otherwise used. 12 | var _ = proto.Marshal 13 | var _ = &json.SyntaxError{} 14 | var _ = math.Inf 15 | 16 | type SSPacketKeepAlive struct { 17 | Flag *int32 `protobuf:"varint,1,req" json:"Flag,omitempty"` 18 | XXX_unrecognized []byte `json:"-"` 19 | } 20 | 21 | func (m *SSPacketKeepAlive) Reset() { *m = SSPacketKeepAlive{} } 22 | func (m *SSPacketKeepAlive) String() string { return proto.CompactTextString(m) } 23 | func (*SSPacketKeepAlive) ProtoMessage() {} 24 | 25 | func (m *SSPacketKeepAlive) GetFlag() int32 { 26 | if m != nil && m.Flag != nil { 27 | return *m.Flag 28 | } 29 | return 0 30 | } 31 | 32 | func init() { 33 | } 34 | -------------------------------------------------------------------------------- /core/builtin/protocol/keepalive.proto: -------------------------------------------------------------------------------- 1 | package protocol; 2 | 3 | message SSPacketKeepAlive { 4 | required int32 Flag = 1; 5 | } -------------------------------------------------------------------------------- /core/builtin/protocol/sessionauth.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: protocol/sessionauth.proto 3 | // DO NOT EDIT! 4 | 5 | package protocol 6 | 7 | import proto "code.google.com/p/goprotobuf/proto" 8 | import json "encoding/json" 9 | import math "math" 10 | 11 | // Reference proto, json, and math imports to suppress error if they are not otherwise used. 12 | var _ = proto.Marshal 13 | var _ = &json.SyntaxError{} 14 | var _ = math.Inf 15 | 16 | type SSPacketAuth struct { 17 | AuthKey *string `protobuf:"bytes,1,req" json:"AuthKey,omitempty"` 18 | Timestamp *int64 `protobuf:"varint,2,req" json:"Timestamp,omitempty"` 19 | XXX_unrecognized []byte `json:"-"` 20 | } 21 | 22 | func (m *SSPacketAuth) Reset() { *m = SSPacketAuth{} } 23 | func (m *SSPacketAuth) String() string { return proto.CompactTextString(m) } 24 | func (*SSPacketAuth) ProtoMessage() {} 25 | 26 | func (m *SSPacketAuth) GetAuthKey() string { 27 | if m != nil && m.AuthKey != nil { 28 | return *m.AuthKey 29 | } 30 | return "" 31 | } 32 | 33 | func (m *SSPacketAuth) GetTimestamp() int64 { 34 | if m != nil && m.Timestamp != nil { 35 | return *m.Timestamp 36 | } 37 | return 0 38 | } 39 | 40 | type SSPacketAuthAck struct { 41 | Msg *string `protobuf:"bytes,1,opt" json:"Msg,omitempty"` 42 | XXX_unrecognized []byte `json:"-"` 43 | } 44 | 45 | func (m *SSPacketAuthAck) Reset() { *m = SSPacketAuthAck{} } 46 | func (m *SSPacketAuthAck) String() string { return proto.CompactTextString(m) } 47 | func (*SSPacketAuthAck) ProtoMessage() {} 48 | 49 | func (m *SSPacketAuthAck) GetMsg() string { 50 | if m != nil && m.Msg != nil { 51 | return *m.Msg 52 | } 53 | return "" 54 | } 55 | 56 | func init() { 57 | } 58 | -------------------------------------------------------------------------------- /core/builtin/protocol/sessionauth.proto: -------------------------------------------------------------------------------- 1 | package protocol; 2 | 3 | message SSPacketAuth { 4 | required string AuthKey = 1; 5 | required int64 Timestamp = 2; 6 | } 7 | 8 | message SSPacketAuthAck { 9 | optional string Msg = 1; 10 | } -------------------------------------------------------------------------------- /core/builtin/protocol/slices.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: protocol/slices.proto 3 | // DO NOT EDIT! 4 | 5 | package protocol 6 | 7 | import proto "code.google.com/p/goprotobuf/proto" 8 | import json "encoding/json" 9 | import math "math" 10 | 11 | // Reference proto, json, and math imports to suppress error if they are not otherwise used. 12 | var _ = proto.Marshal 13 | var _ = &json.SyntaxError{} 14 | var _ = math.Inf 15 | 16 | type SSPacketSlices struct { 17 | SeqNo *int32 `protobuf:"varint,1,req" json:"SeqNo,omitempty"` 18 | TotalSize *int32 `protobuf:"varint,2,req" json:"TotalSize,omitempty"` 19 | Offset *int32 `protobuf:"varint,3,req" json:"Offset,omitempty"` 20 | PacketData []byte `protobuf:"bytes,4,req" json:"PacketData,omitempty"` 21 | XXX_unrecognized []byte `json:"-"` 22 | } 23 | 24 | func (m *SSPacketSlices) Reset() { *m = SSPacketSlices{} } 25 | func (m *SSPacketSlices) String() string { return proto.CompactTextString(m) } 26 | func (*SSPacketSlices) ProtoMessage() {} 27 | 28 | func (m *SSPacketSlices) GetSeqNo() int32 { 29 | if m != nil && m.SeqNo != nil { 30 | return *m.SeqNo 31 | } 32 | return 0 33 | } 34 | 35 | func (m *SSPacketSlices) GetTotalSize() int32 { 36 | if m != nil && m.TotalSize != nil { 37 | return *m.TotalSize 38 | } 39 | return 0 40 | } 41 | 42 | func (m *SSPacketSlices) GetOffset() int32 { 43 | if m != nil && m.Offset != nil { 44 | return *m.Offset 45 | } 46 | return 0 47 | } 48 | 49 | func (m *SSPacketSlices) GetPacketData() []byte { 50 | if m != nil { 51 | return m.PacketData 52 | } 53 | return nil 54 | } 55 | 56 | func init() { 57 | } 58 | -------------------------------------------------------------------------------- /core/builtin/protocol/slices.proto: -------------------------------------------------------------------------------- 1 | package protocol; 2 | 3 | message SSPacketSlices { 4 | required int32 SeqNo = 1; 5 | required int32 TotalSize = 2; 6 | required int32 Offset = 3; 7 | required bytes PacketData = 4; 8 | } -------------------------------------------------------------------------------- /core/builtin/protocol/transact.proto: -------------------------------------------------------------------------------- 1 | package protocol; 2 | 3 | message TransactStart { 4 | required TransactParam MyTNP = 1; 5 | required TransactParam ParenTNP = 2; 6 | optional bytes CustomData = 3; 7 | } 8 | 9 | message TransactCtrlCmd { 10 | required int64 TId = 1; 11 | required int32 Cmd = 2; 12 | } 13 | 14 | message TransactResult { 15 | required int64 MyTId = 1; 16 | required int64 ChildTId = 2; 17 | required int32 RetCode = 3; 18 | optional bytes CustomData = 4; 19 | } 20 | 21 | message TransactParam { 22 | required int64 TransNodeID = 1; 23 | required int32 TransType = 2; 24 | required int32 OwnerType = 3; 25 | required int32 OwnerID = 4; 26 | required int32 SkeletonID = 5; 27 | required int32 LevelNo = 6; 28 | required int32 AreaID = 7; 29 | required int64 TimeOut = 8; 30 | required int32 TransCommitType = 9; 31 | } -------------------------------------------------------------------------------- /core/cmdline/cmdline_exit.go: -------------------------------------------------------------------------------- 1 | package cmdline 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/idealeak/goserver/core/module" 7 | ) 8 | 9 | type exitExecuter struct { 10 | } 11 | 12 | func (this exitExecuter) Execute(args []string) { 13 | module.Stop() 14 | } 15 | 16 | func (this exitExecuter) ShowUsage() { 17 | fmt.Println("usage: exit") 18 | } 19 | 20 | func init() { 21 | RegisteCmd("exit", &exitExecuter{}) 22 | } 23 | -------------------------------------------------------------------------------- /core/cmdline/cmdline_help.go: -------------------------------------------------------------------------------- 1 | package cmdline 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type helpExecuter struct { 8 | } 9 | 10 | func (this helpExecuter) Execute(args []string) { 11 | if len(args) > 0 { 12 | if cmde, exist := cmdpool[args[0]]; exist { 13 | cmde.ShowUsage() 14 | } 15 | } else { 16 | this.ShowUsage() 17 | fmt.Println("The commands are:") 18 | for k, _ := range cmdpool { 19 | if k != "help" { 20 | fmt.Println("\t", k) 21 | } 22 | } 23 | fmt.Println("Use \"help [command]\" for more information about a command.") 24 | } 25 | } 26 | 27 | func (this helpExecuter) ShowUsage() { 28 | fmt.Println("Help is a help command like window or linux shell's command") 29 | fmt.Println("Usage:") 30 | fmt.Println("\t", "help command") 31 | } 32 | 33 | func init() { 34 | RegisteCmd("help", &helpExecuter{}) 35 | } 36 | -------------------------------------------------------------------------------- /core/cmdline/command_cmdline.go: -------------------------------------------------------------------------------- 1 | package cmdline 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core/basic" 5 | ) 6 | 7 | type cmdlineCommand struct { 8 | exec cmdExecuter 9 | args []string 10 | } 11 | 12 | func (cmd *cmdlineCommand) Done(o *basic.Object) error { 13 | defer o.ProcessSeqnum() 14 | cmd.exec.Execute(cmd.args) 15 | return nil 16 | } 17 | 18 | func PostCmd(p *basic.Object, exec cmdExecuter, args []string) bool { 19 | return p.SendCommand(&cmdlineCommand{exec: exec, args: args}, true) 20 | } 21 | -------------------------------------------------------------------------------- /core/cmdline/config.go: -------------------------------------------------------------------------------- 1 | package cmdline 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core" 5 | ) 6 | 7 | var Config = Configuration{} 8 | 9 | type Configuration struct { 10 | SupportCmdLine bool 11 | } 12 | 13 | func (c *Configuration) Name() string { 14 | return "cmdline" 15 | } 16 | 17 | func (c *Configuration) Init() error { 18 | return nil 19 | } 20 | 21 | func (c *Configuration) Close() error { 22 | return nil 23 | } 24 | 25 | func init() { 26 | core.RegistePackage(&Config) 27 | } 28 | -------------------------------------------------------------------------------- /core/config.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "runtime" 5 | ) 6 | 7 | var Config = Configuration{} 8 | 9 | type Configuration struct { 10 | MaxProcs int 11 | Debug bool 12 | } 13 | 14 | func (c *Configuration) Name() string { 15 | return "core" 16 | } 17 | 18 | func (c *Configuration) Init() error { 19 | if c.MaxProcs <= 0 { 20 | c.MaxProcs = 1 21 | } 22 | runtime.GOMAXPROCS(c.MaxProcs) 23 | return nil 24 | } 25 | 26 | func (c *Configuration) Close() error { 27 | return nil 28 | } 29 | 30 | func init() { 31 | RegistePackage(&Config) 32 | } 33 | -------------------------------------------------------------------------------- /core/container/doc.go: -------------------------------------------------------------------------------- 1 | package container 2 | -------------------------------------------------------------------------------- /core/container/queue/queue.go: -------------------------------------------------------------------------------- 1 | // queue 2 | package queue 3 | 4 | import ( 5 | "time" 6 | ) 7 | 8 | type Queue interface { 9 | Len() int 10 | Enqueue(interface{}, time.Duration) bool 11 | Dequeue(time.Duration) (interface{}, bool) 12 | } 13 | -------------------------------------------------------------------------------- /core/container/queue/queue_chan.go: -------------------------------------------------------------------------------- 1 | // queue 2 | package queue 3 | 4 | import "time" 5 | 6 | type queueC struct { 7 | c chan interface{} 8 | } 9 | 10 | func NewQueueC(backlog int) Queue { 11 | return &queueC{ 12 | c: make(chan interface{}, backlog), 13 | } 14 | } 15 | 16 | func (q *queueC) Enqueue(i interface{}, timeout time.Duration) bool { 17 | if timeout > 0 { 18 | timer := time.NewTimer(timeout) 19 | select { 20 | case q.c <- i: 21 | case <-timer.C: 22 | return false 23 | } 24 | } else { 25 | q.c <- i 26 | } 27 | 28 | return true 29 | } 30 | 31 | func (q *queueC) Dequeue(timeout time.Duration) (i interface{}, ok bool) { 32 | if timeout > 0 { 33 | timer := time.NewTimer(timeout) 34 | select { 35 | case i, ok = <-q.c: 36 | return i, ok 37 | case <-timer.C: 38 | return nil, false 39 | } 40 | } else { 41 | select { 42 | case i, ok = <-q.c: 43 | return i, ok 44 | } 45 | } 46 | return nil, false 47 | } 48 | 49 | func (q *queueC) Len() int { 50 | return len(q.c) 51 | } 52 | -------------------------------------------------------------------------------- /core/container/queue/queue_sync.go: -------------------------------------------------------------------------------- 1 | package queue 2 | 3 | import ( 4 | "container/list" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | type queueS struct { 10 | fifo *list.List 11 | lock *sync.RWMutex 12 | } 13 | 14 | func NewQueueS() Queue { 15 | q := &queueS{ 16 | fifo: list.New(), 17 | lock: new(sync.RWMutex), 18 | } 19 | return q 20 | } 21 | 22 | func (q *queueS) Enqueue(i interface{}, timeout time.Duration) bool { 23 | q.lock.Lock() 24 | q.fifo.PushBack(i) 25 | q.lock.Unlock() 26 | return true 27 | } 28 | 29 | func (q *queueS) Dequeue(timeout time.Duration) (interface{}, bool) { 30 | if q.fifo.Len() == 0 { 31 | return nil, false 32 | } 33 | 34 | q.lock.Lock() 35 | e := q.fifo.Front() 36 | if e != nil { 37 | q.fifo.Remove(e) 38 | q.lock.Unlock() 39 | return e.Value, true 40 | } 41 | q.lock.Unlock() 42 | return nil, false 43 | } 44 | 45 | func (q *queueS) Len() int { 46 | q.lock.RLock() 47 | l := q.fifo.Len() 48 | q.lock.RUnlock() 49 | return l 50 | } 51 | -------------------------------------------------------------------------------- /core/container/queue/queue_test.go: -------------------------------------------------------------------------------- 1 | // queue_test 2 | package queue 3 | 4 | import ( 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestSyncQueneEnqueue(t *testing.T) { 10 | const CNT int = 10 11 | q := NewQueueS() 12 | for i := 0; i < CNT; i++ { 13 | q.Enqueue(i, 0) 14 | } 15 | if q.Len() != CNT { 16 | t.Error("sync queue Enqueue error") 17 | } 18 | } 19 | 20 | func TestSyncQueneDequeue(t *testing.T) { 21 | const CNT int = 10 22 | q := NewQueueS() 23 | for i := 0; i < CNT; i++ { 24 | q.Enqueue(i, 0) 25 | } 26 | 27 | var ( 28 | b bool = true 29 | d interface{} 30 | cnt int 31 | ) 32 | 33 | for b { 34 | d, b = q.Dequeue(0) 35 | if b { 36 | cnt++ 37 | t.Log("Dequeue data:", d) 38 | } 39 | } 40 | if cnt != CNT { 41 | t.Error("sync queue Dequeue error") 42 | } 43 | } 44 | 45 | func BenchmarkSyncQueneEnqueue(b *testing.B) { 46 | q := NewQueueS() 47 | b.StartTimer() 48 | for i := 0; i < b.N; i++ { 49 | q.Enqueue(i, 0) 50 | } 51 | b.StopTimer() 52 | } 53 | 54 | func BenchmarkSyncQueneDequeue(b *testing.B) { 55 | q := NewQueueS() 56 | for i := 0; i < b.N; i++ { 57 | q.Enqueue(i, 0) 58 | } 59 | b.StartTimer() 60 | for i := 0; i < b.N; i++ { 61 | q.Dequeue(0) 62 | } 63 | b.StopTimer() 64 | } 65 | 66 | func BenchmarkChanQueneEnqueue(b *testing.B) { 67 | q := NewQueueC(b.N) 68 | b.StartTimer() 69 | for i := 0; i < b.N; i++ { 70 | q.Enqueue(i, time.Millisecond) 71 | } 72 | b.StopTimer() 73 | } 74 | 75 | func BenchmarkChanQueneDequeue(b *testing.B) { 76 | q := NewQueueC(b.N) 77 | for i := 0; i < b.N; i++ { 78 | q.Enqueue(i, 0) 79 | } 80 | b.StartTimer() 81 | for i := 0; i < b.N; i++ { 82 | q.Dequeue(0) 83 | } 84 | b.StopTimer() 85 | } 86 | -------------------------------------------------------------------------------- /core/container/recycler/recycler.go: -------------------------------------------------------------------------------- 1 | // recycler 2 | package recycler 3 | 4 | import ( 5 | "container/list" 6 | "time" 7 | ) 8 | 9 | var RecyclerBacklogDefault int = 5 10 | 11 | type element struct { 12 | when time.Time 13 | data interface{} 14 | } 15 | 16 | type Recycler struct { 17 | get chan interface{} 18 | give chan interface{} 19 | ocf func() interface{} 20 | que *list.List 21 | timeout *time.Timer 22 | makecnt int 23 | name string 24 | running bool 25 | } 26 | 27 | func NewRecycler(backlog int, ocf func() interface{}, name string) *Recycler { 28 | r := &Recycler{ 29 | get: make(chan interface{}, backlog), 30 | give: make(chan interface{}, backlog), 31 | ocf: ocf, 32 | que: list.New(), 33 | timeout: time.NewTimer(time.Minute), 34 | name: name, 35 | running: true, 36 | } 37 | 38 | go r.run() 39 | return r 40 | } 41 | 42 | func (this *Recycler) run() { 43 | RecyclerMgr.registe(this) 44 | defer RecyclerMgr.unregiste(this) 45 | 46 | for this.running { 47 | if this.que.Len() == 0 { 48 | this.que.PushFront(element{when: time.Now(), data: this.ocf()}) 49 | this.makecnt++ 50 | } 51 | 52 | this.timeout.Reset(time.Minute) 53 | e := this.que.Front() 54 | select { 55 | case d := <-this.give: 56 | this.timeout.Stop() 57 | this.que.PushFront(element{when: time.Now(), data: d}) 58 | case this.get <- e.Value.(element).data: 59 | this.timeout.Stop() 60 | this.que.Remove(e) 61 | case <-this.timeout.C: 62 | e := this.que.Front() 63 | for e != nil { 64 | n := e.Next() 65 | if time.Since(e.Value.(element).when) > time.Minute { 66 | this.que.Remove(e) 67 | e.Value = nil 68 | this.makecnt-- 69 | } 70 | e = n 71 | } 72 | } 73 | } 74 | } 75 | 76 | func (this *Recycler) Get() interface{} { 77 | i := <-this.get 78 | return i 79 | } 80 | 81 | func (this *Recycler) Give(i interface{}) { 82 | this.give <- i 83 | } 84 | 85 | func (this *Recycler) Close() { 86 | this.running = false 87 | } 88 | -------------------------------------------------------------------------------- /core/container/recycler/recycler_bytebuf.go: -------------------------------------------------------------------------------- 1 | package recycler 2 | 3 | import ( 4 | "bytes" 5 | ) 6 | 7 | const ( 8 | BytebufRecyclerBacklog int = 128 9 | ) 10 | 11 | var BytebufRecycler = NewRecycler( 12 | BytebufRecyclerBacklog, 13 | func() interface{} { 14 | return bytes.NewBuffer(nil) 15 | }, 16 | "bytebuf_recycler", 17 | ) 18 | 19 | func AllocBytebuf() *bytes.Buffer { 20 | b := BytebufRecycler.Get() 21 | buf := b.(*bytes.Buffer) 22 | buf.Reset() 23 | return buf 24 | } 25 | 26 | func FreeBytebuf(buf *bytes.Buffer) { 27 | BytebufRecycler.Give(buf) 28 | } 29 | -------------------------------------------------------------------------------- /core/container/recycler/recycler_mgr.go: -------------------------------------------------------------------------------- 1 | package recycler 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "sync" 7 | ) 8 | 9 | var RecyclerMgr = &recyclerMgr{ 10 | recyclers: make(map[interface{}]*Recycler), 11 | lock: new(sync.Mutex), 12 | } 13 | 14 | type recyclerMgr struct { 15 | recyclers map[interface{}]*Recycler 16 | lock *sync.Mutex 17 | } 18 | 19 | func (this *recyclerMgr) registe(r *Recycler) { 20 | this.lock.Lock() 21 | this.recyclers[r] = r 22 | this.lock.Unlock() 23 | } 24 | 25 | func (this *recyclerMgr) unregiste(r *Recycler) { 26 | this.lock.Lock() 27 | delete(this.recyclers, r) 28 | this.lock.Unlock() 29 | } 30 | 31 | func (this *recyclerMgr) CloseAll() { 32 | this.lock.Lock() 33 | defer this.lock.Unlock() 34 | for _, r := range this.recyclers { 35 | r.Close() 36 | } 37 | } 38 | 39 | func (this *recyclerMgr) Dump(w io.Writer) { 40 | this.lock.Lock() 41 | for _, r := range this.recyclers { 42 | w.Write([]byte(fmt.Sprintf("(%s) alloc object (%d)", r.name, r.makecnt))) 43 | } 44 | this.lock.Unlock() 45 | } 46 | -------------------------------------------------------------------------------- /core/container/recycler/recycler_test.go: -------------------------------------------------------------------------------- 1 | // recycler_test 2 | package recycler 3 | 4 | import ( 5 | "runtime" 6 | "testing" 7 | ) 8 | 9 | func makeBuffer() interface{} { 10 | buf := make([]byte, 0, 1024) 11 | return buf 12 | } 13 | 14 | var MyRecycler = NewRecycler(RecyclerBacklogDefault, makeBuffer, "test") 15 | 16 | func TestGet(t *testing.T) { 17 | MyRecycler.Get() 18 | } 19 | 20 | func TestGive(t *testing.T) { 21 | MyRecycler.Give(nil) 22 | } 23 | 24 | func BenchmarkGet(b *testing.B) { 25 | b.StartTimer() 26 | for i := 0; i < b.N; i++ { 27 | MyRecycler.Get() 28 | } 29 | b.StopTimer() 30 | } 31 | -------------------------------------------------------------------------------- /core/container/recycler/recycler_timer.go: -------------------------------------------------------------------------------- 1 | package recycler 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | const ( 8 | NewTimerDefaultDuration time.Duration = time.Minute 9 | TimerRecyclerBacklog int = 128 10 | ) 11 | 12 | var TimerRecycler = NewRecycler( 13 | TimerRecyclerBacklog, 14 | func() interface{} { 15 | return time.NewTimer(NewTimerDefaultDuration) 16 | }, 17 | "timer_recycler", 18 | ) 19 | 20 | func GetTimer(timeout time.Duration) *time.Timer { 21 | t := TimerRecycler.Get() 22 | timer := t.(*time.Timer) 23 | timer.Reset(timeout) 24 | return timer 25 | } 26 | 27 | func GiveTimer(t *time.Timer) { 28 | TimerRecycler.Give(t) 29 | } 30 | -------------------------------------------------------------------------------- /core/container/synchronizedlist.go: -------------------------------------------------------------------------------- 1 | package container 2 | 3 | import ( 4 | "container/list" 5 | "sync" 6 | ) 7 | 8 | type SynchronizedList struct { 9 | list *list.List 10 | lock *sync.Mutex 11 | } 12 | 13 | func NewSynchronizedList() *SynchronizedList { 14 | sl := &SynchronizedList{ 15 | list: list.New(), 16 | lock: new(sync.Mutex), 17 | } 18 | return sl 19 | } 20 | 21 | func (sl *SynchronizedList) PushFront(v interface{}) { 22 | sl.lock.Lock() 23 | sl.list.PushFront(v) 24 | sl.lock.Unlock() 25 | } 26 | 27 | func (sl *SynchronizedList) PopFront() (v interface{}) { 28 | sl.lock.Lock() 29 | e := sl.list.Front() 30 | if e != nil { 31 | v = e.Value 32 | sl.list.Remove(e) 33 | } 34 | sl.lock.Unlock() 35 | return v 36 | } 37 | 38 | func (sl *SynchronizedList) PushBack(v interface{}) { 39 | sl.lock.Lock() 40 | sl.list.PushBack(v) 41 | sl.lock.Unlock() 42 | } 43 | 44 | func (sl *SynchronizedList) PopBack() (v interface{}) { 45 | sl.lock.Lock() 46 | e := sl.list.Back() 47 | if e != nil { 48 | v = e.Value 49 | sl.list.Remove(e) 50 | } 51 | sl.lock.Unlock() 52 | return v 53 | } 54 | 55 | func (sl *SynchronizedList) Len() (n int) { 56 | sl.lock.Lock() 57 | n = sl.list.Len() 58 | sl.lock.Unlock() 59 | return 60 | } 61 | -------------------------------------------------------------------------------- /core/container/synchronizedmap.go: -------------------------------------------------------------------------------- 1 | package container 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | type SynchronizedMap struct { 8 | lock *sync.RWMutex 9 | m map[interface{}]interface{} 10 | } 11 | 12 | // NewSynchronizedMap return new SynchronizedMap 13 | func NewSynchronizedMap() *SynchronizedMap { 14 | return &SynchronizedMap{ 15 | lock: new(sync.RWMutex), 16 | m: make(map[interface{}]interface{}), 17 | } 18 | } 19 | 20 | // Get from maps return the k's value 21 | func (m *SynchronizedMap) Get(k interface{}) interface{} { 22 | m.lock.RLock() 23 | if val, ok := m.m[k]; ok { 24 | m.lock.RUnlock() 25 | return val 26 | } 27 | m.lock.RUnlock() 28 | return nil 29 | } 30 | 31 | // Maps the given key and value. Returns false 32 | // if the key is already in the map and changes nothing. 33 | func (m *SynchronizedMap) Set(k interface{}, v interface{}) bool { 34 | m.lock.Lock() 35 | if val, ok := m.m[k]; !ok { 36 | m.m[k] = v 37 | } else if val != v { 38 | m.m[k] = v 39 | } else { 40 | m.lock.Unlock() 41 | return false 42 | } 43 | m.lock.Unlock() 44 | return true 45 | } 46 | 47 | // Returns true if k is exist in the map. 48 | func (m *SynchronizedMap) IsExist(k interface{}) bool { 49 | m.lock.RLock() 50 | if _, ok := m.m[k]; !ok { 51 | m.lock.RUnlock() 52 | return false 53 | } 54 | m.lock.RUnlock() 55 | return true 56 | } 57 | 58 | // Delete the given key and value. 59 | func (m *SynchronizedMap) Delete(k interface{}) { 60 | m.lock.Lock() 61 | delete(m.m, k) 62 | m.lock.Unlock() 63 | } 64 | 65 | // Items returns all items in SynchronizedMap. 66 | func (m *SynchronizedMap) Items() map[interface{}]interface{} { 67 | mm := make(map[interface{}]interface{}) 68 | m.lock.RLock() 69 | for k, v := range m.m { 70 | mm[k] = v 71 | } 72 | m.lock.RUnlock() 73 | return mm 74 | } 75 | 76 | func (m *SynchronizedMap) Foreach(cb func(k, v interface{})) { 77 | m.lock.Lock() 78 | defer m.lock.Unlock() 79 | for k, v := range m.m { 80 | cb(k, v) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /core/ctx.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | 8 | "github.com/idealeak/goserver/core/basic" 9 | "github.com/idealeak/goserver/core/utils" 10 | ) 11 | 12 | const ( 13 | HOOK_BEFORE_START int = iota 14 | HOOK_AFTER_STOP 15 | HOOK_MAX 16 | ) 17 | 18 | var ( 19 | AppCtx *Ctx = newCtx() 20 | hooks [HOOK_MAX][]hookfunc 21 | ) 22 | 23 | type hookfunc func() error 24 | 25 | type Ctx struct { 26 | *basic.Object 27 | CoreObj *basic.Object 28 | } 29 | 30 | func newCtx() *Ctx { 31 | ctx := &Ctx{} 32 | ctx.init() 33 | return ctx 34 | } 35 | 36 | func (ctx *Ctx) init() { 37 | ctx.Object = basic.NewObject(ObjId_RootId, 38 | "root", 39 | basic.Options{ 40 | MaxDone: 1024, 41 | QueueBacklog: 1024, 42 | }, 43 | nil) 44 | ctx.Object.Waitor = utils.NewWaitor("core.Ctx") 45 | ctx.UserData = ctx 46 | ctx.Active() 47 | } 48 | 49 | func LaunchChild(o *basic.Object) { 50 | AppCtx.LaunchChild(o) 51 | } 52 | 53 | func Terminate(o *basic.Object) { 54 | AppCtx.Terminate(o) 55 | } 56 | 57 | func CoreObject() *basic.Object { 58 | //return AppCtx.GetChildById(ObjId_CoreId) 59 | return AppCtx.CoreObj 60 | } 61 | 62 | func RegisteHook(hookpos int, f hookfunc) { 63 | if hookpos < 0 || hookpos > HOOK_MAX { 64 | return 65 | } 66 | hooks[hookpos] = append(hooks[hookpos], f) 67 | } 68 | 69 | func ExecuteHook(hookpos int) error { 70 | if hookpos < 0 || hookpos > HOOK_MAX { 71 | return nil 72 | } 73 | var err error 74 | for _, h := range hooks[hookpos] { 75 | err = h() 76 | if err != nil { 77 | return err 78 | } 79 | } 80 | return nil 81 | } 82 | 83 | func WritePid() { 84 | if len(os.Args) > 0 { 85 | baseName := filepath.Base(os.Args[0]) 86 | f, err := os.OpenFile(baseName+".pid", os.O_CREATE|os.O_TRUNC|os.O_RDWR, os.ModePerm) 87 | if err != nil { 88 | panic(fmt.Sprintf("%s had running", os.Args[0])) 89 | return 90 | } 91 | 92 | f.WriteString(fmt.Sprintf("%v", os.Getpid())) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /core/doc.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | /* 4 | 5 | core struct 6 | 7 | AppCtx--------------------------------------------- 8 | | | | | 9 | | TimerMgr TaskExecutor Profile 10 | | 11 | AppModules-------------------------------------- 12 | | | | 13 | | | XXX_UserCustomModule 14 | | | 15 | | TransactModule 16 | | 17 | | 18 | NetModule------------------------ 19 | | | 20 | | Connector----------------- 21 | | | | 22 | | Session Socket Connect 23 | | 24 | Acceptor--------------------- 25 | | | 26 | Session0 Session1..n 27 | */ 28 | -------------------------------------------------------------------------------- /core/ids.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | const ( 4 | ObjId_RootId int = iota 5 | ObjId_CoreId 6 | ObjId_ExecutorId 7 | ObjId_TimerId 8 | ObjId_ProfileId 9 | ) 10 | -------------------------------------------------------------------------------- /core/logger/ilogger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | type ILogger interface { 4 | Tracef(format string, params ...interface{}) 5 | Debugf(format string, params ...interface{}) 6 | Infof(format string, params ...interface{}) 7 | Warnf(format string, params ...interface{}) error 8 | Errorf(format string, params ...interface{}) error 9 | Criticalf(format string, params ...interface{}) error 10 | 11 | Trace(v ...interface{}) 12 | Debug(v ...interface{}) 13 | Info(v ...interface{}) 14 | Warn(v ...interface{}) error 15 | Error(v ...interface{}) error 16 | Critical(v ...interface{}) error 17 | 18 | Close() 19 | Flush() 20 | Closed() bool 21 | } 22 | -------------------------------------------------------------------------------- /core/logger/log.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/cihub/seelog" 7 | ) 8 | 9 | var ( 10 | Logger seelog.LoggerInterface 11 | ) 12 | 13 | func init() { 14 | Logger, _ = seelog.LoggerFromConfigAsFile("logger.xml") 15 | seelog.ReplaceLogger(Logger) 16 | } 17 | 18 | func Reload(fileName string) error { 19 | newLogger, err := seelog.LoggerFromConfigAsFile(fileName) 20 | if err != nil { 21 | return err 22 | } 23 | if newLogger != nil { 24 | Logger = newLogger 25 | seelog.ReplaceLogger(Logger) 26 | fmt.Println("Reload success") 27 | } 28 | return nil 29 | } 30 | 31 | func Tracef(format string, params ...interface{}) { 32 | if Logger != nil { 33 | Logger.Tracef(format, params...) 34 | } 35 | } 36 | 37 | func Debugf(format string, params ...interface{}) { 38 | if Logger != nil { 39 | Logger.Debugf(format, params...) 40 | } 41 | } 42 | 43 | func Infof(format string, params ...interface{}) { 44 | if Logger != nil { 45 | Logger.Infof(format, params...) 46 | } 47 | } 48 | 49 | func Warnf(format string, params ...interface{}) error { 50 | if Logger != nil { 51 | return Logger.Warnf(format, params...) 52 | } 53 | return nil 54 | } 55 | 56 | func Errorf(format string, params ...interface{}) error { 57 | if Logger != nil { 58 | return Logger.Errorf(format, params...) 59 | } 60 | return nil 61 | } 62 | 63 | func Criticalf(format string, params ...interface{}) error { 64 | if Logger != nil { 65 | return Logger.Criticalf(format, params...) 66 | } 67 | return nil 68 | } 69 | 70 | func Trace(v ...interface{}) { 71 | if Logger != nil { 72 | Logger.Trace(v...) 73 | } 74 | } 75 | 76 | func Debug(v ...interface{}) { 77 | if Logger != nil { 78 | Logger.Debug(v...) 79 | } 80 | } 81 | 82 | func Info(v ...interface{}) { 83 | if Logger != nil { 84 | Logger.Info(v...) 85 | } 86 | } 87 | 88 | func Warn(v ...interface{}) error { 89 | if Logger != nil { 90 | return Logger.Warn(v...) 91 | } 92 | return nil 93 | } 94 | 95 | func Error(v ...interface{}) error { 96 | if Logger != nil { 97 | return Logger.Error(v...) 98 | } 99 | return nil 100 | } 101 | 102 | func Critical(v ...interface{}) error { 103 | if Logger != nil { 104 | return Logger.Critical(v...) 105 | } 106 | return nil 107 | } 108 | -------------------------------------------------------------------------------- /core/module/config.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/idealeak/goserver/core" 7 | "github.com/idealeak/goserver/core/basic" 8 | ) 9 | 10 | var Config = Configuration{} 11 | 12 | type Configuration struct { 13 | Options basic.Options 14 | } 15 | 16 | func (c *Configuration) Name() string { 17 | return "module" 18 | } 19 | 20 | func (c *Configuration) Init() error { 21 | if c.Options.QueueBacklog <= 0 { 22 | c.Options.QueueBacklog = 1024 23 | } 24 | if c.Options.MaxDone <= 0 { 25 | c.Options.MaxDone = 1024 26 | } 27 | if c.Options.Interval <= 0 { 28 | c.Options.Interval = time.Millisecond * 10 29 | } else { 30 | c.Options.Interval = time.Millisecond * c.Options.Interval 31 | } 32 | 33 | return nil 34 | } 35 | 36 | func (c *Configuration) Close() error { 37 | return nil 38 | } 39 | 40 | func init() { 41 | core.RegistePackage(&Config) 42 | } 43 | -------------------------------------------------------------------------------- /core/module/module.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | const ( 4 | ModuleName_Net string = "net-module" 5 | ModuleName_Transact = "dtc-module" 6 | ) 7 | 8 | type Module interface { 9 | ModuleName() string 10 | Init() 11 | Update() 12 | Shutdown() 13 | } 14 | -------------------------------------------------------------------------------- /core/module/preload.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | type PreloadModule interface { 4 | Start() 5 | } 6 | -------------------------------------------------------------------------------- /core/netlib/acceptor.go: -------------------------------------------------------------------------------- 1 | package netlib 2 | 3 | import "net" 4 | 5 | type Acceptor interface { 6 | ioService 7 | GetSessionConfig() *SessionConfig 8 | Addr() net.Addr 9 | } 10 | -------------------------------------------------------------------------------- /core/netlib/action.go: -------------------------------------------------------------------------------- 1 | package netlib 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "github.com/idealeak/goserver/core/logger" 8 | "github.com/idealeak/goserver/core/profile" 9 | "github.com/idealeak/goserver/core/utils" 10 | ) 11 | 12 | type action struct { 13 | s *Session 14 | p interface{} 15 | n string 16 | packid int 17 | logicNo uint32 18 | next *action 19 | } 20 | 21 | func (this *action) do() { 22 | watch := profile.TimeStatisticMgr.WatchStart(fmt.Sprintf("/action/%v", this.n), profile.TIME_ELEMENT_ACTION) 23 | defer func() { 24 | FreeAction(this) 25 | if watch != nil { 26 | watch.Stop() 27 | } 28 | utils.DumpStackIfPanic(fmt.Sprintf("netlib.session.task.do exe error, packet type:%v", reflect.TypeOf(this.p))) 29 | }() 30 | 31 | h := GetHandler(this.packid) 32 | if h != nil { 33 | err := h.Process(this.s, this.packid, this.p) 34 | if err != nil { 35 | logger.Logger.Infof("%v process error %v", this.n, err) 36 | } 37 | } else { 38 | logger.Logger.Infof("%v not registe handler", this.n) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/netlib/command_start_ioservice.go: -------------------------------------------------------------------------------- 1 | package netlib 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core" 5 | "github.com/idealeak/goserver/core/basic" 6 | ) 7 | 8 | type startIoService struct { 9 | sc *SessionConfig 10 | } 11 | 12 | func (sis *startIoService) Done(o *basic.Object) error { 13 | 14 | s := NetModule.newIoService(sis.sc) 15 | if s != nil { 16 | NetModule.pool[sis.sc.Id] = s 17 | s.start() 18 | } 19 | 20 | return nil 21 | } 22 | 23 | func SendStartNetIoService(sc *SessionConfig) bool { 24 | return core.CoreObject().SendCommand(&startIoService{sc: sc}, false) 25 | } 26 | -------------------------------------------------------------------------------- /core/netlib/connector.go: -------------------------------------------------------------------------------- 1 | package netlib 2 | 3 | import "time" 4 | 5 | const ( 6 | ReconnectInterval time.Duration = 5 * time.Second 7 | ) 8 | 9 | type Connector interface { 10 | ioService 11 | GetSessionConfig() *SessionConfig 12 | } 13 | -------------------------------------------------------------------------------- /core/netlib/connectormgr.go: -------------------------------------------------------------------------------- 1 | package netlib 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | var ( 9 | ConnectorMgr = &connectorMgr{ 10 | pool: make(map[string]Connector), 11 | } 12 | ) 13 | 14 | type connectorMgr struct { 15 | pool map[string]Connector 16 | lock sync.Mutex 17 | } 18 | 19 | func (cm *connectorMgr) IsConnecting(sc *SessionConfig) bool { 20 | strKey := fmt.Sprintf("%v:%v", sc.Ip, sc.Port) 21 | cm.lock.Lock() 22 | defer cm.lock.Unlock() 23 | if _, exist := cm.pool[strKey]; exist { 24 | return true 25 | } 26 | return false 27 | } 28 | 29 | func (cm *connectorMgr) registeConnector(c Connector) { 30 | sc := c.GetSessionConfig() 31 | strKey := fmt.Sprintf("%v:%v", sc.Ip, sc.Port) 32 | cm.lock.Lock() 33 | defer cm.lock.Unlock() 34 | cm.pool[strKey] = c 35 | } 36 | 37 | func (cm *connectorMgr) unregisteConnector(c Connector) { 38 | cm.lock.Lock() 39 | defer cm.lock.Unlock() 40 | for k, v := range cm.pool { 41 | if v == c { 42 | delete(cm.pool, k) 43 | return 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core/netlib/defaultprotocol.go: -------------------------------------------------------------------------------- 1 | // protocol 2 | package netlib 3 | 4 | import ( 5 | "encoding/binary" 6 | "fmt" 7 | ) 8 | 9 | var ( 10 | LenOfPacketHeader int 11 | LenOfProtoHeader int 12 | MaxPacketSize int = 64 * 1024 13 | ) 14 | 15 | type ProtoHeader struct { 16 | Len uint16 //包长度 17 | Seq uint16 //包序号 18 | LogicNo uint32 //逻辑号 19 | } 20 | 21 | type PacketHeader struct { 22 | EncodeType int16 23 | PacketId int16 24 | } 25 | 26 | type RWBuffer struct { 27 | pheader ProtoHeader 28 | seq uint16 29 | buf []byte 30 | } 31 | 32 | func (rwb *RWBuffer) Init() { 33 | rwb.seq = 0 34 | } 35 | 36 | func init() { 37 | LenOfPacketHeader = binary.Size(&PacketHeader{}) 38 | LenOfProtoHeader = binary.Size(&ProtoHeader{}) 39 | fmt.Println("sizeof(PacketHeader)=", LenOfPacketHeader, " sizeof(ProtoHeader)=", LenOfProtoHeader) 40 | } 41 | -------------------------------------------------------------------------------- /core/netlib/enc-binary.go: -------------------------------------------------------------------------------- 1 | // binary 2 | package netlib 3 | 4 | import ( 5 | "bytes" 6 | "encoding/binary" 7 | ) 8 | 9 | var Bcd = &BinaryEncDecoder{} 10 | 11 | type BinaryEncDecoder struct { 12 | } 13 | 14 | func (this *BinaryEncDecoder) Unmarshal(buf []byte, pack interface{}) error { 15 | return binary.Read(bytes.NewReader(buf), binary.LittleEndian, pack) 16 | } 17 | 18 | func (this *BinaryEncDecoder) Marshal(pack interface{}) ([]byte, error) { 19 | writer := bytes.NewBuffer(nil) 20 | err := binary.Write(writer, binary.LittleEndian, pack) 21 | return writer.Bytes(), err 22 | } 23 | 24 | func init() { 25 | RegisteEncoding(EncodingTypeBinary, Bcd, func(pack interface{}) int { 26 | if _, ok := pack.([]byte); ok { 27 | return EncodingTypeBinary 28 | } 29 | return -1 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /core/netlib/enc-gbp.go: -------------------------------------------------------------------------------- 1 | // Gbp 2 | package netlib 3 | 4 | import ( 5 | "errors" 6 | 7 | "code.google.com/p/goprotobuf/proto" 8 | ) 9 | 10 | var ErrorTypeNotFit = errors.New("packet not proto.Message type") 11 | 12 | var Gpb = &GbpEncDecoder{} 13 | 14 | type GbpEncDecoder struct { 15 | } 16 | 17 | func (this *GbpEncDecoder) Unmarshal(buf []byte, pack interface{}) error { 18 | if protomsg, ok := pack.(proto.Message); ok { 19 | err := proto.Unmarshal(buf, protomsg) 20 | if err != nil { 21 | return err 22 | } else { 23 | return nil 24 | } 25 | } 26 | 27 | return ErrorTypeNotFit 28 | } 29 | 30 | func (this *GbpEncDecoder) Marshal(pack interface{}) ([]byte, error) { 31 | if protomsg, ok := pack.(proto.Message); ok { 32 | return proto.Marshal(protomsg) 33 | } 34 | 35 | return nil, ErrorTypeNotFit 36 | } 37 | 38 | func init() { 39 | RegisteEncoding(EncodingTypeGPB, Gpb, func(pack interface{}) int { 40 | if _, ok := pack.(proto.Message); ok { 41 | return EncodingTypeGPB 42 | } 43 | return -1 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /core/netlib/enc-gob.go: -------------------------------------------------------------------------------- 1 | // Gob 2 | package netlib 3 | 4 | import ( 5 | "bytes" 6 | "encoding/gob" 7 | ) 8 | 9 | var Gob = &GobEncDecoder{} 10 | 11 | type GobEncDecoder struct { 12 | } 13 | 14 | func (this *GobEncDecoder) Unmarshal(buf []byte, pack interface{}) error { 15 | network := bytes.NewBuffer(buf) 16 | // Create a decoder and receive a value. 17 | dec := gob.NewDecoder(network) 18 | err := dec.Decode(pack) 19 | if err != nil { 20 | return err 21 | } 22 | 23 | return nil 24 | } 25 | 26 | func (this *GobEncDecoder) Marshal(pack interface{}) ([]byte, error) { 27 | var network bytes.Buffer // Stand-in for the network. 28 | 29 | // Create an encoder and send a value. 30 | enc := gob.NewEncoder(&network) 31 | err := enc.Encode(pack) 32 | if err != nil { 33 | return nil, err 34 | } 35 | 36 | return network.Bytes(), nil 37 | } 38 | 39 | func init() { 40 | RegisteEncoding(EncodingTypeGob, Gob, func(pack interface{}) int { 41 | return EncodingTypeGob 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /core/netlib/enc-nill.go: -------------------------------------------------------------------------------- 1 | // nil 2 | package netlib 3 | 4 | var Nil = &NilEncDecoder{} 5 | 6 | type NilEncDecoder struct { 7 | } 8 | 9 | func (this *NilEncDecoder) Unmarshal(buf []byte, pack interface{}) error { 10 | return nil 11 | } 12 | 13 | func (this *NilEncDecoder) Marshal(pack interface{}) ([]byte, error) { 14 | if binarymsg, ok := pack.([]byte); ok { 15 | return binarymsg, nil 16 | } 17 | 18 | return nil, ErrorTypeNotFit 19 | } 20 | 21 | func init() { 22 | RegisteEncoding(EncodingTypeNil, Nil, nil) 23 | } 24 | -------------------------------------------------------------------------------- /core/netlib/error.go: -------------------------------------------------------------------------------- 1 | // error 2 | package netlib 3 | 4 | type NetLibParamError struct { 5 | Src string 6 | Param string 7 | } 8 | 9 | func (self *NetLibParamError) Error() string { 10 | return "Invalid Parameter: " + self.Src + self.Param 11 | } 12 | 13 | func newNetLibParamError(src, param string) *NetLibParamError { 14 | return &NetLibParamError{Src: src, Param: param} 15 | } 16 | -------------------------------------------------------------------------------- /core/netlib/errorpackethandler.go: -------------------------------------------------------------------------------- 1 | package netlib 2 | 3 | var ( 4 | errorPacketHandlerCreatorPool = make(map[string]ErrorPacketHandlerCreator) 5 | ) 6 | 7 | type ErrorPacketHandlerCreator func() ErrorPacketHandler 8 | 9 | type ErrorPacketHandler interface { 10 | OnErrorPacket(s *Session, packetid int, logicNo uint32, data []byte) bool //run in session receive goroutine 11 | } 12 | 13 | type ErrorPacketHandlerWrapper func(session *Session, packetid int, logicNo uint32, data []byte) bool 14 | 15 | func (hw ErrorPacketHandlerWrapper) OnErrorPacket(session *Session, packetid int, logicNo uint32, data []byte) bool { 16 | return hw(session, packetid, logicNo, data) 17 | } 18 | 19 | func RegisteErrorPacketHandlerCreator(name string, ephc ErrorPacketHandlerCreator) { 20 | if ephc == nil { 21 | return 22 | } 23 | if _, exist := errorPacketHandlerCreatorPool[name]; exist { 24 | panic("repeate registe ErrorPacketHandler:" + name) 25 | } 26 | 27 | errorPacketHandlerCreatorPool[name] = ephc 28 | } 29 | 30 | func GetErrorPacketHandlerCreator(name string) ErrorPacketHandlerCreator { 31 | if ephc, exist := errorPacketHandlerCreatorPool[name]; exist { 32 | return ephc 33 | } 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /core/netlib/ioservice.go: -------------------------------------------------------------------------------- 1 | package netlib 2 | 3 | type SessionStats struct { 4 | Id int 5 | GroupId int 6 | RunningTime int64 7 | SendedBytes int64 8 | RecvedBytes int64 9 | SendedPack int64 10 | RecvedPack int64 11 | PendSendPack int 12 | PendRecvPack int 13 | RemoteAddr string 14 | } 15 | 16 | type ServiceStats struct { 17 | Id int 18 | Type int 19 | Name string 20 | Addr string 21 | MaxActive int 22 | MaxDone int 23 | RunningTime int64 24 | SessionStats []SessionStats 25 | } 26 | 27 | type ioService interface { 28 | start() error 29 | update() 30 | shutdown() 31 | dump() 32 | stats() ServiceStats 33 | } 34 | -------------------------------------------------------------------------------- /core/netlib/packetfactory.go: -------------------------------------------------------------------------------- 1 | package netlib 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | var factories = make(map[int]PacketFactory) 9 | var packetQuickMap = make(map[reflect.Type]packetInfo) 10 | 11 | type packetInfo struct { 12 | ptype int 13 | pid int 14 | } 15 | 16 | type PacketFactory interface { 17 | CreatePacket() interface{} 18 | } 19 | 20 | type PacketFactoryWrapper func() interface{} 21 | 22 | func (pfw PacketFactoryWrapper) CreatePacket() interface{} { 23 | return pfw() 24 | } 25 | 26 | func RegisterFactory(packetId int, factory PacketFactory) { 27 | if _, ok := factories[packetId]; ok { 28 | panic(fmt.Sprintf("repeate register packet factory: %v", packetId)) 29 | } 30 | 31 | factories[packetId] = factory 32 | tp := factory.CreatePacket() 33 | if tp != nil { 34 | pt := typetest(tp) 35 | packetQuickMap[reflect.TypeOf(tp)] = packetInfo{ptype: pt, pid: packetId} 36 | } 37 | } 38 | 39 | func CreatePacket(packetId int) interface{} { 40 | if v, ok := factories[packetId]; ok { 41 | return v.CreatePacket() 42 | } 43 | return nil 44 | } 45 | 46 | func GetPacketTypeAndId(pack interface{}) (int, int) { 47 | t := reflect.TypeOf(pack) 48 | if tp, exist := packetQuickMap[t]; exist { 49 | return tp.ptype, tp.pid 50 | } 51 | return 0, 0 52 | } 53 | -------------------------------------------------------------------------------- /core/netlib/packethandler.go: -------------------------------------------------------------------------------- 1 | // handler 2 | package netlib 3 | 4 | import ( 5 | "fmt" 6 | "reflect" 7 | ) 8 | 9 | var handlers = make(map[int]Handler) 10 | 11 | type Handler interface { 12 | Process(session *Session, packetid int, data interface{}) error 13 | } 14 | 15 | type HandlerWrapper func(session *Session, packetid int, data interface{}) error 16 | 17 | func (hw HandlerWrapper) Process(session *Session, packetid int, data interface{}) error { 18 | return hw(session, packetid, data) 19 | } 20 | 21 | func RegisterHandler(packetId int, h Handler) { 22 | if _, ok := handlers[packetId]; ok { 23 | panic(fmt.Sprintf("repeate register handler: %v Handler type=%v", packetId, reflect.TypeOf(h))) 24 | } 25 | 26 | handlers[packetId] = h 27 | } 28 | 29 | func Register1ToMHandler(h Handler, packetIds ...int) { 30 | for _, packetId := range packetIds { 31 | RegisterHandler(packetId, h) 32 | } 33 | } 34 | 35 | func RegisterRangeHandler(start, end int, h Handler) { 36 | for ; start <= end; start++ { 37 | RegisterHandler(start, h) 38 | } 39 | } 40 | 41 | func GetHandler(packetId int) Handler { 42 | if h, ok := handlers[packetId]; ok { 43 | return h 44 | } 45 | 46 | return nil 47 | } 48 | -------------------------------------------------------------------------------- /core/netlib/packetpool.go: -------------------------------------------------------------------------------- 1 | package netlib 2 | 3 | import "sync" 4 | 5 | var pp = NewPacketPool(10240) 6 | 7 | func AllocPacket() *packet { 8 | return pp.Get() 9 | } 10 | 11 | func FreePacket(p *packet) { 12 | pp.Give(p) 13 | } 14 | 15 | type PacketPool struct { 16 | free *packet 17 | lock *sync.Mutex 18 | num int 19 | allocNum int 20 | remainNum int 21 | } 22 | 23 | func NewPacketPool(num int) *PacketPool { 24 | pp := &PacketPool{ 25 | lock: new(sync.Mutex), 26 | num: num, 27 | } 28 | return pp 29 | } 30 | 31 | func (pp *PacketPool) grow() { 32 | var ( 33 | i int 34 | p *packet 35 | ps = make([]packet, pp.num) 36 | ) 37 | pp.free = &(ps[0]) 38 | p = pp.free 39 | for i = 1; i < pp.num; i++ { 40 | p.next = &(ps[i]) 41 | p = p.next 42 | } 43 | p.next = nil 44 | pp.allocNum += pp.num 45 | pp.remainNum += pp.num 46 | return 47 | } 48 | 49 | func (pp *PacketPool) Get() (p *packet) { 50 | pp.lock.Lock() 51 | if p = pp.free; p == nil { 52 | pp.grow() 53 | p = pp.free 54 | } 55 | pp.free = p.next 56 | p.next = nil 57 | pp.remainNum-- 58 | pp.lock.Unlock() 59 | return 60 | } 61 | 62 | func (pp *PacketPool) Give(p *packet) { 63 | if p.next != nil { 64 | return 65 | } 66 | pp.lock.Lock() 67 | p.next = pp.free 68 | pp.free = p 69 | pp.remainNum++ 70 | pp.lock.Unlock() 71 | } 72 | -------------------------------------------------------------------------------- /core/netlib/recycler_action.go: -------------------------------------------------------------------------------- 1 | package netlib 2 | 3 | import "sync" 4 | 5 | var ap = NewActionPool(1024) 6 | 7 | func AllocAction() *action { 8 | return ap.Get() 9 | } 10 | 11 | func FreeAction(a *action) { 12 | ap.Give(a) 13 | } 14 | 15 | type ActionPool struct { 16 | free *action 17 | lock *sync.Mutex 18 | num int 19 | allocNum int 20 | remainNum int 21 | } 22 | 23 | func NewActionPool(num int) *ActionPool { 24 | ap := &ActionPool{ 25 | lock: new(sync.Mutex), 26 | num: num, 27 | } 28 | return ap 29 | } 30 | 31 | func (ap *ActionPool) grow() { 32 | var ( 33 | i int 34 | a *action 35 | as = make([]action, ap.num) 36 | ) 37 | ap.free = &(as[0]) 38 | a = ap.free 39 | for i = 1; i < ap.num; i++ { 40 | a.next = &(as[i]) 41 | a = a.next 42 | } 43 | a.next = nil 44 | ap.allocNum += ap.num 45 | ap.remainNum += ap.num 46 | return 47 | } 48 | 49 | func (ap *ActionPool) Get() (a *action) { 50 | ap.lock.Lock() 51 | if a = ap.free; a == nil { 52 | ap.grow() 53 | a = ap.free 54 | } 55 | ap.free = a.next 56 | a.next = nil 57 | ap.remainNum-- 58 | ap.lock.Unlock() 59 | return 60 | } 61 | 62 | func (ap *ActionPool) Give(a *action) { 63 | ap.lock.Lock() 64 | a.next = ap.free 65 | ap.free = a 66 | ap.remainNum++ 67 | ap.lock.Unlock() 68 | } 69 | -------------------------------------------------------------------------------- /core/netlib/recycler_rwbuf.go: -------------------------------------------------------------------------------- 1 | package netlib 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core/container/recycler" 5 | ) 6 | 7 | const ( 8 | RWBufRecyclerBacklog int = 128 9 | ) 10 | 11 | var RWRecycler = recycler.NewRecycler( 12 | RWBufRecyclerBacklog, 13 | func() interface{} { 14 | rb := &RWBuffer{ 15 | buf: make([]byte, 0, MaxPacketSize), 16 | } 17 | 18 | return rb 19 | }, 20 | "rwbuf_recycler", 21 | ) 22 | 23 | func AllocRWBuf() *RWBuffer { 24 | b := RWRecycler.Get() 25 | rb := b.(*RWBuffer) 26 | rb.Init() 27 | return rb 28 | } 29 | 30 | func FreeRWBuf(buf *RWBuffer) { 31 | RWRecycler.Give(buf) 32 | } 33 | -------------------------------------------------------------------------------- /core/netlib/tcpkeepalive/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Felix Geisendörfer (felix@debuggable.com) and contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /core/netlib/tcpkeepalive/README.md: -------------------------------------------------------------------------------- 1 | # tcpkeepalive 2 | 3 | **Known Issues:** Some problems with the implementation were [reported](https://groups.google.com/d/msg/golang-nuts/rRu6ibLNdeI/TIzShZCmbzwJ), I'll try to fix them when I get a chance, or if somebody sends a PR. 4 | 5 | Package tcpkeepalive implements additional TCP keepalive control beyond what is 6 | currently offered by the net pkg. 7 | 8 | Only Linux \>= 2.4, DragonFly, FreeBSD, NetBSD and OS X \>= 10.8 are supported 9 | at this point, but patches for additional platforms are welcome. 10 | 11 | See also: http://felixge.de/2014/08/26/tcp-keepalive-with-golang.html 12 | 13 | **License:** MIT 14 | 15 | **Docs:** http://godoc.org/github.com/felixge/tcpkeepalive 16 | -------------------------------------------------------------------------------- /core/netlib/tcpkeepalive/keepalive_bsd.go: -------------------------------------------------------------------------------- 1 | // +build dragonfly freebsd netbsd 2 | 3 | package tcpkeepalive 4 | 5 | import ( 6 | "os" 7 | "syscall" 8 | ) 9 | 10 | func setIdle(fd int, secs int) error { 11 | return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, secs)) 12 | } 13 | 14 | func setCount(fd int, n int) error { 15 | return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPCNT, n)) 16 | } 17 | 18 | func setInterval(fd int, secs int) error { 19 | return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs)) 20 | } 21 | -------------------------------------------------------------------------------- /core/netlib/tcpkeepalive/keepalive_darwin.go: -------------------------------------------------------------------------------- 1 | package tcpkeepalive 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | ) 7 | 8 | // from netinet/tcp.h (OS X 10.9.4) 9 | const ( 10 | _TCP_KEEPINTVL = 0x101 /* interval between keepalives */ 11 | _TCP_KEEPCNT = 0x102 /* number of keepalives before close */ 12 | ) 13 | 14 | func setIdle(fd int, secs int) error { 15 | return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, secs)) 16 | } 17 | 18 | func setCount(fd int, n int) error { 19 | return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, _TCP_KEEPCNT, n)) 20 | } 21 | 22 | func setInterval(fd int, secs int) error { 23 | return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, _TCP_KEEPINTVL, secs)) 24 | } 25 | -------------------------------------------------------------------------------- /core/netlib/tcpkeepalive/keepalive_linux.go: -------------------------------------------------------------------------------- 1 | package tcpkeepalive 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | ) 7 | 8 | func setIdle(fd int, secs int) error { 9 | return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, secs)) 10 | } 11 | 12 | func setCount(fd int, n int) error { 13 | return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPCNT, n)) 14 | } 15 | 16 | func setInterval(fd int, secs int) error { 17 | return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs)) 18 | } 19 | -------------------------------------------------------------------------------- /core/netlib/tcpkeepalive/keepalive_solaris.go: -------------------------------------------------------------------------------- 1 | package tcpkeepalive 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | ) 7 | 8 | func setIdle(fd int, secs int) error { 9 | return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, secs)) 10 | } 11 | 12 | func setCount(fd int, n int) error { 13 | return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPCNT, n)) 14 | } 15 | 16 | func setInterval(fd int, secs int) error { 17 | return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs)) 18 | } 19 | -------------------------------------------------------------------------------- /core/netlib/tcpkeepalive/keepalive_windows.go: -------------------------------------------------------------------------------- 1 | package tcpkeepalive 2 | 3 | func setIdle(fd int, secs int) error { 4 | return nil 5 | } 6 | 7 | func setCount(fd int, n int) error { 8 | return nil 9 | } 10 | 11 | func setInterval(fd int, secs int) error { 12 | return nil 13 | } 14 | -------------------------------------------------------------------------------- /core/netlib/test.go: -------------------------------------------------------------------------------- 1 | package netlib 2 | 3 | import "testing" 4 | 5 | func TestAllocAction(t *testing.T) { 6 | AllocAction() 7 | } 8 | 9 | func TestFreeAction(t *testing.T) { 10 | a := AllocAction() 11 | FreeAction(a) 12 | } 13 | 14 | func BenchmarkAllocAction(b *testing.B) { 15 | tt := make([]*action, 0, b.N) 16 | b.StartTimer() 17 | for i := 0; i < b.N; i++ { 18 | tt = append(tt, AllocAction()) 19 | } 20 | b.StopTimer() 21 | } 22 | -------------------------------------------------------------------------------- /core/profile/config.go: -------------------------------------------------------------------------------- 1 | package profile 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core" 5 | ) 6 | 7 | var Config = Configuration{} 8 | 9 | type Configuration struct { 10 | SlowMS int 11 | } 12 | 13 | func (c *Configuration) Name() string { 14 | return "profile" 15 | } 16 | 17 | func (c *Configuration) Init() error { 18 | if c.SlowMS <= 0 { 19 | c.SlowMS = 1000 20 | } 21 | return nil 22 | } 23 | 24 | func (c *Configuration) Close() error { 25 | return nil 26 | } 27 | 28 | func init() { 29 | core.RegistePackage(&Config) 30 | } 31 | -------------------------------------------------------------------------------- /core/profile/recycler_watcher.go: -------------------------------------------------------------------------------- 1 | package profile 2 | 3 | import "sync" 4 | 5 | var wp = NewWatcherPool(1024) 6 | 7 | func AllocWatcher() *TimeWatcher { 8 | return wp.Get() 9 | } 10 | 11 | func FreeWatcher(t *TimeWatcher) { 12 | wp.Give(t) 13 | } 14 | 15 | type WatcherPool struct { 16 | free *TimeWatcher 17 | lock *sync.Mutex 18 | num int 19 | allocNum int 20 | remainNum int 21 | } 22 | 23 | func NewWatcherPool(num int) *WatcherPool { 24 | wp := &WatcherPool{ 25 | lock: new(sync.Mutex), 26 | num: num, 27 | } 28 | return wp 29 | } 30 | 31 | func (wp *WatcherPool) grow() { 32 | var ( 33 | i int 34 | t *TimeWatcher 35 | ts = make([]TimeWatcher, wp.num) 36 | ) 37 | wp.free = &(ts[0]) 38 | t = wp.free 39 | for i = 1; i < wp.num; i++ { 40 | t.next = &(ts[i]) 41 | t = t.next 42 | } 43 | t.next = nil 44 | wp.allocNum += wp.num 45 | wp.remainNum += wp.num 46 | return 47 | } 48 | 49 | func (wp *WatcherPool) Get() (t *TimeWatcher) { 50 | wp.lock.Lock() 51 | if t = wp.free; t == nil { 52 | wp.grow() 53 | t = wp.free 54 | } 55 | wp.free = t.next 56 | t.next = nil 57 | wp.remainNum-- 58 | wp.lock.Unlock() 59 | return 60 | } 61 | 62 | func (wp *WatcherPool) Give(t *TimeWatcher) { 63 | wp.lock.Lock() 64 | t.next = wp.free 65 | wp.free = t 66 | wp.remainNum++ 67 | wp.lock.Unlock() 68 | } 69 | -------------------------------------------------------------------------------- /core/profile/timewatcher.go: -------------------------------------------------------------------------------- 1 | package profile 2 | 3 | import "time" 4 | 5 | type TimeWatcher struct { 6 | name string //模块名称 7 | elementype int //类型 8 | tStart time.Time //开始时间 9 | next *TimeWatcher 10 | } 11 | 12 | func newTimeWatcher(name string, elementype int) *TimeWatcher { 13 | w := AllocWatcher() 14 | w.name = name 15 | w.elementype = elementype 16 | w.tStart = time.Now() 17 | return w 18 | } 19 | 20 | func (this *TimeWatcher) Stop() { 21 | defer FreeWatcher(this) 22 | d := time.Now().Sub(this.tStart) 23 | TimeStatisticMgr.addStatistic(this.name, this.elementype, int64(d)) 24 | } 25 | -------------------------------------------------------------------------------- /core/schedule/task_test.go: -------------------------------------------------------------------------------- 1 | package schedule 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func TestParse(t *testing.T) { 11 | tk := NewTask("taska", "0/30 * * * * *", func() error { fmt.Println("hello world"); return nil }) 12 | err := tk.Run() 13 | if err != nil { 14 | t.Fatal(err) 15 | } 16 | AddTask("taska", tk) 17 | StartTask() 18 | time.Sleep(6 * time.Second) 19 | StopTask() 20 | } 21 | 22 | func TestSpec(t *testing.T) { 23 | wg := &sync.WaitGroup{} 24 | wg.Add(2) 25 | tk1 := NewTask("tk1", "0 12 * * * *", func() error { fmt.Println("tk1"); return nil }) 26 | tk2 := NewTask("tk2", "0,10,20 * * * * *", func() error { fmt.Println("tk2"); wg.Done(); return nil }) 27 | tk3 := NewTask("tk3", "0 10 * * * *", func() error { fmt.Println("tk3"); wg.Done(); return nil }) 28 | 29 | AddTask("tk1", tk1) 30 | AddTask("tk2", tk2) 31 | AddTask("tk3", tk3) 32 | StartTask() 33 | defer StopTask() 34 | 35 | select { 36 | case <-time.After(200 * time.Second): 37 | t.FailNow() 38 | case <-wait(wg): 39 | } 40 | } 41 | 42 | func wait(wg *sync.WaitGroup) chan bool { 43 | ch := make(chan bool) 44 | go func() { 45 | wg.Wait() 46 | ch <- true 47 | }() 48 | return ch 49 | } 50 | -------------------------------------------------------------------------------- /core/signal/config.go: -------------------------------------------------------------------------------- 1 | package signal 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core" 5 | ) 6 | 7 | var Config = Configuration{} 8 | 9 | type Configuration struct { 10 | SupportSignal bool 11 | } 12 | 13 | func (c *Configuration) Name() string { 14 | return "signal" 15 | } 16 | 17 | func (c *Configuration) Init() error { 18 | if c.SupportSignal { 19 | //demon goroutine 20 | go SignalHandlerModule.ProcessSignal() 21 | } 22 | return nil 23 | } 24 | 25 | func (c *Configuration) Close() error { 26 | return nil 27 | } 28 | 29 | func init() { 30 | core.RegistePackage(&Config) 31 | } 32 | -------------------------------------------------------------------------------- /core/signal/interrupt_handler.go: -------------------------------------------------------------------------------- 1 | package signal 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/idealeak/goserver/core/logger" 7 | "github.com/idealeak/goserver/core/module" 8 | ) 9 | 10 | type InterruptSignalHandler struct { 11 | } 12 | 13 | func (ish *InterruptSignalHandler) Process(s os.Signal, ud interface{}) error { 14 | logger.Logger.Warn("Receive Interrupt signal, process start quit.") 15 | module.Stop() 16 | return nil 17 | } 18 | 19 | func init() { 20 | SignalHandlerModule.RegisteHandler(os.Interrupt, &InterruptSignalHandler{}, nil) 21 | } 22 | -------------------------------------------------------------------------------- /core/signal/kill_handler.go: -------------------------------------------------------------------------------- 1 | package signal 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/idealeak/goserver/core/logger" 7 | "github.com/idealeak/goserver/core/module" 8 | ) 9 | 10 | type KillSignalHandler struct { 11 | } 12 | 13 | func (ish *KillSignalHandler) Process(s os.Signal, ud interface{}) error { 14 | logger.Logger.Warn("Receive Kill signal, process be close") 15 | module.Stop() 16 | return nil 17 | } 18 | 19 | func init() { 20 | SignalHandlerModule.RegisteHandler(os.Kill, &KillSignalHandler{}, nil) 21 | } 22 | -------------------------------------------------------------------------------- /core/task/command_task_exe.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core/basic" 5 | "github.com/idealeak/goserver/core/utils" 6 | ) 7 | 8 | type taskExeCommand struct { 9 | t *Task 10 | } 11 | 12 | func (ttc *taskExeCommand) Done(o *basic.Object) error { 13 | defer o.ProcessSeqnum() 14 | defer utils.DumpStackIfPanic("taskExeCommand") 15 | ttc.t.afterQueCnt = o.GetPendingCommandCnt() 16 | return ttc.t.run(o) 17 | } 18 | 19 | func SendTaskExe(o *basic.Object, t *Task) bool { 20 | t.beforeQueCnt = o.GetPendingCommandCnt() 21 | return o.SendCommand(&taskExeCommand{t: t}, true) 22 | } 23 | -------------------------------------------------------------------------------- /core/task/command_task_res.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core/basic" 5 | "github.com/idealeak/goserver/core/utils" 6 | ) 7 | 8 | type taskResCommand struct { 9 | t *Task 10 | } 11 | 12 | func (trc *taskResCommand) Done(o *basic.Object) error { 13 | defer o.ProcessSeqnum() 14 | defer utils.DumpStackIfPanic("taskExeCommand") 15 | trc.t.n.Done(<-trc.t.r, trc.t) 16 | return nil 17 | } 18 | 19 | func SendTaskRes(o *basic.Object, t *Task) bool { 20 | if o == nil { 21 | return false 22 | } 23 | return o.SendCommand(&taskResCommand{t: t}, true) 24 | } 25 | -------------------------------------------------------------------------------- /core/task/config.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core" 5 | "github.com/idealeak/goserver/core/basic" 6 | ) 7 | 8 | var Config = Configuration{} 9 | 10 | type WorkerConfig struct { 11 | Options basic.Options 12 | WorkerCnt int 13 | } 14 | 15 | type Configuration struct { 16 | Options basic.Options 17 | Worker WorkerConfig 18 | } 19 | 20 | func (c *Configuration) Name() string { 21 | return "executor" 22 | } 23 | 24 | func (c *Configuration) Init() error { 25 | if c.Options.QueueBacklog <= 0 { 26 | c.Options.QueueBacklog = 1024 27 | } 28 | if c.Options.MaxDone <= 0 { 29 | c.Options.MaxDone = 1024 30 | } 31 | if c.Worker.Options.QueueBacklog <= 0 { 32 | c.Worker.Options.QueueBacklog = 1024 33 | } 34 | if c.Worker.Options.MaxDone <= 0 { 35 | c.Worker.Options.MaxDone = 1024 36 | } 37 | if c.Worker.WorkerCnt <= 0 { 38 | c.Worker.WorkerCnt = 8 39 | } 40 | TaskExecutor.Start() 41 | return nil 42 | } 43 | 44 | func (c *Configuration) Close() error { 45 | return nil 46 | } 47 | 48 | func init() { 49 | core.RegistePackage(&Config) 50 | } 51 | -------------------------------------------------------------------------------- /core/task/worker.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core/basic" 5 | ) 6 | 7 | type Worker struct { 8 | *basic.Object 9 | } 10 | -------------------------------------------------------------------------------- /core/timer/command_start_timer.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "container/heap" 5 | "time" 6 | 7 | "github.com/idealeak/goserver/core" 8 | "github.com/idealeak/goserver/core/basic" 9 | ) 10 | 11 | type startTimerCommand struct { 12 | src *basic.Object 13 | ta TimerAction 14 | ud interface{} 15 | interval time.Duration 16 | times int 17 | h TimerHandle 18 | } 19 | 20 | func (stc *startTimerCommand) Done(o *basic.Object) error { 21 | defer o.ProcessSeqnum() 22 | 23 | te := &TimerEntity{ 24 | sink: stc.src, 25 | ud: stc.ud, 26 | ta: stc.ta, 27 | interval: stc.interval, 28 | times: stc.times, 29 | h: stc.h, 30 | next: time.Now().Add(stc.interval), 31 | } 32 | 33 | heap.Push(TimerModule.tq, te) 34 | 35 | return nil 36 | } 37 | 38 | // StartTimer only can be called in main module 39 | func StartTimer(ta TimerAction, ud interface{}, interval time.Duration, times int) (TimerHandle, bool) { 40 | return StartTimerByObject(core.CoreObject(), ta, ud, interval, times) 41 | } 42 | func AfterTimer(taw TimerActionWrapper, ud interface{}, interval time.Duration) (TimerHandle, bool) { 43 | var tac = &TimerActionCommon{ 44 | Taw: taw, 45 | } 46 | return StartTimerByObject(core.CoreObject(), tac, ud, interval, 1) 47 | } 48 | 49 | func StartTimerByObject(src *basic.Object, ta TimerAction, ud interface{}, interval time.Duration, times int) (TimerHandle, bool) { 50 | h := generateTimerHandle() 51 | ret := TimerModule.SendCommand( 52 | &startTimerCommand{ 53 | src: src, 54 | ta: ta, 55 | ud: ud, 56 | interval: interval, 57 | times: times, 58 | h: h, 59 | }, 60 | true) 61 | return h, ret 62 | } 63 | -------------------------------------------------------------------------------- /core/timer/command_stop_timer.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "container/heap" 5 | 6 | "github.com/idealeak/goserver/core/basic" 7 | ) 8 | 9 | type stopTimerCommand struct { 10 | h TimerHandle 11 | } 12 | 13 | func (stc *stopTimerCommand) Done(o *basic.Object) error { 14 | defer o.ProcessSeqnum() 15 | 16 | if v, ok := TimerModule.tq.ref[stc.h]; ok { 17 | heap.Remove(TimerModule.tq, v) 18 | } 19 | 20 | return nil 21 | } 22 | 23 | func StopTimer(h TimerHandle) bool { 24 | return TimerModule.SendCommand(&stopTimerCommand{h: h}, true) 25 | } 26 | -------------------------------------------------------------------------------- /core/timer/command_timeout_timer.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "fmt" 5 | "github.com/idealeak/goserver/core/basic" 6 | "github.com/idealeak/goserver/core/profile" 7 | "reflect" 8 | ) 9 | 10 | type timeoutCommand struct { 11 | te *TimerEntity 12 | } 13 | 14 | func (tc *timeoutCommand) Done(o *basic.Object) error { 15 | tta := reflect.TypeOf(tc.te.ta) 16 | watch := profile.TimeStatisticMgr.WatchStart(fmt.Sprintf("/timer/%v/ontimer", tta.Name()), profile.TIME_ELEMENT_TIMER) 17 | defer func() { 18 | o.ProcessSeqnum() 19 | if watch != nil { 20 | watch.Stop() 21 | } 22 | }() 23 | if tc.te.stoped { 24 | return nil 25 | } 26 | if tc.te.ta.OnTimer(tc.te.h, tc.te.ud) == false { 27 | tc.te.stoped = true 28 | if tc.te.times < 0 { 29 | StopTimer(tc.te.h) 30 | } 31 | } 32 | return nil 33 | } 34 | 35 | func SendTimeout(te *TimerEntity) bool { 36 | if te.sink == nil { 37 | return false 38 | } 39 | 40 | return te.sink.SendCommand(&timeoutCommand{te: te}, true) 41 | } 42 | -------------------------------------------------------------------------------- /core/timer/config.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/idealeak/goserver/core" 7 | "github.com/idealeak/goserver/core/basic" 8 | ) 9 | 10 | var Config = Configuration{} 11 | 12 | type Configuration struct { 13 | Options basic.Options 14 | } 15 | 16 | func (c *Configuration) Name() string { 17 | return "timer" 18 | } 19 | 20 | func (c *Configuration) Init() error { 21 | if c.Options.QueueBacklog <= 0 { 22 | c.Options.QueueBacklog = 1024 23 | } 24 | if c.Options.MaxDone <= 0 { 25 | c.Options.MaxDone = 1024 26 | } 27 | if c.Options.Interval <= 0 { 28 | c.Options.Interval = time.Millisecond * 10 29 | } else { 30 | c.Options.Interval = time.Millisecond * c.Options.Interval 31 | } 32 | TimerModule.Start() 33 | return nil 34 | } 35 | 36 | func (c *Configuration) Close() error { 37 | return nil 38 | } 39 | 40 | func init() { 41 | core.RegistePackage(&Config) 42 | } 43 | -------------------------------------------------------------------------------- /core/timer/timer.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "container/heap" 5 | "time" 6 | 7 | "github.com/idealeak/goserver/core" 8 | "github.com/idealeak/goserver/core/basic" 9 | "github.com/idealeak/goserver/core/logger" 10 | ) 11 | 12 | var ( 13 | TimerHandleGenerator uint32 = 1 14 | InvalidTimerHandle TimerHandle = 0 15 | TimerModule *TimerMgr = NewTimerMgr() 16 | ) 17 | 18 | type TimerMgr struct { 19 | *basic.Object 20 | tq *TimerQueue 21 | } 22 | 23 | func NewTimerMgr() *TimerMgr { 24 | tm := &TimerMgr{ 25 | tq: NewTimerQueue(), 26 | } 27 | 28 | return tm 29 | } 30 | 31 | func (tm *TimerMgr) Start() { 32 | logger.Logger.Trace("Timer Start") 33 | defer logger.Logger.Trace("Timer Start [ok]") 34 | 35 | tm.Object = basic.NewObject(core.ObjId_TimerId, 36 | "timer", 37 | Config.Options, 38 | tm) 39 | tm.UserData = tm 40 | 41 | core.LaunchChild(TimerModule.Object) 42 | } 43 | 44 | func (tm *TimerMgr) TimerCount() int { 45 | return tm.tq.Len() 46 | } 47 | 48 | func (tm *TimerMgr) OnTick() { 49 | nowTime := time.Now() 50 | for { 51 | if tm.tq.Len() > 0 { 52 | t := heap.Pop(tm.tq) 53 | if te, ok := t.(*TimerEntity); ok { 54 | if !te.stoped && te.next.Before(nowTime) { 55 | if te.times > 0 { 56 | te.times-- 57 | } 58 | //Avoid async stop timer failed 59 | if te.times != 0 { 60 | te.next = te.next.Add(te.interval) 61 | heap.Push(tm.tq, te) 62 | } 63 | if !SendTimeout(te) { 64 | if v, ok := tm.tq.ref[te.h]; ok { 65 | heap.Remove(tm.tq, v) 66 | } 67 | } 68 | } else { 69 | if !te.stoped { 70 | heap.Push(tm.tq, te) 71 | } 72 | return 73 | } 74 | } 75 | } else { 76 | return 77 | } 78 | } 79 | } 80 | 81 | func (tm *TimerMgr) OnStart() {} 82 | 83 | func (tm *TimerMgr) OnStop() {} 84 | -------------------------------------------------------------------------------- /core/timer/timer_action.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | type TimerHandle uint32 4 | 5 | type TimerAction interface { 6 | OnTimer(h TimerHandle, ud interface{}) bool 7 | } 8 | 9 | type TimerActionWrapper func(h TimerHandle, ud interface{}) bool 10 | 11 | func (taw TimerActionWrapper) OnTimer(h TimerHandle, ud interface{}) bool { 12 | return taw(h, ud) 13 | } 14 | 15 | type TimerActionCommon struct { 16 | Taw TimerActionWrapper 17 | } 18 | 19 | func (this TimerActionCommon) OnTimer(h TimerHandle, ud interface{}) bool { 20 | return this.Taw(h, ud) 21 | } 22 | -------------------------------------------------------------------------------- /core/timer/timer_queue.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "container/heap" 5 | "sync/atomic" 6 | "time" 7 | 8 | "github.com/idealeak/goserver/core/basic" 9 | ) 10 | 11 | type TimerEntity struct { 12 | sink *basic.Object 13 | ud interface{} 14 | interval time.Duration 15 | next time.Time 16 | times int 17 | ta TimerAction 18 | h TimerHandle 19 | stoped bool 20 | } 21 | 22 | type TimerQueue struct { 23 | queue []*TimerEntity 24 | ref map[TimerHandle]int 25 | } 26 | 27 | func generateTimerHandle() TimerHandle { 28 | return TimerHandle(atomic.AddUint32(&TimerHandleGenerator, 1)) 29 | } 30 | 31 | func NewTimerQueue() *TimerQueue { 32 | tq := &TimerQueue{ 33 | ref: make(map[TimerHandle]int), 34 | } 35 | heap.Init(tq) 36 | return tq 37 | } 38 | func (tq TimerQueue) Len() int { 39 | return len(tq.queue) 40 | } 41 | 42 | func (tq TimerQueue) Less(i, j int) bool { 43 | return tq.queue[i].next.Before(tq.queue[j].next) 44 | } 45 | 46 | func (tq *TimerQueue) Swap(i, j int) { 47 | tq.queue[i], tq.queue[j] = tq.queue[j], tq.queue[i] 48 | tq.ref[tq.queue[i].h] = i 49 | tq.ref[tq.queue[j].h] = j 50 | } 51 | 52 | func (tq *TimerQueue) Push(x interface{}) { 53 | n := len(tq.queue) 54 | te := x.(*TimerEntity) 55 | tq.ref[te.h] = n 56 | tq.queue = append(tq.queue, te) 57 | } 58 | 59 | func (tq *TimerQueue) Pop() interface{} { 60 | old := tq.queue 61 | n := len(old) 62 | te := old[n-1] 63 | delete(tq.ref, te.h) 64 | tq.queue = old[0 : n-1] 65 | return te 66 | } 67 | -------------------------------------------------------------------------------- /core/timer/timer_queue_test.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "container/heap" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestTimerQueuePush(t *testing.T) { 10 | tq := NewTimerQueue() 11 | tNow := time.Now() 12 | te1 := &TimerEntity{ 13 | ud: int(2), 14 | next: tNow.Add(time.Minute), 15 | } 16 | te2 := &TimerEntity{ 17 | ud: int(1), 18 | next: tNow.Add(time.Second), 19 | } 20 | te3 := &TimerEntity{ 21 | ud: int(3), 22 | next: tNow.Add(time.Hour), 23 | } 24 | heap.Push(tq, te2) 25 | heap.Push(tq, te1) 26 | heap.Push(tq, te3) 27 | 28 | if tq.Len() != 3 { 29 | t.Fatal("Timer Queue Size error") 30 | } 31 | var ( 32 | tee interface{} 33 | te *TimerEntity 34 | ok bool 35 | ) 36 | tee = heap.Pop(tq) 37 | if te, ok = tee.(*TimerEntity); ok { 38 | if te.ud.(int) != 1 { 39 | t.Fatal("First Must 1.") 40 | } 41 | } 42 | 43 | tee = heap.Pop(tq) 44 | if te, ok = tee.(*TimerEntity); ok { 45 | if te.ud.(int) != 2 { 46 | t.Fatal("Second Must 2.") 47 | } 48 | } 49 | 50 | tee = heap.Pop(tq) 51 | if te, ok = tee.(*TimerEntity); ok { 52 | if te.ud.(int) != 3 { 53 | t.Fatal("Third Must 3.") 54 | } 55 | } 56 | } 57 | 58 | func BenchmarkTimerQueuePush(b *testing.B) { 59 | tq := NewTimerQueue() 60 | b.StartTimer() 61 | for i := 0; i < b.N; i++ { 62 | h := generateTimerHandle() 63 | te := &TimerEntity{ 64 | h: h, 65 | } 66 | tq.Push(te) 67 | } 68 | b.StopTimer() 69 | } 70 | 71 | func BenchmarkTimerQueuePop(b *testing.B) { 72 | tq := NewTimerQueue() 73 | 74 | for i := 0; i < b.N; i++ { 75 | h := generateTimerHandle() 76 | te := &TimerEntity{ 77 | h: h, 78 | } 79 | tq.Push(te) 80 | } 81 | 82 | b.StartTimer() 83 | for i := 0; i < b.N; i++ { 84 | te := tq.Pop() 85 | tq.Push(te) 86 | } 87 | b.StopTimer() 88 | } 89 | -------------------------------------------------------------------------------- /core/transact/command_trans_resume.go: -------------------------------------------------------------------------------- 1 | package transact 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core/basic" 5 | ) 6 | 7 | type transactResumeCommand struct { 8 | tnode *TransNode 9 | } 10 | 11 | func (trc *transactResumeCommand) Done(o *basic.Object) error { 12 | defer o.ProcessSeqnum() 13 | trc.tnode.checkExeOver() 14 | return nil 15 | } 16 | 17 | func SendTranscatResume(tnode *TransNode) bool { 18 | return tnode.ownerObj.SendCommand(&transactResumeCommand{tnode: tnode}, true) 19 | } 20 | -------------------------------------------------------------------------------- /core/transact/command_trans_yield.go: -------------------------------------------------------------------------------- 1 | package transact 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core/basic" 5 | ) 6 | 7 | type transactYieldCommand struct { 8 | tnode *TransNode 9 | } 10 | 11 | func (trc *transactYieldCommand) Done(o *basic.Object) error { 12 | defer o.ProcessSeqnum() 13 | trc.tnode.checkExeOver() 14 | return nil 15 | } 16 | 17 | func SendTranscatYield(tnode *TransNode) bool { 18 | return tnode.ownerObj.SendCommand(&transactYieldCommand{tnode: tnode}, true) 19 | } 20 | -------------------------------------------------------------------------------- /core/transact/config.go: -------------------------------------------------------------------------------- 1 | // config 2 | package transact 3 | 4 | import ( 5 | "github.com/idealeak/goserver/core" 6 | "github.com/idealeak/goserver/core/logger" 7 | ) 8 | 9 | var Config = Configuration{} 10 | 11 | type Configuration struct { 12 | TxSkeletonName string 13 | tcs TransactCommSkeleton 14 | } 15 | 16 | func (this *Configuration) Name() string { 17 | return "tx" 18 | } 19 | 20 | func (this *Configuration) Init() error { 21 | if this.TxSkeletonName != "" { 22 | this.tcs = GetTxCommSkeleton(this.TxSkeletonName) 23 | if this.tcs == nil { 24 | logger.Logger.Warnf("%v TxSkeletonName not registed!!!", this.TxSkeletonName) 25 | } 26 | } 27 | return nil 28 | } 29 | 30 | func (this *Configuration) Close() error { 31 | return nil 32 | } 33 | 34 | func init() { 35 | core.RegistePackage(&Config) 36 | } 37 | -------------------------------------------------------------------------------- /core/transact/doc.go: -------------------------------------------------------------------------------- 1 | package transact 2 | 3 | // 2pc 4 | -------------------------------------------------------------------------------- /core/transact/transcommitpolicy.go: -------------------------------------------------------------------------------- 1 | package transact 2 | 3 | const ( 4 | TransactCommitPolicy_SelfDecide TransactCommitPolicy = iota 5 | TransactCommitPolicy_TwoPhase 6 | ) 7 | 8 | type TransactCommitPolicy int 9 | -------------------------------------------------------------------------------- /core/transact/transcommskeleton.go: -------------------------------------------------------------------------------- 1 | // transcommskeleton 2 | package transact 3 | 4 | var txSkeletons = make(map[string]TransactCommSkeleton) 5 | 6 | type TransactCommSkeleton interface { 7 | SendTransResult(parent, me *TransNodeParam, tr *TransResult) bool 8 | SendTransStart(parent, me *TransNodeParam, ud interface{}) bool 9 | SendCmdToTransNode(tnp *TransNodeParam, cmd TransCmd) bool 10 | GetSkeletonID() int 11 | GetAreaID() int 12 | } 13 | 14 | func RegisteTxCommSkeleton(name string, tcs TransactCommSkeleton) { 15 | if _, exist := txSkeletons[name]; exist { 16 | panic("repeate registe TxCommSkeleton:" + name) 17 | } 18 | txSkeletons[name] = tcs 19 | } 20 | 21 | func GetTxCommSkeleton(name string) TransactCommSkeleton { 22 | if t, exist := txSkeletons[name]; exist { 23 | return t 24 | } 25 | return nil 26 | } 27 | -------------------------------------------------------------------------------- /core/transact/transctx.go: -------------------------------------------------------------------------------- 1 | // transctx 2 | package transact 3 | 4 | import ( 5 | "sync" 6 | ) 7 | 8 | type TransCtx struct { 9 | fields map[interface{}]interface{} 10 | lock *sync.RWMutex 11 | } 12 | 13 | func NewTransCtx() *TransCtx { 14 | tc := &TransCtx{ 15 | lock: new(sync.RWMutex), 16 | } 17 | return tc 18 | } 19 | 20 | func (this *TransCtx) SetField(k, v interface{}) { 21 | this.lock.Lock() 22 | if this.fields == nil { 23 | this.fields = make(map[interface{}]interface{}) 24 | } 25 | this.fields[k] = v 26 | this.lock.Unlock() 27 | } 28 | 29 | func (this *TransCtx) GetField(k interface{}) interface{} { 30 | this.lock.RLock() 31 | if this.fields != nil { 32 | if v, exist := this.fields[k]; exist { 33 | this.lock.RUnlock() 34 | return v 35 | } 36 | } 37 | this.lock.RUnlock() 38 | return nil 39 | } 40 | -------------------------------------------------------------------------------- /core/transact/transfactory.go: -------------------------------------------------------------------------------- 1 | package transact 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/idealeak/goserver/core/logger" 7 | ) 8 | 9 | var transactionHandlerPool = make(map[TransType]TransHandler) 10 | 11 | func GetHandler(tt TransType) TransHandler { 12 | if v, exist := transactionHandlerPool[tt]; exist { 13 | return v 14 | } 15 | return nil 16 | } 17 | 18 | func RegisteHandler(tt TransType, th TransHandler) { 19 | if _, exist := transactionHandlerPool[tt]; exist { 20 | panic(fmt.Sprintf("TransHandlerFactory repeate registe handler, type=%v", tt)) 21 | return 22 | } 23 | logger.Logger.Trace("transact.RegisteHandler:", tt) 24 | transactionHandlerPool[tt] = th 25 | } 26 | -------------------------------------------------------------------------------- /core/transact/transhandler.go: -------------------------------------------------------------------------------- 1 | // transhandler 2 | package transact 3 | 4 | type TransHandler interface { 5 | OnExcute(n *TransNode, ud interface{}) TransExeResult 6 | OnCommit(n *TransNode) TransExeResult 7 | OnRollBack(n *TransNode) TransExeResult 8 | OnChildTransRep(n *TransNode, hChild TransNodeID, retCode int, ud interface{}) TransExeResult 9 | } 10 | 11 | type OnExecuteWrapper func(n *TransNode, ud interface{}) TransExeResult 12 | type OnCommitWrapper func(n *TransNode) TransExeResult 13 | type OnRollBackWrapper func(n *TransNode) TransExeResult 14 | type OnChildRespWrapper func(n *TransNode, hChild TransNodeID, retCode int, ud interface{}) TransExeResult 15 | 16 | type TransHanderWrapper struct { 17 | OnExecuteWrapper 18 | OnCommitWrapper 19 | OnRollBackWrapper 20 | OnChildRespWrapper 21 | } 22 | 23 | func (wrapper *TransHanderWrapper) OnExcute(n *TransNode, ud interface{}) TransExeResult { 24 | if wrapper.OnExecuteWrapper != nil { 25 | return wrapper.OnExecuteWrapper(n, ud) 26 | } 27 | return TransExeResult_Success 28 | } 29 | 30 | func (wrapper *TransHanderWrapper) OnCommit(n *TransNode) TransExeResult { 31 | if wrapper.OnCommitWrapper != nil { 32 | return wrapper.OnCommitWrapper(n) 33 | } 34 | return TransExeResult_Success 35 | } 36 | 37 | func (wrapper *TransHanderWrapper) OnRollBack(n *TransNode) TransExeResult { 38 | if wrapper.OnRollBackWrapper != nil { 39 | return wrapper.OnRollBackWrapper(n) 40 | } 41 | return TransExeResult_Success 42 | } 43 | 44 | func (wrapper *TransHanderWrapper) OnChildTransRep(n *TransNode, hChild TransNodeID, retCode int, ud interface{}) TransExeResult { 45 | if wrapper.OnChildRespWrapper != nil { 46 | return wrapper.OnChildRespWrapper(n, hChild, retCode, ud) 47 | } 48 | return TransExeResult_Success 49 | } 50 | -------------------------------------------------------------------------------- /core/transact/transtimeouthandler.go: -------------------------------------------------------------------------------- 1 | package transact 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core/timer" 5 | ) 6 | 7 | type transactTimerAction struct { 8 | } 9 | 10 | func (t transactTimerAction) OnTimer(h timer.TimerHandle, ud interface{}) bool { 11 | if trans, ok := ud.(*TransNode); ok { 12 | trans.timeout() 13 | return true 14 | } 15 | return false 16 | } 17 | -------------------------------------------------------------------------------- /core/transact/transtype.go: -------------------------------------------------------------------------------- 1 | // transtype 2 | package transact 3 | 4 | type TransType int 5 | -------------------------------------------------------------------------------- /core/utils/atomicidgen.go: -------------------------------------------------------------------------------- 1 | // AtomicIdGen 2 | package utils 3 | 4 | import ( 5 | "sync/atomic" 6 | ) 7 | 8 | type AtomicIdGen struct { 9 | cur uint32 10 | beg uint32 11 | } 12 | 13 | func (this *AtomicIdGen) NextId() uint32 { 14 | return atomic.AddUint32(&this.cur, 1) 15 | } 16 | 17 | func (this *AtomicIdGen) Reset() { 18 | atomic.StoreUint32(&this.cur, this.beg) 19 | } 20 | 21 | func (this *AtomicIdGen) SetStartPoint(startPoint uint32) { 22 | this.beg = startPoint 23 | this.Reset() 24 | } 25 | 26 | func (this *AtomicIdGen) CurrId() uint32 { 27 | return this.cur 28 | } 29 | -------------------------------------------------------------------------------- /core/utils/clone_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "testing" 5 | 6 | "code.google.com/p/goprotobuf/proto" 7 | ) 8 | 9 | type StructD struct { 10 | Int4 int 11 | } 12 | 13 | type StructC struct { 14 | Int3 int 15 | DMap map[int]*StructD 16 | DArr []StructD 17 | TMap map[int]struct{} 18 | } 19 | 20 | type StructB struct { 21 | StructC 22 | C *int32 23 | IntSlice []*int32 24 | Map map[int]string 25 | } 26 | type StructA struct { 27 | IntValue int 28 | StrValue string 29 | InnerValue *StructB 30 | } 31 | 32 | func TestClone(t *testing.T) { 33 | a := &StructA{IntValue: 1, StrValue: "test", 34 | InnerValue: &StructB{ 35 | C: proto.Int(9), 36 | IntSlice: []*int32{proto.Int(1), proto.Int(2), proto.Int(3), proto.Int(4), proto.Int(5), proto.Int(6), proto.Int(7), proto.Int(8), proto.Int(9), proto.Int(0)}, 37 | Map: map[int]string{1: "test", 2: "Hello"}, 38 | StructC: StructC{Int3: 33, DMap: map[int]*StructD{1: &StructD{Int4: 44}}}, 39 | }, 40 | } 41 | b := Clone(a).(*StructA) 42 | //t.Trace(a, b) 43 | 44 | b.InnerValue.IntSlice[0] = proto.Int(99) 45 | b.InnerValue.IntSlice = b.InnerValue.IntSlice[:7] 46 | //t.Tracef("%#v %#v %#v\r\n", a, a.InnerValue.IntSlice, *a.InnerValue.C) 47 | //t.Tracef("%#v %#v %#v\r\n", b, b.InnerValue.IntSlice, *b.InnerValue.C) 48 | //t.Tracef("%#v\r\n", a.InnerValue.Map) 49 | //t.Tracef("%#v\r\n", b.InnerValue.Map) 50 | //t.Tracef("%#v\r\n", a.InnerValue.StructC) 51 | //t.Tracef("%#v\r\n", b.InnerValue.StructC) 52 | } 53 | 54 | func BenchmarkClone(b *testing.B) { 55 | a := &StructA{IntValue: 1, StrValue: "test", 56 | InnerValue: &StructB{ 57 | C: proto.Int(9), 58 | IntSlice: []*int32{proto.Int(1), proto.Int(2), proto.Int(3), proto.Int(4), proto.Int(5), proto.Int(6), proto.Int(7), proto.Int(8), proto.Int(9), proto.Int(0)}, 59 | Map: map[int]string{1: "test", 2: "Hello"}, 60 | StructC: StructC{Int3: 33, DMap: map[int]*StructD{1: &StructD{Int4: 44}}}, 61 | }, 62 | } 63 | 64 | b.StartTimer() 65 | for i := 0; i < b.N; i++ { 66 | _ = Clone(a).(*StructA) 67 | } 68 | b.StopTimer() 69 | } 70 | -------------------------------------------------------------------------------- /core/utils/debug_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | type mytype struct { 8 | next *mytype 9 | prev *mytype 10 | } 11 | 12 | func TestPrint(t *testing.T) { 13 | Display("v1", 1, "v2", 2, "v3", 3) 14 | } 15 | 16 | func TestPrintPoint(t *testing.T) { 17 | var v1 = new(mytype) 18 | var v2 = new(mytype) 19 | 20 | v1.prev = nil 21 | v1.next = v2 22 | 23 | v2.prev = v1 24 | v2.next = nil 25 | 26 | Display("v1", v1, "v2", v2) 27 | } 28 | 29 | func TestPrintString(t *testing.T) { 30 | str := GetDisplayString("v1", 1, "v2", 2) 31 | println(str) 32 | } 33 | -------------------------------------------------------------------------------- /core/utils/healthcheck.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | //type DatabaseCheck struct { 4 | //} 5 | 6 | //func (dc *DatabaseCheck) Check() error { 7 | // if dc.isConnected() { 8 | // return nil 9 | // } else { 10 | // return errors.New("can't connect database") 11 | // } 12 | //} 13 | 14 | //AddHealthCheck("database",&DatabaseCheck{}) 15 | 16 | var AdminCheckList map[string]HealthChecker 17 | 18 | type HealthChecker interface { 19 | Check() error 20 | } 21 | 22 | type HealthCheckerWrapper func() error 23 | 24 | func (hcw HealthCheckerWrapper) Check() error { 25 | return hcw() 26 | } 27 | 28 | func AddHealthCheck(name string, hc HealthChecker) { 29 | AdminCheckList[name] = hc 30 | } 31 | 32 | func init() { 33 | AdminCheckList = make(map[string]HealthChecker) 34 | } 35 | -------------------------------------------------------------------------------- /core/utils/idgen.go: -------------------------------------------------------------------------------- 1 | // idgen 2 | package utils 3 | 4 | import ( 5 | "sync/atomic" 6 | ) 7 | 8 | type IdGen struct { 9 | beg int32 10 | seq int32 11 | } 12 | 13 | func (this *IdGen) NextId() int { 14 | seq := atomic.AddInt32(&this.seq, 1) 15 | return int(seq) 16 | } 17 | 18 | func (this *IdGen) Reset() { 19 | atomic.StoreInt32(&this.seq, this.beg) 20 | } 21 | 22 | func (this *IdGen) SetSeq(seq int) { 23 | atomic.StoreInt32(&this.seq, int32(seq)) 24 | } 25 | 26 | func (this *IdGen) SetStartPoint(startPoint int) { 27 | atomic.StoreInt32(&this.beg, int32(startPoint)) 28 | } 29 | 30 | func (this *IdGen) CurrId() int { 31 | return int(atomic.LoadInt32(&this.seq)) 32 | } 33 | -------------------------------------------------------------------------------- /core/utils/panic.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "runtime" 5 | 6 | "encoding/json" 7 | "fmt" 8 | "github.com/idealeak/goserver/core/logger" 9 | "sync" 10 | "sync/atomic" 11 | "time" 12 | ) 13 | 14 | var _panicStackMgr = &PanicStackMgr{ 15 | items: make(map[string]*PanicStackInfo), 16 | } 17 | 18 | type PanicStackMgr struct { 19 | sync.RWMutex 20 | items map[string]*PanicStackInfo 21 | } 22 | 23 | type PanicStackInfo struct { 24 | FirstTime time.Time 25 | LastTime time.Time 26 | Times int64 27 | ErrorMsg string 28 | StackBuf string 29 | } 30 | 31 | func DumpStackIfPanic(f string) { 32 | if err := recover(); err != nil { 33 | defer func() { //防止二次panic 34 | if err := recover(); err != nil { 35 | logger.Logger.Error(f, " panic.panic,error=", err) 36 | } 37 | }() 38 | logger.Logger.Error(f, " panic,error=", err) 39 | errMsg := fmt.Sprintf("%v", err) 40 | var buf [4096]byte 41 | n := runtime.Stack(buf[:], false) 42 | logger.Logger.Error("stack--->", string(buf[:n])) 43 | stk := make([]uintptr, 32) 44 | m := runtime.Callers(0, stk[:]) 45 | stk = stk[:m] 46 | if len(stk) > 0 { 47 | d, err := json.Marshal(stk) 48 | if err == nil && len(d) > 0 { 49 | key := string(d) 50 | _panicStackMgr.Lock() 51 | defer _panicStackMgr.Unlock() 52 | tNow := time.Now() 53 | if ps, exist := _panicStackMgr.items[key]; exist { 54 | atomic.AddInt64(&ps.Times, 1) 55 | ps.LastTime = tNow 56 | } else { 57 | ps = &PanicStackInfo{ 58 | ErrorMsg: errMsg, 59 | Times: 1, 60 | StackBuf: string(buf[:n]), 61 | FirstTime: tNow, 62 | LastTime: tNow, 63 | } 64 | _panicStackMgr.items[key] = ps 65 | } 66 | } 67 | } 68 | } 69 | } 70 | 71 | func DumpStack(f string) { 72 | logger.Logger.Error(f) 73 | var buf [4096]byte 74 | len := runtime.Stack(buf[:], false) 75 | logger.Logger.Error("stack--->", string(buf[:len])) 76 | } 77 | 78 | func GetPanicStats() map[string]PanicStackInfo { 79 | stats := make(map[string]PanicStackInfo) 80 | _panicStackMgr.RLock() 81 | defer _panicStackMgr.RUnlock() 82 | for k, v := range _panicStackMgr.items { 83 | stats[k] = *v 84 | } 85 | return stats 86 | } 87 | -------------------------------------------------------------------------------- /core/utils/profile_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | ) 7 | 8 | func TestProcessInput(t *testing.T) { 9 | ProcessInput("lookup goroutine", os.Stdout) 10 | ProcessInput("lookup heap", os.Stdout) 11 | ProcessInput("lookup threadcreate", os.Stdout) 12 | ProcessInput("lookup block", os.Stdout) 13 | ProcessInput("gc summary", os.Stdout) 14 | } 15 | -------------------------------------------------------------------------------- /core/utils/rand.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "errors" 5 | "math/rand" 6 | "strconv" 7 | "strings" 8 | "time" 9 | ) 10 | 11 | var MinMaxError = errors.New("Min cannot be greater than max.") 12 | var Char_Buff = [26]string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", 13 | "t", "u", "v", "w", "x", "y", "z"} 14 | 15 | func RandChoice(choices []interface{}) (interface{}, error) { 16 | var winner interface{} 17 | length := len(choices) 18 | i, err := IntRange(0, length) 19 | if err != nil { 20 | return nil, err 21 | } 22 | winner = choices[i] 23 | return winner, nil 24 | } 25 | 26 | func IntRange(min, max int) (int, error) { 27 | var result int 28 | switch { 29 | case min > max: 30 | return result, MinMaxError 31 | case min == max: 32 | result = max 33 | case min < max: 34 | rand.Seed(time.Now().UnixNano()) 35 | result = min + rand.Intn(max-min) 36 | } 37 | return result, nil 38 | } 39 | 40 | func RandCode(codelen int) string { 41 | if codelen == 0 { 42 | return "" 43 | } 44 | numLen := rand.Intn(codelen) 45 | charLen := codelen - numLen 46 | var buff string 47 | for i := 0; i < numLen; i++ { 48 | buff = buff + strconv.Itoa(rand.Intn(10)) 49 | } 50 | for i := 0; i < charLen; i++ { 51 | buff = buff + Char_Buff[rand.Intn(26)] 52 | } 53 | var code string 54 | arr := rand.Perm(codelen) 55 | for i := 0; i < 6; i++ { 56 | code = code + string(buff[arr[i]]) 57 | } 58 | return strings.ToUpper(code) 59 | } 60 | func RandNumCode(codelen int) string { 61 | if codelen == 0 { 62 | return "" 63 | } 64 | var buff string 65 | for i := 0; i < codelen; i++ { 66 | buff = buff + strconv.Itoa(rand.Intn(10)) 67 | } 68 | return strings.ToUpper(buff) 69 | } 70 | -------------------------------------------------------------------------------- /core/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "github.com/idealeak/goserver/core/logger" 6 | "runtime" 7 | "time" 8 | ) 9 | 10 | func Avg(items []time.Duration) time.Duration { 11 | var sum time.Duration 12 | for _, item := range items { 13 | sum += item 14 | } 15 | return time.Duration(int64(sum) / int64(len(items))) 16 | } 17 | 18 | // human readable format 19 | func ToH(bytes uint64) string { 20 | switch { 21 | case bytes < 1024: 22 | return fmt.Sprintf("%dB", bytes) 23 | case bytes < 1024*1024: 24 | return fmt.Sprintf("%.2fK", float64(bytes)/1024) 25 | case bytes < 1024*1024*1024: 26 | return fmt.Sprintf("%.2fM", float64(bytes)/1024/1024) 27 | default: 28 | return fmt.Sprintf("%.2fG", float64(bytes)/1024/1024/1024) 29 | } 30 | } 31 | 32 | // short string format 33 | func ToS(d time.Duration) string { 34 | 35 | u := uint64(d) 36 | if u < uint64(time.Second) { 37 | switch { 38 | case u == 0: 39 | return "0" 40 | case u < uint64(time.Microsecond): 41 | return fmt.Sprintf("%.2fns", float64(u)) 42 | case u < uint64(time.Millisecond): 43 | return fmt.Sprintf("%.2fus", float64(u)/1000) 44 | default: 45 | return fmt.Sprintf("%.2fms", float64(u)/1000/1000) 46 | } 47 | } else { 48 | switch { 49 | case u < uint64(time.Minute): 50 | return fmt.Sprintf("%.2fs", float64(u)/1000/1000/1000) 51 | case u < uint64(time.Hour): 52 | return fmt.Sprintf("%.2fm", float64(u)/1000/1000/1000/60) 53 | default: 54 | return fmt.Sprintf("%.2fh", float64(u)/1000/1000/1000/60/60) 55 | } 56 | } 57 | 58 | } 59 | 60 | func CatchPanic(f func()) (err interface{}) { 61 | defer func() { 62 | err = recover() 63 | if err != nil { 64 | logger.Logger.Warnf("%s panic: %s", f, err) 65 | var buf [4096]byte 66 | n := runtime.Stack(buf[:], false) 67 | logger.Logger.Error("stack--->", string(buf[:n])) 68 | } 69 | }() 70 | f() 71 | return 72 | } 73 | 74 | func RunPanicless(f func()) (panicless bool) { 75 | defer func() { 76 | err := recover() 77 | panicless = err == nil 78 | if err != nil { 79 | logger.Logger.Warnf("%s panic: %s", f, err) 80 | var buf [4096]byte 81 | n := runtime.Stack(buf[:], false) 82 | logger.Logger.Error("stack--->", string(buf[:n])) 83 | } 84 | }() 85 | 86 | f() 87 | return 88 | } 89 | 90 | func RepeatUntilPanicless(f func()) { 91 | for !RunPanicless(f) { 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /core/utils/waitor.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "sync/atomic" 5 | 6 | "github.com/idealeak/goserver/core/logger" 7 | ) 8 | 9 | type Waitor struct { 10 | name string 11 | counter int32 12 | waiters int32 13 | c chan string 14 | } 15 | 16 | func NewWaitor(name string) *Waitor { 17 | w := &Waitor{name: name, c: make(chan string, 16)} 18 | return w 19 | } 20 | 21 | func (w *Waitor) Add(name string, delta int) { 22 | v := atomic.AddInt32(&w.counter, int32(delta)) 23 | if v < 0 { 24 | panic("negative Waitor counter") 25 | } 26 | cnt := atomic.LoadInt32(&w.counter) 27 | logger.Logger.Debugf("(w *Waitor)(%v:%p) Add(%v,%v) counter(%v)", w.name, w, name, delta, cnt) 28 | } 29 | 30 | func (w *Waitor) Wait(name string) { 31 | v := atomic.AddInt32(&w.waiters, 1) 32 | if v > 1 { 33 | panic("only support one waitor") 34 | } 35 | cnt := atomic.LoadInt32(&w.waiters) 36 | logger.Logger.Debugf("(w *Waitor)(%v:%p) Waiter(%v) waiters(%v)", w.name, w, name, cnt) 37 | for w.counter > 0 { 38 | dname := <-w.c 39 | v = atomic.AddInt32(&w.counter, -1) 40 | cnt = atomic.LoadInt32(&w.counter) 41 | logger.Logger.Debugf("(w *Waitor)(%v:%p) Waiter(%v) after(%v)done! counter(%v)", w.name, w, name, dname, cnt) 42 | } 43 | } 44 | 45 | func (w *Waitor) Done(name string) { 46 | w.c <- name 47 | logger.Logger.Debugf("(w *Waitor)(%v:%p) Done(%v)!!!", w.name, w, name) 48 | } 49 | -------------------------------------------------------------------------------- /core/zk/zk_test.go: -------------------------------------------------------------------------------- 1 | package zk 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | func TestZK(t *testing.T) { 9 | conn, err := Connect([]string{"10.33.21.152:2181"}, time.Second*30) 10 | if err != nil { 11 | t.Error(err) 12 | } 13 | defer conn.Close() 14 | err = Create(conn, "/test/test") 15 | if err != nil { 16 | t.Error(err) 17 | } 18 | // registertmp 19 | err = RegisterTemp(conn, "/test/test", "1") 20 | if err != nil { 21 | t.Error(err) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | package goserver 2 | -------------------------------------------------------------------------------- /examples/echoclient/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "netlib": { 3 | "SrvInfo":{ 4 | "Name": "EchoClient", 5 | "Type": 1, 6 | "Id": 101, 7 | "AreaID": 1, 8 | "Banner": [ 9 | "=================", 10 | "echo client", 11 | "=================" 12 | ] 13 | }, 14 | 15 | "IoServices": [] 16 | }, 17 | 18 | "module": { 19 | "Options": { 20 | "QueueBacklog": 1024, 21 | "MaxDone": 1024, 22 | "Interval": 100 23 | } 24 | }, 25 | 26 | "executor": { 27 | "Options": { 28 | "QueueBacklog": 1024, 29 | "MaxDone": 1024, 30 | "Interval": 0 31 | }, 32 | "Worker": { 33 | "WorkerCnt": 8, 34 | "Options": { 35 | "QueueBacklog": 1024, 36 | "MaxDone": 1024, 37 | "Interval": 0 38 | } 39 | } 40 | }, 41 | 42 | "timer": { 43 | "Options": { 44 | "QueueBacklog": 1024, 45 | "MaxDone": 1024, 46 | "Interval": 100 47 | } 48 | }, 49 | 50 | "core": { 51 | "MaxProcs": 4 52 | }, 53 | 54 | "pressure": { 55 | "Count":1, 56 | "Connects": { 57 | "Id": 201, 58 | "Type": 2, 59 | "AreaID": 0, 60 | "Name": "EchoService", 61 | "Ip": "gt.doudoubei.com", 62 | "Port": 11111, 63 | "Protocol":"tcp", 64 | "Path":"/", 65 | "MaxDone": 20, 66 | "MaxPend": 20, 67 | "MaxPacket": 65535, 68 | "MaxConn": 8, 69 | "RcvBuff": 8192, 70 | "SndBuff": 8192, 71 | "WriteTimeout": 30, 72 | "ReadTimeout": 30, 73 | "NoDelay": true, 74 | "IsInnerLink": true, 75 | "IsClient": true, 76 | "IsAutoReconn": true, 77 | "AllowMultiConn": true, 78 | "SupportFragment": true, 79 | "AuthKey": "1234567890", 80 | "FilterChain": ["session-filter-trace","session-filter-auth","serversessionfilter"] 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /examples/echoclient/logger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/echoclient/main.go: -------------------------------------------------------------------------------- 1 | // main 2 | package main 3 | 4 | import ( 5 | "github.com/idealeak/goserver/core" 6 | "github.com/idealeak/goserver/core/module" 7 | ) 8 | 9 | func main() { 10 | defer core.ClosePackages() 11 | core.LoadPackages("config.json") 12 | 13 | waiter := module.Start() 14 | waiter.Wait("main") 15 | } 16 | -------------------------------------------------------------------------------- /examples/echoclient/pressure.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/idealeak/goserver/core" 7 | _ "github.com/idealeak/goserver/core/builtin/action" 8 | _ "github.com/idealeak/goserver/core/builtin/filter" 9 | "github.com/idealeak/goserver/core/module" 10 | "github.com/idealeak/goserver/core/netlib" 11 | ) 12 | 13 | var ( 14 | Config = Configuration{} 15 | PressureModule = &PressureTest{} 16 | StartCnt = 0 17 | ) 18 | 19 | type Configuration struct { 20 | Count int 21 | Connects netlib.SessionConfig 22 | } 23 | 24 | func (this *Configuration) Name() string { 25 | return "pressure" 26 | } 27 | 28 | func (this *Configuration) Init() error { 29 | this.Connects.Init() 30 | return nil 31 | } 32 | 33 | func (this *Configuration) Close() error { 34 | return nil 35 | } 36 | 37 | type PressureTest struct { 38 | } 39 | 40 | func (this PressureTest) ModuleName() string { 41 | return "pressure-module" 42 | } 43 | 44 | func (this *PressureTest) Init() { 45 | cfg := Config.Connects 46 | for i := 0; i < Config.Count; i++ { 47 | cfg.Id += i 48 | netlib.Connect(&cfg) 49 | } 50 | } 51 | 52 | func (this *PressureTest) Update() { 53 | return 54 | } 55 | 56 | func (this *PressureTest) Shutdown() { 57 | module.UnregisteModule(this) 58 | } 59 | 60 | func init() { 61 | core.RegistePackage(&Config) 62 | module.RegisteModule(PressureModule, time.Second*30, 50) 63 | } 64 | -------------------------------------------------------------------------------- /examples/echoclient/scpacketponghandler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "code.google.com/p/goprotobuf/proto" 7 | "github.com/idealeak/goserver/core/netlib" 8 | "github.com/idealeak/goserver/examples/protocol" 9 | ) 10 | 11 | type SCPacketPongPacketFactory struct { 12 | } 13 | 14 | type SCPacketPongHandler struct { 15 | } 16 | 17 | func (this *SCPacketPongPacketFactory) CreatePacket() interface{} { 18 | pack := &protocol.SCPacketPong{} 19 | return pack 20 | } 21 | 22 | func (this *SCPacketPongHandler) Process(session *netlib.Session, packetid int, data interface{}) error { 23 | if pong, ok := data.(*protocol.SCPacketPong); ok { 24 | ping := &protocol.CSPacketPing{ 25 | TimeStamb: proto.Int64(time.Now().Unix()), 26 | Message: pong.GetMessage(), 27 | } 28 | proto.SetDefaults(ping) 29 | session.Send(int(protocol.PacketID_PACKET_CS_PING), ping) 30 | } 31 | return nil 32 | } 33 | 34 | func init() { 35 | netlib.RegisterHandler(int(protocol.PacketID_PACKET_SC_PONG), &SCPacketPongHandler{}) 36 | netlib.RegisterFactory(int(protocol.PacketID_PACKET_SC_PONG), &SCPacketPongPacketFactory{}) 37 | } 38 | -------------------------------------------------------------------------------- /examples/echoclient/serversessionfilter.go: -------------------------------------------------------------------------------- 1 | // serversessionfilter 2 | package main 3 | 4 | import ( 5 | "time" 6 | 7 | "code.google.com/p/goprotobuf/proto" 8 | "github.com/idealeak/goserver/core/logger" 9 | "github.com/idealeak/goserver/core/netlib" 10 | "github.com/idealeak/goserver/examples/protocol" 11 | ) 12 | 13 | var ( 14 | ServerSessionFilterName = "serversessionfilter" 15 | ) 16 | 17 | type ServerSessionFilter struct { 18 | netlib.BasicSessionFilter 19 | } 20 | 21 | func (ssf ServerSessionFilter) GetName() string { 22 | return ServerSessionFilterName 23 | } 24 | 25 | func (ssf *ServerSessionFilter) GetInterestOps() uint { 26 | return 1 << netlib.InterestOps_Opened 27 | } 28 | 29 | func (ssf *ServerSessionFilter) OnSessionOpened(s *netlib.Session) bool { 30 | logger.Logger.Trace("(ssf *ServerSessionFilter) OnSessionOpened") 31 | packet := &protocol.CSPacketPing{ 32 | TimeStamb: proto.Int64(time.Now().Unix()), 33 | Message: []byte("=1234567890abcderghijklmnopqrstuvwxyz="), 34 | } 35 | //for i := 0; i < 1024*32; i++ { 36 | // packet.Message = append(packet.Message, byte('x')) 37 | //} 38 | proto.SetDefaults(packet) 39 | s.Send(int(protocol.PacketID_PACKET_CS_PING), packet) 40 | return true 41 | } 42 | 43 | func init() { 44 | netlib.RegisteSessionFilterCreator(ServerSessionFilterName, func() netlib.SessionFilter { 45 | return &ServerSessionFilter{} 46 | }) 47 | } 48 | -------------------------------------------------------------------------------- /examples/echoserver/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "netlib": { 3 | "SrvInfo":{ 4 | "Name": "EchoServer", 5 | "Type": 2, 6 | "Id": 201, 7 | "AreaID": 1, 8 | "Banner": [ 9 | "=================", 10 | "echo server", 11 | "=================" 12 | ] 13 | }, 14 | 15 | "IoServices": [ 16 | { 17 | "Id": 201, 18 | "Type": 2, 19 | "AreaId": 1, 20 | "Name": "EchoService", 21 | "Ip": "", 22 | "Port": 2345, 23 | "Protocol":"ws", 24 | "Path":"/", 25 | "MaxDone": 20, 26 | "MaxPend": 20, 27 | "MaxPacket": 65535, 28 | "MaxConn": 10000, 29 | "RcvBuff": 8192, 30 | "SndBuff": 8192, 31 | "WriteTimeout": 30, 32 | "ReadTimeout": 30, 33 | "IsInnerLink": true, 34 | "NoDelay": true, 35 | "SupportFragment": true, 36 | "AuthKey": "1234567890", 37 | "FilterChain": ["session-filter-trace","session-filter-auth"] 38 | } 39 | ] 40 | }, 41 | 42 | "module": { 43 | "Options": { 44 | "QueueBacklog": 1024, 45 | "MaxDone": 1024, 46 | "Interval": 100 47 | } 48 | }, 49 | 50 | "executor": { 51 | "Options": { 52 | "QueueBacklog": 1024, 53 | "MaxDone": 1024, 54 | "Interval": 0 55 | }, 56 | "Worker": { 57 | "WorkerCnt": 8, 58 | "Options": { 59 | "QueueBacklog": 1024, 60 | "MaxDone": 1024, 61 | "Interval": 0 62 | } 63 | } 64 | }, 65 | 66 | "timer": { 67 | "Options": { 68 | "QueueBacklog": 1024, 69 | "MaxDone": 1024, 70 | "Interval": 100 71 | } 72 | }, 73 | 74 | "core": { 75 | "MaxProcs": 4 76 | }, 77 | 78 | "cmdline": { 79 | "SupportCmdLine": true 80 | } 81 | } -------------------------------------------------------------------------------- /examples/echoserver/logger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/echoserver/main.go: -------------------------------------------------------------------------------- 1 | // main 2 | package main 3 | 4 | import ( 5 | "net/http" 6 | _ "net/http/pprof" 7 | 8 | "github.com/idealeak/goserver/core" 9 | _ "github.com/idealeak/goserver/core/builtin/filter" 10 | "github.com/idealeak/goserver/core/module" 11 | ) 12 | 13 | func main() { 14 | defer core.ClosePackages() 15 | core.LoadPackages("config.json") 16 | //usage: go tool pprof http://localhost:6060/debug/pprof/heap 17 | go func() { 18 | http.ListenAndServe("localhost:6060", nil) 19 | }() 20 | 21 | waiter := module.Start() 22 | waiter.Wait("main") 23 | } 24 | -------------------------------------------------------------------------------- /examples/echoserver/scpacketponghandler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "code.google.com/p/goprotobuf/proto" 5 | "github.com/idealeak/goserver/core/netlib" 6 | "github.com/idealeak/goserver/examples/protocol" 7 | ) 8 | 9 | type CSPacketPingPacketFactory struct { 10 | } 11 | 12 | type CSPacketPingHandler struct { 13 | } 14 | 15 | func (this *CSPacketPingPacketFactory) CreatePacket() interface{} { 16 | pack := &protocol.CSPacketPing{} 17 | return pack 18 | } 19 | 20 | func (this *CSPacketPingHandler) Process(session *netlib.Session, packetid int, data interface{}) error { 21 | if ping, ok := data.(*protocol.CSPacketPing); ok { 22 | pong := &protocol.SCPacketPong{ 23 | TimeStamb: proto.Int64(ping.GetTimeStamb()), 24 | Message: ping.GetMessage(), 25 | } 26 | proto.SetDefaults(pong) 27 | session.Send(int(protocol.PacketID_PACKET_SC_PONG), pong) 28 | } 29 | return nil 30 | } 31 | 32 | func init() { 33 | netlib.RegisterHandler(int(protocol.PacketID_PACKET_CS_PING), &CSPacketPingHandler{}) 34 | netlib.RegisterFactory(int(protocol.PacketID_PACKET_CS_PING), &CSPacketPingPacketFactory{}) 35 | } 36 | -------------------------------------------------------------------------------- /examples/gen_go.bat: -------------------------------------------------------------------------------- 1 | protoc --go_out=. protocol/*.proto 2 | pause -------------------------------------------------------------------------------- /examples/other/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "netlib": { 3 | "SrvInfo": 4 | { 5 | "Name": "TimerServer", 6 | "Banner": [ 7 | "=================", 8 | "timer server", 9 | "=================" 10 | ] 11 | } 12 | }, 13 | 14 | "core": { 15 | "MaxProcs": 4, 16 | "SupportCmdLine":true, 17 | "SupportSignal": true, 18 | "SupportAdmin": true, 19 | "SlowMS": 200, 20 | "Object": { 21 | "QueueBacklog": 1024, 22 | "MaxDone": 1024, 23 | "Interval": 100 24 | }, 25 | 26 | "Executor": { 27 | "Object": { 28 | "QueueBacklog": 1024, 29 | "MaxDone": 1024, 30 | "Interval": 0 31 | }, 32 | "Worker": { 33 | "WorkerCnt": 8, 34 | "Object": { 35 | "QueueBacklog": 1024, 36 | "MaxDone": 1024, 37 | "Interval": 0 38 | } 39 | } 40 | }, 41 | 42 | "Timer": { 43 | "Object": { 44 | "QueueBacklog": 1024, 45 | "MaxDone": 1024, 46 | "Interval": 100 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /examples/other/logger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/other/main.go: -------------------------------------------------------------------------------- 1 | // main 2 | package main 3 | 4 | import ( 5 | "github.com/idealeak/goserver/core" 6 | "github.com/idealeak/goserver/core/module" 7 | ) 8 | 9 | func main() { 10 | defer core.ClosePackages() 11 | core.LoadPackages("config.json") 12 | 13 | waiter := module.Start() 14 | waiter.Wait("main") 15 | } 16 | -------------------------------------------------------------------------------- /examples/other/task.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/idealeak/goserver/core/basic" 6 | "math/rand" 7 | "time" 8 | 9 | "github.com/idealeak/goserver/core/module" 10 | "github.com/idealeak/goserver/core/task" 11 | ) 12 | 13 | var TaskExampleSington = &TaskExample{} 14 | 15 | type TaskExample struct { 16 | id int 17 | } 18 | 19 | //in task.Worker goroutine 20 | func (this *TaskExample) Call(o *basic.Object) interface{} { 21 | tNow := time.Now() 22 | fmt.Println("[", this.id, "]TaskExample execute start ") 23 | time.Sleep(time.Second * time.Duration(rand.Intn(10))) 24 | fmt.Println("[", this.id, "]TaskExample execute end, take ", time.Now().Sub(tNow)) 25 | return nil 26 | } 27 | 28 | // in laucher goroutine 29 | func (this *TaskExample) Done(i interface{}, t *task.Task) { 30 | fmt.Println("TaskExample execute over") 31 | } 32 | 33 | //////////////////////////////////////////////////////////////////// 34 | /// Module Implement [beg] 35 | //////////////////////////////////////////////////////////////////// 36 | func (this *TaskExample) ModuleName() string { 37 | return "taskexample" 38 | } 39 | 40 | func (this *TaskExample) Init() { 41 | for i := 1; i < 100; i++ { 42 | th := &TaskExample{id: i} 43 | t := task.New(nil, th, th,"test") 44 | if b := t.StartByExecutor(fmt.Sprintf("%v", i)); !b { 45 | fmt.Println("[", i, "]task lauch failed") 46 | } else { 47 | fmt.Println("[", i, "]task lauch success") 48 | } 49 | } 50 | 51 | for i := 100; i < 200; i++ { 52 | th := &TaskExample{id: i} 53 | t := task.New(nil, th, th,"test") 54 | w := rand.Intn(100) 55 | go func(id, n int) { 56 | if b := t.StartByFixExecutor(fmt.Sprintf("test%v", n)); !b { 57 | fmt.Println("[", id, "]task lauch failed") 58 | } else { 59 | fmt.Println("[", id, "]task lauch success") 60 | } 61 | }(i, w) 62 | } 63 | } 64 | 65 | func (this *TaskExample) Update() { 66 | fmt.Println("TaskExample.Update") 67 | } 68 | 69 | func (this *TaskExample) Shutdown() { 70 | module.UnregisteModule(this) 71 | } 72 | 73 | //////////////////////////////////////////////////////////////////// 74 | /// Module Implement [end] 75 | //////////////////////////////////////////////////////////////////// 76 | 77 | func init() { 78 | module.RegisteModule(TaskExampleSington, time.Second, 0) 79 | } 80 | -------------------------------------------------------------------------------- /examples/other/timer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/idealeak/goserver/core/module" 8 | "github.com/idealeak/goserver/core/timer" 9 | ) 10 | 11 | var TimerExampleSington = &TimerExample{} 12 | 13 | type TimerExample struct { 14 | } 15 | 16 | //////////////////////////////////////////////////////////////////// 17 | /// Module Implement [beg] 18 | //////////////////////////////////////////////////////////////////// 19 | func (this *TimerExample) ModuleName() string { 20 | return "timerexample" 21 | } 22 | 23 | func (this *TimerExample) Init() { 24 | var i int 25 | h, b := timer.StartTimer(timer.TimerActionWrapper(func(h timer.TimerHandle, ud interface{}) bool { 26 | i++ 27 | fmt.Println(i, time.Now()) 28 | 29 | if i > 5 { 30 | return false 31 | } 32 | 33 | return true 34 | }), nil, time.Second, 10) 35 | fmt.Println("timer lauch ", h, b) 36 | } 37 | 38 | func (this *TimerExample) Update() { 39 | fmt.Println("timer queue len=", timer.TimerModule.TimerCount()) 40 | } 41 | 42 | func (this *TimerExample) Shutdown() { 43 | module.UnregisteModule(this) 44 | } 45 | 46 | //////////////////////////////////////////////////////////////////// 47 | /// Module Implement [end] 48 | //////////////////////////////////////////////////////////////////// 49 | 50 | func init() { 51 | module.RegisteModule(TimerExampleSington, time.Second, 0) 52 | } 53 | -------------------------------------------------------------------------------- /examples/protocol/packetid.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: protocol/packetid.proto 3 | // DO NOT EDIT! 4 | 5 | package protocol 6 | 7 | import proto "code.google.com/p/goprotobuf/proto" 8 | import json "encoding/json" 9 | import math "math" 10 | 11 | // Reference proto, json, and math imports to suppress error if they are not otherwise used. 12 | var _ = proto.Marshal 13 | var _ = &json.SyntaxError{} 14 | var _ = math.Inf 15 | 16 | type PacketID int32 17 | 18 | const ( 19 | PacketID_PACKET_CS_PING PacketID = 1000 20 | PacketID_PACKET_SC_PONG PacketID = 1001 21 | ) 22 | 23 | var PacketID_name = map[int32]string{ 24 | 1000: "PACKET_CS_PING", 25 | 1001: "PACKET_SC_PONG", 26 | } 27 | var PacketID_value = map[string]int32{ 28 | "PACKET_CS_PING": 1000, 29 | "PACKET_SC_PONG": 1001, 30 | } 31 | 32 | func (x PacketID) Enum() *PacketID { 33 | p := new(PacketID) 34 | *p = x 35 | return p 36 | } 37 | func (x PacketID) String() string { 38 | return proto.EnumName(PacketID_name, int32(x)) 39 | } 40 | func (x PacketID) MarshalJSON() ([]byte, error) { 41 | return json.Marshal(x.String()) 42 | } 43 | func (x *PacketID) UnmarshalJSON(data []byte) error { 44 | value, err := proto.UnmarshalJSONEnum(PacketID_value, data, "PacketID") 45 | if err != nil { 46 | return err 47 | } 48 | *x = PacketID(value) 49 | return nil 50 | } 51 | 52 | func init() { 53 | proto.RegisterEnum("protocol.PacketID", PacketID_name, PacketID_value) 54 | } 55 | -------------------------------------------------------------------------------- /examples/protocol/packetid.proto: -------------------------------------------------------------------------------- 1 | package protocol; 2 | 3 | enum PacketID { 4 | PACKET_CS_PING = 1000; 5 | PACKET_SC_PONG = 1001; 6 | } -------------------------------------------------------------------------------- /examples/protocol/pingpong.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: protocol/pingpong.proto 3 | // DO NOT EDIT! 4 | 5 | package protocol 6 | 7 | import proto "code.google.com/p/goprotobuf/proto" 8 | import json "encoding/json" 9 | import math "math" 10 | 11 | // Reference proto, json, and math imports to suppress error if they are not otherwise used. 12 | var _ = proto.Marshal 13 | var _ = &json.SyntaxError{} 14 | var _ = math.Inf 15 | 16 | type CSPacketPing struct { 17 | TimeStamb *int64 `protobuf:"varint,1,req" json:"TimeStamb,omitempty"` 18 | Message []byte `protobuf:"bytes,2,req" json:"Message,omitempty"` 19 | XXX_unrecognized []byte `json:"-"` 20 | } 21 | 22 | func (m *CSPacketPing) Reset() { *m = CSPacketPing{} } 23 | func (m *CSPacketPing) String() string { return proto.CompactTextString(m) } 24 | func (*CSPacketPing) ProtoMessage() {} 25 | 26 | func (m *CSPacketPing) GetTimeStamb() int64 { 27 | if m != nil && m.TimeStamb != nil { 28 | return *m.TimeStamb 29 | } 30 | return 0 31 | } 32 | 33 | func (m *CSPacketPing) GetMessage() []byte { 34 | if m != nil { 35 | return m.Message 36 | } 37 | return nil 38 | } 39 | 40 | type SCPacketPong struct { 41 | TimeStamb *int64 `protobuf:"varint,1,req" json:"TimeStamb,omitempty"` 42 | Message []byte `protobuf:"bytes,2,req" json:"Message,omitempty"` 43 | XXX_unrecognized []byte `json:"-"` 44 | } 45 | 46 | func (m *SCPacketPong) Reset() { *m = SCPacketPong{} } 47 | func (m *SCPacketPong) String() string { return proto.CompactTextString(m) } 48 | func (*SCPacketPong) ProtoMessage() {} 49 | 50 | func (m *SCPacketPong) GetTimeStamb() int64 { 51 | if m != nil && m.TimeStamb != nil { 52 | return *m.TimeStamb 53 | } 54 | return 0 55 | } 56 | 57 | func (m *SCPacketPong) GetMessage() []byte { 58 | if m != nil { 59 | return m.Message 60 | } 61 | return nil 62 | } 63 | 64 | func init() { 65 | } 66 | -------------------------------------------------------------------------------- /examples/protocol/pingpong.proto: -------------------------------------------------------------------------------- 1 | package protocol; 2 | 3 | message CSPacketPing { 4 | required int64 TimeStamb = 1; 5 | required bytes Message = 2; 6 | } 7 | 8 | message SCPacketPong { 9 | required int64 TimeStamb = 1; 10 | required bytes Message = 2; 11 | } -------------------------------------------------------------------------------- /examples/protocol/txtype.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core/transact" 5 | ) 6 | 7 | const ( 8 | TxTrace transact.TransType = 1000 9 | ) 10 | -------------------------------------------------------------------------------- /examples/protocol/txuserdata.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | type StructA struct { 4 | X, Y, Z int 5 | P *int 6 | Desc string 7 | } 8 | -------------------------------------------------------------------------------- /examples/txserver1/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "netlib": { 3 | "SrvInfo": 4 | { 5 | "Name": "TxServer1", 6 | "Type": 2, 7 | "Id": 201, 8 | "AreaID": 1, 9 | "Banner": [ 10 | "=================", 11 | "tx server 1", 12 | "=================" 13 | ] 14 | }, 15 | 16 | "IoServices": [ 17 | { 18 | "Id": 201, 19 | "Type": 2, 20 | "AreaId": 1, 21 | "Name": "TxService1", 22 | "Ip": "127.0.0.1", 23 | "Port": 2346, 24 | "MaxDone": 20, 25 | "MaxPend": 20, 26 | "MaxPacket": 65535, 27 | "MaxConn": 10, 28 | "RcvBuff": 8192, 29 | "SndBuff": 8192, 30 | "WriteTimeout": 30, 31 | "ReadTimeout": 30, 32 | "IsInnerLink": true, 33 | "NoDelay": true, 34 | "SupportFragment": true, 35 | "AuthKey": "1234567890", 36 | "FilterChain": ["session-filter-trace","session-filter-auth","session-filter-keepalive"], 37 | "HandlerChain": ["session-srv-registe"] 38 | }, 39 | { 40 | "Id": 202, 41 | "Type": 2, 42 | "AreaId": 1, 43 | "Name": "TxService2", 44 | "Ip": "127.0.0.1", 45 | "Port": 2347, 46 | "MaxDone": 20, 47 | "MaxPend": 20, 48 | "MaxPacket": 65535, 49 | "MaxConn": 10, 50 | "RcvBuff": 8192, 51 | "SndBuff": 8192, 52 | "WriteTimeout": 30, 53 | "ReadTimeout": 30, 54 | "IsInnerLink": true, 55 | "IsClient": true, 56 | "IsAutoReconn": true, 57 | "NoDelay": true, 58 | "SupportFragment": true, 59 | "AuthKey": "1234567890", 60 | "FilterChain": ["session-filter-trace","session-filter-auth","session-filter-keepalive"], 61 | "HandlerChain": ["session-srv-registe"] 62 | } 63 | ] 64 | }, 65 | 66 | "tx": { 67 | "TxSkeletonName": "github.com/idealeak/goserver/srvlib/txcommskeleton" 68 | }, 69 | 70 | "core": { 71 | "MaxProcs": 4 72 | } 73 | } -------------------------------------------------------------------------------- /examples/txserver1/dependent.go: -------------------------------------------------------------------------------- 1 | // dummy 2 | package main 3 | 4 | import ( 5 | _ "github.com/idealeak/goserver/core/builtin/action" 6 | _ "github.com/idealeak/goserver/core/builtin/filter" 7 | _ "github.com/idealeak/goserver/srvlib" 8 | _ "github.com/idealeak/goserver/srvlib/handler" 9 | ) 10 | -------------------------------------------------------------------------------- /examples/txserver1/logger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/txserver1/main.go: -------------------------------------------------------------------------------- 1 | // main 2 | package main 3 | 4 | import ( 5 | "github.com/idealeak/goserver/core" 6 | "github.com/idealeak/goserver/core/module" 7 | ) 8 | 9 | func main() { 10 | defer core.ClosePackages() 11 | core.LoadPackages("config.json") 12 | 13 | waiter := module.Start() 14 | waiter.Wait("main") 15 | } 16 | -------------------------------------------------------------------------------- /examples/txserver1/tx_trace.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core/logger" 5 | "github.com/idealeak/goserver/core/netlib" 6 | "github.com/idealeak/goserver/core/transact" 7 | "github.com/idealeak/goserver/examples/protocol" 8 | "github.com/idealeak/goserver/srvlib" 9 | ) 10 | 11 | type traceTransHandler struct { 12 | } 13 | 14 | func init() { 15 | transact.RegisteHandler(protocol.TxTrace, &traceTransHandler{}) 16 | srvlib.ServerSessionMgrSington.AddListener(&MyServerSessionRegisteListener{}) 17 | } 18 | 19 | func (this *traceTransHandler) OnExcute(tNode *transact.TransNode, ud interface{}) transact.TransExeResult { 20 | logger.Logger.Trace("traceTransHandler.OnExcute ") 21 | userData := &protocol.StructA{} 22 | err := netlib.UnmarshalPacketNoPackId(ud.([]byte), userData) 23 | if err == nil { 24 | logger.Logger.Tracef("==========%#v", userData) 25 | } 26 | return transact.TransExeResult_Success 27 | } 28 | 29 | func (this *traceTransHandler) OnCommit(tNode *transact.TransNode) transact.TransExeResult { 30 | logger.Logger.Trace("traceTransHandler.OnCommit ") 31 | return transact.TransExeResult_Success 32 | } 33 | 34 | func (this *traceTransHandler) OnRollBack(tNode *transact.TransNode) transact.TransExeResult { 35 | logger.Logger.Trace("traceTransHandler.OnRollBack ") 36 | return transact.TransExeResult_Success 37 | } 38 | 39 | func (this *traceTransHandler) OnChildTransRep(tNode *transact.TransNode, hChild transact.TransNodeID, retCode int, ud interface{}) transact.TransExeResult { 40 | logger.Logger.Trace("traceTransHandler.OnChildTransRep ") 41 | return transact.TransExeResult_Success 42 | } 43 | 44 | type MyServerSessionRegisteListener struct { 45 | } 46 | 47 | func (mssrl *MyServerSessionRegisteListener) OnRegiste(*netlib.Session) { 48 | logger.Logger.Trace("MyServerSessionRegisteListener.OnRegiste") 49 | } 50 | 51 | func (mssrl *MyServerSessionRegisteListener) OnUnregiste(*netlib.Session) { 52 | logger.Logger.Trace("MyServerSessionRegisteListener.OnUnregiste") 53 | } 54 | -------------------------------------------------------------------------------- /examples/txserver2/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "netlib": { 3 | "SrvInfo": 4 | { 5 | "Name": "TxServer2", 6 | "Type": 2, 7 | "Id": 202, 8 | "AreaID": 1, 9 | "Banner": [ 10 | "=================", 11 | "tx server 2", 12 | "=================" 13 | ] 14 | }, 15 | 16 | "IoServices": [ 17 | { 18 | "Id": 202, 19 | "Type": 2, 20 | "AreaId": 1, 21 | "Name": "TxService2", 22 | "Ip": "127.0.0.1", 23 | "Port": 2347, 24 | "MaxDone": 20, 25 | "MaxPend": 20, 26 | "MaxPacket": 65535, 27 | "MaxConn": 10, 28 | "RcvBuff": 8192, 29 | "SndBuff": 8192, 30 | "WriteTimeout": 30, 31 | "ReadTimeout": 30, 32 | "IsInnerLink": true, 33 | "NoDelay": true, 34 | "SupportFragment": true, 35 | "AuthKey": "1234567890", 36 | "FilterChain": ["session-filter-trace","session-filter-auth","session-filter-keepalive"], 37 | "HandlerChain": ["session-srv-registe"] 38 | } 39 | ] 40 | }, 41 | 42 | "tx": { 43 | "TxSkeletonName": "github.com/idealeak/goserver/srvlib/txcommskeleton" 44 | }, 45 | 46 | "core": { 47 | "MaxProcs": 4 48 | } 49 | } -------------------------------------------------------------------------------- /examples/txserver2/dependent.go: -------------------------------------------------------------------------------- 1 | // dummy 2 | package main 3 | 4 | import ( 5 | _ "github.com/idealeak/goserver/core/builtin/action" 6 | _ "github.com/idealeak/goserver/core/builtin/filter" 7 | _ "github.com/idealeak/goserver/srvlib" 8 | _ "github.com/idealeak/goserver/srvlib/handler" 9 | ) 10 | -------------------------------------------------------------------------------- /examples/txserver2/logger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/txserver2/main.go: -------------------------------------------------------------------------------- 1 | // main 2 | package main 3 | 4 | import ( 5 | "github.com/idealeak/goserver/core" 6 | "github.com/idealeak/goserver/core/module" 7 | ) 8 | 9 | func main() { 10 | defer core.ClosePackages() 11 | core.LoadPackages("config.json") 12 | 13 | waiter := module.Start() 14 | waiter.Wait("main") 15 | } 16 | -------------------------------------------------------------------------------- /mmo/accountsrv/doc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Account server. 4 | // Responsibilities: 5 | // 1:Responsible for account verification, login, logout. 6 | -------------------------------------------------------------------------------- /mmo/accountsrv/logger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /mmo/accountsrv/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "github.com/idealeak/goserver/mmo" 5 | 6 | "github.com/idealeak/goserver/core" 7 | "github.com/idealeak/goserver/core/module" 8 | ) 9 | 10 | func main() { 11 | defer core.ClosePackages() 12 | core.LoadPackages("config.json") 13 | 14 | waiter := module.Start() 15 | waiter.Wait("main") 16 | } 17 | -------------------------------------------------------------------------------- /mmo/balancesrv/doc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Load balancing server in traditional sense. 4 | // Responsibilities: 5 | // 1:according to the load on each gatesrv, select the current load a minimum. 6 | -------------------------------------------------------------------------------- /mmo/balancesrv/logger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /mmo/balancesrv/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "github.com/idealeak/goserver/mmo" 5 | 6 | "github.com/idealeak/goserver/core" 7 | "github.com/idealeak/goserver/core/module" 8 | ) 9 | 10 | func main() { 11 | defer core.ClosePackages() 12 | core.LoadPackages("config.json") 13 | 14 | waiter := module.Start() 15 | waiter.Wait("main") 16 | } 17 | -------------------------------------------------------------------------------- /mmo/build.bat: -------------------------------------------------------------------------------- 1 | cd accountsrv 2 | go build 3 | cd ../balancesrv 4 | go build 5 | cd ../gamesrv 6 | go build 7 | cd ../gatesrv 8 | go build 9 | cd ../mgrsrv 10 | go build 11 | cd ../worldsrv 12 | go build 13 | pause -------------------------------------------------------------------------------- /mmo/clean.bat: -------------------------------------------------------------------------------- 1 | del /F/S accountsrv\accountsrv.exe 2 | del /F/S balancesrv\balancesrv.exe 3 | del /F/S gamesrv\gamesrv.exe 4 | del /F/S gatesrv\gatesrv.exe 5 | del /F/S mgrsrv\mgrsrv.exe 6 | del /F/S worldsrv\worldsrv.exe -------------------------------------------------------------------------------- /mmo/client/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "netlib": { 3 | "SrvInfo":{ 4 | "Name": "Client", 5 | "Type": 1, 6 | "Id": 1, 7 | "AreaID": 1, 8 | "Banner": [ 9 | "=================", 10 | "client", 11 | "=================" 12 | ] 13 | }, 14 | 15 | "IoServices": [ 16 | { 17 | "Id": 101, 18 | "Type": 1, 19 | "AreaId": 1, 20 | "Name": "ClientService", 21 | "Ip": "127.0.0.1", 22 | "Port": 11001, 23 | "MaxDone": 20, 24 | "MaxPend": 20, 25 | "MaxPacket": 1024, 26 | "MaxConn": 1, 27 | "RcvBuff": 1024, 28 | "SndBuff": 1024, 29 | "WriteTimeout": 30, 30 | "ReadTimeout": 30, 31 | "SoLinger": 10, 32 | "IsInnerLink": false, 33 | "IsClient": true, 34 | "NoDelay": true, 35 | "SupportFragment": true, 36 | "AuthKey": "1234567890", 37 | "FilterChain": ["session-filter-trace","session-filter-auth"], 38 | "HandlerChain": [] 39 | } 40 | ] 41 | }, 42 | 43 | "module": { 44 | "Options": { 45 | "QueueBacklog": 1024, 46 | "MaxDone": 1024, 47 | "Interval": 100 48 | } 49 | }, 50 | 51 | "executor": { 52 | "Options": { 53 | "QueueBacklog": 1024, 54 | "MaxDone": 1024, 55 | "Interval": 0 56 | }, 57 | "Worker": { 58 | "WorkerCnt": 8, 59 | "Options": { 60 | "QueueBacklog": 1024, 61 | "MaxDone": 1024, 62 | "Interval": 0 63 | } 64 | } 65 | }, 66 | 67 | "timer": { 68 | "Options": { 69 | "QueueBacklog": 1024, 70 | "MaxDone": 1024, 71 | "Interval": 100 72 | } 73 | }, 74 | 75 | "core": { 76 | "MaxProcs": 4 77 | }, 78 | 79 | "cmdline": { 80 | "SupportCmdLine": true 81 | } 82 | } -------------------------------------------------------------------------------- /mmo/client/logger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /mmo/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "github.com/idealeak/goserver/mmo" 5 | 6 | "github.com/idealeak/goserver/core" 7 | "github.com/idealeak/goserver/core/module" 8 | ) 9 | 10 | func main() { 11 | defer core.ClosePackages() 12 | core.LoadPackages("config.json") 13 | 14 | waiter := module.Start() 15 | waiter.Wait("main") 16 | } 17 | -------------------------------------------------------------------------------- /mmo/client/packet_scgateinfo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core/logger" 5 | "github.com/idealeak/goserver/core/netlib" 6 | "github.com/idealeak/goserver/mmo/protocol" 7 | ) 8 | 9 | func init() { 10 | netlib.RegisterFactory(int(protocol.MmoPacketID_PACKET_SC_GATEINFO), netlib.PacketFactoryWrapper(func() interface{} { 11 | return &protocol.SCGateInfo{} 12 | })) 13 | netlib.RegisterHandler(int(protocol.MmoPacketID_PACKET_SC_GATEINFO), netlib.HandlerWrapper(func(s *netlib.Session, packetid int, pack interface{}) error { 14 | logger.Logger.Trace("receive gateinfo==", pack) 15 | if sr, ok := pack.(*protocol.SCGateInfo); ok { 16 | sc := &netlib.SessionConfig{ 17 | Id: int(sr.GetSrvId()), 18 | Type: int(sr.GetSrvType()), 19 | Ip: sr.GetIp(), 20 | Port: int(sr.GetPort()), 21 | AuthKey: sr.GetAuthKey(), 22 | WriteTimeout: 30, 23 | ReadTimeout: 30, 24 | IdleTimeout: 30, 25 | MaxDone: 20, 26 | MaxPend: 20, 27 | MaxPacket: 1024, 28 | RcvBuff: 1024, 29 | SndBuff: 1024, 30 | IsClient: true, 31 | NoDelay: true, 32 | FilterChain: []string{"session-filter-trace", "session-filter-auth"}, 33 | } 34 | sc.Init() 35 | err := netlib.Connect(sc) 36 | if err != nil { 37 | logger.Logger.Warn("connect server failed err:", err) 38 | } 39 | } 40 | return nil 41 | })) 42 | } 43 | -------------------------------------------------------------------------------- /mmo/close.bat: -------------------------------------------------------------------------------- 1 | TASKKILL /F /IM accountsrv.exe 2 | TASKKILL /F /IM balancesrv.exe 3 | TASKKILL /F /IM gamesrv.exe 4 | TASKKILL /F /IM gatesrv.exe 5 | TASKKILL /F /IM mgrsrv.exe 6 | TASKKILL /F /IM worldsrv.exe -------------------------------------------------------------------------------- /mmo/clrlogs.bat: -------------------------------------------------------------------------------- 1 | del /F/S accountsrv\all.log 2 | del /F/S balancesrv\all.log 3 | del /F/S gamesrv\all.log 4 | del /F/S gatesrv\all.log 5 | del /F/S mgrsrv\all.log 6 | del /F/S worldsrv\all.log -------------------------------------------------------------------------------- /mmo/gamesrv/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "netlib": { 3 | "SrvInfo":{ 4 | "Name": "GameServer", 5 | "Type": 7, 6 | "Id": 701, 7 | "AreaID": 1, 8 | "Banner": [ 9 | "=================", 10 | "game server", 11 | "=================" 12 | ] 13 | }, 14 | 15 | "IoServices": [ 16 | { 17 | "Id": 701, 18 | "Type": 7, 19 | "AreaId": 1, 20 | "Name": "GameService", 21 | "Ip": "127.0.0.1", 22 | "Port": 7001, 23 | "MaxDone": 20, 24 | "MaxPend": 20, 25 | "MaxPacket": 65535, 26 | "MaxConn": 10000, 27 | "RcvBuff": 8192, 28 | "SndBuff": 8192, 29 | "WriteTimeout": 30, 30 | "ReadTimeout": 30, 31 | "IsInnerLink": true, 32 | "NoDelay": true, 33 | "SupportFragment": true, 34 | "AuthKey": "1234567890", 35 | "FilterChain": ["session-filter-auth","session-filter-keepalive"], 36 | "HandlerChain": ["session-srv-registe"] 37 | }, 38 | { 39 | "Id": 501, 40 | "Type": 5, 41 | "AreaId": 1, 42 | "Name": "ManagerService", 43 | "Ip": "127.0.0.1", 44 | "Port": 5555, 45 | "MaxDone": 20, 46 | "MaxPend": 20, 47 | "MaxPacket": 65535, 48 | "MaxConn": 10000, 49 | "RcvBuff": 8192, 50 | "SndBuff": 8192, 51 | "WriteTimeout": 30, 52 | "ReadTimeout": 30, 53 | "IsInnerLink": true, 54 | "NoDelay": true, 55 | "IsClient": true, 56 | "SupportFragment": true, 57 | "AuthKey": "1234567890", 58 | "FilterChain": ["session-filter-auth","session-filter-keepalive"], 59 | "HandlerChain": ["session-srv-registe","srv-service-handler"] 60 | } 61 | ] 62 | }, 63 | 64 | "module": { 65 | "Options": { 66 | "QueueBacklog": 1024, 67 | "MaxDone": 1024, 68 | "Interval": 100 69 | } 70 | }, 71 | 72 | "executor": { 73 | "Options": { 74 | "QueueBacklog": 1024, 75 | "MaxDone": 1024, 76 | "Interval": 0 77 | }, 78 | "Worker": { 79 | "WorkerCnt": 8, 80 | "Options": { 81 | "QueueBacklog": 1024, 82 | "MaxDone": 1024, 83 | "Interval": 0 84 | } 85 | } 86 | }, 87 | 88 | "timer": { 89 | "Options": { 90 | "QueueBacklog": 1024, 91 | "MaxDone": 1024, 92 | "Interval": 100 93 | } 94 | }, 95 | 96 | "core": { 97 | "MaxProcs": 4 98 | }, 99 | 100 | "cmdline": { 101 | "SupportCmdLine": true 102 | } 103 | } -------------------------------------------------------------------------------- /mmo/gamesrv/doc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Game logic server. 4 | // Responsibilities: 5 | // 1:The logic is mainly responsible for the game. 6 | -------------------------------------------------------------------------------- /mmo/gamesrv/logger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /mmo/gamesrv/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "github.com/idealeak/goserver/mmo" 5 | 6 | "github.com/idealeak/goserver/core" 7 | "github.com/idealeak/goserver/core/module" 8 | ) 9 | 10 | func main() { 11 | defer core.ClosePackages() 12 | core.LoadPackages("config.json") 13 | 14 | waiter := module.Start() 15 | waiter.Wait("main") 16 | } 17 | -------------------------------------------------------------------------------- /mmo/gatesrv/broadcasthandler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "code.google.com/p/goprotobuf/proto" 5 | "github.com/idealeak/goserver/core/logger" 6 | "github.com/idealeak/goserver/core/netlib" 7 | "github.com/idealeak/goserver/srvlib" 8 | "github.com/idealeak/goserver/srvlib/protocol" 9 | ) 10 | 11 | var ( 12 | BroadcastMaker = &BroadcastPacketFactory{} 13 | ) 14 | 15 | type BroadcastPacketFactory struct { 16 | } 17 | 18 | type BroadcastHandler struct { 19 | } 20 | 21 | func init() { 22 | netlib.RegisterHandler(int(protocol.SrvlibPacketID_PACKET_SS_BROADCAST), &BroadcastHandler{}) 23 | netlib.RegisterFactory(int(protocol.SrvlibPacketID_PACKET_SS_BROADCAST), BroadcastMaker) 24 | } 25 | 26 | func (this *BroadcastPacketFactory) CreatePacket() interface{} { 27 | pack := &protocol.SSPacketBroadcast{} 28 | return pack 29 | } 30 | 31 | func (this *BroadcastPacketFactory) CreateBroadcastPacket(sp *protocol.BCSessionUnion, packetid int, data interface{}) (proto.Message, error) { 32 | pack := &protocol.SSPacketBroadcast{ 33 | SessParam: sp, 34 | PacketId: proto.Int(packetid), 35 | } 36 | if byteData, ok := data.([]byte); ok { 37 | pack.Data = byteData 38 | } else { 39 | byteData, err := netlib.MarshalPacket(packetid, data) 40 | if err == nil { 41 | pack.Data = byteData 42 | } else { 43 | logger.Logger.Warn("BroadcastPacketFactory.CreateBroadcastPacket err:", err) 44 | return nil, err 45 | } 46 | } 47 | proto.SetDefaults(pack) 48 | return pack, nil 49 | } 50 | 51 | func (this *BroadcastHandler) Process(s *netlib.Session, packetid int, data interface{}) error { 52 | if bp, ok := data.(*protocol.SSPacketBroadcast); ok { 53 | pd := bp.GetData() 54 | sp := bp.GetSessParam() 55 | if bcss := sp.GetBcss(); bcss != nil { 56 | srvlib.ServerSessionMgrSington.Broadcast(int(bp.GetPacketId()), pd, int(bcss.GetSArea()), int(bcss.GetSType())) 57 | } else { 58 | BundleMgrSington.Broadcast(int(bp.GetPacketId()), pd) 59 | } 60 | } 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /mmo/gatesrv/clientsessionload.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "code.google.com/p/goprotobuf/proto" 5 | "github.com/idealeak/goserver/core/logger" 6 | "github.com/idealeak/goserver/core/netlib" 7 | "github.com/idealeak/goserver/mmo/protocol" 8 | "github.com/idealeak/goserver/srvlib" 9 | ) 10 | 11 | var ( 12 | SessionHandlerClientLoadName = "handler-client-load" 13 | ) 14 | 15 | type SessionHandlerClientLoad struct { 16 | netlib.BasicSessionHandler 17 | } 18 | 19 | func (sfcl SessionHandlerClientLoad) GetName() string { 20 | return SessionHandlerClientLoadName 21 | } 22 | 23 | func (sfcl *SessionHandlerClientLoad) GetInterestOps() uint { 24 | return 1< 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /mmo/gatesrv/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "github.com/idealeak/goserver/mmo" 5 | 6 | "github.com/idealeak/goserver/core" 7 | "github.com/idealeak/goserver/core/module" 8 | ) 9 | 10 | func main() { 11 | defer core.ClosePackages() 12 | core.LoadPackages("config.json") 13 | 14 | waiter := module.Start() 15 | waiter.Wait("main") 16 | } 17 | -------------------------------------------------------------------------------- /mmo/gatesrv/multicasthandler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "code.google.com/p/goprotobuf/proto" 5 | "github.com/idealeak/goserver/core/logger" 6 | "github.com/idealeak/goserver/core/netlib" 7 | "github.com/idealeak/goserver/srvlib" 8 | "github.com/idealeak/goserver/srvlib/protocol" 9 | ) 10 | 11 | var ( 12 | MulticastMaker = &MulticastPacketFactory{} 13 | ) 14 | 15 | type MulticastPacketFactory struct { 16 | } 17 | 18 | type MulticastHandler struct { 19 | } 20 | 21 | func init() { 22 | netlib.RegisterHandler(int(protocol.SrvlibPacketID_PACKET_SS_MULTICAST), &MulticastHandler{}) 23 | netlib.RegisterFactory(int(protocol.SrvlibPacketID_PACKET_SS_MULTICAST), MulticastMaker) 24 | } 25 | 26 | func (this *MulticastPacketFactory) CreatePacket() interface{} { 27 | pack := &protocol.SSPacketMulticast{} 28 | return pack 29 | } 30 | 31 | func (this *MulticastPacketFactory) CreateMulticastPacket(packetid int, data interface{}, sis ...*protocol.MCSessionUnion) (proto.Message, error) { 32 | pack := &protocol.SSPacketMulticast{ 33 | Sessions: sis, 34 | PacketId: proto.Int(packetid), 35 | } 36 | if byteData, ok := data.([]byte); ok { 37 | pack.Data = byteData 38 | } else { 39 | byteData, err := netlib.MarshalPacket(packetid, data) 40 | if err == nil { 41 | pack.Data = byteData 42 | } else { 43 | logger.Logger.Info("MulticastPacketFactory.CreateMulticastPacket err:", err) 44 | return nil, err 45 | } 46 | } 47 | proto.SetDefaults(pack) 48 | return pack, nil 49 | } 50 | 51 | func (this *MulticastHandler) Process(s *netlib.Session, packetid int, data interface{}) error { 52 | if mp, ok := data.(*protocol.SSPacketMulticast); ok { 53 | pd := mp.GetData() 54 | sis := mp.GetSessions() 55 | for _, si := range sis { 56 | cs := si.GetMccs() 57 | if cs != nil { 58 | sid := srvlib.SessionId(cs.GetSId()) 59 | bundleId := sid.SeqId() 60 | bs := BundleMgrSington.GetBundleSession(uint16(bundleId)) 61 | if bs != nil { 62 | bs.Send(int(mp.GetPacketId()), pd) 63 | } 64 | } else { 65 | ss := si.GetMcss() 66 | if ss != nil { 67 | ns := srvlib.ServerSessionMgrSington.GetSession(int(ss.GetSArea()), int(ss.GetSType()), int(ss.GetSId())) 68 | if ns != nil { 69 | ns.Send(int(mp.GetPacketId()), pd /*, s.GetSessionConfig().IsInnerLink*/) 70 | } 71 | } 72 | } 73 | } 74 | } 75 | return nil 76 | } 77 | -------------------------------------------------------------------------------- /mmo/gatesrv/packetdispatchhandler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "sync/atomic" 6 | 7 | "code.google.com/p/goprotobuf/proto" 8 | "games.jiexunjiayin.com/jxjyqp/protocol" 9 | "github.com/idealeak/goserver/core/builtin/filter" 10 | "github.com/idealeak/goserver/core/logger" 11 | "github.com/idealeak/goserver/core/netlib" 12 | ) 13 | 14 | func init() { 15 | netlib.RegisteErrorPacketHandlerCreator("packetdispatchhandler", func() netlib.ErrorPacketHandler { 16 | return netlib.ErrorPacketHandlerWrapper(func(s *netlib.Session, packetid int, logicNo uint32, data []byte) bool { 17 | if s.GetAttribute(filter.SessionAttributeAuth) == nil { 18 | logger.Logger.Trace("packetdispatchhandler session not auth! ") 19 | return false 20 | } 21 | 22 | bs := BundleMgrSington.GetBundleSession(uint16(s.GroupId)) 23 | if bs == nil { 24 | logger.Logger.Trace("packetdispatchhandler BundleSession is nil! ") 25 | return false 26 | } 27 | 28 | if atomic.CompareAndSwapUint32(&bs.rcvLogicNo, logicNo-1, logicNo) { 29 | var ss *netlib.Session 30 | if packetid >= 2000 && packetid < 3000 { 31 | ss = bs.worldsrvSession 32 | } else { 33 | ss = bs.gamesrvSession 34 | } 35 | if ss == nil { 36 | logger.Logger.Trace("packetdispatchhandler redirect server session is nil ", packetid) 37 | return true 38 | } 39 | //must copy 40 | buf := bytes.NewBuffer(nil) 41 | buf.Write(data) 42 | pack := &protocol.SSTransmit{ 43 | SessionId: proto.Int64(s.Sid), 44 | PacketData: buf.Bytes(), 45 | } 46 | proto.SetDefaults(pack) 47 | ss.Send(int(protocol.MmoPacketID_PACKET_SS_PACKET_TRANSMIT), pack) 48 | return true 49 | } 50 | 51 | //丢掉 52 | return false 53 | }) 54 | }) 55 | } 56 | -------------------------------------------------------------------------------- /mmo/gen_go.bat: -------------------------------------------------------------------------------- 1 | protoc --go_out=. protocol/*.proto 2 | pause -------------------------------------------------------------------------------- /mmo/imports.go: -------------------------------------------------------------------------------- 1 | package mmo 2 | 3 | import ( 4 | _ "github.com/idealeak/goserver/core/builtin/action" 5 | _ "github.com/idealeak/goserver/core/builtin/filter" 6 | _ "github.com/idealeak/goserver/core/cmdline" 7 | _ "github.com/idealeak/goserver/core/netlib" 8 | _ "github.com/idealeak/goserver/core/signal" 9 | _ "github.com/idealeak/goserver/srvlib/action" 10 | _ "github.com/idealeak/goserver/srvlib/handler" 11 | ) 12 | -------------------------------------------------------------------------------- /mmo/mgrsrv/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "netlib": { 3 | "SrvInfo":{ 4 | "Name": "ManagerServer", 5 | "Type": 5, 6 | "Id": 501, 7 | "AreaID": 1, 8 | "Banner": [ 9 | "=================", 10 | "manager server", 11 | "=================" 12 | ] 13 | }, 14 | 15 | "IoServices": [ 16 | { 17 | "Id": 501, 18 | "Type": 5, 19 | "AreaId": 1, 20 | "Name": "ManagerService", 21 | "Ip": "", 22 | "Port": 5555, 23 | "MaxDone": 20, 24 | "MaxPend": 20, 25 | "MaxPacket": 65535, 26 | "MaxConn": 10000, 27 | "RcvBuff": 8192, 28 | "SndBuff": 8192, 29 | "WriteTimeout": 30, 30 | "ReadTimeout": 30, 31 | "IsInnerLink": true, 32 | "NoDelay": true, 33 | "SupportFragment": true, 34 | "AuthKey": "1234567890", 35 | "FilterChain": ["session-filter-auth","session-filter-keepalive"], 36 | "HandlerChain": ["session-srv-registe","srv-service-handler"] 37 | } 38 | ] 39 | }, 40 | 41 | "module": { 42 | "Options": { 43 | "QueueBacklog": 1024, 44 | "MaxDone": 1024, 45 | "Interval": 100 46 | } 47 | }, 48 | 49 | "executor": { 50 | "Options": { 51 | "QueueBacklog": 1024, 52 | "MaxDone": 1024, 53 | "Interval": 0 54 | }, 55 | "Worker": { 56 | "WorkerCnt": 8, 57 | "Options": { 58 | "QueueBacklog": 1024, 59 | "MaxDone": 1024, 60 | "Interval": 0 61 | } 62 | } 63 | }, 64 | 65 | "timer": { 66 | "Options": { 67 | "QueueBacklog": 1024, 68 | "MaxDone": 1024, 69 | "Interval": 100 70 | } 71 | }, 72 | 73 | "core": { 74 | "MaxProcs": 4 75 | }, 76 | 77 | "cmdline": { 78 | "SupportCmdLine": true 79 | } 80 | } -------------------------------------------------------------------------------- /mmo/mgrsrv/doc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Responsibilities: 4 | // 1:responsible for managing the relationship between the server group. 5 | // 2:message forwarding. 6 | -------------------------------------------------------------------------------- /mmo/mgrsrv/logger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /mmo/mgrsrv/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "github.com/idealeak/goserver/mmo" 5 | 6 | "github.com/idealeak/goserver/core" 7 | "github.com/idealeak/goserver/core/module" 8 | ) 9 | 10 | func main() { 11 | defer core.ClosePackages() 12 | core.LoadPackages("config.json") 13 | 14 | waiter := module.Start() 15 | waiter.Wait("main") 16 | } 17 | -------------------------------------------------------------------------------- /mmo/protocol/gateinfo.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: protocol/gateinfo.proto 3 | // DO NOT EDIT! 4 | 5 | package protocol 6 | 7 | import proto "code.google.com/p/goprotobuf/proto" 8 | import json "encoding/json" 9 | import math "math" 10 | 11 | // Reference proto, json, and math imports to suppress error if they are not otherwise used. 12 | var _ = proto.Marshal 13 | var _ = &json.SyntaxError{} 14 | var _ = math.Inf 15 | 16 | type SCGateInfo struct { 17 | SrvType *int32 `protobuf:"varint,1,opt" json:"SrvType,omitempty"` 18 | SrvId *int32 `protobuf:"varint,2,opt" json:"SrvId,omitempty"` 19 | AuthKey *string `protobuf:"bytes,3,opt" json:"AuthKey,omitempty"` 20 | Ip *string `protobuf:"bytes,4,opt" json:"Ip,omitempty"` 21 | Port *int32 `protobuf:"varint,5,opt" json:"Port,omitempty"` 22 | XXX_unrecognized []byte `json:"-"` 23 | } 24 | 25 | func (m *SCGateInfo) Reset() { *m = SCGateInfo{} } 26 | func (m *SCGateInfo) String() string { return proto.CompactTextString(m) } 27 | func (*SCGateInfo) ProtoMessage() {} 28 | 29 | func (m *SCGateInfo) GetSrvType() int32 { 30 | if m != nil && m.SrvType != nil { 31 | return *m.SrvType 32 | } 33 | return 0 34 | } 35 | 36 | func (m *SCGateInfo) GetSrvId() int32 { 37 | if m != nil && m.SrvId != nil { 38 | return *m.SrvId 39 | } 40 | return 0 41 | } 42 | 43 | func (m *SCGateInfo) GetAuthKey() string { 44 | if m != nil && m.AuthKey != nil { 45 | return *m.AuthKey 46 | } 47 | return "" 48 | } 49 | 50 | func (m *SCGateInfo) GetIp() string { 51 | if m != nil && m.Ip != nil { 52 | return *m.Ip 53 | } 54 | return "" 55 | } 56 | 57 | func (m *SCGateInfo) GetPort() int32 { 58 | if m != nil && m.Port != nil { 59 | return *m.Port 60 | } 61 | return 0 62 | } 63 | 64 | func init() { 65 | } 66 | -------------------------------------------------------------------------------- /mmo/protocol/gateinfo.proto: -------------------------------------------------------------------------------- 1 | package protocol; 2 | 3 | 4 | message SCGateInfo { 5 | optional int32 SrvType = 1; 6 | optional int32 SrvId = 2; 7 | optional string AuthKey = 3; 8 | optional string Ip = 4; 9 | optional int32 Port = 5; 10 | } 11 | 12 | message CSSessionBundle { 13 | required string Key = 1; 14 | required int64 Ts = 2; 15 | } 16 | 17 | message CSSessionAck { 18 | required uint32 LogicNo = 1; 19 | } -------------------------------------------------------------------------------- /mmo/protocol/packetid.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: protocol/packetid.proto 3 | // DO NOT EDIT! 4 | 5 | package protocol 6 | 7 | import proto "code.google.com/p/goprotobuf/proto" 8 | import json "encoding/json" 9 | import math "math" 10 | 11 | // Reference proto, json, and math imports to suppress error if they are not otherwise used. 12 | var _ = proto.Marshal 13 | var _ = &json.SyntaxError{} 14 | var _ = math.Inf 15 | 16 | type MmoPacketID int32 17 | 18 | const ( 19 | MmoPacketID_PACKET_GB_CUR_LOAD MmoPacketID = 1000 20 | MmoPacketID_PACKET_GB_STATE_SWITCH MmoPacketID = 1001 21 | MmoPacketID_PACKET_SC_GATEINFO MmoPacketID = 1002 22 | ) 23 | 24 | var MmoPacketID_name = map[int32]string{ 25 | 1000: "PACKET_GB_CUR_LOAD", 26 | 1001: "PACKET_GB_STATE_SWITCH", 27 | 1002: "PACKET_SC_GATEINFO", 28 | } 29 | var MmoPacketID_value = map[string]int32{ 30 | "PACKET_GB_CUR_LOAD": 1000, 31 | "PACKET_GB_STATE_SWITCH": 1001, 32 | "PACKET_SC_GATEINFO": 1002, 33 | } 34 | 35 | func (x MmoPacketID) Enum() *MmoPacketID { 36 | p := new(MmoPacketID) 37 | *p = x 38 | return p 39 | } 40 | func (x MmoPacketID) String() string { 41 | return proto.EnumName(MmoPacketID_name, int32(x)) 42 | } 43 | func (x MmoPacketID) MarshalJSON() ([]byte, error) { 44 | return json.Marshal(x.String()) 45 | } 46 | func (x *MmoPacketID) UnmarshalJSON(data []byte) error { 47 | value, err := proto.UnmarshalJSONEnum(MmoPacketID_value, data, "MmoPacketID") 48 | if err != nil { 49 | return err 50 | } 51 | *x = MmoPacketID(value) 52 | return nil 53 | } 54 | 55 | func init() { 56 | proto.RegisterEnum("protocol.MmoPacketID", MmoPacketID_name, MmoPacketID_value) 57 | } 58 | -------------------------------------------------------------------------------- /mmo/protocol/packetid.proto: -------------------------------------------------------------------------------- 1 | package protocol; 2 | 3 | enum MmoPacketID { 4 | PACKET_GB_CUR_LOAD = 1000; 5 | PACKET_GB_STATE_SWITCH = 1001; 6 | PACKET_SC_GATEINFO = 1002; 7 | PACKET_CS_SESSIONBUNDLE = 1003; 8 | PACKET_CS_SESSIONACK = 1004; 9 | } -------------------------------------------------------------------------------- /mmo/protocol/serverload.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: protocol/serverload.proto 3 | // DO NOT EDIT! 4 | 5 | package protocol 6 | 7 | import proto "code.google.com/p/goprotobuf/proto" 8 | import json "encoding/json" 9 | import math "math" 10 | 11 | // Reference proto, json, and math imports to suppress error if they are not otherwise used. 12 | var _ = proto.Marshal 13 | var _ = &json.SyntaxError{} 14 | var _ = math.Inf 15 | 16 | type ServerLoad struct { 17 | SrvType *int32 `protobuf:"varint,1,req" json:"SrvType,omitempty"` 18 | SrvId *int32 `protobuf:"varint,2,req" json:"SrvId,omitempty"` 19 | CurLoad *int32 `protobuf:"varint,3,req" json:"CurLoad,omitempty"` 20 | XXX_unrecognized []byte `json:"-"` 21 | } 22 | 23 | func (m *ServerLoad) Reset() { *m = ServerLoad{} } 24 | func (m *ServerLoad) String() string { return proto.CompactTextString(m) } 25 | func (*ServerLoad) ProtoMessage() {} 26 | 27 | func (m *ServerLoad) GetSrvType() int32 { 28 | if m != nil && m.SrvType != nil { 29 | return *m.SrvType 30 | } 31 | return 0 32 | } 33 | 34 | func (m *ServerLoad) GetSrvId() int32 { 35 | if m != nil && m.SrvId != nil { 36 | return *m.SrvId 37 | } 38 | return 0 39 | } 40 | 41 | func (m *ServerLoad) GetCurLoad() int32 { 42 | if m != nil && m.CurLoad != nil { 43 | return *m.CurLoad 44 | } 45 | return 0 46 | } 47 | 48 | type ServerStateSwitch struct { 49 | SrvType *int32 `protobuf:"varint,1,req" json:"SrvType,omitempty"` 50 | SrvId *int32 `protobuf:"varint,2,req" json:"SrvId,omitempty"` 51 | XXX_unrecognized []byte `json:"-"` 52 | } 53 | 54 | func (m *ServerStateSwitch) Reset() { *m = ServerStateSwitch{} } 55 | func (m *ServerStateSwitch) String() string { return proto.CompactTextString(m) } 56 | func (*ServerStateSwitch) ProtoMessage() {} 57 | 58 | func (m *ServerStateSwitch) GetSrvType() int32 { 59 | if m != nil && m.SrvType != nil { 60 | return *m.SrvType 61 | } 62 | return 0 63 | } 64 | 65 | func (m *ServerStateSwitch) GetSrvId() int32 { 66 | if m != nil && m.SrvId != nil { 67 | return *m.SrvId 68 | } 69 | return 0 70 | } 71 | 72 | func init() { 73 | } 74 | -------------------------------------------------------------------------------- /mmo/protocol/serverload.proto: -------------------------------------------------------------------------------- 1 | package protocol; 2 | 3 | message ServerLoad { 4 | required int32 SrvType = 1; 5 | required int32 SrvId = 2; 6 | required int32 CurLoad = 3; 7 | } 8 | 9 | message ServerStateSwitch { 10 | required int32 SrvType = 1; 11 | required int32 SrvId = 2; 12 | } -------------------------------------------------------------------------------- /mmo/startup.bat: -------------------------------------------------------------------------------- 1 | cd accountsrv 2 | start accountsrv 3 | cd ../balancesrv 4 | start balancesrv 5 | cd ../gamesrv 6 | start gamesrv 7 | cd ../gatesrv 8 | start gatesrv 9 | cd ../mgrsrv 10 | start mgrsrv 11 | cd ../worldsrv 12 | start worldsrv -------------------------------------------------------------------------------- /mmo/worldsrv/doc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Game world server(The whole world only). 4 | // Responsibilities: 5 | // 1:Responsible for the overall business in the game. 6 | // For example: social relations 7 | -------------------------------------------------------------------------------- /mmo/worldsrv/logger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /mmo/worldsrv/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "github.com/idealeak/goserver/mmo" 5 | 6 | "github.com/idealeak/goserver/core" 7 | "github.com/idealeak/goserver/core/module" 8 | ) 9 | 10 | func main() { 11 | defer core.ClosePackages() 12 | core.LoadPackages("config.json") 13 | 14 | waiter := module.Start() 15 | waiter.Wait("main") 16 | } 17 | -------------------------------------------------------------------------------- /srvlib/action/redirecthandler.go: -------------------------------------------------------------------------------- 1 | package action 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core/logger" 5 | "github.com/idealeak/goserver/core/netlib" 6 | "github.com/idealeak/goserver/srvlib" 7 | "github.com/idealeak/goserver/srvlib/protocol" 8 | ) 9 | 10 | type PacketRedirectPacketFactory struct { 11 | } 12 | 13 | type PacketRedirectHandler struct { 14 | } 15 | 16 | func init() { 17 | netlib.RegisterHandler(int(protocol.SrvlibPacketID_PACKET_SS_REDIRECT), &PacketRedirectHandler{}) 18 | netlib.RegisterFactory(int(protocol.SrvlibPacketID_PACKET_SS_REDIRECT), &PacketRedirectPacketFactory{}) 19 | } 20 | 21 | func (this *PacketRedirectPacketFactory) CreatePacket() interface{} { 22 | pack := &protocol.SSPacketRedirect{} 23 | return pack 24 | } 25 | 26 | func (this *PacketRedirectHandler) Process(s *netlib.Session, packetid int, data interface{}) error { 27 | logger.Logger.Trace("PacketRedirectHandler.Process") 28 | if pr, ok := data.(*protocol.SSPacketRedirect); ok { 29 | packid, pack, err := netlib.UnmarshalPacket(pr.GetData()) 30 | if err != nil { 31 | return err 32 | } 33 | h := srvlib.GetHandler(packid) 34 | if h != nil { 35 | return h.Process(s, packid, pack, pr.GetClientSid(), pr.GetSrvRoutes()) 36 | } else { 37 | nh := netlib.GetHandler(packid) 38 | if nh != nil { 39 | return nh.Process(s, packid, pack) 40 | } 41 | } 42 | } 43 | return nil 44 | } 45 | -------------------------------------------------------------------------------- /srvlib/action/transithandler.go: -------------------------------------------------------------------------------- 1 | package action 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core/logger" 5 | "github.com/idealeak/goserver/core/netlib" 6 | "github.com/idealeak/goserver/srvlib" 7 | "github.com/idealeak/goserver/srvlib/protocol" 8 | ) 9 | 10 | type PacketTransitPacketFactory struct { 11 | } 12 | 13 | type PacketTransitHandler struct { 14 | } 15 | 16 | func init() { 17 | netlib.RegisterHandler(int(protocol.SrvlibPacketID_PACKET_SS_TRANSIT), &PacketTransitHandler{}) 18 | netlib.RegisterFactory(int(protocol.SrvlibPacketID_PACKET_SS_TRANSIT), &PacketTransitPacketFactory{}) 19 | } 20 | 21 | func (this *PacketTransitPacketFactory) CreatePacket() interface{} { 22 | pack := &protocol.SSPacketTransit{} 23 | return pack 24 | } 25 | 26 | func (this *PacketTransitHandler) Process(s *netlib.Session, packetid int, data interface{}) error { 27 | logger.Logger.Trace("PacketTransitHandler.Process") 28 | if pr, ok := data.(*protocol.SSPacketTransit); ok { 29 | targetS := srvlib.ServerSessionMgrSington.GetSession(int(pr.GetSArea()), int(pr.GetSType()), int(pr.GetSId())) 30 | if targetS != nil { 31 | targetS.Send(int(pr.GetPacketId()), pr.GetData()) 32 | } 33 | } 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /srvlib/clientsessionmgr.go: -------------------------------------------------------------------------------- 1 | package srvlib 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core/logger" 5 | "github.com/idealeak/goserver/core/netlib" 6 | ) 7 | 8 | var ( 9 | SessionAttributeClientSession = &ClientSessionMgr{} 10 | ClientSessionMgrSington = &ClientSessionMgr{sessions: make(map[int64]*netlib.Session)} 11 | ) 12 | 13 | type ClientSessionMgr struct { 14 | sessions map[int64]*netlib.Session //keys=>sessionid 15 | } 16 | 17 | func (csm *ClientSessionMgr) RegisteSession(s *netlib.Session) bool { 18 | attr := s.GetAttribute(SessionAttributeClientSession) 19 | if attr == nil { 20 | sid := NewSessionId(s) 21 | s.SetAttribute(SessionAttributeClientSession, sid) 22 | csm.sessions[sid.Get()] = s 23 | logger.Logger.Tracef("ClientSessionMgr(%p).RegisteSession client session %v registe", csm, sid.Get()) 24 | } 25 | return true 26 | } 27 | 28 | func (csm *ClientSessionMgr) UnregisteSession(s *netlib.Session) bool { 29 | attr := s.GetAttribute(SessionAttributeClientSession) 30 | if attr != nil { 31 | if sid, ok := attr.(SessionId); ok { 32 | delete(csm.sessions, sid.Get()) 33 | logger.Logger.Tracef("ClientSessionMgr(%p).UnregisteSession client session %v unregiste", csm, sid.Get()) 34 | } 35 | } 36 | return true 37 | } 38 | 39 | func (csm *ClientSessionMgr) GetSession(srvId int64) *netlib.Session { 40 | if s, exist := csm.sessions[srvId]; exist { 41 | return s 42 | } 43 | return nil 44 | } 45 | 46 | func (csm *ClientSessionMgr) GetSessions() map[int64]*netlib.Session { 47 | return csm.sessions 48 | } 49 | 50 | func (csm *ClientSessionMgr) Broadcast(packetid int, pack interface{}) { 51 | for _, s := range csm.sessions { 52 | s.Send(packetid, pack) 53 | } 54 | } 55 | 56 | func (csm *ClientSessionMgr) Count() int { 57 | return len(csm.sessions) 58 | } 59 | 60 | func (csm *ClientSessionMgr) CloseAll() { 61 | logger.Logger.Tracef("ClientSessionMgr(%p).CloseAll!!!!!!!!!!!! session's cnt=%v", csm, len(csm.sessions)) 62 | for _, s := range csm.sessions { 63 | s.Close() 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /srvlib/const.go: -------------------------------------------------------------------------------- 1 | package srvlib 2 | 3 | const ( 4 | UnknowServiceType int = 0 5 | ClientServiceType = 1 6 | BalanceServiceType = 2 7 | AccountServiceType = 3 8 | GateServiceType = 4 9 | ManagerServiceType = 5 10 | WorldServiceType = 6 11 | GameServiceType = 7 12 | MaxServiceType = 8 13 | ) 14 | 15 | const ( 16 | UnknowServerType int = 0 17 | _ 18 | BalanceServerType = 2 19 | AccountServerType = 3 20 | GateServerType = 4 21 | ManagerServerType = 5 22 | WorldServerType = 6 23 | GameServerType = 7 24 | MaxServerType = 8 25 | ) 26 | -------------------------------------------------------------------------------- /srvlib/gen_go.bat: -------------------------------------------------------------------------------- 1 | protoc --go_out=. protocol/*.proto 2 | pause -------------------------------------------------------------------------------- /srvlib/handler.go: -------------------------------------------------------------------------------- 1 | package srvlib 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "github.com/idealeak/goserver/core/netlib" 8 | "github.com/idealeak/goserver/srvlib/protocol" 9 | ) 10 | 11 | var handlers = make(map[int]Handler) 12 | 13 | type Handler interface { 14 | Process(s *netlib.Session, packetid int, data interface{}, sid int64, routes []*protocol.SrvInfo) error 15 | } 16 | 17 | type HandlerWrapper func(s *netlib.Session, packetid int, data interface{}, sid int64, routes []*protocol.SrvInfo) error 18 | 19 | func (hw HandlerWrapper) Process(s *netlib.Session, packetid int, data interface{}, sid int64, routes []*protocol.SrvInfo) error { 20 | return hw(s, packetid, data, sid, routes) 21 | } 22 | 23 | func RegisterHandler(packetId int, h Handler) { 24 | if _, ok := handlers[packetId]; ok { 25 | panic(fmt.Sprintf("repeate register handler: %v Handler type=%v", packetId, reflect.TypeOf(h))) 26 | } 27 | 28 | handlers[packetId] = h 29 | } 30 | 31 | func Register1ToMHandler(h Handler, packetIds ...int) { 32 | for _, packetId := range packetIds { 33 | RegisterHandler(packetId, h) 34 | } 35 | } 36 | 37 | func RegisterRangeHandler(start, end int, h Handler) { 38 | for ; start <= end; start++ { 39 | RegisterHandler(start, h) 40 | } 41 | } 42 | 43 | func GetHandler(packetId int) Handler { 44 | if h, ok := handlers[packetId]; ok { 45 | return h 46 | } 47 | 48 | return nil 49 | } 50 | -------------------------------------------------------------------------------- /srvlib/handler/clientsessionregiste.go: -------------------------------------------------------------------------------- 1 | // SessionHandlerClientRegiste 2 | package handler 3 | 4 | import ( 5 | "github.com/idealeak/goserver/core/netlib" 6 | "github.com/idealeak/goserver/srvlib" 7 | ) 8 | 9 | var ( 10 | SessionHandlerClientRegisteName = "session-client-registe" 11 | ) 12 | 13 | type SessionHandlerClientRegiste struct { 14 | } 15 | 16 | func (sfcr SessionHandlerClientRegiste) GetName() string { 17 | return SessionHandlerClientRegisteName 18 | } 19 | 20 | func (sfl *SessionHandlerClientRegiste) GetInterestOps() uint { 21 | return 1<", sc.Name) 30 | /*报告自己的监听信息*/ 31 | srvlib.ServiceMgr.ReportService(s) 32 | } else { 33 | s.SetAttribute(srvlib.SessionAttributeServiceFlag, 1) 34 | } 35 | } 36 | 37 | func (this *SessionHandlerServiceRegiste) OnSessionClosed(s *netlib.Session) { 38 | sc := s.GetSessionConfig() 39 | if !sc.IsClient { 40 | logger.Logger.Warn("SessionHandlerServiceRegiste:OnSessionClosed ClearServiceBySession") 41 | srvlib.ServiceMgr.ClearServiceBySession(s) 42 | } 43 | } 44 | 45 | func (this *SessionHandlerServiceRegiste) OnSessionIdle(s *netlib.Session) { 46 | } 47 | 48 | func (this *SessionHandlerServiceRegiste) OnPacketReceived(s *netlib.Session, packetid int, logicNo uint32, packet interface{}) { 49 | } 50 | 51 | func (this *SessionHandlerServiceRegiste) OnPacketSent(s *netlib.Session, packetid int, logicNo uint32, data []byte) { 52 | } 53 | 54 | func init() { 55 | netlib.RegisteSessionHandlerCreator(ServiceHandlerServiceRegisteName, func() netlib.SessionHandler { 56 | return &SessionHandlerServiceRegiste{} 57 | }) 58 | } 59 | -------------------------------------------------------------------------------- /srvlib/handler/serversessionregiste.go: -------------------------------------------------------------------------------- 1 | // SessionHandlerSrvRegiste 2 | package handler 3 | 4 | import ( 5 | "code.google.com/p/goprotobuf/proto" 6 | "github.com/idealeak/goserver/core/netlib" 7 | "github.com/idealeak/goserver/srvlib" 8 | "github.com/idealeak/goserver/srvlib/protocol" 9 | ) 10 | 11 | var ( 12 | SessionHandlerSrvRegisteName = "session-srv-registe" 13 | ) 14 | 15 | type SessionHandlerSrvRegiste struct { 16 | } 17 | 18 | func (sfl SessionHandlerSrvRegiste) GetName() string { 19 | return SessionHandlerSrvRegisteName 20 | } 21 | 22 | func (sfl *SessionHandlerSrvRegiste) GetInterestOps() uint { 23 | return 1<>SessionIdSrvAreaOffset) & SessionIdSrvAreaIdMask 48 | } 49 | 50 | func (id SessionId) SrvType() uint32 { 51 | return uint32(id>>SessionIdSrvTypeOffset) & SessionIdSrvTypeMask 52 | } 53 | 54 | func (id SessionId) SrvId() uint32 { 55 | return uint32(id>>SessionIdSrvIdOffset) & SessionIdSrvIdMask 56 | } 57 | 58 | func (id SessionId) SeqId() uint32 { 59 | return uint32(id) & SessionIdSeqIdMask 60 | } 61 | -------------------------------------------------------------------------------- /srvlib/srvertable.go: -------------------------------------------------------------------------------- 1 | package srvlib 2 | 3 | var ( 4 | sessionServiceERtable = make(map[int32][]int32) 5 | serviceSessionERtable = make(map[int32][]int32) 6 | ) 7 | 8 | var arrER = [][]int32{ 9 | {0, 0, 0, 0, 0, 0, 0, 0}, 10 | {0, 0, 0, 0, 0, 0, 0, 0}, 11 | {0, 0, 0, 0, 0, 0, 0, 0}, 12 | {0, 0, 0, 0, 0, 0, 0, 0}, 13 | {2, 3, 6, 7, 0, 0, 0, 0}, 14 | {0, 0, 0, 0, 0, 0, 0, 0}, 15 | {3, 0, 0, 0, 0, 0, 0, 0}, 16 | {6, 0, 0, 0, 0, 0, 0, 0}, 17 | } 18 | 19 | func init() { 20 | buildSessionTable() 21 | buildServiceTable() 22 | } 23 | 24 | func buildSessionTable() { 25 | for k1, v1 := range arrER { 26 | t := make([]int32, 0, MaxServerType) 27 | for _, v2 := range v1 { 28 | if v2 != 0 { 29 | t = append(t, int32(v2)) 30 | } 31 | } 32 | sessionServiceERtable[int32(k1)] = t 33 | } 34 | } 35 | 36 | func buildServiceTable() { 37 | for k1, v1 := range sessionServiceERtable { 38 | for _, v2 := range v1 { 39 | if _, has := serviceSessionERtable[v2]; !has { 40 | serviceSessionERtable[v2] = make([]int32, 0, MaxServerType) 41 | } 42 | 43 | serviceSessionERtable[v2] = append(serviceSessionERtable[v2], k1) 44 | } 45 | } 46 | } 47 | 48 | func SessionCareService(sessionType, serviceType int32) bool { 49 | if v, has := sessionServiceERtable[sessionType]; has { 50 | for _, service := range v { 51 | if service == serviceType { 52 | return true 53 | } 54 | } 55 | } 56 | 57 | return false 58 | } 59 | 60 | func GetCareSessionsByService(serviceType int32) []int32 { 61 | if v, has := serviceSessionERtable[serviceType]; has { 62 | return v 63 | } 64 | 65 | return nil 66 | } 67 | 68 | func GetCareServicesBySession(sessionType int32) []int32 { 69 | if v, has := sessionServiceERtable[sessionType]; has { 70 | return v 71 | } 72 | 73 | return nil 74 | } 75 | -------------------------------------------------------------------------------- /srvlib/txcommskeleton.go: -------------------------------------------------------------------------------- 1 | package srvlib 2 | 3 | import ( 4 | "github.com/idealeak/goserver/core/builtin/action" 5 | "github.com/idealeak/goserver/core/builtin/protocol" 6 | "github.com/idealeak/goserver/core/logger" 7 | "github.com/idealeak/goserver/core/netlib" 8 | "github.com/idealeak/goserver/core/transact" 9 | ) 10 | 11 | type TxCommSkeleton struct { 12 | } 13 | 14 | func (tcs *TxCommSkeleton) SendTransResult(parent, me *transact.TransNodeParam, tr *transact.TransResult) bool { 15 | //logger.Logger.Trace("TxCommSkeleton.SendTransResult") 16 | p := action.ContructTxResultPacket(parent, me, tr) 17 | if p == nil { 18 | return false 19 | } 20 | s := ServerSessionMgrSington.GetSession(parent.AreaID, int(parent.Ot), parent.Oid) 21 | if s == nil { 22 | logger.Logger.Trace("TxCommSkeleton.SendTransResult s=nil") 23 | return false 24 | } 25 | 26 | s.Send(int(protocol.CoreBuiltinPacketID_PACKET_SS_TX_RESULT), p) 27 | //logger.Logger.Trace("TxCommSkeleton.SendTransResult success") 28 | return true 29 | } 30 | 31 | func (tcs *TxCommSkeleton) SendTransStart(parent, me *transact.TransNodeParam, ud interface{}) bool { 32 | //logger.Logger.Trace("TxCommSkeleton.SendTransStart") 33 | p := action.ContructTxStartPacket(parent, me, ud) 34 | if p == nil { 35 | return false 36 | } 37 | s := ServerSessionMgrSington.GetSession(me.AreaID, int(me.Ot), me.Oid) 38 | if s == nil { 39 | logger.Logger.Trace("TxCommSkeleton.SendTransStart s=nil") 40 | return false 41 | } 42 | 43 | s.Send(int(protocol.CoreBuiltinPacketID_PACKET_SS_TX_START), p) 44 | return true 45 | } 46 | 47 | func (tcs *TxCommSkeleton) SendCmdToTransNode(tnp *transact.TransNodeParam, c transact.TransCmd) bool { 48 | //logger.Logger.Trace("TxCommSkeleton.SendCmdToTransNode") 49 | p := action.ConstructTxCmdPacket(tnp, c) 50 | if p == nil { 51 | return false 52 | } 53 | s := ServerSessionMgrSington.GetSession(tnp.AreaID, int(tnp.Ot), tnp.Oid) 54 | if s == nil { 55 | logger.Logger.Trace("TxCommSkeleton.SendCmdToTransNode s=nil") 56 | return false 57 | } 58 | 59 | s.Send(int(protocol.CoreBuiltinPacketID_PACKET_SS_TX_CMD), p) 60 | return true 61 | } 62 | 63 | func (tcs *TxCommSkeleton) GetSkeletonID() int { 64 | return netlib.Config.SrvInfo.Id 65 | } 66 | 67 | func (tcs *TxCommSkeleton) GetAreaID() int { 68 | return netlib.Config.SrvInfo.AreaID 69 | } 70 | 71 | func init() { 72 | transact.RegisteTxCommSkeleton("github.com/idealeak/goserver/srvlib/txcommskeleton", &TxCommSkeleton{}) 73 | } 74 | --------------------------------------------------------------------------------