Example #1
0
// get stored service name
func (p *service_pool) load_names() {
	p.service_names = make(map[string]bool)
	client := p.client_pool.Get().(*etcd.Client)
	defer func() {
		p.client_pool.Put(client)
	}()

	// get the keys under directory
	log.Info("reading names:", DEFAULT_NAME_FILE)
	resp, err := client.Get(DEFAULT_NAME_FILE, false, false)
	if err != nil {
		log.Error(err)
		return
	}

	// validation check
	if resp.Node.Dir {
		log.Error("names is not a file")
		return
	}

	// split names
	names := strings.Split(resp.Node.Value, "\n")
	log.Info("all service names:", names)
	for _, v := range names {
		p.service_names[DEFAULT_SERVICE_PATH+"/"+strings.TrimSpace(v)] = true
	}

	p.enable_name_check = true
}
Example #2
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()
}
Example #3
0
// connect to all services
func (p *service_pool) connect_all(directory string) {
	client := p.client_pool.Get().(*etcd.Client)
	defer func() {
		p.client_pool.Put(client)
	}()

	// get the keys under directory
	log.Info("connecting services under:", directory)
	resp, err := client.Get(directory, true, true)
	if err != nil {
		log.Error(err)
		return
	}

	// validation check
	if !resp.Node.Dir {
		log.Error("not a directory")
		return
	}

	for _, node := range resp.Node.Nodes {
		if node.Dir { // service directory
			for _, service := range node.Nodes {
				p.add_service(service.Key, service.Value)
			}
		} else {
			log.Warning("malformed service directory:", node.Key)
		}
	}
	log.Info("services add complete")
}
Example #4
0
// generate an unique uuid
func (s *server) GetUUID(context.Context, *pb.Snowflake_NullRequest) (*pb.Snowflake_UUID, error) {
	s.Lock()
	defer s.Unlock()

	// get a correct serial number
	t := s.ts()
	if t < s.last_ts { // clock shift backward
		log.Error("clock shift happened, waiting until the clock moving to the next millisecond.")
		t = s.wait_ms(s.last_ts)
	}

	if s.last_ts == t { // same millisecond
		s.sn = (s.sn + 1) & SN_MASK
		if s.sn == 0 { // serial number overflows, wait until next ms
			t = s.wait_ms(s.last_ts)
		}
	} else { // new millsecond, reset serial number to 0
		s.sn = 0
	}
	// remember last timestamp
	s.last_ts = t

	// generate uuid, format:
	//
	// 0		0.................0		0..............0	0........0
	// 1-bit	41bit timestamp			10bit machine-id	12bit sn
	var uuid uint64
	uuid |= (uint64(t) & TS_MASK) << 22
	uuid |= s.machine_id
	uuid |= s.sn

	return &pb.Snowflake_UUID{uuid}, nil
}
Example #5
0
func (ps *PubSub) init() {
	ps.ch_msg = make(chan interface{})
	call := func(rf reflect.Value, in []reflect.Value) {
		defer func() { // do not let callback panic the pubsub
			if err := recover(); err != nil {
				log.Error(err)
			}
		}()
		rf.Call(in)
	}

	go func() {
		for v := range ps.ch_msg {
			rv := reflect.ValueOf(v)
			ps.Lock()
			for _, sub := range ps.subs {
				rf := reflect.ValueOf(sub.f)
				if rv.Type() == reflect.ValueOf(sub.f).Type().In(0) { // parameter type match
					call(rf, []reflect.Value{rv})
				}
			}
			ps.Unlock()
		}
	}()
}
Example #6
0
// uuid generator
func (s *server) uuid_task() {
	var sn uint64     // 12-bit serial no
	var last_ts int64 // last timestamp
	for {
		ret := <-s.ch_proc
		// get a correct serial number
		t := ts()
		if t < last_ts { // clock shift backward
			log.Error("clock shift happened, waiting until the clock moving to the next millisecond.")
			t = s.wait_ms(last_ts)
		}

		if last_ts == t { // same millisecond
			sn = (sn + 1) & SN_MASK
			if sn == 0 { // serial number overflows, wait until next ms
				t = s.wait_ms(last_ts)
			}
		} else { // new millsecond, reset serial number to 0
			sn = 0
		}
		// remember last timestamp
		last_ts = t

		// generate uuid, format:
		//
		// 0		0.................0		0..............0	0........0
		// 1-bit	41bit timestamp			10bit machine-id	12bit sn
		var uuid uint64
		uuid |= (uint64(t) & TS_MASK) << 22
		uuid |= s.machine_id
		uuid |= sn
		ret <- uuid
	}
}
Example #7
0
// get next value of a key, like auto-increment in mysql
func (s *server) Next(ctx context.Context, in *pb.Snowflake_Key) (*pb.Snowflake_Value, error) {
	client := s.client_pool.Get().(*etcd.Client)
	defer func() {
		s.client_pool.Put(client)
	}()
	key := PATH + in.Name

	for i := 0; i < RETRY_MAX; i++ {
		// get the key
		resp, err := client.Get(key, false, false)
		if err != nil {
			log.Critical(err)
			return nil, errors.New("Key not exists, need to create first")
		}

		// get prevValue & prevIndex
		prevValue, err := strconv.Atoi(resp.Node.Value)
		if err != nil {
			log.Critical(err)
			return nil, errors.New("marlformed value")
		}
		prevIndex := resp.Node.ModifiedIndex

		// CAS
		resp, err = client.CompareAndSwap(key, fmt.Sprint(prevValue+1), 0, resp.Node.Value, prevIndex)
		if err != nil {
			log.Error(err)
			<-time.After(RETRY_DELAY)
			continue
		}
		return &pb.Snowflake_Value{int64(prevValue + 1)}, nil
	}
	return nil, errors.New("etcd server busy")
}
Example #8
0
func (arch *Archiver) archive_task() {
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGTERM)
	timer := time.After(REDO_ROTATE_INTERVAL)
	db := arch.new_redolog()
	for {
		select {
		case msg := <-arch.pending:
			var record map[string]interface{}
			err := msgpack.Unmarshal(msg, &record)
			if err != nil {
				log.Error(err)
				continue
			}

			db.Update(func(tx *bolt.Tx) error {
				b := tx.Bucket([]byte(BOLTDB_BUCKET))
				err := b.Put([]byte(fmt.Sprint(record["TS"])), msg)
				return err
			})
		case <-timer:
			db.Close()
			// rotate redolog
			db = arch.new_redolog()
			timer = time.After(REDO_ROTATE_INTERVAL)
		case <-sig:
			db.Close()
			log.Info("SIGTERM")
			os.Exit(0)
		}
	}
}
Example #9
0
// unlock a key on etcd, returns false if the key cannot be successfully unlocked
func (m *Mutex) Unlock() bool {
	client := _client_pool.Get().(*etcd.Client)
	_, err := client.CompareAndDelete(LOCK_PATH+m.key, VALUE, m.prevIndex)
	if err != nil {
		log.Error(SERVICE, err)
		return false
	}
	return true
}
Example #10
0
func (s *server) query(ip net.IP) *City {
	city := &City{}
	err := s.mmdb.Lookup(ip, city)
	if err != nil {
		log.Error(err)
		return nil
	}

	return city
}
Example #11
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)
}
Example #12
0
// 玩家1分钟定时器
func timer_work(sess *Session, out *Buffer) {
	// 发包频率控制,太高的RPS直接踢掉
	interval := time.Now().Sub(sess.ConnectTime).Minutes()
	if interval >= 1 { // 登录时长超过1分钟才开始统计rpm。防脉冲
		rpm := float64(sess.PacketCount) / interval

		if rpm > RPM_LIMIT {
			sess.Flag |= SESS_KICKED_OUT
			log.Error("玩家RPM太高 RPM:", rpm)
			return
		}
	}
}
Example #13
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)
}
Example #14
0
func PrintPanicStack(extras ...interface{}) {
	if x := recover(); x != nil {
		log.Error(x)
		i := 0
		funcName, file, line, ok := runtime.Caller(i)
		for ok {
			log.Errorf("frame %v:[func:%v,file:%v,line:%v]\n", i, runtime.FuncForPC(funcName).Name(), file, line)
			i++
			funcName, file, line, ok = runtime.Caller(i)
		}

		for k := range extras {
			log.Errorf("EXRAS#%v DATA:%v\n", k, spew.Sdump(extras[k]))
		}
	}
}
Example #15
0
File: pprof.go Project: xinhp/libs
func init() {
	addr := DEFAULT_STATSD_HOST
	if env := os.Getenv(ENV_STATSD); env != "" {
		addr = env
	}

	s, err := g2s.Dial("udp", addr)
	if err == nil {
		_statter = s
	} else {
		_statter = g2s.Noop()
		log.Error(err)
	}

	go pprof_task()
}
Example #16
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)
}
Example #17
0
// forward messages to game server
func forward(sess *Session, p []byte) error {
	frame := &pb.Game_Frame{
		Type:    pb.Game_Message,
		Message: p,
	}

	// check stream
	if sess.Stream == nil {
		return ERROR_STREAM_NOT_OPEN
	}

	// forward the frame to game
	if err := sess.Stream.Send(frame); err != nil {
		log.Error(err)
		return err
	}
	return nil
}
Example #18
0
// subscribe to an endpoint & receive server streams
func (s *server) Subscribe(p *Chat_Id, stream ChatService_SubscribeServer) error {
	// read endpoint
	ep := s.read_ep(p.Id)
	if ep == nil {
		log.Errorf("cannot find endpoint %v", p)
		return ERROR_NOT_EXISTS
	}

	// send history chat messages
	msgs := ep.Read()
	for k := range msgs {
		if err := stream.Send(&msgs[k]); err != nil {
			return nil
		}
	}

	// create subscriber
	e := make(chan error, 1)
	var once sync.Once
	f := NewSubscriber(func(msg *Chat_Message) {
		if err := stream.Send(msg); err != nil {
			once.Do(func() { // protect for channel blocking
				e <- err
			})
		}
	})

	// subscribe to the endpoint
	log.Tracef("subscribe to:%v", p.Id)
	ep.ps.Sub(f)
	defer func() {
		ep.ps.Leave(f)
		log.Tracef("leave from:%v", p.Id)
	}()

	// client send cancel to stop receiving, see service_test.go for example
	select {
	case <-stream.Context().Done():
	case <-e:
		log.Error(e)
	}
	return nil
}
Example #19
0
// lock a key on etcd and return mutex,returns nil if cannot lock the key
func Lock(key string) *Mutex {
	m := &Mutex{}
	m.key = key
	client := _client_pool.Get().(*etcd.Client)
	defer func() {
		_client_pool.Put(client)
	}()

	for i := 0; i < RETRY_MAX; i++ {
		// create a key with ttl
		resp, err := client.Create(LOCK_PATH+key, VALUE, TTL)
		if err != nil {
			log.Error(SERVICE, err)
			<-time.After(RETRY_WAIT)
			continue
		}
		// remember index
		m.prevIndex = resp.Node.ModifiedIndex
		return m
	}
	return nil
}
Example #20
0
func (s *server) init_machine_id() {
	client := s.client_pool.Get().(*etcd.Client)
	defer func() {
		s.client_pool.Put(client)
	}()

	for i := 0; i < RETRY_MAX; i++ {
		// get the key
		resp, err := client.Get(UUID_KEY, false, false)
		if err != nil {
			log.Critical(err)
			os.Exit(-1)
		}

		// get prevValue & prevIndex
		prevValue, err := strconv.Atoi(resp.Node.Value)
		if err != nil {
			log.Critical(err)
			os.Exit(-1)
		}
		prevIndex := resp.Node.ModifiedIndex

		// CAS
		resp, err = client.CompareAndSwap(UUID_KEY, fmt.Sprint(prevValue+1), 0, resp.Node.Value, prevIndex)
		if err != nil {
			log.Error(err)
			<-time.After(RETRY_DELAY)
			continue
		}

		// record serial number of this service, already shifted
		s.machine_id = (uint64(prevValue+1) & MACHINE_ID_MASK) << 12
		return
	}

	// failed to get machine id, exit
	os.Exit(-1)
}
Example #21
0
func (ns *numbers) init(path string) {
	ns.tables = make(map[string]*table)
	kapi := etcdclient.KeysAPI()
	resp, err := kapi.Get(context.Background(), path, nil)
	if err != nil {
		log.Error(err)
		return
	}

	// 解码xlsx
	xlsx_bin, err := base64.StdEncoding.DecodeString(resp.Node.Value)
	if err != nil {
		log.Critical(err)
		return
	}

	// 读取xlsx
	xlsx_reader, err := xlsx.OpenBinary(xlsx_bin)
	if err != nil {
		log.Critical(err)
		return
	}
	ns.parse(xlsx_reader.Sheets)
}
Example #22
0
// PIPELINE #1: handleClient
// the goroutine is used for reading incoming PACKETS
// each packet is defined as :
// | 2B size |     DATA       |
//
func handleClient(conn *net.TCPConn) {
	defer utils.PrintPanicStack()
	// set socket read buffer
	conn.SetReadBuffer(SO_RCVBUF)
	// set socket write buffer
	conn.SetWriteBuffer(SO_SNDBUF)

	// for reading the 2-Byte header
	header := make([]byte, 2)
	// the input channel for agent()
	in := make(chan []byte)
	defer func() {
		close(in) // session will close
	}()

	// create a new session object for the connection
	// and record it's IP address
	var sess Session
	host, port, err := net.SplitHostPort(conn.RemoteAddr().String())
	if err != nil {
		log.Error("cannot get remote address:", err)
		return
	}
	sess.IP = net.ParseIP(host)
	log.Infof("new connection from:%v port:%v", host, port)

	// session die signal, will be triggered by agent()
	sess.Die = make(chan struct{})

	// create a write buffer
	out := new_buffer(conn, sess.Die)
	go out.start()

	// start agent for PACKET processing
	wg.Add(1)
	go agent(&sess, in, out)

	// read loop
	for {
		// solve dead link problem:
		// physical disconnection without any communcation between client and server
		// will cause the read to block FOREVER, so a timeout is a rescue.
		conn.SetReadDeadline(time.Now().Add(TCP_READ_DEADLINE * time.Second))

		// read 2B header
		n, err := io.ReadFull(conn, header)
		if err != nil {
			log.Warningf("read header failed, ip:%v reason:%v size:%v", sess.IP, err, n)
			return
		}
		size := binary.BigEndian.Uint16(header)

		// alloc a byte slice of the size defined in the header for reading data
		payload := make([]byte, size)
		n, err = io.ReadFull(conn, payload)
		if err != nil {
			log.Warningf("read payload failed, ip:%v reason:%v size:%v", sess.IP, err, n)
			return
		}

		// deliver the data to the input queue of agent()
		select {
		case in <- payload: // payload queued
		case <-sess.Die:
			log.Warningf("connection closed by logic, flag:%v ip:%v", sess.Flag, sess.IP)
			return
		}
	}
}
Example #23
0
File: main.go Project: CowLeo/agent
// start a goroutine when a new connection is accepted
func handleClient(conn *net.TCPConn) {
	defer utils.PrintPanicStack()
	// set per-connection socket buffer
	conn.SetReadBuffer(SO_RCVBUF)

	// set initial socket buffer
	conn.SetWriteBuffer(SO_SNDBUF)

	// initial network control struct
	header := make([]byte, 2)
	in := make(chan []byte)
	defer func() {
		close(in) // session will close
	}()

	// create a new session object for the connection
	var sess Session
	host, port, err := net.SplitHostPort(conn.RemoteAddr().String())
	if err != nil {
		log.Error("cannot get remote address:", err)
		return
	}
	sess.IP = net.ParseIP(host)
	log.Infof("new connection from:%v port:%v", host, port)

	// session die signal
	sess.Die = make(chan struct{})

	// create a write buffer
	out := new_buffer(conn, sess.Die)
	go out.start()

	// start one agent for handling packet
	wg.Add(1)
	go agent(&sess, in, out)

	// network loop
	for {
		// solve dead link problem
		conn.SetReadDeadline(time.Now().Add(TCP_READ_DEADLINE * time.Second))
		n, err := io.ReadFull(conn, header)
		if err != nil {
			log.Warningf("read header failed, ip:%v reason:%v size:%v", sess.IP, err, n)
			return
		}
		size := binary.BigEndian.Uint16(header)

		// alloc a byte slice for reading
		payload := make([]byte, size)
		// read msg
		n, err = io.ReadFull(conn, payload)
		if err != nil {
			log.Warningf("read payload failed, ip:%v reason:%v size:%v", sess.IP, err, n)
			return
		}

		select {
		case in <- payload: // payload queued
		case <-sess.Die:
			log.Warningf("connection closed by logic, flag:%v ip:%v", sess.Flag, sess.IP)
			return
		}
	}
}
Example #24
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
}
Example #25
0
func checkErr(err error) {
	if err != nil {
		log.Error(err)
		panic("error occured in protocol module")
	}
}