Exemple #1
0
func (s *server) init() {
	s.dirty_words = make(map[string]bool)

	dict_path, dirty_words_path := s.data_path()
	// 载入字典
	log.Trace("Loading Dictionary...")
	s.segmenter.LoadDictionary(dict_path)
	log.Trace("Dictionary Loaded")

	// 读取脏词库
	log.Trace(SERVICE, "Loading Dirty Words...")
	f, err := os.Open(dirty_words_path)
	if err != nil {
		log.Critical(err)
		os.Exit(-1)
	}
	defer f.Close()

	// 逐行扫描
	scanner := bufio.NewScanner(f)
	scanner.Split(bufio.ScanLines)

	for scanner.Scan() {
		word := strings.ToUpper(strings.TrimSpace(scanner.Text())) // 均处理为大写
		if word != "" {
			s.dirty_words[word] = true
		}
	}
	log.Trace("Dirty Words Loaded")
}
Exemple #2
0
func (s *server) init() {
	// 载入IP表
	log.Trace("Loading GEOIP City...")
	reader, err := maxminddb.Open(s.data_path())
	if err != nil {
		log.Critical(err)
		os.Exit(-1)
	}

	s.mmdb = reader
	log.Trace("GEOIP City Load Complete.")
}
Exemple #3
0
//---------------------------------------------------------- 读取GridFS文件
func LoadFile(filename string) (ok bool, content []byte) {
	ms := _global_ms.Copy()
	defer ms.Close()

	buf := &bytes.Buffer{}
	file, err := ms.DB("").GridFS("fs").Open(filename)
	if err != nil {
		log.Warning("gridfs", filename, err)
		return false, nil
	}

	n, err := io.Copy(buf, file)
	if err != nil {
		log.Error("gridfs", filename, n, err)
		return false, nil
	}

	err = file.Close()
	if err != nil {
		log.Error("gridfs", filename, err)
		return false, nil
	}

	log.Trace("gridfs", filename, "load from GridFS!!")
	return true, buf.Bytes()
}
Exemple #4
0
func (arch *Archiver) init() {
	arch.pending = make(chan []byte)
	arch.stop = make(chan bool)
	cfg := nsq.NewConfig()
	consumer, err := nsq.NewConsumer(TOPIC, CHANNEL, cfg)
	if err != nil {
		log.Critical(err)
		os.Exit(-1)
	}

	// message process
	consumer.AddHandler(nsq.HandlerFunc(func(msg *nsq.Message) error {
		arch.pending <- msg.Body
		return nil
	}))

	// read environtment variable
	addresses := []string{DEFAULT_NSQLOOKUPD}
	if env := os.Getenv(ENV_NSQLOOKUPD); env != "" {
		addresses = strings.Split(env, ";")
	}

	// connect to nsqlookupd
	log.Trace("connect to nsqlookupds ip:", addresses)
	if err := consumer.ConnectToNSQLookupds(addresses); err != nil {
		log.Critical(err)
		return
	}
	log.Info("nsqlookupd connected")

	go arch.archive_task()
}
Exemple #5
0
// 玩家登陆过程
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)
}
Exemple #6
0
// 玩家登陆过程
func P_user_login_req(sess *Session, reader *packet.Packet) []byte {
	// TODO: 登陆鉴权
	sess.UserId = 1

	// TODO: 选择登陆服务器
	sess.GSID = DEFAULT_GSID

	// 选服
	conn := sp.GetServiceWithId(sp.DEFAULT_SERVICE_PATH+"/game", sess.GSID)
	if conn == nil {
		log.Critical("cannot get game service:", sess.GSID)
		return nil
	}
	cli := pb.NewGameServiceClient(conn)

	// 开启到游戏服的流
	// TODO: 处理context,设定超时
	stream, err := cli.Stream(context.Background())
	if err != nil {
		log.Critical(err)
		return nil
	}
	sess.Stream = stream

	// 在game注册
	// TODO: 新用户的创建由game处理
	sess.Stream.Send(&pb.Game_Frame{Type: pb.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
			}
			select {
			case sess.MQ <- *in:
			case <-sess.Die:
			}
		}
	}
	go fetcher_task(sess)
	return packet.Pack(Code["user_login_succeed_ack"], S_user_snapshot{F_uid: sess.UserId}, nil)
}
Exemple #7
0
//---------------------------------------------------------- 删除GridFS文件
func RemoveFile(filename string) bool {
	ms := _global_ms.Copy()
	defer ms.Close()

	gridfs := ms.DB("").GridFS("fs")

	// 删除同名文件
	err := gridfs.Remove(filename)
	if err != nil {
		log.Warning("gridfs", filename, err)
		return false
	}

	log.Trace("gridfs", filename, "removed from GridFS!!")
	return true
}
Exemple #8
0
// 玩家登陆过程
func P_user_login_req(sess *Session, reader *packet.Packet) []byte {
	// TODO: 登陆鉴权
	// 简单鉴权可以在agent直接完成,通常公司都存在一个用户中心服务器用于鉴权
	sess.UserId = 1

	// TODO: 选择GAME服务器
	// 选服策略依据业务进行,比如小服可以固定选取某台,大服可以采用HASH或一致性HASH
	sess.GSID = DEFAULT_GSID

	// 连接到已选定GAME服务器
	conn := sp.GetServiceWithId(sp.DEFAULT_SERVICE_PATH+"/game", sess.GSID)
	if conn == nil {
		log.Critical("cannot get game service:", sess.GSID)
		return nil
	}
	cli := pb.NewGameServiceClient(conn)

	// 开启到游戏服的流
	ctx := metadata.NewContext(context.Background(), metadata.New(map[string]string{"userid": fmt.Sprint(sess.UserId)}))
	stream, err := cli.Stream(ctx)
	if err != nil {
		log.Critical(err)
		return nil
	}
	sess.Stream = stream

	// 读取GAME返回消息的goroutine
	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
			}
			select {
			case sess.MQ <- *in:
			case <-sess.Die:
			}
		}
	}
	go fetcher_task(sess)
	return packet.Pack(Code["user_login_succeed_ack"], S_user_snapshot{F_uid: sess.UserId}, nil)
}
Exemple #9
0
// stream server
func (s *server) Stream(stream GameService_StreamServer) error {
	var sess Session
	ch_agent := s.recv(stream)
	ch_ipc := make(chan *Game_Frame, DEFAULT_CH_IPC_SIZE)

	defer func() {
		if sess.Flag&SESS_REGISTERED != 0 {
			// TODO: destroy session
			sess.Flag &^= SESS_REGISTERED
			registry.Unregister(sess.UserId)
		}
		log.Trace("stream end:", sess.UserId)
	}()

	// >> main message loop <<
	for {
		select {
		case frame, ok := <-ch_agent: // frames from agent
			if !ok { // EOF
				return nil
			}
			switch frame.Type {
			case Game_Message:
				// validation
				if sess.Flag&SESS_REGISTERED == 0 {
					log.Critical("user not registered")
					return ERROR_USER_NOT_REGISTERED
				}

				// locate handler by proto number
				reader := packet.Reader(frame.Message)
				c, err := reader.ReadS16()
				if err != nil {
					log.Critical(err)
					return err
				}
				handle := client_handler.Handlers[c]
				if handle == nil {
					log.Criticalf("service not bind: %v", c)
					return ERROR_SERVICE_NOT_BIND

				}

				// serialized processing, no future locks needed.
				// multiple agents can connect simutaneously to games
				var ret []byte
				wrap := func() { ret = handle(&sess, reader) }
				s.latch(wrap)

				// construct frame & return message from logic
				if ret != nil {
					if err := stream.Send(&Game_Frame{Type: Game_Message, Message: ret}); err != nil {
						log.Critical(err)
						return err
					}
				}

				// session control by logic
				if sess.Flag&SESS_KICKED_OUT != 0 { // logic kick out
					if err := stream.Send(&Game_Frame{Type: Game_Kick}); err != nil {
						log.Critical(err)
						return err
					}
					return nil
				}
			case Game_Register:
				if sess.Flag&SESS_REGISTERED == 0 {
					// TODO: create session
					sess.Flag |= SESS_REGISTERED
					sess.UserId = frame.UserId
					registry.Register(frame.UserId, ch_ipc)
					log.Trace("user registered")
				} else {
					log.Critical("user already registered")
				}
			case Game_Unregister:
				if sess.Flag&SESS_REGISTERED != 0 {
					// TODO: destroy session
					sess.Flag &^= SESS_REGISTERED
					registry.Unregister(sess.UserId)
					log.Trace("user unregistered")
				} else {
					log.Critical("user not registered")
				}
			case Game_Ping:
				if err := stream.Send(&Game_Frame{Type: Game_Ping, Message: frame.Message}); err != nil {
					log.Critical(err)
					return err
				}
				log.Trace("pinged")
			default:
				log.Criticalf("incorrect frame type: %v", frame.Type)
				return ERROR_INCORRECT_FRAME_TYPE
			}
		case frame := <-ch_ipc: // forward async messages from interprocess(goroutines) communication
			if err := stream.Send(frame); err != nil {
				log.Critical(err)
				return err
			}
		}
	}
}
Exemple #10
0
// client protocol handle proxy
func proxy_user_request(sess *Session, p []byte) []byte {
	start := time.Now()
	defer utils.PrintPanicStack(sess, p)
	// 解密
	if sess.Flag&SESS_ENCRYPT != 0 {
		sess.Decoder.XORKeyStream(p, p)
	}

	// 封装为reader
	reader := packet.Reader(p)

	// 读客户端数据包序列号(1,2,3...)
	// 可避免重放攻击-REPLAY-ATTACK
	seq_id, err := reader.ReadU32()
	if err != nil {
		log.Error("read client timestamp failed:", err)
		sess.Flag |= SESS_KICKED_OUT
		return nil
	}

	// 数据包序列号验证
	if seq_id != sess.PacketCount {
		log.Errorf("illegal packet sequence id:%v should be:%v size:%v", seq_id, sess.PacketCount, len(p)-6)
		sess.Flag |= SESS_KICKED_OUT
		return nil
	}

	// 读协议号
	b, err := reader.ReadS16()
	if err != nil {
		log.Error("read protocol number failed.")
		sess.Flag |= SESS_KICKED_OUT
		return nil
	}

	// 根据协议号断做服务划分
	var ret []byte
	if b > MAX_PROTO_NUM {
		if err := forward(sess, p[4:]); err != nil {
			log.Errorf("service id:%v execute failed, error:%v", b, err)
			sess.Flag |= SESS_KICKED_OUT
			return nil
		}
	} else {
		if h := client_handler.Handlers[b]; h != nil {
			ret = h(sess, reader)
		} else {
			log.Errorf("service id:%v not bind", b)
			sess.Flag |= SESS_KICKED_OUT
			return nil
		}
	}

	// 统计处理时间
	elasped := time.Now().Sub(start)
	if b != 0 { // 排除心跳包日志
		log.Trace("[REQ]", client_handler.RCode[b])
		_statter.Timing(1.0, fmt.Sprintf("%v%v", STATSD_PREFIX, client_handler.RCode[b]), elasped)
	}
	return ret
}
Exemple #11
0
// PIPELINE #2 stream processing
// the center of game logic
func (s *server) Stream(stream GameService_StreamServer) error {
	defer PrintPanicStack()
	// session init
	var sess Session
	sess_die := make(chan struct{})
	ch_agent := s.recv(stream, sess_die)
	ch_ipc := make(chan *Game_Frame, DEFAULT_CH_IPC_SIZE)

	defer func() {
		registry.Unregister(sess.UserId)
		close(sess_die)
		log.Trace("stream end:", sess.UserId)
	}()

	// read metadata from context
	md, ok := metadata.FromContext(stream.Context())
	if !ok {
		log.Critical("cannot read metadata from context")
		return ERROR_INCORRECT_FRAME_TYPE
	}
	// read key
	if len(md["userid"]) == 0 {
		log.Critical("cannot read key:userid from metadata")
		return ERROR_INCORRECT_FRAME_TYPE
	}
	// parse userid
	userid, err := strconv.Atoi(md["userid"][0])
	if err != nil {
		log.Critical(err)
		return ERROR_INCORRECT_FRAME_TYPE
	}

	// register user
	sess.UserId = int32(userid)
	registry.Register(sess.UserId, ch_ipc)
	log.Finef("userid %v logged in", sess.UserId)

	// >> main message loop <<
	for {
		select {
		case frame, ok := <-ch_agent: // frames from agent
			if !ok { // EOF
				return nil
			}
			switch frame.Type {
			case Game_Message: // the passthrough message from client->agent->game
				// locate handler by proto number
				reader := packet.Reader(frame.Message)
				c, err := reader.ReadS16()
				if err != nil {
					log.Critical(err)
					return err
				}
				handle := client_handler.Handlers[c]
				if handle == nil {
					log.Criticalf("service not bind: %v", c)
					return ERROR_SERVICE_NOT_BIND

				}

				// handle request
				ret := handle(&sess, reader)

				// construct frame & return message from logic
				if ret != nil {
					if err := stream.Send(&Game_Frame{Type: Game_Message, Message: ret}); err != nil {
						log.Critical(err)
						return err
					}
				}

				// session control by logic
				if sess.Flag&SESS_KICKED_OUT != 0 { // logic kick out
					if err := stream.Send(&Game_Frame{Type: Game_Kick}); err != nil {
						log.Critical(err)
						return err
					}
					return nil
				}
			case Game_Ping:
				if err := stream.Send(&Game_Frame{Type: Game_Ping, Message: frame.Message}); err != nil {
					log.Critical(err)
					return err
				}
				log.Trace("pinged")
			default:
				log.Criticalf("incorrect frame type: %v", frame.Type)
				return ERROR_INCORRECT_FRAME_TYPE
			}
		case frame := <-ch_ipc: // forward async messages from interprocess(goroutines) communication
			if err := stream.Send(frame); err != nil {
				log.Critical(err)
				return err
			}
		}
	}
}