├── README.md └── pomelo-go ├── bin └── gocode.exe └── src ├── agent ├── agent.go ├── masterAgent.go └── monitorAgent.go ├── component ├── cobackendsession │ └── cobackendsession.go ├── cochannel │ └── cochannel.go ├── cochannelrpcserver │ └── cochannelrpcserver.go ├── coconnection │ └── coconnection.go ├── coconnector │ └── coconnector.go ├── comaster │ └── comaster.go ├── comonitor │ └── comonitor.go ├── corpcclient │ └── corpcclient.go ├── corpcserver │ └── corpcserver.go ├── coserver │ └── coserver.go ├── cosession │ └── cosession.go └── cosessionrpcserver │ └── cosessionrpcserver.go ├── connector ├── connector_common.go └── tcp_connector │ ├── tcp_connector.go │ └── tcp_socket.go ├── context ├── context.go └── logConfig.xml ├── logger └── redis_log.go ├── main └── pomelo_go.go ├── master └── master.go ├── module ├── module.go └── reportInfo │ └── reportInfo.go ├── pomelo_admin ├── consoleService.go ├── masterConsoleService.go └── monitorConsoleService.go ├── remote_service ├── channelRpcServer │ └── channelRpcServer.go └── sessionRpcServer │ └── sessionRpcServer.go ├── rpcclient └── rpcClient.go ├── rpcserver └── rpcServer.go ├── server └── server.go ├── service ├── backendSessionService │ └── backendSessionService.go ├── channelService │ └── channelService.go ├── connectionService │ └── connectionService.go └── sessionService │ └── sessionService.go └── test ├── connectorTest ├── README ├── client │ ├── client.exe │ └── client.go └── server │ └── server.go ├── cosessionrpcserverTest ├── README ├── client │ ├── client.exe │ ├── client.go │ ├── criticalAndError.log │ ├── log.log │ └── logConfig.xml └── server │ ├── criticalAndError.log │ ├── log.log │ ├── logConfig.xml │ ├── server.exe~ │ └── server.go ├── reportInfoTest ├── master │ ├── masterConsole │ └── masterConsole.go └── monitorConsole │ ├── monitoConsole │ └── monitoConsole.go └── rpcTest ├── rpcClient ├── criticalAndError.log ├── log.log ├── logConfig.xml ├── rpcClient.exe └── rpcClient.go └── rpcServer ├── log.log ├── logConfig.xml ├── rpcServer.exe └── rpcServer.go /README.md: -------------------------------------------------------------------------------- 1 | # server-framework 2 | 基于pomelo/nodejs的go重写 3 | -------------------------------------------------------------------------------- /pomelo-go/bin/gocode.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liweisheng/server-framework/46df96a74ea25a936c0480eed9e6f41c6b104485/pomelo-go/bin/gocode.exe -------------------------------------------------------------------------------- /pomelo-go/src/agent/agent.go: -------------------------------------------------------------------------------- 1 | package agent 2 | 3 | import ( 4 | // "fmt" 5 | // "net" 6 | ) 7 | 8 | const ( 9 | AG_INIT = iota 10 | AG_START = iota 11 | AG_CLOSE = iota 12 | ) 13 | 14 | type Agent interface { 15 | IsMaster() bool 16 | } 17 | -------------------------------------------------------------------------------- /pomelo-go/src/agent/masterAgent.go: -------------------------------------------------------------------------------- 1 | package agent 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "sync" 7 | ) 8 | 9 | type MasterAgent struct { 10 | Conns map[net.Conn]bool 11 | MasterInfo map[string]interface{} 12 | 13 | Ch chan int8 14 | lock *sync.RWMutex 15 | } 16 | 17 | func (ma *MasterAgent) NotifyAll() { 18 | for k, v := range ma.Conns { 19 | if v { 20 | _, err := k.Write([]byte("notify")) 21 | if err != nil { 22 | fmt.Println(err.Error()) 23 | } 24 | } 25 | } 26 | } 27 | 28 | func (ma *MasterAgent) GetMasterInfo() map[string]interface{} { 29 | return ma.MasterInfo 30 | } 31 | 32 | func (ma *MasterAgent) AddConnection(conn net.Conn) { 33 | ma.lock.Lock() 34 | defer ma.lock.Unlock() 35 | ma.Conns[conn] = true 36 | } 37 | 38 | func (ma *MasterAgent) RemoveConnection(conn net.Conn) { 39 | ma.lock.Lock() 40 | defer ma.lock.Unlock() 41 | delete(ma.Conns, conn) 42 | } 43 | 44 | func (ma *MasterAgent) IsMaster() bool { 45 | return true 46 | } 47 | 48 | func NewMasterAgent(ch chan int8, masterInfo map[string]interface{}) *MasterAgent { 49 | var conns = make(map[net.Conn]bool) 50 | return &MasterAgent{conns, masterInfo, ch, &sync.RWMutex{}} 51 | } 52 | -------------------------------------------------------------------------------- /pomelo-go/src/agent/monitorAgent.go: -------------------------------------------------------------------------------- 1 | package agent 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | "strconv" 8 | ) 9 | 10 | type MonitorAgent struct { 11 | MasterInfo map[string]interface{} 12 | ServerInfo map[string]interface{} 13 | conn net.Conn 14 | status int8 15 | } 16 | 17 | func NewMonitorAgent(masterInfo map[string]interface{}, servInfo map[string]interface{}) *MonitorAgent { 18 | return &MonitorAgent{masterInfo, servInfo, nil, AG_INIT} 19 | } 20 | 21 | func (ma *MonitorAgent) IsMaster() bool { 22 | return false 23 | } 24 | 25 | /// 获得加载当前monitor组建的服务的信息,由于monitor组建同时被master加载, 26 | /// 所以对于 master服务器其返回的信息就是master的信息. 27 | func (ma *MonitorAgent) GetServerInfo() map[string]interface{} { 28 | return ma.ServerInfo 29 | } 30 | 31 | /// 获得master服务器的信息. 32 | func (ma *MonitorAgent) GetMasterInfo() map[string]interface{} { 33 | return ma.MasterInfo 34 | } 35 | 36 | /// 给master发送通知消息,发送成功后返回. 37 | /// 38 | /// @param moduleID 对应master端处理该通知的moduleID 39 | /// @param msg 通知的消息体. 40 | func (ma *MonitorAgent) Notify(moduleID string, msg map[string]string) {} 41 | 42 | /// 发送请求给master,请求发送成功后并不等待到master端回复,而是直接返回. 43 | /// 44 | /// @param moduleID 是请求的master端的module id 45 | /// @param msg 请求的消息 46 | func (ma *MonitorAgent) Request(moduleID string, msg map[string]string) {} 47 | 48 | func (ma *MonitorAgent) Close() { 49 | if ma.status != AG_START { 50 | return 51 | } 52 | 53 | ma.status = AG_CLOSE 54 | 55 | if ma.conn != nil { 56 | ma.conn.Close() 57 | } 58 | } 59 | 60 | /// 连接Master 61 | func (ma *MonitorAgent) Connect() (net.Conn, error) { 62 | if ma.status == AG_START { 63 | return nil, nil 64 | } 65 | 66 | host, ok := ma.MasterInfo["host"] 67 | if !ok { 68 | fmt.Fprintf(os.Stdout, "Error: Master host not set\n") 69 | return nil, *new(error) 70 | } 71 | 72 | port, ok := ma.MasterInfo["port"] 73 | if !ok { 74 | fmt.Fprintf(os.Stdout, "Error: Master port not set\n") 75 | return nil, *new(error) 76 | } 77 | host_s := host.(string) 78 | port_i := port.(int) 79 | hostAndPort := host_s + ":" + strconv.Itoa(port_i) 80 | masterAddr, err := net.ResolveTCPAddr("tcp4", hostAndPort) 81 | if err != nil { 82 | fmt.Fprintf(os.Stdout, "Error: Resolve tcp4 addr error,error message:%v\n", err.Error()) 83 | return nil, err 84 | } 85 | conn, err := net.DialTCP("tcp", nil, masterAddr) 86 | if err != nil { 87 | fmt.Fprintf(os.Stdout, "Error: Dial TCP error,error message:%v\n", err.Error()) 88 | return nil, err 89 | } 90 | 91 | ma.conn = conn 92 | return conn, err 93 | 94 | } 95 | -------------------------------------------------------------------------------- /pomelo-go/src/component/cobackendsession/cobackendsession.go: -------------------------------------------------------------------------------- 1 | package cobackendsession 2 | 3 | import ( 4 | "context" 5 | //"github.com/cihub/seelog" 6 | "service/backendSessionService" 7 | ) 8 | 9 | type CoBackendSession struct { 10 | *backendSessionService.BackendSessionService 11 | } 12 | 13 | func NewCoBackendSession() *CoBackendSession { 14 | ctx := context.GetContext() 15 | 16 | coBS, ok := ctx.GetComponent("cobackendsession").(*CoBackendSession) 17 | if ok == true { 18 | return coBS 19 | } 20 | bss := backendSessionService.NewBackendSessionService(ctx) 21 | coBS = &CoBackendSession{bss} 22 | 23 | ctx.RegisteComponent("cobackendsession", coBS) 24 | 25 | return coBS 26 | } 27 | -------------------------------------------------------------------------------- /pomelo-go/src/component/cochannel/cochannel.go: -------------------------------------------------------------------------------- 1 | package cochannel 2 | 3 | import ( 4 | "context" 5 | "github.com/cihub/seelog" 6 | "service/channelService" 7 | ) 8 | 9 | type CoChannel struct { 10 | *channelService.ChannelService 11 | } 12 | 13 | func NewCoChannel() *CoChannel { 14 | ctx := context.GetContext() 15 | 16 | coChan, ok := ctx.GetComponent("cochannel").(*CoChannel) 17 | if ok == true { 18 | return coChan 19 | } 20 | chanS := channelService.NewChannelService() 21 | coChan = &CoChannel{chanS} 22 | ctx.RegisteComponent("cochannel", coChan) 23 | seelog.Info("CoChannel create successfully") 24 | return coChan 25 | 26 | } 27 | -------------------------------------------------------------------------------- /pomelo-go/src/component/cochannelrpcserver/cochannelrpcserver.go: -------------------------------------------------------------------------------- 1 | package cochannelrpcserver 2 | 3 | import ( 4 | "context" 5 | "github.com/cihub/seelog" 6 | "remote_service/channelRpcServer" 7 | ) 8 | 9 | type CoChannelRpcServer struct { 10 | *channelRpcServer.ChannelRpcServer 11 | } 12 | 13 | func NewCoChannelRpcServer() *CoChannelRpcServer { 14 | 15 | ctx := context.GetContext() 16 | 17 | coChanRS, ok := ctx.GetComponent("cochannelrpcserver").(*CoChannelRpcServer) 18 | if ok == false { 19 | seelog.Infof("CoChannelRpcServer not found,create new...") 20 | chanRpcS := channelRpcServer.NewChannelRpcServer() 21 | coChanRS = &CoChannelRpcServer{chanRpcS} 22 | ctx.RegisteComponent("cochannelrpcserver", coChanRS) 23 | } 24 | 25 | seelog.Infof("CoChannelRpcServer create successfully") 26 | return coChanRS 27 | } 28 | -------------------------------------------------------------------------------- /pomelo-go/src/component/coconnection/coconnection.go: -------------------------------------------------------------------------------- 1 | package coconnection 2 | 3 | import ( 4 | "context" 5 | "github.com/cihub/seelog" 6 | "service/connectionService" 7 | ) 8 | 9 | type CoConnection struct { 10 | *connectionService.ConnectionService 11 | ctx *context.Context 12 | } 13 | 14 | func NewCoConnection() *CoConnection { 15 | ctx := context.GetContext() 16 | coconn, ok := ctx.GetComponent("coconnection").(*CoConnection) 17 | if ok == true { 18 | return coconn 19 | } 20 | 21 | cs := connectionService.NewConnectionService(ctx.GetServerID()) 22 | 23 | coconn = &CoConnection{cs, ctx} 24 | ctx.RegisteComponent("coconnection", coconn) 25 | 26 | seelog.Infof("CoConnetion create successfully") 27 | return coconn 28 | } 29 | -------------------------------------------------------------------------------- /pomelo-go/src/component/coconnector/coconnector.go: -------------------------------------------------------------------------------- 1 | /** 2 | * author:liweisheng date:2015/07/14 3 | */ 4 | 5 | /** 6 | * CoConnector组件由前端服务器加载,负责接收客户端连接,维护所有到来的连接信息,接收客户端请求 7 | * 并响应客户端请求。并对不同的用户请求做出不同处理: 8 | * (1)如果用户请求的是前端服务,则前端服务器 9 | * (2)如果用户请求的不是 10 | 11 | */ 12 | 13 | package coconnector 14 | 15 | import ( 16 | "component/coconnection" 17 | "component/coserver" 18 | "component/cosession" 19 | "connector" 20 | "connector/tcp_connector" 21 | "context" 22 | seelog "github.com/cihub/seelog" 23 | "service/sessionService" 24 | "strconv" 25 | "strings" 26 | ) 27 | 28 | type CoConnector struct { 29 | ctx *context.Context 30 | cnct connector.Connector 31 | coserv *coserver.CoServer 32 | cosess *cosession.CoSession 33 | coconn *coconnection.CoConnection 34 | decode func([]byte) (interface{}, error) 35 | encode func(string, string, map[string]interface{}) ([]byte, error) 36 | } 37 | 38 | /// 创建新的CoConnetor组件. 39 | /// 40 | /// 创建CoConnector组件时,CoConnector组件使用到的CoSession组件,CoConnection组件一同创建, 41 | /// CoServer组件则通过Context拿到,在CoConnector组件启动时加载. 42 | func NewCoConnector(ctx *context.Context) *CoConnector { 43 | 44 | cocnct, ok := ctx.GetComponent("coconnector").(*CoConnector) 45 | if ok == true { 46 | return cocnct 47 | } 48 | 49 | var decode func([]byte) (interface{}, error) 50 | var encode func(string, string, map[string]interface{}) ([]byte, error) 51 | 52 | cnct := getConnector(ctx) 53 | 54 | if opts, ok := ctx.AllOpts["coconnector"]; ok == true { 55 | decode, _ = opts["decode"].(func([]byte) (interface{}, error)) 56 | encode, _ = opts["encode"].(func(string, string, map[string]interface{}) ([]byte, error)) 57 | } 58 | 59 | coserv, ok1 := ctx.GetComponent("coserver").(*coserver.CoServer) 60 | if ok1 == false { 61 | coserv = coserver.NewCoServer() 62 | } 63 | 64 | cosess, ok2 := ctx.GetComponent("cosession").(*cosession.CoSession) 65 | if ok2 == false { 66 | cosess = cosession.NewCoSession() 67 | } 68 | 69 | coconn, ok3 := ctx.GetComponent("coconnection").(*coconnection.CoConnection) 70 | if ok3 == false { 71 | coconn = coconnection.NewCoConnection() 72 | } 73 | 74 | cocnct = &CoConnector{ctx, cnct, coserv, cosess, coconn, decode, encode} 75 | ctx.RegisteComponent("coconnector", cocnct) 76 | return cocnct 77 | } 78 | 79 | /// 向sids标示的所有session发送消息. 80 | /// 81 | /// @param reqID 请求id 82 | /// @param route 路由 83 | /// @param msg 发送的消息 84 | /// @param sids 接受消息的session 85 | func (cocnct *CoConnector) Send(reqID string, route string, msg map[string]interface{}, sids []uint32) { 86 | seelog.Debugf("<%v> send msg<%v> with reqID<%v>,route<%v> to sids<%v>", cocnct.ctx.GetServerID(), msg, reqID, route, sids) 87 | 88 | var encodedMsg []byte 89 | var err error 90 | if cocnct.encode != nil { 91 | encodedMsg, err = cocnct.encode(reqID, route, msg) 92 | } else { 93 | encodeFunc := cocnct.cnct.Encode 94 | encodedMsg, err = encodeFunc(reqID, route, msg) 95 | } 96 | 97 | if err != nil { 98 | seelog.Errorf("<%v> encode msg<%v> error<%v>", cocnct.ctx.GetServerID(), msg, err.Error()) 99 | return 100 | } 101 | 102 | for _, sid := range sids { 103 | go cocnct.cosess.SendMsgBySID(sid, encodedMsg) 104 | } 105 | } 106 | 107 | /// 回调函数,当有新连接到来时调用该回调函数,创建并记录session,该回调函数注册给connector使用. 108 | func (cocnct *CoConnector) ConnectionEventCB(sock connector.Socket) *sessionService.Session { 109 | session := cocnct.cosess.CreateSession(sock.ID(), cocnct.ctx.GetServerID(), sock) 110 | return session 111 | } 112 | 113 | /// 回调函数,当连接上有新的message到来时调用该回调函数,该回调函数注册给connector使用. 114 | func (cocnct *CoConnector) MessageEventCB(sid uint32, msg map[string]interface{}) { 115 | route, _ := msg["route"].(string) 116 | if cocnct.checkRouteValidity(route) == false { 117 | seelog.Errorf("<%v> invalid route<%v>", cocnct.ctx.GetServerID(), route) 118 | return 119 | } 120 | } 121 | 122 | /// 检查路由的合法性,路由格式是:serverType.handler.method 123 | /// 124 | /// 如考虑请求聊天服务器chatServer新用户登录,则route格式为chatServer.UserManager. 125 | func (cocnct *CoConnector) checkRouteValidity(route string) bool { 126 | return strings.Index(route, ".") != -1 127 | } 128 | 129 | /// 启动组件. 130 | func (cc *CoConnector) Start() { 131 | 132 | } 133 | 134 | /// 获取CoConnector组件内部用于发送和接收消息的connector服务. 135 | /// 136 | /// 如果用户配置了connector(保存在Context中),则使用全局配置的connector, 137 | /// 否者使用默认的TcpConnector. 138 | func getConnector(ctx *context.Context) connector.Connector { 139 | opts := ctx.AllOpts["coconnector"] 140 | if opts != nil { 141 | if c, setted := opts["connector"]; setted == true { 142 | if cnct, ok := c.(connector.Connector); ok == true { 143 | return cnct 144 | } 145 | } 146 | } 147 | 148 | curServer := ctx.CurrentServer 149 | host, _ := curServer["host"].(string) 150 | port := strconv.Itoa(curServer["port"].(int)) 151 | return tcp_connector.NewTcpConnector(host, port, nil) 152 | } 153 | -------------------------------------------------------------------------------- /pomelo-go/src/component/comaster/comaster.go: -------------------------------------------------------------------------------- 1 | package comaster 2 | 3 | import ( 4 | "context" 5 | "github.com/cihub/seelog" 6 | "pomelo_admin" 7 | ) 8 | 9 | type CoMaster struct { 10 | *pomelo_admin.MasterConsoleService 11 | } 12 | 13 | func NewCoMaster() *CoMaster { 14 | ctx := context.GetContext() 15 | coMaster, ok := ctx.GetComponent("comaster").(*CoMaster) 16 | if ok == true { 17 | return coMaster 18 | } 19 | 20 | mcs := pomelo_admin.NewMasterConsoleService(ctx) 21 | coMaster = &CoMaster{mcs} 22 | seelog.Infof("<%v> component CoMaster created...", ctx.GetServerID()) 23 | ctx.RegisteComponent("comaster", coMaster) 24 | return coMaster 25 | } 26 | -------------------------------------------------------------------------------- /pomelo-go/src/component/comonitor/comonitor.go: -------------------------------------------------------------------------------- 1 | package comonitor 2 | 3 | import ( 4 | "context" 5 | "github.com/cihub/seelog" 6 | "pomelo_admin" 7 | ) 8 | 9 | type CoMonitor struct { 10 | *pomelo_admin.MonitorConsoleService 11 | } 12 | 13 | func NewCoMonitor() *CoMonitor { 14 | ctx := context.GetContext() 15 | coMonitor, ok := ctx.GetComponent("comonitor").(*CoMonitor) 16 | if ok == true { 17 | return coMonitor 18 | } 19 | 20 | mcs := pomelo_admin.NewMonitorConsoleService(ctx) 21 | coMonitor = &CoMonitor{mcs} 22 | seelog.Infof("<%v> component CoMonitor created...", ctx.GetServerID()) 23 | ctx.RegisteComponent("comonitor", coMonitor) 24 | return coMonitor 25 | } 26 | -------------------------------------------------------------------------------- /pomelo-go/src/component/corpcclient/corpcclient.go: -------------------------------------------------------------------------------- 1 | package corpcclient 2 | 3 | import ( 4 | "context" 5 | "github.com/cihub/seelog" 6 | "rpcclient" 7 | ) 8 | 9 | type CoRpcClient struct { 10 | *rpcclient.RpcClient 11 | } 12 | 13 | func NewCoRpcClient() *CoRpcClient { 14 | ctx := context.GetContext() 15 | 16 | coRpcC, ok := ctx.GetComponent("corpcclient").(*CoRpcClient) 17 | 18 | if ok == true { 19 | return coRpcC 20 | } 21 | 22 | rpcC := rpcclient.NewRpcClient(ctx) 23 | coRpcC = &CoRpcClient{rpcC} 24 | 25 | ctx.RegisteComponent("corpcclient", coRpcC) 26 | seelog.Info("CoRpcClient create successfully") 27 | return coRpcC 28 | 29 | } 30 | -------------------------------------------------------------------------------- /pomelo-go/src/component/corpcserver/corpcserver.go: -------------------------------------------------------------------------------- 1 | package corpcserver 2 | 3 | import ( 4 | "context" 5 | "github.com/cihub/seelog" 6 | "rpcserver" 7 | ) 8 | 9 | type CoRpcServer struct { 10 | *rpcserver.RpcServer 11 | } 12 | 13 | func NewCoRpcServer() *CoRpcServer { 14 | ctx := context.GetContext() 15 | 16 | coRpcS, ok := ctx.GetComponent("corpcserver").(*CoRpcServer) 17 | if ok == true { 18 | return coRpcS 19 | } 20 | 21 | host, _ := ctx.CurrentServer["host"].(string) 22 | port, _ := ctx.CurrentServer["port"].(int) 23 | rpcS := rpcserver.NewRpcServer(host, port) 24 | 25 | coRpcS = &CoRpcServer{rpcS} 26 | ctx.RegisteComponent("corpcserver", coRpcS) 27 | seelog.Info("CoRpcServer create successfully") 28 | return coRpcS 29 | } 30 | -------------------------------------------------------------------------------- /pomelo-go/src/component/coserver/coserver.go: -------------------------------------------------------------------------------- 1 | package coserver 2 | 3 | import ( 4 | "context" 5 | "github.com/cihub/seelog" 6 | "server" 7 | ) 8 | 9 | type CoServer struct { 10 | *server.Server 11 | } 12 | 13 | func NewCoServer() *CoServer { 14 | ctx := context.GetContext() 15 | coServ, ok := ctx.GetComponent("coserver").(*CoServer) 16 | if ok == true { 17 | return coServ 18 | } 19 | serv := server.NewServer() 20 | coServ = &CoServer{serv} 21 | seelog.Infof("<%v> component server created", ctx.GetServerID()) 22 | return coServ 23 | } 24 | -------------------------------------------------------------------------------- /pomelo-go/src/component/cosession/cosession.go: -------------------------------------------------------------------------------- 1 | /** 2 | * author:liweisheng date:2015/07/15 3 | */ 4 | 5 | /** 6 | * cosesssion 是对sessionService的代理. 7 | */ 8 | 9 | package cosession 10 | 11 | import ( 12 | "context" 13 | "github.com/cihub/seelog" 14 | "service/sessionService" 15 | ) 16 | 17 | type CoSession struct { 18 | *sessionService.SessionService 19 | } 20 | 21 | /// 创建CoSession. 22 | func NewCoSession() *CoSession { 23 | ctx := context.GetContext() 24 | 25 | cosess, ok := ctx.GetComponent("cosession").(*CoSession) 26 | if ok == true { 27 | return cosess 28 | } 29 | ss := sessionService.NewSessionService(ctx.AllOpts["cosession"]) 30 | 31 | cosess = &CoSession{ss} 32 | 33 | ctx.RegisteComponent("cosession", cosess) 34 | seelog.Info("CoSession create successufully") 35 | return cosess 36 | } 37 | 38 | func (cs *CoSession) Start() { 39 | ctx := context.GetContext() 40 | seelog.Infof("frontendserver<%v> cosession start", ctx.GetServerID()) 41 | } 42 | -------------------------------------------------------------------------------- /pomelo-go/src/component/cosessionrpcserver/cosessionrpcserver.go: -------------------------------------------------------------------------------- 1 | /** 2 | * author: liweisheng date:2015/07/25 3 | */ 4 | 5 | /// 组建cosessionrpcserver 内部封装sessionRpcServer, 详细介绍参考remote_service/sessionRpcServer.go 6 | package cosessionrpcserver 7 | 8 | import ( 9 | "context" 10 | "remote_service/sessionRpcServer" 11 | ) 12 | 13 | type CoSessionRpcServer struct { 14 | *sessionRpcServer.SessionRpcServer 15 | } 16 | 17 | /// 创建CoSessionRpcServer组建. 18 | func NewCoSessionRpcServer() *CoSessionRpcServer { 19 | ctx := context.GetContext() 20 | coSRS, ok := ctx.GetComponent("cosessionrpcserver").(*CoSessionRpcServer) 21 | 22 | if ok == true { 23 | return coSRS 24 | } 25 | 26 | srs := sessionRpcServer.NewSessionRpcServer() 27 | coSRS = &CoSessionRpcServer{srs} 28 | 29 | ctx.RegisteComponent("cosessionrpcserver", coSRS) 30 | 31 | return coSRS 32 | } 33 | -------------------------------------------------------------------------------- /pomelo-go/src/connector/connector_common.go: -------------------------------------------------------------------------------- 1 | //author:liweisheng date:2015/07/07 2 | 3 | package connector 4 | 5 | const ( 6 | ST_INITED = iota 7 | ST_CLOSED = iota 8 | ) 9 | 10 | type Socket interface { 11 | ID() uint32 12 | Socket() interface{} 13 | RemoteAddress() map[string]interface{} 14 | Send([]byte) (int, error) 15 | SendBatch(...[]byte) 16 | Receive([]byte) (int, error) 17 | Disconnect() 18 | } 19 | 20 | type Connector interface { 21 | Start() 22 | Decode([]byte) (interface{}, error) 23 | Encode(string, string, map[string]interface{}) ([]byte, error) 24 | } 25 | -------------------------------------------------------------------------------- /pomelo-go/src/connector/tcp_connector/tcp_connector.go: -------------------------------------------------------------------------------- 1 | /* 2 | author:liweisheng date:2015/07/08 3 | */ 4 | 5 | /* 6 | 实现tcp connector 7 | */ 8 | package tcp_connector 9 | 10 | import ( 11 | // "context" 12 | 13 | "context" 14 | "encoding/json" 15 | "github.com/cihub/seelog" 16 | "log" 17 | "net" 18 | "os" 19 | ) 20 | 21 | var curID uint32 = 0 22 | 23 | type TcpConnector struct { 24 | host string 25 | port string 26 | opts map[string]string 27 | registedEvents map[string]func(args ...interface{}) 28 | ctx *context.Context 29 | } 30 | 31 | /// 创建新的TcpConnector 32 | func NewTcpConnector(host string, port string, opts map[string]string) *TcpConnector { 33 | regE := make(map[string]func(args ...interface{})) 34 | return &TcpConnector{host, port, opts, regE, context.GetContext()} 35 | } 36 | 37 | /// 处理新接收到的连接. 38 | /// 39 | /// 接收tcpSkt上的数据,并解析数据包,调用注册的message事件(函数回调)处理收到的数据. 40 | /// 41 | /// @param tcpSkt 与客户端连接的socket. 42 | func (tc *TcpConnector) HandleNewConnection(tcpSkt *TcpSocket) { 43 | defer tcpSkt.Disconnect() 44 | 45 | cb, ok := tc.registedEvents["connection"] 46 | if ok == false { 47 | seelog.Critical("Fail to load \n") 48 | os.Exit(0) 49 | } 50 | cb(tcpSkt) 51 | seelog.Infof("<%v> handle new connection with id<%v>", tc.ctx.GetServerID(), tcpSkt.ID()) 52 | 53 | const BUFSIZE uint16 = 1024 * 8 54 | var buff, recvBuff []byte 55 | var begin, end, packSize, unProcess uint16 56 | 57 | recvBuff = make([]byte, BUFSIZE) 58 | buff = make([]byte, BUFSIZE) 59 | 60 | for { 61 | n, err := tcpSkt.Receive(recvBuff) 62 | 63 | if err != nil { 64 | seelog.Errorf("<%v> Read from sockid<%v> error<%v> ", tc.ctx.GetServerID(), tcpSkt.ID(), err.Error()) 65 | // errEv, ok := tc.registedEvents["error"] 66 | // if ok == false { 67 | // fmt.Fprintf(os.Stderr, "Error: Can not find registed event handler<'error'>") 68 | // os.Exit(1) 69 | // } 70 | 71 | // errEv(tcpSkt) 72 | // break 73 | break 74 | } 75 | if begin >= end { 76 | begin = 0 77 | end = 0 78 | } 79 | 80 | buff = append(buff[begin:end], recvBuff[0:n]...) 81 | // fmt.Fprintf(os.Stdout, "current buff is: %v\n", buff[:]) 82 | unProcess = uint16(len(buff)) 83 | begin = 0 84 | 85 | for unProcess >= 1 { 86 | packSize = uint16(0x00FF&buff[begin])<<8 + uint16(0x00FF&buff[begin+1]) 87 | 88 | if unProcess >= packSize { 89 | msg, err := tc.Decode(buff[begin+2 : begin+packSize]) 90 | if err == nil { 91 | // goto DecodeErr 92 | msgEv, ok := tc.registedEvents["message"] 93 | if ok == false { 94 | seelog.Critical("Error: Can not find registed event handler<'message'>") 95 | os.Exit(1) 96 | } 97 | seelog.Debugf("<%v> recive msg<%v> from sid<%v>", tc.ctx.GetServerID(), msg, tcpSkt.ID()) 98 | //处理接收到的消息 99 | go msgEv(msg) 100 | } else { 101 | seelog.Errorf("<%v> Decode message from sid<%v> error<%v>", tc.ctx.GetServerID(), tcpSkt.ID(), err.Error()) 102 | return 103 | } 104 | unProcess -= packSize 105 | begin += packSize 106 | } else { 107 | break 108 | } 109 | } //end inner for 110 | } //end outter for 111 | } 112 | 113 | /// 监听服务器端口,接收新的连接.对于新来的连接首先调用为其注册的connection事件(函数回调) 114 | /// 之后开始监听新的连接. 115 | func (tc *TcpConnector) Start() { 116 | tcpAddr, err := net.ResolveTCPAddr("tcp", tc.host+":"+tc.port) 117 | 118 | if err != nil { 119 | log.Fatal(err.Error()) 120 | } 121 | // context.CheckError(err) 122 | listener, err := net.ListenTCP("tcp", tcpAddr) 123 | if err != nil { 124 | log.Fatal(err.Error()) 125 | } 126 | go func(ln *net.TCPListener) { 127 | defer ln.Close() 128 | for { 129 | conn, err := ln.AcceptTCP() 130 | // context.CheckError(err) 131 | if err != nil { 132 | seelog.Criticalf("AcceptTcp on host<%v> port<%v> error<%v>", tc.host, tc.port, err.Error()) 133 | os.Exit(0) 134 | } 135 | tcpSocket := NewTcpSocket(curID, conn) 136 | 137 | go tc.HandleNewConnection(tcpSocket) 138 | } //end for 139 | }(listener) 140 | } //end Start() 141 | 142 | /// 为TcpConnector注册事件相应回调. 143 | /// 144 | /// 至少要注册两个回调,一个是connection回调,用于新的连接到来时回调, 145 | /// 一个是message回调,当有新的message到来时回掉. 146 | /// 147 | /// @param evName 事件名称,connection事件名称"connection",message事件名称为"message". 148 | /// @param callback 对应事件的回调函数. 149 | func (tc *TcpConnector) RegistEvents(evName string, callback func(...interface{})) { 150 | tc.registedEvents[evName] = callback 151 | } 152 | 153 | /// Start之前调用,可以做一些必要的检查. 154 | /// XXX:未实现机制 155 | func (tc *TcpConnector) beforeStart() { 156 | if _, ok := tc.registedEvents["connection"]; ok == false { 157 | log.Fatalln("Did not find call-back function for 'connection' events") 158 | } 159 | 160 | if _, ok := tc.registedEvents["message"]; ok == false { 161 | log.Fatalln("Did not find call-back function for 'message' events") 162 | } 163 | } 164 | 165 | /// 解码收到的客户端信息. 166 | /// 167 | /// 客户端的信息应该符合约定好的消息格式,否则解码失败. 168 | /// 169 | /// @param buff 收到的信息. 170 | /// @return rst {map[string]interface{} } error 为nil表示解码成功,rst中以name:value形式. 171 | func (tc *TcpConnector) Decode(buff []byte) (interface{}, error) { 172 | var result interface{} 173 | err := json.Unmarshal(buff, &result) 174 | return result, err 175 | } 176 | 177 | /// 编码消息,编码成json格式. 178 | /// 179 | /// @reqID 请求ID 180 | /// @route 请求路由 181 | /// @body 消息内容 182 | /// @return result 第二返回值error为nil的情况下result中存放编码成json后的内容 183 | func (tc *TcpConnector) Encode(reqID string, route string, body map[string]interface{}) ([]byte, error) { 184 | msg := make(map[string]interface{}) 185 | msg["id"] = reqID 186 | msg["route"] = route 187 | msg["body"] = body 188 | msgJson, err := json.Marshal(msg) 189 | 190 | if err != nil { 191 | return nil, err 192 | } 193 | return msgJson, nil 194 | } 195 | -------------------------------------------------------------------------------- /pomelo-go/src/connector/tcp_connector/tcp_socket.go: -------------------------------------------------------------------------------- 1 | /* 2 | author:liweisheng date:2015/07/08 3 | */ 4 | 5 | /* 6 | 实现tcp socket相关的方法 7 | */ 8 | 9 | package tcp_connector 10 | 11 | import ( 12 | "connector" 13 | // "context" 14 | "context" 15 | "github.com/cihub/seelog" 16 | "log" 17 | "net" 18 | ) 19 | 20 | type TcpSocket struct { 21 | socket *net.TCPConn 22 | id uint32 23 | remoteAddr map[string]interface{} 24 | status int8 25 | } 26 | 27 | //创建新的TcpSocket.参数id,sock不可以为空 28 | func NewTcpSocket(id uint32, sock *net.TCPConn) *TcpSocket { 29 | remoteAddr := make(map[string]interface{}) 30 | addr := sock.RemoteAddr() 31 | host, port, err := net.SplitHostPort(addr.String()) 32 | // context.CheckError(err) 33 | if err != nil { 34 | log.Fatal(err.Error()) 35 | } 36 | remoteAddr["host"] = host 37 | remoteAddr["port"] = port 38 | 39 | return &TcpSocket{sock, id, remoteAddr, connector.ST_INITED} 40 | } 41 | 42 | func (ts *TcpSocket) Socket() interface{} { 43 | return ts.socket 44 | } 45 | 46 | func (ts *TcpSocket) ID() uint32 { 47 | return ts.id 48 | } 49 | 50 | func (ts *TcpSocket) RemoteAddr() map[string]interface{} { 51 | return ts.remoteAddr 52 | } 53 | 54 | func (ts *TcpSocket) Send(msg []byte) (int, error) { 55 | if ts.status != connector.ST_INITED { 56 | return -1, nil 57 | } 58 | 59 | return ts.socket.Write(msg) 60 | } 61 | 62 | func (ts *TcpSocket) SendBatch(msgs ...[]byte) {} 63 | func (ts *TcpSocket) Receive(recv []byte) (int, error) { 64 | if ts.status != connector.ST_INITED { 65 | return -1, nil 66 | } 67 | 68 | return ts.socket.Read(recv) 69 | } 70 | 71 | func (ts *TcpSocket) Disconnect() { 72 | seelog.Debugf("<%v> Disconnect sid<%v>", context.GetContext().GetServerID(), ts.id) 73 | if ts.status == connector.ST_CLOSED { 74 | return 75 | } 76 | 77 | ts.status = connector.ST_CLOSED 78 | ts.socket.Close() 79 | } 80 | -------------------------------------------------------------------------------- /pomelo-go/src/context/context.go: -------------------------------------------------------------------------------- 1 | // author:李为胜 2015-7-7 2 | 3 | /* 4 | package context用于记录一些全局的信息,包括:注册的modules,master服务器的配置信息,servers的配置信息 5 | */ 6 | package context 7 | 8 | import ( 9 | "fmt" 10 | seelog "github.com/cihub/seelog" 11 | "module" 12 | "os" 13 | ) 14 | 15 | var globalContext *Context = nil 16 | 17 | func init() { 18 | globalContext = newContext() 19 | } 20 | 21 | func GetContext() *Context { 22 | return globalContext 23 | } 24 | 25 | type Context struct { 26 | Ch chan int8 27 | Env string 28 | Server interface{} 29 | Modules []module.Module 30 | CurrentServer map[string]interface{} 31 | MasterInfo map[string]interface{} 32 | ServerInfo map[string][]map[string]interface{} 33 | AllOpts map[string]map[string]interface{} ///< 保存组件,模块的配置信息 34 | DefaultComponents map[string]interface{} 35 | Logger seelog.LoggerInterface 36 | } 37 | 38 | //创建新的上下文 39 | func newContext() *Context { 40 | ch := make(chan int8) 41 | mods := make([]module.Module, 0, 10) 42 | 43 | curS := make(map[string]interface{}) 44 | masterInfo := make(map[string]interface{}) 45 | serverInfo := make(map[string][]map[string]interface{}) 46 | allOpts := make(map[string]map[string]interface{}) 47 | defaultComponents := make(map[string]interface{}) 48 | logger, err := seelog.LoggerFromConfigAsFile("./logConfig.xml") 49 | 50 | if err != nil { 51 | fmt.Fprintf(os.Stderr, "Error: Fail to create logger,error message:<%v>\n", err.Error()) 52 | os.Exit(1) 53 | } 54 | if err := seelog.UseLogger(logger); err != nil { 55 | fmt.Fprintf(os.Stderr, "Error: Fail to use logger,error message:<%v>\n", err.Error()) 56 | os.Exit(1) 57 | } 58 | return &Context{ch, "", mods, nil, curS, masterInfo, serverInfo, allOpts, defaultComponents, logger} 59 | } 60 | 61 | /// 向上下文中注册一个module. 62 | func (ctx *Context) RegisteModule(mod module.Module) { 63 | ctx.Modules = append(ctx.Modules, mod) 64 | fmt.Println(len(ctx.Modules)) 65 | } 66 | 67 | func (ctx *Context) RegisteComponent(name string, comp interface{}) { 68 | seelog.Tracef("Registe component <%v>", name) 69 | ctx.DefaultComponents[name] = comp 70 | } 71 | 72 | /// 根据组件名称获得组件实例. 73 | func (ctx *Context) GetComponent(name string) interface{} { 74 | return ctx.DefaultComponents[name] 75 | } 76 | 77 | // func (ctx *context) SetMasterInfo(mi map[string]interface{}) { 78 | // ctx.MasterInfo = mi 79 | // } 80 | 81 | func CheckError(err error) { 82 | if err != nil { 83 | fmt.Fprintf(os.Stderr, "Fatal Error Exit: %s\n", err.Error()) 84 | os.Exit(1) 85 | } 86 | } 87 | 88 | func (ctx *Context) GetServerID() string { 89 | return ctx.CurrentServer["id"].(string) 90 | } 91 | 92 | func (ctx *Context) GetServerType() string { 93 | return ctx.CurrentServer["serverType"].(string) 94 | } 95 | 96 | func (ctx *Context) GetCurrentServerInfo() map[string]interface{} { 97 | return ctx.CurrentServer 98 | } 99 | 100 | /// 根据server id获得server的详细信息. 101 | /// 102 | /// @param id server id 103 | /// @return server的详细信息 104 | /// XXX: 当前实现只是为了测试. 105 | func (ctx *Context) GetServerInfoByID(id string) map[string]interface{} { 106 | return ctx.CurrentServer 107 | } 108 | 109 | /// 根据服务器类型获得server id,获得server id可以配置route规则,来从多个同类型服务器中 110 | /// 选择要返回的server id. 111 | /// @param stype 服务器类型. 112 | /// @return server id 113 | /// TODO: 未实现. 114 | func (ctx *Context) GetServerIDByType(stype string) string { 115 | return "" 116 | } 117 | -------------------------------------------------------------------------------- /pomelo-go/src/context/logConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /pomelo-go/src/logger/redis_log.go: -------------------------------------------------------------------------------- 1 | /** 2 | * 向redis服务器写日志. 3 | */ 4 | 5 | package logger 6 | 7 | import ( 8 | "fmt" 9 | "redis" 10 | "time" 11 | ) 12 | 13 | ///log level 14 | const ( 15 | LOG_INFO = iota 16 | LOG_DEBUG = iota 17 | LOG_WARN = iota 18 | LOG_ERROR = iota 19 | LOG_FATAL = iota 20 | ) 21 | 22 | /// 在日志写向服务器之前,格式化日志. 23 | /// 24 | /// 实现该接口可以自定义格式化器. 25 | type Formatter interface { 26 | Format(msg []byte) []byte 27 | } 28 | 29 | /// 默认的日志格式化器 30 | type defaultFormatter struct{} 31 | 32 | func (*defaultFormatter) Format(msg []byte) []byte { 33 | afterFmt := fmt.Sprintf("{%v} {%s}", time.Now(), msg) 34 | 35 | return []byte(afterFmt) 36 | } 37 | 38 | type Logger struct { 39 | logLev uint8 /// 限制日志输出级别,大于等于这个级别可以输出. 40 | servAddr string /// redis服务器地址 41 | servPort int /// redis服务器端口 42 | client redis.Client 43 | fmter Formatter /// 格式化器 44 | } 45 | 46 | /// 创建新的日志记录器. 47 | /// 48 | /// @param servAddr redis服务器地址 49 | /// @param servPort redis服务器端口 50 | /// @param logLev 限制日志输出级别 51 | /// @return 成功则返回日志记录器,同时error为nil. 52 | func NewLogger(servAddr string, servPort int, logLev uint8) (*Logger, error) { 53 | spec := redis.DefaultSpec().Host(servAddr).Port(servPort) 54 | cli, err := redis.NewSynchClientWithSpec(spec) 55 | 56 | if nil != err { 57 | return nil, err 58 | } 59 | 60 | return &Logger{logLev, servAddr, servPort, cli, new(defaultFormatter)}, nil 61 | } 62 | 63 | /// 设置格式化器. 64 | func (log *Logger) SetFormatter(fmt Formatter) { 65 | log.fmter = fmt 66 | } 67 | 68 | /// 写如FATAL级别日志. 69 | func (log *Logger) Fatal(msg []byte) { 70 | if log.logLev > LOG_FATAL { 71 | return 72 | } 73 | msg = log.fmter.Format(msg) 74 | log.client.Lpush("FATAL", msg) 75 | } 76 | 77 | /// ERROR级别日志. 78 | func (log *Logger) Error(msg []byte) { 79 | if log.logLev > LOG_ERROR { 80 | return 81 | } 82 | msg = log.fmter.Format(msg) 83 | log.client.Lpush("ERROR", msg) 84 | } 85 | 86 | /// WARN级别日志. 87 | func (log *Logger) Warn(msg []byte) { 88 | if log.logLev > LOG_WARN { 89 | return 90 | } 91 | msg = log.fmter.Format(msg) 92 | log.client.Lpush("WARN", msg) 93 | } 94 | 95 | /// DEBUG级别日志. 96 | func (log *Logger) Debug(msg []byte) { 97 | if log.logLev > LOG_DEBUG { 98 | return 99 | } 100 | msg = log.fmter.Format(msg) 101 | log.client.Lpush("DEBUG", msg) 102 | } 103 | 104 | /// INFO级别. 105 | func (log *Logger) Info(msg []byte) { 106 | if log.logLev > LOG_INFO { 107 | return 108 | } 109 | msg = log.fmter.Format(msg) 110 | log.client.Lpush("INFO", msg) 111 | } 112 | 113 | /// 写入由参数level指定的级别的日志. 114 | func (log *Logger) Log(level uint8, msg []byte) { 115 | if log.logLev > level { 116 | return 117 | } 118 | switch level { 119 | case LOG_INFO: 120 | log.Info(msg) 121 | case LOG_WARN: 122 | log.Warn(msg) 123 | case LOG_ERROR: 124 | log.Error(msg) 125 | case LOG_FATAL: 126 | log.Fatal(msg) 127 | case LOG_DEBUG: 128 | log.Debug(msg) 129 | default: 130 | return 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /pomelo-go/src/main/pomelo_go.go: -------------------------------------------------------------------------------- 1 | package pomelo_go 2 | 3 | import ( 4 | "context" 5 | // "bufio" 6 | "encoding/json" 7 | "fmt" 8 | // "io" 9 | "os" 10 | ) 11 | 12 | type pomelo_go struct { 13 | Context *context.Context 14 | } 15 | 16 | func NewPomeloGo() *pomelo_go { 17 | var ctx *context.Context = context.NewContext() 18 | 19 | return &pomelo_go{ctx} 20 | } 21 | 22 | ///从./config/master.json中加载master信息 23 | func (p *pomelo_go) LoadMasterInfo() { 24 | inputFile, err := os.Open("./config/master.json") 25 | if err != nil { 26 | fmt.Fprintf(os.Stderr, "Error: Failed to open %v\n", "./config/master.json") 27 | os.Exit(1) 28 | } 29 | 30 | decoder := json.NewDecoder(inputFile) 31 | 32 | var masterInfo map[string]interface{} 33 | 34 | for { 35 | if err := decoder.Decode(&masterInfo); err != nil { 36 | fmt.Fprintf(os.Stderr, "Error: Failed to decode %v,Error Message:<%v>\n", "./config/master.json", err.Error()) 37 | os.Exit(1) 38 | } 39 | } 40 | 41 | p.Context.MasterInfo = masterInfo[p.Context.Env] 42 | } 43 | 44 | ///从./config/servers.json中加载server信息 45 | func (p *pomelo_go) LoadServerInfo() { 46 | inputFile, err := os.Open("./config/servers.json") 47 | 48 | if err != nil { 49 | fmt.Fprintf(os.Stderr, "Error: Failed to open %v\n", "./config/servers.json") 50 | os.Exit(1) 51 | } 52 | 53 | decoder := json.NewDecoder(inputFile) 54 | 55 | var serversInfo map[string]interface{} 56 | 57 | for { 58 | if err := decoder.Decode(&serversInfo); err != nil { 59 | fmt.Fprintf(os.Stderr, "Error: Failed to decode %v,Error Message:<%v>\n", "./config/servers.json", err.Error()) 60 | os.Exit(1) 61 | } 62 | } 63 | 64 | p.Context.ServerInfo = serversInfo[p.Context.Env] 65 | } 66 | 67 | func (p *pomelo_go) SetEnv(env string) { 68 | p.Context.Env = env 69 | } 70 | 71 | 72 | ///分析命令行参数 73 | func (p *pomelo_go) ParseArgs{ 74 | 75 | } 76 | -------------------------------------------------------------------------------- /pomelo-go/src/master/master.go: -------------------------------------------------------------------------------- 1 | // master 2 | package main 3 | 4 | import ( 5 | "context" 6 | "fmt" 7 | "pomelo_admin" 8 | ) 9 | 10 | type Master struct { 11 | MasterInfo map[string]interface{} 12 | Context *context.Context 13 | MasterConsoleService *pomelo_admin.MasterConsoleService 14 | } 15 | 16 | ///创建Master 17 | func NewMaster(context *context.Context) Master { 18 | var masterInfo = make(map[string]interface{}) 19 | var masterConsoleService = pomelo_admin.NewMasterConsoleService(context) 20 | var master = Master{masterInfo, context, masterConsoleService} 21 | return master 22 | } 23 | 24 | func main() { 25 | fmt.Print("hello main") 26 | 27 | } 28 | -------------------------------------------------------------------------------- /pomelo-go/src/module/module.go: -------------------------------------------------------------------------------- 1 | // module.go 2 | 3 | package module 4 | 5 | import ( 6 | "agent" 7 | "log" 8 | "net" 9 | "time" 10 | ) 11 | 12 | type Module interface { 13 | MonitorHandler(agent agent.Agent, conn net.Conn, msg map[string]interface{}) 14 | MasterHandler(agent agent.Agent, conn net.Conn, msg map[string]interface{}) 15 | ClientHandler(agent agent.Agent, conn net.Conn, msg map[string]interface{}) 16 | Start() 17 | ModuleID() string 18 | GetType() string 19 | GetInterval() int16 20 | } 21 | 22 | ///以seconds为周期调用cb 23 | func PeriodicScheduler(cb interface{}, ag agent.Agent, seconds int16) { 24 | callback, ok := cb.(func(agent.Agent, net.Conn, map[string]interface{})) 25 | if ok == false { 26 | log.Fatal("In PeriodicScheduler: Fail to convert callback function") 27 | } 28 | 29 | timer := time.NewTicker(time.Duration(seconds) * time.Second) 30 | 31 | for { 32 | select { 33 | case <-timer.C: 34 | go callback(ag, nil, nil) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /pomelo-go/src/module/reportInfo/reportInfo.go: -------------------------------------------------------------------------------- 1 | /** 2 | * author:liweisheng date:2015/07/14 3 | */ 4 | 5 | /** 6 | * reportModule模块实现的功能是:定期上报加载该模块的服务器的信息. 7 | * 加载模块的monitor服务定期的执行MonitorHandler上报自身服务的信息(serverType,serverID,ip,clientPort,port) 8 | * 该模块底层使用redis来上报自身的信息, 并设置信息过期时间为MonitorHandler执行周期的2倍. 9 | */ 10 | package reportInfo 11 | 12 | import ( 13 | "agent" 14 | "log" 15 | //"module" 16 | // "fmt" 17 | "github.com/cihub/seelog" 18 | "net" 19 | "os" 20 | "redis" 21 | "strconv" 22 | "sync" 23 | ) 24 | 25 | var rwLock sync.RWMutex 26 | 27 | type ReportInfo struct { 28 | moduleId string 29 | moduleType string 30 | interval int16 31 | client redis.Client 32 | } 33 | 34 | func NewReportInfo(mid string, mt string, intv int16, reportAddr string, reportPort int) (*ReportInfo, error) { 35 | 36 | spec := redis.DefaultSpec().Host(reportAddr).Port(reportPort) 37 | cli, err := redis.NewSynchClientWithSpec(spec) 38 | 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | return &ReportInfo{mid, mt, intv, cli}, nil 44 | } 45 | 46 | func (ri *ReportInfo) getServerInfoAsString(si map[string]interface{}) string { 47 | id := si["id"].(string) 48 | host := si["host"].(string) 49 | port := strconv.Itoa(si["port"].(int)) 50 | clientPort := strconv.Itoa(si["clientPort"].(int)) 51 | frontend := si["frontend"].(string) 52 | return id + "@" + host + "@" + port + "@" + clientPort + "@" + frontend 53 | } 54 | 55 | func (ri *ReportInfo) MonitorHandler(ag agent.Agent, conn net.Conn, msg map[string]interface{}) { 56 | log.Println("MonitorHandler is called") 57 | rwLock.Lock() 58 | defer rwLock.Unlock() 59 | // msg == nil表示是定期执行的任务. 60 | if msg == nil { 61 | if ag.IsMaster() { 62 | return 63 | } 64 | monitorAgent, ok := ag.(*agent.MonitorAgent) 65 | if ok == false { 66 | seelog.Criticalf("MonitorHandler: Fail to convert to MonitorAgent,exit...") 67 | os.Exit(0) 68 | } 69 | serverInfo := monitorAgent.GetServerInfo() 70 | if serverInfo != nil { 71 | infoAsString := ri.getServerInfoAsString(serverInfo) 72 | ri.client.Sadd(serverInfo["serverType"].(string), []byte(serverInfo["id"].(string))) 73 | ri.client.Set(serverInfo["id"].(string), []byte(infoAsString)) 74 | ri.client.Expire(serverInfo["id"].(string), int64(2*ri.interval)) 75 | } 76 | 77 | } 78 | } 79 | 80 | func (ri *ReportInfo) MasterHandler(agent agent.Agent, conn net.Conn, msg map[string]interface{}) {} 81 | func (ri *ReportInfo) ClientHandler(agent agent.Agent, conn net.Conn, msg map[string]interface{}) {} 82 | func (ri *ReportInfo) Start() { 83 | } 84 | func (ri *ReportInfo) ModuleID() string { 85 | return ri.moduleId 86 | } 87 | func (ri *ReportInfo) GetType() string { 88 | return ri.moduleType 89 | } 90 | func (ri *ReportInfo) GetInterval() int16 { 91 | return ri.interval 92 | } 93 | -------------------------------------------------------------------------------- /pomelo-go/src/pomelo_admin/consoleService.go: -------------------------------------------------------------------------------- 1 | package pomelo_admin 2 | 3 | import ( 4 | "agent" 5 | "context" 6 | "encoding/json" 7 | "fmt" 8 | "module" 9 | "net" 10 | "os" 11 | ) 12 | 13 | const ( 14 | SV_INIT = iota 15 | SV_START = iota 16 | SV_CLOSE = iota 17 | ) 18 | 19 | type packageInfo struct { 20 | ModuleID string 21 | Type string 22 | Source string 23 | Msg map[string]interface{} 24 | } 25 | 26 | type ConsoleService interface { 27 | GetModuleByID(string) module.Module 28 | // HandleNewAcception(conn net.Conn) 29 | // Listen(hostAndPort string) 30 | Start() 31 | Stop() 32 | GetAgent() agent.Agent 33 | } 34 | 35 | ///处理接受到的包,解析包中包含的信息,来决定调用的module 36 | func processPackage(service ConsoleService, pack []byte, conn net.Conn) { 37 | fmt.Fprintf(os.Stdout, "Info: In processPackage...") 38 | var packInfo packageInfo 39 | var mod module.Module 40 | err := json.Unmarshal(pack, &packInfo) 41 | context.CheckError(err) 42 | mod = service.GetModuleByID(packInfo.ModuleID) 43 | if nil == mod { 44 | fmt.Fprintf(os.Stderr, "Error: Fail to get ModuleID: <%s>\n", packInfo.ModuleID) 45 | os.Exit(0) 46 | } 47 | 48 | fmt.Println("*************packInfo************") 49 | fmt.Println("ModuleID:", packInfo.ModuleID) 50 | fmt.Println("Type:", packInfo.Type) 51 | fmt.Println("Source:", packInfo.Source) 52 | fmt.Println("Msg:", packInfo.Msg) 53 | fmt.Println("*************packInfo************") 54 | switch packInfo.Source { 55 | case "master": 56 | mod.MasterHandler(service.GetAgent(), conn, packInfo.Msg) 57 | case "monitor": 58 | mod.MonitorHandler(service.GetAgent(), conn, packInfo.Msg) 59 | case "client": 60 | mod.ClientHandler(service.GetAgent(), conn, packInfo.Msg) 61 | default: 62 | fmt.Fprintf(os.Stderr, "Error: Unknown Source:<%s>", packInfo.Source) 63 | return 64 | } 65 | } 66 | 67 | ///处理连接上接收的数据 68 | /// 69 | ///BUG: 传递给processPackage参数有问题 70 | func handlerConnectionRecv(service ConsoleService, conn net.Conn) { 71 | fmt.Fprintf(os.Stdout, "In handlerConnectionRecv, conn<%v>\n", conn) 72 | const BUFSIZE int16 = 512 73 | 74 | var recvBuff []byte 75 | var buff []byte 76 | var begin, end, packSize, unProcess int16 77 | 78 | recvBuff = make([]byte, BUFSIZE) 79 | buff = make([]byte, BUFSIZE) 80 | 81 | defer conn.Close() 82 | for { 83 | 84 | n, err := conn.Read(recvBuff) 85 | 86 | if err != nil { 87 | masterServ, ok := service.(*MasterConsoleService) 88 | if ok { 89 | masterServ.GetAgent().(*agent.MasterAgent).RemoveConnection(conn) 90 | } 91 | 92 | fmt.Fprintf(os.Stderr, "Error: Read from conn , err message :%v\n", err.Error()) 93 | break 94 | } 95 | // fmt.Fprintf(os.Stdout, "what I receive is :%v", recvBuff[0:n]) 96 | context.CheckError(err) 97 | if begin >= end { 98 | begin = 0 99 | end = 0 100 | } 101 | 102 | buff = append(buff[begin:end], recvBuff[0:n]...) 103 | // fmt.Fprintf(os.Stdout, "current buff is: %v\n", buff[:]) 104 | unProcess = int16(len(buff)) 105 | begin = 0 106 | 107 | // fmt.Fprintf(os.Stdout, "after read begin: %v,end: %v\n", begin, end) 108 | // var reciveSize int16 = (end - begin + SIZE) % SIZE 109 | // fmt.Fprintf(os.Stdout, "reciveSize %v\n", reciveSize) 110 | for unProcess >= 1 { 111 | packSize = int16(buff[begin]) 112 | fmt.Fprintf(os.Stdout, "packsize is %v\n", packSize) 113 | if unProcess >= packSize { 114 | // for i := 1; int16(i) < packsize; i++ { 115 | // fmt.Fprintf(os.Stdout, "pos is %v\n", begin+int16(i)) 116 | // fmt.Fprintf(os.Stdout, "recive %dth is %d\n", int16(i), buff[begin+int16(i)]) 117 | // } 118 | fmt.Fprintf(os.Stdout, "Info: Packinfo :%v\n", buff[begin+1:begin+packSize]) 119 | go processPackage(service, buff[begin+1:begin+packSize], conn) 120 | unProcess -= packSize 121 | begin += packSize 122 | } else { 123 | break 124 | } 125 | // fmt.Fprintf(os.Stdout, "after pocess begin: %v,end: %v\n", begin, end) 126 | } //end inner for 127 | // fmt.Fprintf(os.Stdout, "after pocess begin: %v,end: %v\n", begin, end) 128 | } //end outter for 129 | 130 | } //end func handleConnectionRecv 131 | -------------------------------------------------------------------------------- /pomelo-go/src/pomelo_admin/masterConsoleService.go: -------------------------------------------------------------------------------- 1 | package pomelo_admin 2 | 3 | import ( 4 | "agent" 5 | "context" 6 | // "encoding/json" 7 | "fmt" 8 | "module" 9 | "net" 10 | "os" 11 | "strconv" 12 | ) 13 | 14 | /// MasterConsoleService实现consoleService接口 15 | type MasterConsoleService struct { 16 | Context *context.Context 17 | ModuleMap map[string]module.Module 18 | MAgent *agent.MasterAgent 19 | Listner *net.TCPListener 20 | status int8 21 | } 22 | 23 | /// 创建新的MasterConsoleService. 24 | /// 25 | /// 创建MasterConsoleService时首先会拿到所有注册在Context中的module,建立moduleID到 26 | /// module的映射 27 | func NewMasterConsoleService(ctx *context.Context) *MasterConsoleService { 28 | var modules = ctx.Modules 29 | var moduleMap = make(map[string]module.Module, 10) 30 | var mAgent = agent.NewMasterAgent(ctx.Ch, ctx.MasterInfo) 31 | for _, v := range modules { 32 | if v != nil { 33 | fmt.Fprintf(os.Stdout, "Registe module<%v> to master \n", v.ModuleID()) 34 | moduleMap[v.ModuleID()] = v 35 | } 36 | 37 | } 38 | return &MasterConsoleService{ctx, moduleMap, mAgent, nil, SV_INIT} 39 | } 40 | 41 | ///通过moduleID获取module 42 | func (m *MasterConsoleService) GetModuleByID(moduleID string) module.Module { 43 | return m.ModuleMap[moduleID] 44 | } 45 | 46 | ///处理接受到的新连接 47 | func (m *MasterConsoleService) HandleNewAcception(conn net.Conn) { 48 | m.MAgent.AddConnection(conn) 49 | fmt.Fprintf(os.Stdout, "In HandlerNewAcception, conn<%v>\n", conn) 50 | defer conn.Close() 51 | handlerConnectionRecv(m, conn) 52 | } 53 | 54 | /// 开启监听端口,接收monitor的连接. 55 | /// 56 | ///hostAndPort host:port 57 | func (m *MasterConsoleService) Listen(hostAndPort string) { 58 | // fmt.Println("In Listen") 59 | // fmt.Fprintf(os.Stdout, "tcp4 addr: %v\n", hostAndPort) 60 | tcpAddr, err := net.ResolveTCPAddr("tcp4", hostAndPort) 61 | // fmt.Println("After Resolve") 62 | context.CheckError(err) 63 | listener, err := net.ListenTCP("tcp4", tcpAddr) 64 | // fmt.Fprintf(os.Stdout, "tcp4 addr: %v\n", tcpAddr) 65 | // fmt.Println("After Listen") 66 | context.CheckError(err) 67 | m.Listner = listener 68 | defer listener.Close() 69 | fmt.Fprintf(os.Stdout, "Info: Listening <%v>\n", hostAndPort) 70 | for { 71 | conn, err := listener.Accept() 72 | fmt.Fprintf(os.Stdout, "Info: New acception<%v>\n", conn.RemoteAddr()) 73 | if nil != err { 74 | break 75 | 76 | } else { 77 | go m.HandleNewAcception(conn) 78 | } 79 | } 80 | fmt.Println("Listen end") 81 | } 82 | 83 | /// 启动MasterConsoleService. 84 | /// 85 | /// 启动时,首先开启监听,遍历所有挂载的模块,如果模块配置类型为pull或者push,这开启定时 86 | /// 调度,默认调度时间为5秒. 然后启动所有module. 87 | func (m *MasterConsoleService) Start() { 88 | if m.status == SV_START { 89 | fmt.Println("Info: Master Server is started already") 90 | return 91 | } 92 | // for _, v := range m.Context.Modules { 93 | // if 94 | // m.ModuleMap[v.ModuleID()] = v 95 | // } 96 | 97 | host, ok := m.Context.MasterInfo["host"] 98 | if !ok { 99 | fmt.Fprintf(os.Stderr, "Error: Master host not set\n") 100 | os.Exit(1) 101 | } 102 | 103 | port, ok := m.Context.MasterInfo["port"] 104 | 105 | if !ok { 106 | fmt.Fprintf(os.Stderr, "Error: Master port not set\n") 107 | os.Exit(1) 108 | } 109 | 110 | host_s := host.(string) 111 | fmt.Println(port) 112 | port_i := port.(int) 113 | 114 | hostAndPort := host_s + ":" + strconv.Itoa(port_i) 115 | go m.Listen(hostAndPort) 116 | 117 | for _, v := range m.Context.Modules { 118 | if v != nil { 119 | if v.GetType() == "pull" { 120 | interval := v.GetInterval() 121 | if interval == 0 { 122 | interval = 5 123 | } 124 | go module.PeriodicScheduler(v.MasterHandler, m.MAgent, interval) 125 | } 126 | } 127 | } 128 | 129 | for _, v := range m.Context.Modules { 130 | if v != nil { 131 | v.Start() 132 | } 133 | } 134 | } 135 | 136 | func (m *MasterConsoleService) Stop() { 137 | if m.status != SV_START { 138 | return 139 | } 140 | 141 | m.Listner.Close() 142 | m.status = SV_CLOSE 143 | } 144 | 145 | func (m *MasterConsoleService) GetAgent() agent.Agent { 146 | return m.MAgent 147 | } 148 | -------------------------------------------------------------------------------- /pomelo-go/src/pomelo_admin/monitorConsoleService.go: -------------------------------------------------------------------------------- 1 | package pomelo_admin 2 | 3 | import ( 4 | "agent" 5 | "context" 6 | // "encoding/json" 7 | "fmt" 8 | "module" 9 | "net" 10 | "os" 11 | ) 12 | 13 | /// MasterConsoleService实现consoleService接口 14 | type MonitorConsoleService struct { 15 | Context *context.Context 16 | ModuleMap map[string]module.Module 17 | monitorAgent *agent.MonitorAgent 18 | status int8 19 | } 20 | 21 | func NewMonitorConsoleService(ctx *context.Context) *MonitorConsoleService { 22 | moduleMap := make(map[string]module.Module) 23 | monitorAgent := agent.NewMonitorAgent(ctx.MasterInfo, ctx.CurrentServer) 24 | return &MonitorConsoleService{ctx, moduleMap, monitorAgent, SV_INIT} 25 | 26 | } 27 | 28 | func (m *MonitorConsoleService) handleConnection(conn net.Conn) { 29 | if m.status != SV_START { 30 | return 31 | } 32 | 33 | handlerConnectionRecv(m, conn) 34 | } 35 | 36 | /// 启动monitor. 37 | /// 38 | /// 启动monitor时会首先拿到所有注册的module,并挂载到MonitorConsoleService上, 39 | /// 然后对于设置类型为“push”的module定时调度其MonitoHandler方法, 为设置interval时 40 | /// 默认定时调度时间5秒. 41 | func (m *MonitorConsoleService) Start() { 42 | if m.status == SV_START { 43 | return 44 | } 45 | 46 | for _, v := range m.Context.Modules { 47 | m.ModuleMap[v.ModuleID()] = v 48 | } 49 | 50 | conn, err := m.monitorAgent.Connect() 51 | if err != nil { 52 | fmt.Fprintf(os.Stdout, "Error:Fail connect to master host:%v post:%v ", m.Context.MasterInfo["host"], m.Context.MasterInfo["port"]) 53 | os.Exit(1) 54 | } 55 | 56 | go m.handleConnection(conn) 57 | 58 | for _, mod := range m.ModuleMap { 59 | if mod != nil { 60 | if mod.GetType() == "push" { 61 | interval := mod.GetInterval() 62 | 63 | if interval == 0 { 64 | interval = 5 65 | } 66 | 67 | go module.PeriodicScheduler(mod.MonitorHandler, m.monitorAgent, interval) 68 | } 69 | } 70 | } 71 | 72 | } 73 | 74 | func (m *MonitorConsoleService) Stop() { 75 | if m.status != SV_START { 76 | return 77 | } 78 | 79 | m.status = SV_CLOSE 80 | 81 | m.monitorAgent.Close() 82 | } 83 | 84 | func (m *MonitorConsoleService) GetAgent() agent.Agent { 85 | return m.monitorAgent 86 | } 87 | 88 | func (m *MonitorConsoleService) GetModuleByID(id string) module.Module { 89 | return m.ModuleMap[id] 90 | } 91 | -------------------------------------------------------------------------------- /pomelo-go/src/remote_service/channelRpcServer/channelRpcServer.go: -------------------------------------------------------------------------------- 1 | package channelRpcServer 2 | 3 | import ( 4 | "component/coconnector" 5 | "component/corpcserver" 6 | "component/cosession" 7 | "context" 8 | "errors" 9 | seelog "github.com/cihub/seelog" 10 | "os" 11 | ) 12 | 13 | type ChannelRpcServer struct { 14 | coCnct *coconnector.CoConnector 15 | } 16 | 17 | func (crs *ChannelRpcServer) Start() { 18 | ctx := context.GetContext() 19 | coRpcS, ok := ctx.GetComponent("corpcserver").(*corpcserver.CoRpcServer) 20 | 21 | if ok == false { 22 | coRpcS = corpcserver.NewCoRpcServer() 23 | } 24 | 25 | seelog.Info("ChannelRpcServer start,registe service to rpcserver") 26 | // srs := NewSessionRpcServer() 27 | coRpcS.RegisteService(crs) 28 | 29 | } 30 | 31 | func NewChannelRpcServer() *ChannelRpcServer { 32 | ctx := context.GetContext() 33 | 34 | coCnct, ok := ctx.GetComponent("coconnector").(*coconnector.CoConnector) 35 | if ok == false { 36 | coCnct = coconnector.NewCoConnector(ctx) 37 | } 38 | 39 | return &ChannelRpcServer{coCnct} 40 | } 41 | 42 | func (crs *ChannelRpcServer) PushMessage(args map[string]interface{}, reply interface{}) error { 43 | route, _ := args["route"].(string) 44 | msg, ok1 := args["msg"].(map[string]interface{}) 45 | if ok1 == false { 46 | seelog.Error("Invalid or empty message") 47 | return errors.New("Invalid or empty message") 48 | } 49 | 50 | coSess, ok2 := context.GetContext().GetComponent("cosession").(*cosession.CoSession) 51 | 52 | if ok2 == false { 53 | seelog.Critical("Failed to get component") 54 | os.Exit(1) 55 | } 56 | 57 | uids, ok3 := args["uids"].([]string) 58 | if ok3 == false { 59 | seelog.Error("Failed to get uids") 60 | return errors.New("Failed to get uids") 61 | } 62 | 63 | sids := make([]uint32, 0, 16) 64 | for _, uid := range uids { 65 | sessions := coSess.GetSessionsByUID(uid) 66 | 67 | if sessions == nil { 68 | seelog.Warnf("Failed to push message to uid<%v> because of nil sessions", uid) 69 | continue 70 | } 71 | 72 | for _, session := range sessions { 73 | sids = append(sids, session.Id) 74 | } 75 | } 76 | 77 | seelog.Debugf("<%v> push messages<%v> to uids<%v> with sessions<%v>", context.GetContext().GetServerID(), msg, uids, sids) 78 | 79 | //XXX:调用coconnector的send方法发送. 80 | crs.coCnct.Send("", route, msg, sids) 81 | return nil 82 | 83 | } 84 | 85 | func (crs *ChannelRpcServer) Broadcast(args map[string]interface{}, reply interface{}) error { 86 | //XXX:调用coconnector的send方法发送. 87 | return nil 88 | } 89 | -------------------------------------------------------------------------------- /pomelo-go/src/remote_service/sessionRpcServer/sessionRpcServer.go: -------------------------------------------------------------------------------- 1 | /** 2 | * author:liweisheng date:2015/07/24 3 | */ 4 | 5 | /** 6 | * sessionRpcServer包与包backendSessionService相对等,相当于rpc服务的服务端与客户端,backendSessionService 7 | * 发起rpc调用请求sessionRpcService服务,将对backendsession的改变影响到前端服务器的session. 8 | * 9 | * sessionRpcServer内部想象session的操作都是用过组建cosession实现的. 10 | */ 11 | package sessionRpcServer 12 | 13 | import ( 14 | "component/corpcserver" 15 | "component/cosession" 16 | "context" 17 | "fmt" 18 | 19 | seelog "github.com/cihub/seelog" 20 | ) 21 | 22 | type NoReply int 23 | type SessionRpcServer struct { 24 | sessionService *cosession.CoSession 25 | } 26 | 27 | func (srs *SessionRpcServer) Start() { 28 | ctx := context.GetContext() 29 | coRpcS, ok := ctx.GetComponent("corpcserver").(*corpcserver.CoRpcServer) 30 | 31 | if ok == false { 32 | coRpcS = corpcserver.NewCoRpcServer() 33 | } 34 | 35 | seelog.Infof("frontendserver<%v> SessionRpcServer start,registe service to rpc server", ctx.GetServerID()) 36 | // srs := NewSessionRpcServer() 37 | coRpcS.RegisteService(srs) 38 | } 39 | 40 | func NewSessionRpcServer() *SessionRpcServer { 41 | ctx := context.GetContext() 42 | 43 | sessionService, ok := ctx.GetComponent("cosession").(*cosession.CoSession) 44 | 45 | if ok == false || sessionService == nil { 46 | sessionService = cosession.NewCoSession() 47 | } 48 | 49 | return &SessionRpcServer{sessionService} 50 | } 51 | 52 | /// rpc服务端操作,通过session id返回前端session的详细信息. 53 | /// 54 | /// @param sid session id 55 | /// @param reply 返回给rpc调用端,name->value形式存放,存放信息包括,sid:session id, uid:用户id,frontendid:前端服务器id,opts:设置的属性 56 | /// @return nil 57 | func (srs *SessionRpcServer) GetSessionBySID(sid *uint32, reply *map[string]interface{}) error { 58 | 59 | seelog.Debugf("SessionRpcServer method is invoked with sid<%v>", sid) 60 | session := srs.sessionService.GetSessionByID(*sid) 61 | 62 | rep := make(map[string]interface{}) 63 | 64 | if session != nil { 65 | rep["sid"] = uint32(*sid) 66 | rep["uid"] = session.Uid 67 | rep["frontendid"] = session.FrontendID 68 | rep["opts"] = session.Opts 69 | *reply = rep 70 | } else { 71 | *reply = rep 72 | } 73 | return nil 74 | } 75 | 76 | /// 通过用户id返回用户id绑定的所有session(如果容许同一个用户id绑定多次,则存在多个session) 77 | /// 78 | /// @param uid 用户id 79 | /// @param reply 返回给rpc 客户端的结果,有多个session组成的数组,每个数组元素以name->value形式存放. 80 | func (srs *SessionRpcServer) GetSessionsByUID(uid string, reply *[]map[string]interface{}) error { 81 | seelog.Debugf("SessionRpcServer method is invoked with uid<%v>", uid) 82 | 83 | sessions := srs.sessionService.GetSessionsByUID(uid) 84 | rep := make([]map[string]interface{}, 0) 85 | if sessions != nil { 86 | for _, elem := range sessions { 87 | 88 | s := make(map[string]interface{}) 89 | s["sid"] = elem.Id 90 | s["uid"] = uid 91 | s["frontendid"] = elem.FrontendID 92 | s["opts"] = elem.Opts 93 | rep = append(rep, s) 94 | } 95 | *reply = rep 96 | } else { 97 | *reply = nil 98 | } 99 | return nil 100 | } 101 | 102 | /// rpc服务端操作,通过制定session id踢除用户. 103 | /// 104 | /// @param args args[0]表示sessionid{uint32} ,args[1]表示reason{string} 105 | /// @param reply 无实际意义参数,rpc客户端传来的nil 106 | /// @return nil 107 | func (srs *SessionRpcServer) KickBySID(args []interface{}, reply *NoReply) error { 108 | 109 | sid, _ := args[0].(float64) 110 | reason, _ := args[1].(string) 111 | 112 | seelog.Debugf("SessionRpcServer method is invoked with sid<%v> reason<%v>", sid, reason) 113 | srs.sessionService.KickBySessionID(uint32(sid), reason) 114 | 115 | return nil 116 | } 117 | 118 | /// rpc服务端操作,通过用户id踢出用户. 119 | /// @param args args[0]{string}用户id, args[1]{string} reason 120 | /// @param reply nil 121 | /// @return nil 122 | func (srs *SessionRpcServer) KickByUID(args []string, reply *NoReply) error { 123 | 124 | uid := args[0] 125 | reason := args[1] 126 | 127 | seelog.Debugf("SessionRpcServer method is invoked with uid<%v> reason<%v>", uid, reason) 128 | 129 | srs.sessionService.KickByUID(uid, reason) 130 | 131 | return nil 132 | } 133 | 134 | /// rpc服务端操作, 将用户id与session id绑定. 135 | /// 136 | /// @param args arg[0]{uint32} sessionid, args[1]{string}用户id 137 | /// @param reply 当前rpc客户端传过来的nil 138 | /// @return nil 139 | func (srs *SessionRpcServer) BindUID(args *[]interface{}, reply *NoReply) error { 140 | 141 | sid, _ := (*args)[0].(float64) 142 | uid, _ := (*args)[1].(string) 143 | fmt.Printf("BindUID args:%v,sid:%v \n", *args, uint32(sid)) 144 | seelog.Debugf("SessionRpcServer method is invoked with sid<%v>, uid<%v>", sid, uid) 145 | 146 | srs.sessionService.BindUID(uid, uint32(sid)) 147 | 148 | return nil 149 | } 150 | 151 | /// rpc服务端操作, 将用户id与session id解绑定. 152 | /// 153 | /// @param args args[0]{uint32} sessionid, args[1] {string} 用户id 154 | /// @param reply 当前rpc客户端传过来为nil 155 | /// @return nil 156 | func (srs *SessionRpcServer) UnbindUID(args *[]interface{}, reply *NoReply) error { 157 | sid, _ := (*args)[0].(float64) 158 | uid, _ := (*args)[1].(string) 159 | 160 | seelog.Debugf("SessionRpcServer method is invoked with sid<%v> uid<%v>", sid, uid) 161 | 162 | srs.sessionService.UnbindUID(uid, uint32(sid)) 163 | 164 | return nil 165 | } 166 | 167 | /// rpc服务端操作,设置用户的属性. 168 | /// 169 | /// @param args args["sid"]{uint32}session id, args["key"]属性名,args["value"]{interface{}}属性值 170 | /// @param reply rpc客户端传递多来为nil 171 | /// @return nil 172 | func (srs *SessionRpcServer) PushOpt(args *map[string]interface{}, reply *NoReply) error { 173 | 174 | sid, _ := (*args)["sid"].(float64) 175 | key, _ := (*args)["key"].(string) 176 | value, _ := (*args)["value"] 177 | 178 | seelog.Debugf("SessionRpcServer method is invoked with sid<%v> key<%v> value<%v>", sid, key, value) 179 | 180 | srs.sessionService.PushOpt(uint32(sid), key, value) 181 | 182 | return nil 183 | } 184 | 185 | /// rpc服务端操作,类似PushOpt, 可以同时设置多个属性. 186 | /// 187 | /// @param args["sid"]{uint32} sessionid,args["setting"] {map[string]interface{}}多个属性的key->value映射. 188 | /// @param reply rpc客户端传递过来为nil 189 | /// @return nil 190 | func (srs *SessionRpcServer) PushAllOpts(args *map[string]interface{}, reply *NoReply) error { 191 | 192 | sid, _ := (*args)["sid"].(float64) 193 | opts, _ := (*args)["settings"].(map[string]interface{}) 194 | 195 | seelog.Debugf("SessionRpcServer method is invoked with sid<%v>", sid) 196 | 197 | srs.sessionService.PushAllOpts(uint32(sid), opts) 198 | 199 | return nil 200 | } 201 | -------------------------------------------------------------------------------- /pomelo-go/src/rpcclient/rpcClient.go: -------------------------------------------------------------------------------- 1 | /** 2 | * author:liweisheng date:2015/07/20 3 | */ 4 | 5 | /** 6 | * rpcClient实现rpc客户端,负责 7 | */ 8 | 9 | package rpcclient 10 | 11 | import ( 12 | "context" 13 | "errors" 14 | "fmt" 15 | seelog "github.com/cihub/seelog" 16 | 17 | // "net/rpc" 18 | "net/rpc/jsonrpc" 19 | ) 20 | 21 | type RpcClient struct { 22 | ctx *context.Context 23 | } 24 | 25 | func NewRpcClient(ctx *context.Context) *RpcClient { 26 | return &RpcClient{ctx} 27 | } 28 | 29 | func (rc *RpcClient) Start() { 30 | seelog.Infof("server<%v> start RpcClient", rc.ctx.GetServerID()) 31 | } 32 | 33 | /// 发起远程调用. 34 | /// 35 | /// @param serverID 接收远程调用的服务器id 36 | /// @param method 请求的方法 37 | /// @param args 传递给远程过程的参数 38 | /// @param reply 用于传输返回值,为空时表示不关心返回值. 39 | /// @return 当参数reply不为空时,返回值意义参见rpc.Go 40 | func (rc *RpcClient) RpcCall(serverID string, method string, args interface{}, reply interface{}) error { 41 | info := rc.ctx.GetServerInfoByID(serverID) 42 | 43 | host, _ := info["host"].(string) 44 | port, _ := info["port"].(int) 45 | 46 | hostPort := fmt.Sprintf("%v:%v", host, port) 47 | 48 | client, err := jsonrpc.Dial("tcp", hostPort) 49 | 50 | if err != nil { 51 | seelog.Errorf("Fail to Dial rpc server,error message:%v", err.Error()) 52 | return errors.New("Fail to Dial rpc server") 53 | } 54 | 55 | defer client.Close() 56 | seelog.Debugf("Rpc client call for remote method<%v>,remote serverid<%v>", method, serverID) 57 | return client.Call(method, args, reply) 58 | 59 | } 60 | -------------------------------------------------------------------------------- /pomelo-go/src/rpcserver/rpcServer.go: -------------------------------------------------------------------------------- 1 | /** 2 | * author:liweisheng date:2015/07/23 3 | */ 4 | 5 | /** 6 | * rpcServer是由后端服务器加载的rpc服务器端,它接收并服务前端服务器发起的rpc调用请求. 7 | * 采用json做编码/解码协议. 8 | */ 9 | 10 | package rpcserver 11 | 12 | import ( 13 | "fmt" 14 | seelog "github.com/cihub/seelog" 15 | "net" 16 | "net/rpc" 17 | "net/rpc/jsonrpc" 18 | "os" 19 | ) 20 | 21 | type RpcServer struct { 22 | host string 23 | port int 24 | rpcServer *rpc.Server 25 | } 26 | 27 | func NewRpcServer(host string, port int) *RpcServer { 28 | rs := rpc.NewServer() 29 | return &RpcServer{host, port, rs} 30 | } 31 | 32 | /// 向rpc服务器注册服务,封装rpc.Register 33 | func (ms *RpcServer) RegisteService(r interface{}) { 34 | err := ms.rpcServer.Register(r) 35 | if err != nil { 36 | seelog.Criticalf("Fail to Register Rpc Service,%v", err.Error()) 37 | os.Exit(1) 38 | } 39 | } 40 | 41 | /// 启动rpcServer,监听rpc服务器端口,由于Start内部调用阻塞的方法,应在go 语句中调用. 42 | func (ms *RpcServer) Start() { 43 | go func() { 44 | seelog.Info("RpcServer start...") 45 | hostAndPort := fmt.Sprintf("%v:%v", ms.host, ms.port) 46 | 47 | servAddr, err := net.ResolveTCPAddr("tcp", hostAndPort) 48 | 49 | if err != nil { 50 | seelog.Criticalf("RpcServer failed to start with err<%v>", err.Error()) 51 | os.Exit(1) 52 | } 53 | 54 | listener, err := net.ListenTCP("tcp4", servAddr) 55 | 56 | if err != nil { 57 | seelog.Criticalf("RpcServer failed to start with err<%v>", err.Error()) 58 | os.Exit(1) 59 | } 60 | 61 | seelog.Debugf("Rpc Server listening: <%v>", servAddr.String()) 62 | defer listener.Close() 63 | 64 | for { 65 | conn, err := listener.Accept() 66 | 67 | seelog.Debug("Rpc Server accept new connection") 68 | if err != nil { 69 | seelog.Critical(err.Error()) 70 | os.Exit(1) 71 | } 72 | go ms.rpcServer.ServeCodec(jsonrpc.NewServerCodec(conn)) 73 | } 74 | }() 75 | 76 | } 77 | -------------------------------------------------------------------------------- /pomelo-go/src/server/server.go: -------------------------------------------------------------------------------- 1 | /** 2 | * author:liweisheng date:2015/07/01 3 | */ 4 | package server 5 | 6 | import ( 7 | "component/corpcclient" 8 | "component/corpcserver" 9 | "context" 10 | "github.com/cihub/seelog" 11 | "reflect" 12 | "service/sessionService" 13 | "strings" 14 | ) 15 | 16 | type Server struct { 17 | ctx *context.Context 18 | coRpcS *corpcserver.CoRpcServer 19 | coRpcC *corpcclient.CoRpcClient 20 | handlers map[string]func(*sessionService.SimpleSession, map[string]interface{}) map[string]interface{} 21 | } 22 | 23 | func NewServer() *Server { 24 | ctx := context.GetContext() 25 | 26 | coRpcS, ok1 := ctx.GetComponent("corpcserver").(*corpcserver.CoRpcServer) 27 | if ok1 == false { 28 | coRpcS = corpcserver.NewCoRpcServer() 29 | } 30 | 31 | coRpcC, ok2 := ctx.GetComponent("corpcclient").(*corpcclient.CoRpcClient) 32 | if ok2 == false { 33 | coRpcC = corpcclient.NewCoRpcClient() 34 | } 35 | handlers := make(map[string]func(*sessionService.SimpleSession, map[string]interface{}) map[string]interface{}) 36 | return &Server{ctx, coRpcS, coRpcC, handlers} 37 | } 38 | 39 | func (s *Server) RegisteAsLocalService(recv interface{}) { 40 | t := reflect.TypeOf(recv) 41 | v := reflect.ValueOf(recv) 42 | numMethod := t.NumMethod() 43 | sName := v.Type().Name() 44 | for index := 0; index < numMethod; index++ { 45 | methodName := t.Method(index).Name 46 | if handler, ok := v.Method(index).Interface().(func(*sessionService.SimpleSession, map[string]interface{}) map[string]interface{}); ok == true { 47 | s.handlers[sName+"."+methodName] = handler 48 | seelog.Infof("<%v> Registe local service<%v>'s method<%v>", context.GetContext().GetServerID(), v.Type().Name(), methodName) 49 | } else { 50 | seelog.Warnf("<%v> Registe local service <%v>'s method<%v> error", context.GetContext().GetServerID(), v.Type().Name(), methodName) 51 | } 52 | } 53 | } 54 | 55 | func (s *Server) RegisteAsRemoteService(recv interface{}) { 56 | s.coRpcS.RegisteService(recv) 57 | } 58 | 59 | func (s *Server) GlobalHandler(msg map[string]interface{}, session *sessionService.SimpleSession, sendCB func(string, string, map[string]interface{}, []uint32)) { 60 | frontendID := s.ctx.GetServerID() 61 | route, _ := msg["route"].(string) 62 | record := parseRoute(route) 63 | if record == nil { 64 | seelog.Errorf("receive invalid route<%v>, route format must be", route) 65 | return 66 | } 67 | handlerMethodName := record.handler + "." + record.method 68 | if context.GetContext().GetServerType() == record.serverType { 69 | ///调用本地方法处理. 70 | seelog.Infof("<%v> receive local handler<%v> request", frontendID, handlerMethodName) 71 | if handlerMethod, ok := s.handlers[handlerMethodName]; ok == true { 72 | replyMsg := handlerMethod(session, msg) 73 | seelog.Debugf("<%v> local handler<%v> reply msg<%v>", frontendID, handlerMethodName, replyMsg) 74 | sids := make([]uint32, 1) 75 | sids[0] = session.Id 76 | reqID, _ := replyMsg["reqID"].(string) 77 | rroute, _ := replyMsg["route"].(string) 78 | msgBody, _ := replyMsg["msg"].(map[string]interface{}) 79 | sendCB(reqID, rroute, msgBody, sids) 80 | } else { 81 | seelog.Errorf("<%v> request local handler<%v> error", frontendID, handlerMethodName) 82 | } 83 | } else { 84 | ///rpc调用远端方法 85 | 86 | servID := s.ctx.GetServerIDByType(record.serverType) 87 | seelog.Infof("<%v> invoke remote handler<%v> request of <%v>", frontendID, handlerMethodName, servID) 88 | reply := make(map[string]interface{}) 89 | if err := s.coRpcC.RpcCall(servID, handlerMethodName, msg, &reply); err != nil { 90 | seelog.Errorf("<%v> rpc call<%v> error<%v>", frontendID, handlerMethodName, err.Error()) 91 | } 92 | } 93 | 94 | } 95 | 96 | func (s *Server) Start() { 97 | seelog.Infof("<%v> component server start...", s.ctx.GetServerID()) 98 | } 99 | 100 | type routeRecord struct { 101 | route string 102 | serverType string 103 | handler string 104 | method string 105 | } 106 | 107 | func parseRoute(route string) *routeRecord { 108 | rs := strings.Split(route, ".") 109 | if len(rs) != 3 { 110 | return nil 111 | } 112 | 113 | return &routeRecord{route, rs[0], rs[1], rs[2]} 114 | 115 | } 116 | -------------------------------------------------------------------------------- /pomelo-go/src/service/backendSessionService/backendSessionService.go: -------------------------------------------------------------------------------- 1 | /** 2 | * author:liweisheng date:2015/07/26 3 | */ 4 | 5 | /** 6 | * 包backendSessionService与包sessionRpcServer相对应,相当于rpc客户端与服务端的关系. 7 | * 包backendSessionService包含BackendSession和BackendSessionService. 8 | * 9 | * BackendSession 相当于前端服务器session在后端的代理,仅由后端服务器加载. 10 | * BackendSessionService管理backendsession,并封装了多backendsession的操作, 11 | * BackendSessionService通过发起rpc调用请求SessionRpcServer的服务,将用户对backendsession的 12 | * 操作同步到前端session. 13 | */ 14 | 15 | package backendSessionService 16 | 17 | import ( 18 | "component/corpcclient" 19 | "context" 20 | 21 | seelog "github.com/cihub/seelog" 22 | ) 23 | 24 | type BackendSessionService struct { 25 | rpcCient *corpcclient.CoRpcClient 26 | } 27 | 28 | func NewBackendSessionService(ctx *context.Context) *BackendSessionService { 29 | 30 | rpcClient, ok := ctx.GetComponent("corpcclient").(*corpcclient.CoRpcClient) 31 | 32 | if ok == false || rpcClient == nil { 33 | rpcClient = corpcclient.NewCoRpcClient() 34 | } 35 | 36 | return &BackendSessionService{rpcClient} 37 | } 38 | 39 | func (bss *BackendSessionService) Start() { 40 | seelog.Infof("server<%v> start BackendSessionService", context.GetContext().GetServerID()) 41 | } 42 | 43 | /// 创建新的BackendSession. 44 | func (bss *BackendSessionService) CreateBackendSession(opts map[string]interface{}) *BackendSession { 45 | return newBackendSession(opts, bss) 46 | } 47 | 48 | /// 通过frontendID 和sessionID获得前端服务器session的信息. 49 | /// 50 | /// @param frontendID 前端服务器id 51 | /// @param sid session id 52 | /// @return backend session 53 | func (bss *BackendSessionService) GetBackendSessionBySID(frontendid string, sid uint32) *BackendSession { 54 | seelog.Tracef("frontendid<%v>,sid<%v>", frontendid, sid) 55 | 56 | reply := make(map[string]interface{}) 57 | method := "SessionRpcServer.GetSessionBySID" 58 | err := bss.rpcCient.RpcCall(frontendid, method, &sid, &reply) 59 | 60 | if err == nil { 61 | // <-rpcRelpy.Done 62 | 63 | if reply == nil || len(reply) == 0 { 64 | return nil 65 | } 66 | opts, _ := reply["opts"].(map[string]interface{}) 67 | 68 | backendSession := bss.CreateBackendSession(opts) 69 | backendSession.uid = reply["uid"].(string) 70 | backendSession.id = uint32(reply["sid"].(float64)) 71 | backendSession.frontendID = reply["frontendid"].(string) 72 | 73 | seelog.Debugf("Receive from rpc server<%v>", reply) 74 | return backendSession 75 | } else { 76 | 77 | seelog.Errorf("Rpc Call failed,error<%v>", err.Error()) 78 | return nil 79 | } 80 | } 81 | 82 | /// 通过user id 获得所有绑定的session 83 | /// 84 | /// @param frontendid 前端服务器id 85 | /// @param uid user id 86 | func (bss *BackendSessionService) GetBackendSessionsByUID(frontendid string, uid string) []*BackendSession { 87 | seelog.Tracef("frontendid<%v>,sid<%v>", frontendid, uid) 88 | 89 | backendSessions := make([]*BackendSession, 0, 5) 90 | 91 | replies := make([]map[string]interface{}, 0, 5) 92 | method := "SessionRpcServer.GetSessionsByUID" 93 | 94 | err := bss.rpcCient.RpcCall(frontendid, method, uid, &replies) 95 | 96 | if err == nil { 97 | // <-rpcReply.Done 98 | 99 | if replies == nil { 100 | return nil 101 | } 102 | for _, elem := range replies { 103 | 104 | opts, _ := elem["opts"].(map[string]interface{}) 105 | seelog.Debugf("Replied session opts<%v>", opts) 106 | 107 | bs := bss.CreateBackendSession(opts) 108 | 109 | bs.uid, _ = elem["uid"].(string) 110 | id, _ := elem["sid"].(float64) 111 | bs.id = uint32(id) 112 | bs.frontendID, _ = elem["frontendid"].(string) 113 | backendSessions = append(backendSessions, bs) 114 | } 115 | 116 | return backendSessions 117 | } else { 118 | seelog.Errorf("GetBackendSessionsByUID error<%v>", err.Error()) 119 | return nil 120 | } 121 | 122 | } 123 | 124 | /// 通过session id从前端服务器踢除用户连接,通过rpc调用前端服务器的同样操作. 125 | /// 126 | /// @param frontendid 前端服务器id 127 | /// @param sid session id 128 | /// @reason 作为踢除用户连接时发送给用户端的提示信息. 129 | /// @return 无返回值 130 | func (bss *BackendSessionService) KickBySID(frontendid string, sid uint32, reason string) { 131 | seelog.Tracef("frontendid<%v>,sid<%v>", frontendid, sid) 132 | 133 | method := "SessionRpcServer.KickBySID" 134 | 135 | args := make([]interface{}, 2) 136 | 137 | args[0] = sid 138 | args[1] = reason 139 | if err := bss.rpcCient.RpcCall(frontendid, method, args, nil); err != nil { 140 | seelog.Errorf("<%v> KickBySID error<%v>", context.GetContext().GetServerID(), err.Error()) 141 | } 142 | } 143 | 144 | /// 通过uid从前端服务器剔除用户,通过rpc调用前端服务器的同样操作. 145 | /// 146 | /// @param frontendid 前端服务器id 147 | /// @param uid 用户id 148 | /// @param reason 作为踢出用户前发送的提示信息 149 | func (bss *BackendSessionService) KickByUID(frontendid string, uid string, reason string) { 150 | seelog.Tracef("frontendif<%v>,uid<%v>", frontendid, uid) 151 | 152 | method := "SessionRpcServer.KickByUID" 153 | 154 | args := make([]string, 2) 155 | 156 | args[0] = uid 157 | args[1] = reason 158 | 159 | if err := bss.rpcCient.RpcCall(frontendid, method, args, nil); err != nil { 160 | 161 | seelog.Errorf("<%v> KickByUID error<%v>", context.GetContext().GetServerID(), err.Error()) 162 | } 163 | } 164 | 165 | /// 绑定用户id与session id,该操作会通过rpc调用在前端服务器完成uid与sid的绑定. 166 | /// 167 | /// @param frontendid 前端服务器id 168 | /// @param sid session id 169 | /// @param uid 用户id 170 | func (bss *BackendSessionService) BindUID(frontendid string, sid uint32, uid string) { 171 | seelog.Tracef("Bind uid<%v> with session id<%v>", uid, sid) 172 | 173 | args := make([]interface{}, 2) 174 | 175 | args[0] = sid 176 | args[1] = uid 177 | 178 | method := "SessionRpcServer.BindUID" 179 | 180 | if err := bss.rpcCient.RpcCall(frontendid, method, &args, nil); err != nil { 181 | 182 | seelog.Errorf("<%v> BindUID uid<%v> with sid<%v> error<%v>", context.GetContext().GetServerID(), uid, sid, err.Error()) 183 | } 184 | } 185 | 186 | /// 解除用户id到session id的绑定,该操作会通过rpc调用影响前端服务器. 187 | /// 188 | /// @param frontendid 前端服务器id 189 | /// @param sid session id 190 | /// @param uid 用户id 191 | func (bss *BackendSessionService) UnbindUID(frontendid string, sid uint32, uid string) { 192 | seelog.Tracef("Unbind uid<%v> with session id<%v>", uid, sid) 193 | 194 | args := make([]interface{}, 2) 195 | 196 | args[0] = sid 197 | args[1] = uid 198 | 199 | method := "SessionRpcServer.UnbindUID" 200 | 201 | if err := bss.rpcCient.RpcCall(frontendid, method, &args, nil); err != nil { 202 | 203 | seelog.Errorf("<%v> UnbindUID uid<%v> with sid<%v> error<%v>", context.GetContext().GetServerID(), uid, sid, err.Error()) 204 | } 205 | } 206 | 207 | /// 将设置sid标识的session的属性同步到前端服务器. 208 | /// 209 | /// @param frontendid 前端服务器id 210 | /// @param sid session id 211 | /// @param key 属性名 212 | /// @param value 属性值 213 | func (bss *BackendSessionService) PushOpt(frontendid string, sid uint32, key string, value interface{}) { 214 | seelog.Tracef("Push opt to <%v> with sid<%v>,key<%v>,value<%v>", frontendid, sid, key, value) 215 | 216 | args := make(map[string]interface{}) 217 | 218 | args["sid"] = sid 219 | args["key"] = key 220 | args["value"] = value 221 | 222 | method := "SessionRpcServer.PushOpt" 223 | 224 | if err := bss.rpcCient.RpcCall(frontendid, method, &args, nil); err != nil { 225 | 226 | seelog.Errorf("<%v> PushOpt with sid<%v> to frontend<%v> error<%v>", context.GetContext().GetServerID(), sid, frontendid, err.Error()) 227 | } 228 | 229 | } 230 | 231 | func (bss *BackendSessionService) PushAllOpts(frontendid string, sid uint32, settings map[string]interface{}) { 232 | seelog.Tracef("Push all opts to <%v> with sid<%v>", frontendid, sid) 233 | 234 | args := make(map[string]interface{}) 235 | 236 | args["sid"] = sid 237 | args["settings"] = settings 238 | 239 | method := "SessionRpcServer.PushAllOpts" 240 | 241 | if err := bss.rpcCient.RpcCall(frontendid, method, &args, nil); err != nil { 242 | seelog.Errorf("<%v> PushAllOpts with sid<%v> to frontend<%v> error<%v>", context.GetContext().GetServerID(), sid, frontendid, err.Error()) 243 | } 244 | } 245 | 246 | type BackendSession struct { 247 | frontendID string 248 | uid string 249 | id uint32 250 | backendSessionService *BackendSessionService 251 | opts map[string]interface{} 252 | } 253 | 254 | /// 创建新的BackendSession,外部包不能访问此方法,创建BackendSession参见CreateBackendSession. 255 | /// 256 | /// @param opts BackendSession选项 257 | /// @param backendSessionService 管理BackendSession的BackendSessionService,及创建BackendSession者. 258 | func newBackendSession(opts map[string]interface{}, backendSessionService *BackendSessionService) *BackendSession { 259 | if nil == opts { 260 | opts = make(map[string]interface{}) 261 | } 262 | return &BackendSession{"", "", 0, backendSessionService, opts} 263 | } 264 | 265 | func (bs *BackendSession) GetFrontendID() string { 266 | return bs.frontendID 267 | } 268 | 269 | func (bs *BackendSession) GetUID() string { 270 | return bs.uid 271 | } 272 | 273 | func (bs *BackendSession) GetID() uint32 { 274 | return bs.id 275 | } 276 | 277 | func (bs *BackendSession) GetOpts() map[string]interface{} { 278 | return bs.opts 279 | } 280 | 281 | func (bs *BackendSession) BindUID(uid string) { 282 | bs.backendSessionService.BindUID(bs.frontendID, bs.id, uid) 283 | } 284 | 285 | func (bs *BackendSession) UnbindUID(uid string) { 286 | bs.backendSessionService.UnbindUID(bs.frontendID, bs.id, uid) 287 | } 288 | 289 | func (bs *BackendSession) SetOpt(key string, value interface{}) { 290 | bs.opts[key] = value 291 | } 292 | 293 | func (bs *BackendSession) GetOpt(key string) interface{} { 294 | return bs.opts[key] 295 | } 296 | 297 | func (bs *BackendSession) PushOpt(key string) { 298 | bs.backendSessionService.PushOpt(bs.frontendID, bs.id, key, bs.opts[key]) 299 | } 300 | 301 | func (bs *BackendSession) PushAllOpts() { 302 | bs.backendSessionService.PushAllOpts(bs.frontendID, bs.id, bs.opts) 303 | } 304 | -------------------------------------------------------------------------------- /pomelo-go/src/service/channelService/channelService.go: -------------------------------------------------------------------------------- 1 | /** 2 | * author:liweisheng date:2015/07/28 3 | */ 4 | 5 | /** 6 | * 包channelService包含Channel和ChannelServevice,Channel可以理解为一个广播组, 7 | * Channel包含多个session,每个session可以当作一个广播组的一个成员,channelService 8 | * 管理所有Channel. 9 | */ 10 | package channelService 11 | 12 | import ( 13 | "component/cochannelrpcserver" 14 | "component/corpcclient" 15 | "context" 16 | seelog "github.com/cihub/seelog" 17 | ) 18 | 19 | type ChannelService struct { 20 | ctx *context.Context 21 | coRpcClient *corpcclient.CoRpcClient 22 | channels map[string]*Channel 23 | } 24 | 25 | /// 创建新的ChannelService,ChannelService管理用户创建的所有Channel,并代理用户对Channel的操作, 26 | /// 用户发送给一个Channel里所有session的消息会通过rpc调用发送给对应的前端服务器,并通过前端服务 27 | /// 器推送给客户端. 28 | func NewChannelService() *ChannelService { 29 | ctx := context.GetContext() 30 | 31 | coRpcClient, ok := ctx.GetComponent("corpcclient").(*corpcclient.CoRpcClient) 32 | 33 | if ok == false { 34 | coRpcClient = corpcclient.NewCoRpcClient() 35 | } 36 | 37 | channels := make(map[string]*Channel) 38 | 39 | return &ChannelService{ctx, coRpcClient, channels} 40 | } 41 | 42 | /// 以name为名称创建新的Channel,如果指定名称的channel存在就返回存在的channel,否则创建新的. 43 | /// 44 | /// @param name channel名称 45 | /// @return {*Channel} 或者nil 46 | func (cs *ChannelService) NewChannel(name string) *Channel { 47 | if name == "" { 48 | seelog.Error("NewChannel need a non-empty name") 49 | return nil 50 | } 51 | 52 | if channel, ok := cs.channels[name]; ok == true { 53 | seelog.Infof("channel with name<%v> already exists", name) 54 | return channel 55 | } else { 56 | seelog.Infof("channel with name<%v> doesn't exists,create new", name) 57 | channel := newChannel() 58 | cs.channels[name] = channel 59 | return channel 60 | } 61 | } 62 | 63 | /// 返回名称为name的channel,如果参数create为true,则指定名称的channel不存在时以name创建新的channel, 64 | /// 否则返回nil. 65 | /// 66 | /// @param name channel名称. 67 | /// @param create 为true时名称为name的channel不存在是创建新的channel 68 | /// @return *Channel 或者nil 69 | func (cs *ChannelService) GetChannel(name string, create bool) *Channel { 70 | if channel, ok := cs.channels[name]; ok == true { 71 | return channel 72 | } else { 73 | if create == true { 74 | 75 | seelog.Infof("Channel with name<%v> doesn't exists ,create new", name) 76 | return cs.NewChannel(name) 77 | } 78 | 79 | return nil 80 | } 81 | 82 | } 83 | 84 | /// 销毁名称为name的channel 85 | /// 86 | /// @param name 待销毁channel的名称 87 | func (cs *ChannelService) DestroyChannel(name string) { 88 | seelog.Infof("Destroy channel<%v>", name) 89 | delete(cs.channels, name) 90 | } 91 | 92 | func (cs *ChannelService) PushMsgByUIDs(route string, msg map[string]interface{}, uid2servid map[string][]string) { 93 | 94 | // uidsX := make([]string, 0) 95 | 96 | // for uid, serverid := range uids { 97 | // if serverid == "" { 98 | // uidsX := append(uidsX, uid) 99 | // } 100 | // } 101 | 102 | // for uid := range uidsX { 103 | // seelog.Warnf("uid<%v> with empty serverid,just ignore it", uid) 104 | // delete(uids, uid) 105 | // } 106 | //serverid ->uids 107 | sid2uid := make(map[string][]string) 108 | 109 | for key, value := range uid2servid { 110 | for _, servid := range value { 111 | if servid == "" { 112 | seelog.Warnf("uid<%v> with empty serverid, just ignore it", key) 113 | continue 114 | } else { 115 | if uids, ok := sid2uid[servid]; ok == false { 116 | uids := make([]string, 5) 117 | uids = append(uids, key) 118 | sid2uid[servid] = uids 119 | } else { 120 | uids = append(uids, key) 121 | sid2uid[servid] = uids 122 | } 123 | } 124 | } 125 | } 126 | cs.sendMsgByGroup(route, msg, sid2uid) 127 | } 128 | 129 | /// 发送消息到groups中的所有用户. 130 | /// 131 | /// @route 路由 132 | /// @param msg 发送的消息 133 | /// @param groups frontendID-> uids的映射 134 | func (cs *ChannelService) sendMsgByGroup(route string, msg map[string]interface{}, groups map[string][]string) { 135 | seelog.Debugf("<%v> channelService sendMsgByGroup with route<%v> msg<%v> groups<%v>", cs.ctx.GetServerID(), route, msg, groups) 136 | 137 | args := make(map[string]interface{}) 138 | 139 | args["route"] = route 140 | args["msg"] = msg 141 | 142 | coChanRpcS, ok := context.GetContext().GetComponent("cochannelrpcserver").(*cochannelrpcserver.CoChannelRpcServer) 143 | if ok == false { 144 | seelog.Error("Fail to get CoChannelRpcServer") 145 | return 146 | } 147 | 148 | sendMsg := func(serverid string) { 149 | if cs.ctx.GetServerID() == serverid { 150 | //TODO:直接调用channelRpcServer相关方法,无需rpc 151 | if err := coChanRpcS.PushMessage(args, nil); err != nil { 152 | seelog.Errorf("Fail to invoke PushMessage to send msg,error<%v>", err.Error()) 153 | return 154 | } 155 | 156 | } else { 157 | //TODO:发起rpc调用. 158 | if err := cs.coRpcClient.RpcCall(serverid, "ChannelRpcServer.PushMessage", args, nil); err != nil { 159 | seelog.Errorf("<%v> fail to invoke rpc PushMessage error<%v>", context.GetContext().GetServerID(), err.Error()) 160 | return 161 | } 162 | } 163 | } 164 | 165 | for frontendID, uids := range groups { 166 | //TODO:逐个发送msg. 167 | seelog.Infof("<%v> PushMessage to uids<%v> connected to frontend<%v>", context.GetContext().GetServerID(), uids, frontendID) 168 | args["uid"] = uids 169 | sendMsg(frontendID) 170 | } 171 | } 172 | 173 | type Channel struct{} 174 | 175 | func newChannel() *Channel { 176 | return nil 177 | } 178 | -------------------------------------------------------------------------------- /pomelo-go/src/service/connectionService/connectionService.go: -------------------------------------------------------------------------------- 1 | /** 2 | * author:liweisheng date:2015-07-13 3 | */ 4 | 5 | /** 6 | *connectionSevice维护连接的统计信息. 7 | */ 8 | package connectionService 9 | 10 | type ConnectionService struct { 11 | serverID string 12 | connCount uint16 13 | loggedCount uint16 14 | loggedInfo map[string]interface{} 15 | } 16 | 17 | func NewConnectionService(serverid string) *ConnectionService { 18 | loggedInfo := make(map[string]interface{}) 19 | 20 | return &ConnectionService{serverid, 0, 0, loggedInfo} 21 | } 22 | 23 | /// 增加登录用户以及其信息. 24 | /// 25 | /// @param uid 用户id 26 | /// @param info 用户信息 27 | /// @TODO 用户信息格式呈现没想好. 28 | func (cs *ConnectionService) AddLoggedUser(uid string, info interface{}) { 29 | if _, ok := cs.loggedInfo[uid]; ok == false { 30 | cs.loggedCount += 1 31 | } 32 | 33 | cs.loggedInfo[uid] = info 34 | } 35 | 36 | /// 更新用户id对应的用户信息. 37 | /// 38 | /// @param uid 需要更新的用户的用户id 39 | /// @param info 用户的信息. 40 | /// FIXIT: 直接将新的info赋值可能会导致旧的info中存在而新的info中不存在的信息丢失. 41 | func (cs *ConnectionService) UpdateUserInfo(uid string, info interface{}) { 42 | if _, ok := cs.loggedInfo[uid]; ok == false { 43 | return 44 | } 45 | 46 | cs.loggedInfo[uid] = info 47 | } 48 | 49 | /// 将连接数加一. 50 | func (cs *ConnectionService) IncreaseConnectionCount() { 51 | cs.connCount += 1 52 | } 53 | 54 | /// 根据用户id移除用户信息. 55 | /// 56 | /// @param uid 用户id 57 | func (cs *ConnectionService) RemoveLoggedUserByUID(uid string) { 58 | if _, ok := cs.loggedInfo[uid]; ok == true { 59 | cs.loggedCount -= 1 60 | } 61 | 62 | delete(cs.loggedInfo, uid) 63 | } 64 | 65 | /// 将当前连接数减1. 66 | /// 67 | /// @param uid 如果uid不为nil,则同时移除uid指定的用户信息 68 | func (cs *ConnectionService) DecreaseConnectionCount(uid string) { 69 | 70 | if cs.connCount > 0 { 71 | cs.connCount -= 1 72 | } 73 | 74 | if uid != "" { 75 | cs.RemoveLoggedUserByUID(uid) 76 | } 77 | } 78 | 79 | /// 获得统计信息. 80 | /// 81 | /// 统计信息包括当前serverid,总连接数,总登录用户数,所有有登录用户信息, 82 | /// 返回的信息的格式为name:value形式,如: 83 | /// {"serverID":"connector-1","connectionCount":10,"loggedCount":6,"infos":[...]}, 84 | /// 其中[...]表示用户信息数组. 85 | func (cs *ConnectionService) GetStatisticsInfo() map[string]interface{} { 86 | statistics := make(map[string]interface{}) 87 | infos := make([]interface{}, 0) 88 | 89 | statistics["serverID"] = cs.serverID 90 | statistics["connectionCount"] = cs.connCount 91 | statistics["loggedCount"] = cs.loggedCount 92 | for _, elem := range cs.loggedInfo { 93 | infos = append(infos, elem) 94 | } 95 | 96 | statistics["infos"] = infos 97 | return statistics 98 | } 99 | -------------------------------------------------------------------------------- /pomelo-go/src/service/sessionService/sessionService.go: -------------------------------------------------------------------------------- 1 | /** 2 | *author:liweisheng date:2015/07/08 3 | */ 4 | 5 | /** 6 | *sessionService用于管理session.每一个session用来维护一条用户连接的所有信息. 7 | * 8 | *sessionService中定义两个struct:SessionService和Session. 9 | *其中Session维护一条用户连接,它维护的信息包括底层通信的socket,用户id等. 10 | *SessionService则负责管理所有的Session,同时也提供对Session方法的外层封装. 11 | */ 12 | package sessionService 13 | 14 | import ( 15 | "connector" 16 | "context" 17 | "fmt" 18 | seelog "github.com/cihub/seelog" 19 | "os" 20 | "sync" 21 | ) 22 | 23 | ///session状态 24 | const ( 25 | SS_CLOSED = iota 26 | SS_INITED = iota 27 | ) 28 | 29 | type SessionService struct { 30 | sessions map[uint32]*Session /// id->session 31 | uidMap map[string][]*Session /// uid->sessions 32 | multiBind bool /// true表示允许uid绑定多个session 33 | options map[string]interface{} /// 选项 34 | rwMutexS *sync.RWMutex /// sessions读写锁 35 | rwMutexUm *sync.RWMutex /// uidMap 读写锁 36 | } 37 | 38 | /// 创建新的SessionService. 39 | /// 40 | /// @param opts 指定创建SessionService的选项,选项是name:value的形式 41 | /// @return *SessionService 42 | func NewSessionService(opts map[string]interface{}) *SessionService { 43 | if nil == opts { 44 | opts = make(map[string]interface{}) 45 | } 46 | sessions := make(map[uint32]*Session) 47 | uidmap := make(map[string][]*Session) 48 | 49 | multibind := opts["multiBind"] != nil && (opts["multiBind"].(string) != "") 50 | rwMutexS := new(sync.RWMutex) 51 | rwMutexUM := new(sync.RWMutex) 52 | seelog.Infof("frontendserver<%v> create sessionservice with opts<%v>", context.GetContext().GetServerID(), opts) 53 | return &SessionService{sessions, uidmap, multibind, opts, rwMutexS, rwMutexUM} 54 | } 55 | 56 | /// 创建并返回新的session,同时SessionService内部维持此新的session 57 | /// 58 | /// @param sid 每个session唯一的id,不应当为空,但是CreateSession内部不检查sid唯一性. 59 | /// @param frontendID 创建此session前端服务器id. 60 | /// @param socket 由session保持的底层连接,连接来自客户端 61 | /// @return *Session 62 | func (ss *SessionService) CreateSession(sid uint32, frontendID string, socket connector.Socket) *Session { 63 | seelog.Debugf("<%v> CreateSession with sid<%v>", frontendID, sid) 64 | session := newSession(sid, frontendID, socket) 65 | ss.rwMutexS.Lock() 66 | defer ss.rwMutexS.Unlock() 67 | ss.sessions[sid] = session 68 | return session 69 | } 70 | 71 | /// 将用户id与session绑定. 72 | /// 73 | /// @param uid 用户id,调用者确保不为空. 74 | /// @param sid 待绑定的session的id. 75 | /// @return 绑定过程出错则返回错误,绑定成功返回nil 76 | func (ss *SessionService) BindUID(uid string, sid uint32) error { 77 | ss.rwMutexS.RLock() 78 | session := ss.sessions[sid] 79 | ss.rwMutexS.RUnlock() 80 | if nil == session { 81 | seelog.Errorf("Failed to find session with sid<%v>\n", sid) 82 | return fmt.Errorf("Error: Failed to find session with sid<%v>\n", sid) 83 | } 84 | 85 | if session.Uid != "" { 86 | if session.Uid == uid { 87 | //session已经绑定的相同的uid,返回 88 | seelog.Infof("frontendserver<%v> sid<%v> has already binded with uid<%v>", session.FrontendID, sid, uid) 89 | return nil 90 | } else { 91 | seelog.Errorf("frontendserver<%v> session with sid<%v> has already bound with uid<%v>", session.FrontendID, sid, session.Uid) 92 | return fmt.Errorf("Error: session with sid<%v> has already bound with uid<%v>\n", sid, uid) 93 | } 94 | } 95 | 96 | ss.rwMutexUm.Lock() 97 | defer ss.rwMutexUm.Unlock() 98 | 99 | sessions, ok := ss.uidMap[uid] 100 | if ss.multiBind == false && ok { 101 | //multiBind == false禁止同一个uid绑定到多个session 102 | seelog.Errorf("uid can not be binded to multi sessions") 103 | return fmt.Errorf("Error: single uid can not be binded to multi sessions\n") 104 | } 105 | 106 | for _, elem := range sessions { 107 | if elem.Id == sid { 108 | //已经有session绑定uid 109 | return nil 110 | } 111 | } 112 | session.bindUID(uid) 113 | 114 | ss.uidMap[uid] = append(ss.uidMap[uid], session) 115 | return nil 116 | 117 | } 118 | 119 | /// 解除用户id与session的绑定关系. 120 | /// 121 | /// @param uid 用户id. 122 | /// @param sid session id. 123 | /// @return {error} 成功解除绑定放回nil,否者返回error. 124 | func (ss *SessionService) UnbindUID(uid string, sid uint32) error { 125 | ss.rwMutexS.RLock() 126 | session, ok := ss.sessions[sid] 127 | ss.rwMutexS.RUnlock() 128 | if ok == false { 129 | //没有id为sid的session 130 | fmt.Fprintf(os.Stderr, "Error: Failed to find session with sid<%v>\n", sid) 131 | return fmt.Errorf("Error: Failed to find session with sid<%v>\n", sid) 132 | } 133 | 134 | if session.Uid != uid { 135 | fmt.Fprintf(os.Stderr, "Error: session with sid<%v> has not bind with uid<%v>\n", sid, uid) 136 | return fmt.Errorf("Error: session with sid<%v> has not bind with uid<%v>\n", sid, uid) 137 | } 138 | 139 | ss.rwMutexUm.Lock() 140 | defer ss.rwMutexUm.Unlock() 141 | 142 | sessions, ok := ss.uidMap[uid] 143 | 144 | ///将绑定uid的session从uid->session的map中移除 145 | if ok == true { 146 | var index int = -1 147 | for i, v := range sessions { 148 | if v.Id == sid { 149 | index = i 150 | break 151 | } 152 | } 153 | 154 | if index >= 0 { 155 | sessions = append(sessions[0:index], sessions[index+1:]...) 156 | if len(sessions) == 0 { 157 | delete(ss.uidMap, uid) 158 | } else { 159 | ss.uidMap[uid] = sessions 160 | } 161 | } 162 | } 163 | 164 | session.unbindUID() 165 | return nil 166 | 167 | } //end UnBindUID 168 | 169 | /// 通过session id返回相应的session. 170 | /// 171 | /// @param sid session id 172 | /// @param 有sid对应的session则返回否则返回nil. 173 | func (ss *SessionService) GetSessionByID(sid uint32) *Session { 174 | ss.rwMutexS.RLock() 175 | defer ss.rwMutexS.RUnlock() 176 | 177 | return ss.sessions[sid] 178 | } 179 | 180 | /// 通过用户id返回用户绑定的所有session. 181 | /// 182 | /// @param uid 用户id. 183 | /// @return 返回nil或者用户绑定的session数组. 184 | func (ss *SessionService) GetSessionsByUID(uid string) []*Session { 185 | ss.rwMutexUm.RLock() 186 | defer ss.rwMutexUm.RUnlock() 187 | 188 | return ss.uidMap[uid] 189 | } //end GetSessionByUID 190 | 191 | /// 通过session id来移除session,如果session有绑定uid, 192 | /// 则同时从uid->sessions中移除session 193 | /// 194 | /// @param sid 移除的session id 195 | func (ss SessionService) RemoveSessionByID(sid uint32) { 196 | ss.rwMutexS.Lock() 197 | ss.rwMutexUm.Lock() 198 | 199 | defer ss.rwMutexUm.Unlock() 200 | defer ss.rwMutexS.Unlock() 201 | 202 | session, ok := ss.sessions[sid] 203 | 204 | if ok == true { 205 | uid := session.Uid 206 | delete(ss.sessions, sid) 207 | sessions := ss.uidMap[uid] 208 | 209 | if sessions != nil { 210 | var index int = -1 211 | 212 | for i, v := range sessions { 213 | if v.Id == sid { 214 | index = i 215 | break 216 | } 217 | } 218 | 219 | if index >= 0 { 220 | sessions = append(sessions[:index], sessions[index+1:]...) 221 | } 222 | 223 | if len(sessions) == 0 { 224 | delete(ss.uidMap, uid) 225 | } else { 226 | ss.uidMap[uid] = sessions 227 | } 228 | 229 | } 230 | } 231 | } //end RemoveSessionByID 232 | 233 | /// 断开所有uid绑定的连接. 234 | /// 235 | /// @param uid 用户id. 236 | /// TODO:目前只是强制断开连接,应该在断开连接之前发送发送提示信息. 237 | /// XXX: 目前断开所有uid绑定的连接后并没有移除相应的session 238 | func (ss *SessionService) KickByUID(uid string, reason string) { 239 | sessions := ss.GetSessionsByUID(uid) 240 | 241 | sess := make([]*Session, 0, 20) 242 | if sessions != nil { 243 | for _, elem := range sessions { 244 | sess = append(sess, elem) 245 | } 246 | 247 | ss.rwMutexS.Lock() 248 | defer ss.rwMutexS.Unlock() 249 | 250 | for _, elem := range sess { 251 | 252 | ss.sessions[elem.Id].close(reason) 253 | } 254 | } 255 | } //end KickByUID 256 | 257 | /// 断开sid指定的session的连接. 258 | /// 259 | /// @param sid session id. 260 | /// TODO: 在断开连接之前应当发送一段由reason表示提示信息. 261 | /// XXX: 断开连接后并未移除session. 262 | func (ss *SessionService) KickBySessionID(sid uint32, reason string) { 263 | ss.rwMutexS.RLock() 264 | session, ok := ss.sessions[sid] 265 | ss.rwMutexS.RUnlock() 266 | fmt.Printf("KickBySessionID Invoked with sid<%v>\n", sid) 267 | if ok { 268 | session.close(reason) 269 | 270 | ss.RemoveSessionByID(sid) 271 | } 272 | 273 | } 274 | 275 | /// 通过session id获得客户端的地址信息. 276 | /// 277 | /// @param sid session id 278 | /// @return 返回地址信息或者nil.在成功返回的情况下,返回值的格式为name:value形式 279 | /// 如host:127.0.0.1 port:10000. 280 | func (ss *SessionService) GetClientAddrBySID(sid uint32) map[string]interface{} { 281 | ss.rwMutexS.RLock() 282 | session, ok := ss.sessions[sid] 283 | ss.rwMutexS.RUnlock() 284 | 285 | if ok == true { 286 | return session.Socket.RemoteAddress() 287 | } 288 | 289 | return nil 290 | } 291 | 292 | func (ss *SessionService) PushOpt(sid uint32, key string, value interface{}) { 293 | ss.rwMutexS.RLock() 294 | session, ok := ss.sessions[sid] 295 | ss.rwMutexS.RUnlock() 296 | 297 | if ok == true { 298 | 299 | seelog.Infof("Push opt with key<%v> value<%v> to session<%v>", key, value, sid) 300 | session.SetOpt(key, value) 301 | } 302 | } 303 | 304 | func (ss *SessionService) PushAllOpts(sid uint32, opts map[string]interface{}) { 305 | ss.rwMutexS.RLock() 306 | session, ok := ss.sessions[sid] 307 | ss.rwMutexS.RUnlock() 308 | 309 | if ok == true { 310 | seelog.Infof("Push all opts to session<%v>", sid) 311 | session.SetAllOpts(opts) 312 | } 313 | } 314 | 315 | /// 发送信息到session id绑定的连接上. 316 | /// 317 | /// @param sid session id 318 | /// @param msg 发送的信息,发送的信息应该有connector模块提供的encode函数编码过的信息 319 | /// XXX: 应该使用日志而不是输出到终端. 320 | func (ss *SessionService) SendMsgBySID(sid uint32, msg []byte) { 321 | ss.rwMutexS.RLock() 322 | session, ok := ss.sessions[sid] 323 | ss.rwMutexS.RUnlock() 324 | 325 | if ok == true { 326 | session.send(msg) 327 | } else { 328 | fmt.Fprintf(os.Stderr, "Try to send message to session with sid<%v>,which dose not exist\n", sid) 329 | return 330 | } 331 | } 332 | 333 | /// 发送信息给指定的用户id,如果一个用户id绑定多个session,则每个session都会收到信息. 334 | /// 335 | /// @param uid 用户id. 336 | /// @param msg 发送的消息,发送的信息应该有connector模块提供的encode函数编码过的信息 337 | func (ss *SessionService) SendMsgByUID(uid string, msg []byte) { 338 | ss.rwMutexUm.RLock() 339 | defer ss.rwMutexUm.RUnlock() 340 | 341 | sessions, ok := ss.uidMap[uid] 342 | if ok == true { 343 | for _, elem := range sessions { 344 | elem.send(msg) 345 | } 346 | } else { 347 | fmt.Fprintf(os.Stderr, "Try to send message to user with uid<%v>,which dose not exist\n", uid) 348 | return 349 | } 350 | 351 | } 352 | 353 | /// XXX: 应该使用日志记录发送失败. 354 | func (ss *SessionService) SendBatchBySID(sid uint32, msgs ...[]byte) { 355 | ss.rwMutexS.RLock() 356 | session, ok := ss.sessions[sid] 357 | ss.rwMutexS.RUnlock() 358 | 359 | if ok == true { 360 | session.sendBatch(msgs...) 361 | } else { 362 | fmt.Fprintf(os.Stderr, "Try to send batch of messages to session with sid<%v>,which dose not exist\n", sid) 363 | return 364 | } 365 | } 366 | 367 | /// 批量发送信息给指定用户id. 368 | /// 369 | /// @param uid 用户id 370 | func (ss *SessionService) SendBatchByUID(uid string, msgs ...[]byte) { 371 | ss.rwMutexUm.RLock() 372 | sessions, ok := ss.uidMap[uid] 373 | ss.rwMutexUm.RUnlock() 374 | 375 | if ok == true { 376 | for _, elem := range sessions { 377 | elem.sendBatch(msgs...) 378 | } 379 | } else { 380 | fmt.Fprintf(os.Stderr, "Try to send batch of messages to user with uid<%v>,which dose not exist\n", uid) 381 | return 382 | } 383 | } 384 | 385 | type SimpleSession struct { 386 | Id uint32 387 | Uid string 388 | FrontendID string 389 | } 390 | 391 | type Session struct { 392 | Status int8 393 | Id uint32 394 | Uid string 395 | FrontendID string 396 | Socket connector.Socket 397 | Opts map[string]interface{} 398 | } 399 | 400 | /// 创建新的session,创建时的参数都不可以为空,由调用者保证. 401 | func newSession(sid uint32, frontendId string, socket connector.Socket) *Session { 402 | opts := make(map[string]interface{}) 403 | return &Session{SS_INITED, sid, "", frontendId, socket, opts} 404 | } 405 | 406 | func (s *Session) ToSimpleSession() *SimpleSession { 407 | return &SimpleSession{s.Id, s.Uid, s.FrontendID} 408 | } 409 | 410 | /// 绑定用户ID. 411 | /// 412 | /// @param uid {string} 用户id 413 | func (s *Session) bindUID(uid string) { 414 | s.Uid = uid 415 | } 416 | 417 | ///解除用户ID的和session的绑定. 418 | func (s *Session) unbindUID() { 419 | s.Uid = "" 420 | } 421 | 422 | func (s *Session) SetOpt(key string, value interface{}) { 423 | s.Opts[key] = value 424 | } 425 | 426 | func (s *Session) GetOpt(key string) interface{} { 427 | return s.Opts[key] 428 | } 429 | 430 | func (s *Session) SetAllOpts(opts map[string]interface{}) { 431 | s.Opts = opts 432 | } 433 | 434 | func (s *Session) GetAllOpts() map[string]interface{} { 435 | return s.Opts 436 | } 437 | 438 | /// 关闭session,关闭session会关闭session保持的socket, 439 | /// 同时将session信息从sessionService中移除. 440 | /// 441 | /// TODO: 应该在断开连接之前给客户端发送一段简短提示信息. 442 | func (s *Session) close(reason string) { 443 | if s.Status == SS_CLOSED { 444 | return 445 | } 446 | 447 | s.Status = SS_CLOSED 448 | // s.socket.RemoteAddress() 449 | if s.Socket == nil { 450 | return 451 | } 452 | s.Socket.Disconnect() 453 | } 454 | 455 | func (s *Session) send(msg []byte) { 456 | s.Socket.Send(msg) 457 | } 458 | 459 | func (s *Session) sendBatch(msgs ...[]byte) { 460 | s.Socket.SendBatch(msgs...) 461 | } 462 | -------------------------------------------------------------------------------- /pomelo-go/src/test/connectorTest/README: -------------------------------------------------------------------------------- 1 | 2 | 测试connector/tcp_connector ,测试时间:2015/08/14,测试未通过. -------------------------------------------------------------------------------- /pomelo-go/src/test/connectorTest/client/client.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liweisheng/server-framework/46df96a74ea25a936c0480eed9e6f41c6b104485/pomelo-go/src/test/connectorTest/client/client.exe -------------------------------------------------------------------------------- /pomelo-go/src/test/connectorTest/client/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net" 7 | "os" 8 | "strconv" 9 | ) 10 | 11 | var reqID uint32 = 0 12 | 13 | func send(route string, body []byte, conn net.Conn) { 14 | msg := make(map[string]interface{}) 15 | msg["reqID"] = fmt.Sprintf("%v", reqID) 16 | msg["route"] = route 17 | msg["body"] = string(body) 18 | fmt.Println("in Send") 19 | sendBuf, err := json.Marshal(msg) 20 | if err != nil { 21 | fmt.Fprintf(os.Stderr, "Json Marshall msg<%v> error,error message<%v>\n", msg, err.Error()) 22 | os.Exit(1) 23 | } 24 | rst := make(map[string]interface{}) 25 | if err = json.Unmarshal(sendBuf, &rst); err == nil { 26 | fmt.Printf("Json UnMarshall<%v> -> <%v>\n", string(sendBuf), rst) 27 | } else { 28 | fmt.Printf("Json UnMarshall<%v> error,error message<%v>\n", string(sendBuf), err.Error()) 29 | os.Exit(1) 30 | } 31 | bufLen := uint16(len(sendBuf)) 32 | lenBuf := make([]byte, 2) 33 | 34 | lenBuf[0] = byte((bufLen >> 8) & 0xFF) 35 | lenBuf[1] = byte(bufLen & 0xFF) 36 | _, err1 := conn.Write(lenBuf) 37 | 38 | if err1 == nil { 39 | fmt.Printf("msg len:high<%v> low<%v>\n", lenBuf[0], lenBuf[1]) 40 | } else { 41 | fmt.Printf("send lenBuf error,error message<%v>\n", err1) 42 | os.Exit(1) 43 | } 44 | 45 | // _, err2 := conn.Write(sendBuf) 46 | _, err2 := conn.Write([]byte("fuck you")) 47 | if err2 == nil { 48 | fmt.Printf("send msg<%v>,send len<%v>\n", string(sendBuf), len(sendBuf)) 49 | } else { 50 | fmt.Printf("send sendBuf error,error message<%v>\n", err2) 51 | os.Exit(1) 52 | } 53 | reqID++ 54 | } 55 | 56 | func main() { 57 | if len(os.Args) < 3 { 58 | fmt.Fprintf(os.Stderr, "too few args,args form: \n") 59 | os.Exit(1) 60 | } 61 | host := os.Args[1] 62 | port, err1 := strconv.Atoi(os.Args[2]) 63 | if err1 != nil { 64 | fmt.Fprintf(os.Stderr, "invalid port,need integer type,your input port: \n", os.Args[2]) 65 | os.Exit(1) 66 | } 67 | 68 | hostAndPort := fmt.Sprintf("%v:%v", host, port) 69 | 70 | conn, err2 := net.Dial("tcp", hostAndPort) 71 | if err2 != nil { 72 | fmt.Fprintf(os.Stderr, "Dial <%v> error,error message<%v>\n", hostAndPort, err2.Error()) 73 | os.Exit(1) 74 | } 75 | // defer conn.Close() 76 | 77 | // route := "chat.Chatroom.Addin" 78 | msgBody := make(map[string]interface{}) 79 | msgBody["type"] = "handshake" 80 | msgBody["body"] = "Hello,I am your father" 81 | body, err3 := json.Marshal(msgBody) 82 | if err3 != nil { 83 | fmt.Fprintf(os.Stderr, "Json Marshall <%v> error,error message<%v>\n", msgBody, err3.Error()) 84 | os.Exit(1) 85 | } 86 | 87 | fmt.Printf("len: %v text: %v\n", len(body), string(body)) 88 | conn.Write([]byte("Fuck You!!!")) 89 | // send(route, body, conn) 90 | ch := make(chan int) 91 | <-ch 92 | } 93 | -------------------------------------------------------------------------------- /pomelo-go/src/test/connectorTest/server/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "connector" 5 | "connector/tcp_connector" 6 | "context" 7 | "fmt" 8 | "github.com/cihub/seelog" 9 | "os" 10 | "strconv" 11 | ) 12 | 13 | /// 新消息到达时回调. 14 | func NewMsgCB(id uint32, msg map[string]interface{}) { 15 | fmt.Printf("from sid<%v> decoded message:<%v>\n", id, msg) 16 | } 17 | 18 | /// 新连接到达时回调. 19 | func NewConnCB(sock connector.Socket) { 20 | fmt.Printf("new connection\n", sock.ID(), sock.RemoteAddress()) 21 | } 22 | 23 | func main() { 24 | 25 | if len(os.Args) < 3 { 26 | fmt.Fprintf(os.Stderr, "too few args,args form: \n") 27 | os.Exit(1) 28 | } 29 | host := os.Args[1] 30 | port, err := strconv.Atoi(os.Args[2]) 31 | if err != nil { 32 | fmt.Fprintf(os.Stderr, "invalid port,need integer type,your input port: \n", os.Args[2]) 33 | os.Exit(1) 34 | } 35 | ctx := context.GetContext() 36 | currentServer := make(map[string]interface{}) 37 | currentServer["id"] = "connector-1" 38 | currentServer["serverType"] = "connector" 39 | currentServer["host"] = "127.0.0.1" 40 | currentServer["port"] = 8888 41 | ctx.CurrentServer = currentServer 42 | defer seelog.Flush() 43 | 44 | tcp_cnct := tcp_connector.NewTcpConnector(host, port, nil) 45 | 46 | tcp_cnct.RegistNewConnCB(NewConnCB) 47 | tcp_cnct.RegistNewMsgCB(NewMsgCB) 48 | tcp_cnct.Start() 49 | ch := make(chan int) 50 | <-ch 51 | } 52 | -------------------------------------------------------------------------------- /pomelo-go/src/test/cosessionrpcserverTest/README: -------------------------------------------------------------------------------- 1 | 本测试用例用来测试组件cobackendsession和组件cosessionrpcserver。 2 | 3 | cobackendsession组件封装backendSessionService的操作,cosessionrpcserver封装 4 | 了sessionRpcServer的操作。实际服务器中cobackendsession由后端服务器加载,前端 5 | 服务器负责承载客户端的连接并创建session来表示每一条连接,并将请求转交给后端 6 | 服务器处理,backendsession在后端服务器中对等于前端服务器session,但是backendsession 7 | 并并保持连接,因此后端服务器对backendsession的操作最终都会需要通过rpc调用影响 8 | 到前端session。因此cosessionrpcserver就是由前端服务器加载的用来作为rpc服务端 9 | 来接受后端服务器的rpc调用请求,其内部直接调用前端的cosession组件来影响session。 10 | 而cobackendsession则由后端服务器加载,内部通过发起rpc调用请求cosessionrpcserver 11 | 服务。 12 | 13 | 运行: 14 | server目录下对应服务器端,先编译运行server 15 | client目录下对应客户端,client在server启动后运行 16 | 17 | 18 | -------------------------------------------------------------------------------- /pomelo-go/src/test/cosessionrpcserverTest/client/client.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liweisheng/server-framework/46df96a74ea25a936c0480eed9e6f41c6b104485/pomelo-go/src/test/cosessionrpcserverTest/client/client.exe -------------------------------------------------------------------------------- /pomelo-go/src/test/cosessionrpcserverTest/client/client.go: -------------------------------------------------------------------------------- 1 | /// 测试backendSessionService,backendSessionService中封装了对backendsession的操作,对backendsession的操作 2 | /// 会通过发起对sessionRpcServer的rpc请求最终将对backendsession的改变反馈到session. 3 | /// 4 | /// 本测试中创建cobackendsession,并创建一个与session对应的backendsession,然后分别测试backendsessionservice的 5 | /// 的方法. 6 | package main 7 | 8 | import ( 9 | "component/cobackendsession" 10 | "component/corpcclient" 11 | "context" 12 | "fmt" 13 | "github.com/cihub/seelog" 14 | ) 15 | 16 | func main() { 17 | ctx := context.GetContext() 18 | 19 | defer seelog.Flush() 20 | 21 | currentServer := make(map[string]interface{}) 22 | currentServer["id"] = "chat-1" 23 | currentServer["serverType"] = "chat" 24 | currentServer["host"] = "127.0.0.1" 25 | currentServer["port"] = 8888 26 | 27 | ctx.CurrentServer = currentServer 28 | 29 | cobackendS := cobackendsession.NewCoBackendSession() 30 | corpcC := corpcclient.NewCoRpcClient() 31 | 32 | cobackendS.Start() 33 | corpcC.Start() 34 | 35 | backendS := cobackendS.GetBackendSessionBySID("connector-1", 1) 36 | 37 | if backendS != nil { 38 | fmt.Printf("--------------GetBackendSessionBySID(%v,%v)--------------\n", "connector-1", 1) 39 | fmt.Printf("frontendid:%v sid:%v uid:%v\n", backendS.GetFrontendID(), backendS.GetID(), backendS.GetUID()) 40 | fmt.Println("---------------------------------------------------------\n") 41 | 42 | backendS.UnbindUID(backendS.GetUID()) 43 | fmt.Printf("--------------UnBindUID(%v)--------------\n", backendS.GetUID()) 44 | backendSN := cobackendS.GetBackendSessionBySID("connector-1", 1) 45 | 46 | if backendSN != nil { 47 | fmt.Printf("--------------After UnBindUID(%v)--------------\n", backendS.GetUID()) 48 | fmt.Printf("frontendid:%v sid:%v uid:%v\n", backendSN.GetFrontendID(), backendSN.GetID(), backendSN.GetUID()) 49 | fmt.Println("-----------------------------------------------------\n") 50 | } 51 | 52 | backendS.SetOpt("age", 12) 53 | fmt.Printf("--------------SetOpt(%v,%v)--------------\n", "age", 12) 54 | backendS.PushOpt("age") 55 | fmt.Printf("--------------PushOpt(%v)--------------\n", "age") 56 | } 57 | 58 | backendS = cobackendS.GetBackendSessionBySID("connector-1", 1) 59 | 60 | if backendS != nil { 61 | fmt.Printf("--------------GetBackendSessionBySID(%v,%v)--------------\n", "connector-1", backendS.GetID()) 62 | fmt.Printf("frontendid:%v sid:%v uid:%v,opts:%v\n", backendS.GetFrontendID(), backendS.GetID(), backendS.GetUID(), backendS.GetOpts()) 63 | fmt.Println("--------------------------------------------------------------\n") 64 | } 65 | 66 | infoByUID := cobackendS.GetBackendSessionsByUID("connector-1", "Li Si") 67 | if infoByUID != nil { 68 | fmt.Printf("--------------GetBackendSessionSByUID(%v,%v)--------------\n", "connector-1", "Li Si") 69 | for _, elem := range infoByUID { 70 | fmt.Printf("frontend id:%v,id:%v,uid:%v \n", elem.GetFrontendID(), elem.GetID(), elem.GetUID()) 71 | } 72 | fmt.Println("---------------------------------------------------\n") 73 | } 74 | 75 | cobackendS.KickBySID("connector-1", 1, "no reason") 76 | fmt.Printf("--------------KickBySID(%v,%v,%v)--------------\n", "connector-1", 1, "no reason") 77 | backendK := cobackendS.GetBackendSessionBySID("connector-1", 1) 78 | if backendK == nil { 79 | fmt.Printf("--------------After Kick sid<%v>,session not exists--------------\n\n", 1) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /pomelo-go/src/test/cosessionrpcserverTest/client/criticalAndError.log: -------------------------------------------------------------------------------- 1 | [Error] backendSessionService.go 76 [2015-08-13 22:29:55] H:/pomelo-go/pomelo-go/src/service/backendSessionService/backendSessionService.go Rpc Call failed 2 | [Error] backendSessionService.go 76 [2015-08-13 22:31:17] H:/pomelo-go/pomelo-go/src/service/backendSessionService/backendSessionService.go Rpc Call failed 3 | [Error] backendSessionService.go 76 [2015-08-13 22:32:06] H:/pomelo-go/pomelo-go/src/service/backendSessionService/backendSessionService.go Rpc Call failed 4 | [Error] backendSessionService.go 76 [2015-08-13 22:33:55] H:/pomelo-go/pomelo-go/src/service/backendSessionService/backendSessionService.go Rpc Call failed,error> 5 | -------------------------------------------------------------------------------- /pomelo-go/src/test/cosessionrpcserverTest/client/logConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /pomelo-go/src/test/cosessionrpcserverTest/server/criticalAndError.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liweisheng/server-framework/46df96a74ea25a936c0480eed9e6f41c6b104485/pomelo-go/src/test/cosessionrpcserverTest/server/criticalAndError.log -------------------------------------------------------------------------------- /pomelo-go/src/test/cosessionrpcserverTest/server/logConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /pomelo-go/src/test/cosessionrpcserverTest/server/server.exe~: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liweisheng/server-framework/46df96a74ea25a936c0480eed9e6f41c6b104485/pomelo-go/src/test/cosessionrpcserverTest/server/server.exe~ -------------------------------------------------------------------------------- /pomelo-go/src/test/cosessionrpcserverTest/server/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "component/corpcserver" 5 | "component/cosession" 6 | "component/cosessionrpcserver" 7 | "context" 8 | 9 | "github.com/cihub/seelog" 10 | ) 11 | 12 | func main() { 13 | ctx := context.GetContext() 14 | allOpts := make(map[string]map[string]interface{}) 15 | cosessOpts := make(map[string]interface{}) 16 | 17 | //指定同一个uid可以绑定多个session 18 | cosessOpts["multiBind"] = "yes" 19 | allOpts["cosession"] = cosessOpts 20 | ctx.AllOpts = allOpts 21 | defer seelog.Flush() 22 | currentServer := make(map[string]interface{}) 23 | currentServer["id"] = "connector-1" 24 | currentServer["serverType"] = "connector" 25 | currentServer["host"] = "127.0.0.1" 26 | currentServer["port"] = 8888 27 | ctx.CurrentServer = currentServer 28 | cosess := cosession.NewCoSession() 29 | cosessRS := cosessionrpcserver.NewCoSessionRpcServer() 30 | corpcS := corpcserver.NewCoRpcServer() 31 | 32 | // 启动cosession,cosessionrpcserver,corpcserver 33 | cosess.Start() 34 | cosessRS.Start() 35 | corpcS.Start() 36 | 37 | cosess.CreateSession(1, "connector-1", nil) 38 | cosess.BindUID("Zhang San", 1) 39 | cosess.CreateSession(2, "connector-1", nil) 40 | cosess.BindUID("Li Si", 2) 41 | cosess.CreateSession(3, "connector-1", nil) 42 | cosess.BindUID("Li Si", 3) 43 | cosess.CreateSession(4, "connector-1", nil) 44 | cosess.BindUID("Wang Wu", 4) 45 | 46 | ch := make(chan int) 47 | <-ch 48 | } 49 | -------------------------------------------------------------------------------- /pomelo-go/src/test/reportInfoTest/master/masterConsole: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liweisheng/server-framework/46df96a74ea25a936c0480eed9e6f41c6b104485/pomelo-go/src/test/reportInfoTest/master/masterConsole -------------------------------------------------------------------------------- /pomelo-go/src/test/reportInfoTest/master/masterConsole.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | // "module/reportInfo" 6 | // "os" 7 | "pomelo_admin" 8 | // "time" 9 | ) 10 | 11 | func main() { 12 | ctx := context.NewContext() 13 | ctx.MasterInfo["id"] = "master" 14 | ctx.MasterInfo["host"] = "127.0.0.1" 15 | ctx.MasterInfo["port"] = 8888 16 | 17 | ctx.CurrentServer["id"] = "master-1" 18 | ctx.CurrentServer["host"] = "192.168.1.2" 19 | ctx.CurrentServer["port"] = 8889 20 | ctx.CurrentServer["clientPort"] = 8889 21 | ctx.CurrentServer["frontend"] = "false" 22 | ch := make(chan int) 23 | 24 | mcs := pomelo_admin.NewMasterConsoleService(ctx) 25 | mcs.Start() 26 | select { 27 | case <-ch: 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /pomelo-go/src/test/reportInfoTest/monitorConsole/monitoConsole: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liweisheng/server-framework/46df96a74ea25a936c0480eed9e6f41c6b104485/pomelo-go/src/test/reportInfoTest/monitorConsole/monitoConsole -------------------------------------------------------------------------------- /pomelo-go/src/test/reportInfoTest/monitorConsole/monitoConsole.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | // "module/reportInfo" 6 | // "os" 7 | // "fmt" 8 | "log" 9 | "module/reportInfo" 10 | "pomelo_admin" 11 | // "time" 12 | ) 13 | 14 | func main() { 15 | ctx := context.NewContext() 16 | ctx.MasterInfo["id"] = "master" 17 | ctx.MasterInfo["host"] = "127.0.0.1" 18 | ctx.MasterInfo["port"] = 8888 19 | 20 | ctx.CurrentServer["serverType"] = "connector" 21 | ctx.CurrentServer["id"] = "connector-1" 22 | ctx.CurrentServer["host"] = "192.168.1.2" 23 | ctx.CurrentServer["port"] = 8889 24 | ctx.CurrentServer["clientPort"] = 8889 25 | ctx.CurrentServer["frontend"] = "false" 26 | 27 | ri, err := reportInfo.NewReportInfo("reportInfo", "push", 5, "127.0.0.1", 6379) 28 | 29 | if err != nil { 30 | log.Fatal(err.Error()) 31 | } 32 | 33 | ctx.RegisteModule(ri) 34 | ch := make(chan int) 35 | 36 | mcs := pomelo_admin.NewMonitorConsoleService(ctx) 37 | mcs.Start() 38 | select { 39 | case <-ch: 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /pomelo-go/src/test/rpcTest/rpcClient/criticalAndError.log: -------------------------------------------------------------------------------- 1 | [Error] rpcClient.go 22 [2015-07-26 12:05:33] rpcClient.go Error,this is just for test 2 | [Error] rpcClient.go 22 [2015-07-26 12:05:52] rpcClient.go Error,this is just for test 3 | -------------------------------------------------------------------------------- /pomelo-go/src/test/rpcTest/rpcClient/log.log: -------------------------------------------------------------------------------- 1 | [Debug] rpcClient.go 50 [2015-07-26 12:01:19] h:/pomelo-go/server-framework/pomelo-go/src/rpcclient/rpcClient.go Rpc client call for remote method,remote serverid 2 | [Error] rpcClient.go 22 [2015-07-26 12:05:33] rpcClient.go Error,this is just for test 3 | [Error] rpcClient.go 22 [2015-07-26 12:05:52] rpcClient.go Error,this is just for test 4 | -------------------------------------------------------------------------------- /pomelo-go/src/test/rpcTest/rpcClient/logConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /pomelo-go/src/test/rpcTest/rpcClient/rpcClient.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liweisheng/server-framework/46df96a74ea25a936c0480eed9e6f41c6b104485/pomelo-go/src/test/rpcTest/rpcClient/rpcClient.exe -------------------------------------------------------------------------------- /pomelo-go/src/test/rpcTest/rpcClient/rpcClient.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | seelog "github.com/cihub/seelog" 7 | "log" 8 | "rpcclient" 9 | ) 10 | 11 | func main() { 12 | ctx := context.NewContext() 13 | 14 | currentServerInfo := make(map[string]interface{}) 15 | 16 | currentServerInfo["host"] = "127.0.0.1" 17 | currentServerInfo["port"] = 8888 18 | 19 | ctx.CurrentServer = currentServerInfo 20 | client := rpcclient.NewRpcClient(ctx) 21 | 22 | seelog.Errorf("Error,this is just for test") 23 | 24 | var reply string 25 | callRst := client.RpcCall("self", "Echo.Hi", "Eric", &reply) 26 | 27 | if callRst == nil { 28 | log.Fatal("What Fuck") 29 | } 30 | <-callRst.Done 31 | 32 | if callRst.Error != nil { 33 | log.Fatal(callRst.Error.Error()) 34 | } 35 | 36 | fmt.Printf("Reply is : %v\n", *callRst.Reply.(*string)) 37 | } 38 | -------------------------------------------------------------------------------- /pomelo-go/src/test/rpcTest/rpcServer/log.log: -------------------------------------------------------------------------------- 1 | [Debug] msgServer.go 58 [2015-07-26 11:30:51] H:/pomelo-go/server-framework/pomelo-go/src/rpcserver/backend/msgServer/msgServer.go Rpc Server listening: <127.0.0.1:8888> 2 | [Debug] msgServer.go 58 [2015-07-26 12:01:15] H:/pomelo-go/server-framework/pomelo-go/src/rpcserver/backend/msgServer/msgServer.go Rpc Server listening: <127.0.0.1:8888> 3 | [Debug] msgServer.go 64 [2015-07-26 12:01:19] H:/pomelo-go/server-framework/pomelo-go/src/rpcserver/backend/msgServer/msgServer.go Rpc Server accept new connection 4 | -------------------------------------------------------------------------------- /pomelo-go/src/test/rpcTest/rpcServer/logConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /pomelo-go/src/test/rpcTest/rpcServer/rpcServer.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liweisheng/server-framework/46df96a74ea25a936c0480eed9e6f41c6b104485/pomelo-go/src/test/rpcTest/rpcServer/rpcServer.exe -------------------------------------------------------------------------------- /pomelo-go/src/test/rpcTest/rpcServer/rpcServer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | // "fmt" 5 | "context" 6 | "log" 7 | "os" 8 | "rpcserver" 9 | "strconv" 10 | ) 11 | 12 | type Echo int 13 | 14 | func (e *Echo) Hi(arg string, reply *string) error { 15 | *reply = "Echo " + arg 16 | return nil 17 | } 18 | 19 | func main() { 20 | if len(os.Args) != 3 { 21 | log.Fatal("too few args to server,commandline form ") 22 | } 23 | 24 | context.NewContext() 25 | host := os.Args[1] 26 | port, err := strconv.Atoi(os.Args[2]) 27 | if err != nil { 28 | log.Fatalf("Fail to convert os.args[2] to port(type int),error message:", err.Error()) 29 | } 30 | 31 | server := rpcserver.NewRpcServer(host, port) 32 | server.RegisteService(new(Echo)) 33 | 34 | server.Start() 35 | } 36 | --------------------------------------------------------------------------------