func stats_sender() { _accum_buffer := make(map[string]map[string]int32) _update_buffer := make(map[string]map[string]string) stats_timer := make(chan int32, 100) stats_timer <- 1 for { select { case req := <-AccumQueue: if _, ok := _accum_buffer[req.F_lang]; !ok { val := make(map[string]int32) val[req.F_key] = 0 _accum_buffer[req.F_lang] = val } val := _accum_buffer[req.F_lang] val[req.F_key] += req.F_value _accum_buffer[req.F_lang] = val case req := <-UpdateQueue: if _, ok := _update_buffer[req.F_lang]; !ok { val := make(map[string]string) val[req.F_key] = "" _update_buffer[req.F_lang] = val } val := _update_buffer[req.F_lang] val[req.F_key] = req.F_value _update_buffer[req.F_lang] = val case <-stats_timer: INFO("Stats Buffer:", len(_accum_buffer), len(_update_buffer)) // 累计 accum := SET_ADDS_REQ{} for accum.F_lang, _ = range _accum_buffer { for accum.F_key, accum.F_value = range _accum_buffer[accum.F_lang] { Send(packet.Pack(Code["set_adds_req"], &accum, nil)) } } _accum_buffer = make(map[string]map[string]int32) // 更新 update := SET_UPDATE_REQ{} for update.F_lang, _ = range _update_buffer { for update.F_key, update.F_value = range _update_buffer[update.F_lang] { Send(packet.Pack(Code["set_update_req"], &update, nil)) } } _update_buffer = make(map[string]map[string]string) // FINI config := cfg.Get() period := STATS_COLLECT_PERIOD if config["stats_collect_period"] != "" { period, _ = strconv.Atoi(config["stats_collect_period"]) } timer.Add(0, time.Now().Unix()+int64(period), stats_timer) runtime.GC() } } }
func (gs *centerGs) SendToUser(userId int64, api int16, tbl interface{}) { payload := packet.Pack(api, tbl, nil) msg := protocol.PKT_forward_msg_info{ F_size: int32(len(payload)), F_session_id: protocol.NIL_SESSION_ID, F_user_id: userId, F_msg: string(payload), } gs.session.Send(packet.Pack(protocol.FORWARD_MSG_NTF, &msg, nil)) }
// 发送公会广播信息(通过Gate广播,所以这条转发消息发给任意GS都可以)。 func AllianceBoardCast(asId int32, api int16, tbl interface{}) { payload := packet.Pack(api, tbl, nil) for _, gs := range gsMap { msg := protocol.PKT_gs_alliance_boardcast_info{ F_alliance_id: asId, F_msg: string(payload), } gs.session.Send(packet.Pack(protocol.GS_ALLIANCE_BOARDCAST_NTF, &msg, nil)) return } }
func BenchmarkAgent(b *testing.B) { fmt.Println("Benchmark", b.N) for i := 0; i < b.N; i++ { addr, err := net.ResolveTCPAddr("tcp", "0.0.0.0:8888") if err != nil { fmt.Println(err) os.Exit(-1) } conn, err := net.DialTCP("tcp", nil, addr) if err != nil { fmt.Println(err) os.Exit(-1) } U := user_login_info{} U.F_user_name = fmt.Sprintf("test%v", i) U.F_mac_addr = fmt.Sprintf("mac%v", i) pkt := packet.Pack(Code["user_login_req"], &U, nil) writer := packet.Writer() writer.WriteU16(uint16(len(pkt) + 4)) writer.WriteU32(0) writer.WriteRawBytes(pkt) ret := make([]byte, 100) conn.Write(writer.Data()) conn.Read(ret) } }
func P_forward_req(hostid int32, pkt *packet.Packet) []byte { tbl, _ := PKT_FORWARDIPC(pkt) object := &IPCObject{} err := json.Unmarshal(tbl.F_IPC, object) if err != nil { log.Println("decode forward IPCObject error") return nil } // if user is online, send to the server, or else send to database state := core.State(object.DestID) //fmt.Println(tbl.F_dest_id, tbl.F_IPC) switch state { case core.ON_PROT, core.ON_FREE: host := core.Host(object.DestID) ch := ForwardChan(host) if ch != nil { ch <- tbl.F_IPC } else { forward_tbl.Push(object) } default: forward_tbl.Push(object) } ret := INT{F_v: 1} return packet.Pack(-1, &ret, nil) }
func P_rank_list_req(sess *Session, reader *packet.Packet) (ret []byte, err error) { ids, scores, err := ipc.GetList(1, -1) if err != nil { return nil, err } out := rank_list{} out.F_items = make([]rank_list_item, len(ids)) for k, v := range ids { info, _ := ipc.GetInfo(v) out.F_items[k].F_id = v out.F_items[k].F_name = info.Name out.F_items[k].F_rank = scores[k] out.F_items[k].F_state = info.State t := int32(info.ProtectTime - time.Now().Unix()) if t > 0 { out.F_items[k].F_protect_time = int32(t) } else { out.F_items[k].F_protect_time = 0 } } writer := packet.Writer() return packet.Pack(Code["rank_list_ack"], out, writer), nil }
func P_cancel_req(reader *packet.Packet) []byte { tbl, _ := PKT_CANCEL_EVENT(reader) core.Cancel(tbl.F_event_id) ret := INT{1} return packet.Pack(-1, &ret, nil) }
func P_add_req(reader *packet.Packet) []byte { tbl, _ := PKT_ADD_EVENT(reader) event_id := core.Add(tbl.F_type, tbl.F_user_id, tbl.F_timeout, tbl.F_params) ret := INT{event_id} return packet.Pack(-1, &ret, nil) }
// 密钥交换 func P_get_seed_req(sess *Session, reader *packet.Packet) []byte { tbl, _ := PKT_seed_info(reader) // KEY1 X1, E1 := dh.DHExchange() KEY1 := dh.DHKey(X1, big.NewInt(int64(tbl.F_client_send_seed))) // KEY2 X2, E2 := dh.DHExchange() KEY2 := dh.DHKey(X2, big.NewInt(int64(tbl.F_client_receive_seed))) ret := seed_info{int32(E1.Int64()), int32(E2.Int64())} // 服务器加密种子是客户端解密种子 encoder, err := rc4.NewCipher([]byte(fmt.Sprintf("%v%v", SALT, KEY2))) if err != nil { log.Critical(err) return nil } decoder, err := rc4.NewCipher([]byte(fmt.Sprintf("%v%v", SALT, KEY1))) if err != nil { log.Critical(err) return nil } sess.Encoder = encoder sess.Decoder = decoder sess.Flag |= SESS_KEYEXCG return packet.Pack(Code["get_seed_ack"], ret, nil) }
func P_add_req(reader *packet.Packet) []byte { tbl, _ := PKT_ADD_REQ(reader) ret := INT{0} fmt.Println(tbl) return packet.Pack(-1, &ret, nil) }
func P_user_login_req(sess *Session, reader *packet.Packet) (ret []byte, err error) { tbl, _ := PKT_user_login_info(reader) writer := packet.Writer() failed := command_result_pack{F_rst: 0} success := user_snapshot{} //------------------------------------------------ config := cfg.Get() version, _ := strconv.Atoi(config["version"]) if tbl.F_client_version != int32(version) { ret = packet.Pack(Code["user_login_faild_ack"], failed, writer) return } if tbl.F_new_user == 0 { if user_tbl.LoginMAC(sess.User.Mac, &sess.User) { ipc.Register(sess, sess.User.Id) _fill_user_snapshot(&sess.User, &success) ret = packet.Pack(Code["user_login_succeed_ack"], success, writer) return } else { ret = packet.Pack(Code["user_login_faild_ack"], failed, writer) return } } else { // register to db & online user sess.User.Name = tbl.F_user_name sess.User.Mac = tbl.F_mac_addr sess.User.CreatedAt = time.Now() if user_tbl.New(&sess.User) { ipc.Register(sess, sess.User.Id) // TODO: add user //ranklist.AddUser(&sess.User) _fill_user_snapshot(&sess.User, &success) ret = packet.Pack(Code["user_login_succeed_ack"], success, writer) return } else { ret = packet.Pack(Code["user_login_faild_ack"], failed, writer) return } } return }
func TestAgent(t *testing.T) { log.Println("Connecting to GS") addr, err := net.ResolveTCPAddr("tcp", "0.0.0.0:8888") if err != nil { fmt.Println(err) os.Exit(-1) } conn, err := net.DialTCP("tcp", nil, addr) if err != nil { fmt.Println(err) os.Exit(-1) } U := &user_login_info{} U.F_user_name = "test1" U.F_mac_addr = "mac1" pkt := packet.Pack(Code["user_login_req"], U, nil) writer := packet.Writer() writer.WriteU16(uint16(len(pkt) + 4)) writer.WriteU32(0) writer.WriteRawBytes(pkt) conn.Write(writer.Data()) ret := make([]byte, 100) n, _ := conn.Read(ret) fmt.Printf("%q\n", ret[:n]) // talk msg := &talk{} msg.F_user = "******" msg.F_msg = "hello world" pkt = packet.Pack(Code["talk_req"], msg, nil) writer = packet.Writer() writer.WriteU16(uint16(len(pkt) + 4)) writer.WriteU32(0) writer.WriteRawBytes(pkt) conn.Write(writer.Data()) n, _ = conn.Read(ret) fmt.Printf("%q\n", ret[:n]) }
func P_changescore_req(hostid int32, pkt *packet.Packet) ([]byte, error) { tbl, _ := PKT_CHGSCORE(pkt) ret := INT{F_v: 0} if ranklist.ChangeScore(tbl.F_id, tbl.F_oldscore, tbl.F_newscore) { ret.F_v = 1 } return packet.Pack(Code["changescore_ack"], ret, nil), nil }
func P_logout_req(hostid int32, pkt *packet.Packet) ([]byte, error) { tbl, _ := PKT_ID(pkt) ret := INT{F_v: 0} if ranklist.Logout(tbl.F_id) { ret.F_v = 1 } return packet.Pack(Code["logout_ack"], ret, nil), nil }
func IPC_talk(sess *Session, obj *IPCObject) []byte { var str string err := json.Unmarshal(obj.Object, &str) if err == nil { ret := &talk{F_user: sess.User.Name, F_msg: str} return packet.Pack(Code["talk_notify"], ret, nil) } return nil }
func send_proto(conn net.Conn, p int16, info interface{}) { seqid++ payload := packet.Pack(p, info, nil) writer := packet.Writer() writer.WriteU16(uint16(len(payload)) + 4) writer.WriteU32(seqid) writer.WriteRawBytes(payload) conn.Write(writer.Data()) time.Sleep(time.Second) }
func P_free_req(hostid int32, pkt *packet.Packet) []byte { tbl, _ := PKT_ID(pkt) ret := INT{F_v: 0} if core.Free(tbl.F_id) { ret.F_v = 1 } return packet.Pack(-1, &ret, nil) }
func P_protect_req(hostid int32, pkt *packet.Packet) []byte { tbl, _ := PKT_PROTECT(pkt) ret := INT{F_v: 0} if core.Protect(tbl.F_id, tbl.F_protecttime) { ret.F_v = 1 } return packet.Pack(-1, &ret, nil) }
func P_changescore_req(hostid int32, pkt *packet.Packet) []byte { tbl, _ := PKT_CHGSCORE(pkt) ret := INT{F_v: 0} if core.UpdateScore(tbl.F_id, tbl.F_oldscore, tbl.F_newscore) { ret.F_v = 1 } return packet.Pack(-1, &ret, nil) }
func P_atk_monster_req(sess *Session, reader *packet.Packet) (ret []byte, err error) { tbl, _ := PKT_command_id_pack(reader) writer := packet.Writer() payload := command_result_pack{} // println(tbl.F_id) ret = packet.Pack(Code["atk_monster_ack"], payload, writer) return }
func P_login_req(hostid int32, pkt *packet.Packet) []byte { tbl, _ := PKT_LOGIN_REQ(pkt) ret := LOGIN_ACK{F_success: 0} if core.Login(tbl.F_id, hostid) { ret.F_success = 1 } return packet.Pack(-1, &ret, nil) }
func P_adduser_req(hostid int32, pkt *packet.Packet) []byte { tbl, _ := PKT_ID(pkt) ret := INT{F_v: 0} if core.LoadUser(tbl.F_id) { core.Login(tbl.F_id, hostid) ret.F_v = 1 } return packet.Pack(-1, &ret, nil) }
func Ping() bool { defer _hub_err() req := INT{} req.F_v = 1 ret := _call(packet.Pack(Code["ping_req"], &req, nil)) if ret == nil { ERR("HUB Ping return", false) return false } return true }
func P_key_exchange_req(sess *Session, reader *packet.Packet) []byte { tbl, _ := PKT_KEY(reader) A := big.NewInt(int64(tbl.F_E)) secret, B := diffie.DHGenKey(diffie.DH1BASE, diffie.DH1PRIME) key := big.NewInt(0).Exp(A, secret, diffie.DH1PRIME) sess.Crypto = pike.NewCtx(uint32(key.Uint64())) ret := KEY{int32(B.Uint64())} return packet.Pack(Code["key_exchange_ack"], &ret, nil) }
func P_user_login_req(sess *Session, reader *packet.Packet) []byte { tbl, _ := PKT_user_login_info(reader) ret := command_result_pack{} if user := user_tbl.LoginMac(tbl.F_user_name, tbl.F_mac_addr); user != nil { sess.User = user AI.LoginProc(sess) } return packet.Pack(Code["user_login_succeed_ack"], &ret, nil) }
func P_getinfo_req(hostid int32, pkt *packet.Packet) ([]byte, error) { tbl, _ := PKT_ID(pkt) ret := INFO{} ret.F_id = tbl.F_id ret.F_state = ranklist.State(tbl.F_id) ret.F_score = ranklist.Score(tbl.F_id) ret.F_clan = ranklist.Score(tbl.F_id) ret.F_protecttime = ranklist.ProtectTime(tbl.F_id) ret.F_name = ranklist.Name(tbl.F_id) return packet.Pack(Code["getinfo_ack"], ret, nil), nil }
func Add(Type int16, user_id int32, timeout int64, params []byte) int32 { defer _event_err() req := event.ADD_EVENT{} req.F_type = Type req.F_user_id = user_id req.F_timeout = timeout req.F_params = params ret := _call(packet.Pack(event.Code["add_req"], &req, nil)) reader := packet.Reader(ret) tbl, _ := event.PKT_INT(reader) return tbl.F_v }
func P_atk_player_req(sess *Session, reader *packet.Packet) (ret []byte, err error) { tbl, _ := PKT_command_id_pack(reader) writer := packet.Writer() success := user_snapshot{} failed := command_result_pack{} if ipc.Raid(tbl.F_id) { opponent, e := user_tbl.Load(tbl.F_id) if e == nil { _fill_user_snapshot(&opponent, &success) ret = packet.Pack(Code["atk_player_succeed_ack"], success, writer) return } } // info, err := ipc.GetInfo(tbl.F_id) failed.F_rst = info.Id ret = packet.Pack(Code["atk_player_faild_ack"], failed, writer) return }
// 玩家登陆过程 func P_user_login_req(sess *Session, reader *packet.Packet) []byte { // TODO: 登陆鉴权 sess.UserId = 1 // TODO: 选择登陆服务器 sess.GSID = DEFAULT_GSID // 选服 cli, err := sp.GetServiceWithId(sp.SERVICE_GAME, sess.GSID) if err != nil { log.Critical(err) return nil } // type assertion game_cli, ok := cli.(spp.GameServiceClient) if !ok { log.Critical("cannot do type assertion on: %v", sess.GSID) return nil } // 开启到游戏服的流 // TODO: 处理context,设定超时 stream, err := game_cli.Stream(context.Background()) if err != nil { log.Critical(err) return nil } sess.Stream = stream // 在game注册 // TODO: 新用户的创建由game处理 sess.Stream.Send(&spp.Game_Frame{Type: spp.Game_Register, UserId: sess.UserId}) // 读取GAME返回消息 fetcher_task := func(sess *Session) { for { in, err := sess.Stream.Recv() if err == io.EOF { // 流关闭 log.Trace(err) return } if err != nil { log.Error(err) return } sess.MQ <- *in } } go fetcher_task(sess) return packet.Pack(Code["user_login_ack"], user_snapshot{F_uid: sess.UserId}, nil) }
func Ping() bool { defer _event_err() req := event.INT{} req.F_v = 1 ret := _call(packet.Pack(event.Code["ping_req"], &req, nil)) reader := packet.Reader(ret) tbl, _ := event.PKT_INT(reader) if tbl.F_v != req.F_v { return false } return true }