//加载数据 func (s *server) restore() { db := s.open_db() defer db.Close() count := 0 //查询 db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte(BOLTDB_BUCKET)) b.ForEach(func(k, v []byte) error { //查询每个用户对应消息记录集合,将其反序列化成ChatMessage[]对象 var msg []Chat_Message err := msgpack.Unmarshal(v, &msg) if err != nil { log.Critical("chat data corrupted:", err) os.Exit(-1) } //id转成uint64 id, err := strconv.ParseUint(string(k), 0, 64) if err != nil { log.Critical("chat data corrupted:", err) os.Exit(-1) } //用NewEndPoint包装msg ep := NewEndPoint() ep.inbox = msg //用过eps包装ep s.eps[id] = ep count++ return nil }) return nil }) log.Infof("restored %v chats", count) }
// 密钥交换 func P_get_seed_req(sess *Session, reader *packet.Packet) []byte { // 读取4字节的send_seed 和 4字节的receive_seed 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_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 service, ok := cli.(spp.GameServiceClient) if !ok { log.Critical("canot do type assertion on: %v", sess.GSID) return nil } //开启到游戏服的流 // TODO: 处理context, 设置超时 stream, err := service.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 (s *server) dump(db *bolt.DB, changes map[uint64]bool) { //写入已经更改的id for k := range changes { //读取message ep := s.read_ep(k) if ep == nil { log.Errorf("canot find endpoint %v", k) continue } //序列化数据 bin, err := msgpack.Marshal(ep.Read()) if err != nil { log.Critical("canot marshal:", err) continue } //更新表 db.Update(func(tx *bolt.Tx) error { //拿到表句柄 b := tx.Bucket([]byte(BOLTDB_BUCKET)) //存入数据, k-v形式 err := b.Put([]byte(fmt.Sprint(k)), bin) return err }) } }
func (s *server) init() { // snappy if env := os.Getenv(ENV_SNAPPY); env != "" { s.enable_snappy = true } // read redis host redis_host := DEFAULT_REDIS_HOST if env := os.Getenv(ENV_REDIS_HOST); env != "" { redis_host = env } // start connection to redis cluster client, err := cluster.NewCluster(redis_host) if err != nil { log.Critical(err) os.Exit(-1) } //存放redis client 句柄 s.redis_client = client // read mongodb host mongodb_url := DEFAULT_MONGODB_URL if env := os.Getenv(ENV_MONGODB_URL); env != "" { mongodb_url = env } // start connection to mongodb sess, err := mgo.Dial(mongodb_url) if err != nil { log.Critical(err) os.Exit(-1) } s.db = sess.DB("") // wait chan s.wait = make(chan string, BUFSIZ) go s.loader_task() }
func init() { addr := DEFAULT_STATSD_HOST if env := os.Getenv(ENV_STATSD); env != "" { addr = env } s, err := g2s.Dial("udp", addr) if err != nil { log.Critical(err) os.Exit(-1) } _statter = s }
func main() { log.SetPrefix(SERVICE) lis, err := net.Listen("tcp", _port) if err != nil { log.Critical(err) os.Exit(-1) } log.Info("listenin on ", lis.Addr()) s := grpc.NewServer() ins := &server{} ins.init() pb.RegisterChatServiceServer(s, ins) s.Serve(lis) }
//打开数据库 func (s *server) open_db() *bolt.DB { db, err := bolt.Open(BOLTDB_FILE, 0600, nil) if err != nil { log.Critical(err) os.Exit(-1) } //创建表 db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucketIfNotExists([]byte(BOLTDB_BUCKET)) if err != nil { log.Criticalf("create bucket: %s", err) os.Exit(-1) } return nil }) return db }
func (s *server) dump(dirty map[string]bool) { //遍历dirty, 取出key for k := range dirty { raw, err := s.redis_client.Cmd("GET", k).Bytes() if err != nil { log.Critical(err) continue } // 解压缩 if s.enable_snappy { if dec, err := snappy.Decode(nil, raw); err == nil { raw = dec } else { log.Critical(err) continue } } var record map[string]interface{} //反序列化 err = msgpack.Unmarshal(raw, &record) if err != nil { log.Critical(err) continue } //分隔拿到key和value strs := strings.Split(k, ":") if len(strs) != 2 { log.Critical("canot split key", k) continue } tblname, id_str := strs[0], strs[1] id, err := strconv.Atoi(id_str) if err != nil { log.Critical(err) continue } // save data to mongodb _, err = s.db.C(tblname).Upsert(bson.M{"Id": id}, record) if err != nil { log.Critical(err) continue } } }
func checkError(err error) { if err != nil { log.Critical(err) os.Exit(-1) } }