Exemplo n.º 1
0
Arquivo: fsm.go Projeto: kingpro/gonet
func Protect(id int32, until int64) bool {
	_lock_players.Lock()
	player := _players[id]
	_lock_players.Unlock()

	if player != nil {
		player.Lock()
		defer player.Unlock()

		switch player.State {
		case ON_FREE:
			player.State = ON_PROT
			player.ProtectTimeout = until
			timer.Add(id, until, _waits_ch)
		case OFF_RAID:
			player.State = OFF_PROT
			player.ProtectTimeout = until
			timer.Add(id, until, _waits_ch)
		case ON_PROT: // protect + protect
			player.ProtectTimeout = until
			timer.Add(id, until, _waits_ch)
		default:
			return false
		}
		return true
	}

	return false
}
Exemplo n.º 2
0
Arquivo: agent.go Projeto: hycxa/gonet
//----------------------------------------------- Start Agent when a client is connected
func StartAgent(sess *Session, in chan []byte, out *Buffer) {
	wg.Add(1)
	defer wg.Done()
	defer helper.PrintPanicStack()

	// init session
	sess.MQ = make(chan IPCObject, DEFAULT_MQ_SIZE)
	sess.ConnectTime = time.Now()
	sess.LastPacketTime = time.Now()

	// custom-sec timer, 60-sec
	custom_timer := make(chan int32, 1)
	timer.Add(-1, time.Now().Unix()+CUSTOM_TIMER, custom_timer)

	// cleanup work
	defer func() {
		close_work(sess)
	}()

	// the main message loop
	for {
		select {
		case msg, ok := <-in: // network protocol
			if !ok {
				return
			}

			sess.PacketTime = time.Now()
			if result := UserRequestProxy(sess, msg); result != nil {
				err := out.Send(result)
				if err != nil {
					helper.ERR("cannot send to client", err)
					return
				}
			}
			sess.LastPacketTime = sess.PacketTime
			sess.PacketCount++ // packet count
		case msg := <-sess.MQ: // internal IPC
			if result := IPCRequestProxy(sess, &msg); result != nil {
				err := out.Send(result)
				if err != nil {
					helper.ERR("cannot send ipc response", err)
					return
				}
			}
		case <-custom_timer: // 60-sec timer
			timer_work(sess)
			timer.Add(-1, time.Now().Unix()+CUSTOM_TIMER, custom_timer)
		case <-die:
			sess.Flag |= SESS_KICKED_OUT
		}

		// is the session been kicked out
		if sess.Flag&SESS_KICKED_OUT != 0 {
			return
		}
	}
}
Exemplo n.º 3
0
func Protect(id int32, until int64) bool {
	_lock_players.RLock()
	player := _players[id]
	_lock_players.RUnlock()

	if player != nil {
		player.Lock()
		defer player.Unlock()

		switch player.State {
		case ON_FREE:
			event_id := atomic.AddInt32(&_event_id_gen, 1)
			timer.Add(event_id, until, _waits_ch)

			player.State = ON_PROT
			player.ProtectTimeout = until
			player.WaitEventId = event_id

			_waits_lock.Lock()
			_waits[event_id] = player
			_waits_lock.Unlock()
		case OFF_RAID:
			event_id := atomic.AddInt32(&_event_id_gen, 1)
			timer.Add(event_id, until, _waits_ch)

			player.State = OFF_PROT
			player.ProtectTimeout = until
			player.WaitEventId = event_id

			_waits_lock.Lock()
			_waits[event_id] = player
			_waits_lock.Unlock()
		case ON_PROT:
			event_id := atomic.AddInt32(&_event_id_gen, 1)
			timer.Add(event_id, until, _waits_ch)

			player.State = ON_PROT
			player.ProtectTimeout = until
			player.WaitEventId = event_id

			_waits_lock.Lock()
			_waits[event_id] = player
			_waits_lock.Unlock()
		default:
			return false
		}
		return true
	}

	return false
}
Exemplo n.º 4
0
//---------------------------------------------------------- system routine
func SysRoutine() {
	var sess Session
	sess.MQ = make(chan IPCObject, SYS_MQ_SIZE)
	gsdb.RegisterOnline(&sess, SYS_USR)

	// timer
	gc_timer := make(chan int32, 10)
	gc_timer <- 1

	for {
		select {
		case msg, ok := <-sess.MQ: // IPCObject to system routine
			if !ok {
				return
			}
			IPCRequestProxy(&sess, &msg)
		case <-gc_timer:
			runtime.GC()
			INFO("== PERFORMANCE LOG ==")
			INFO("Goroutine Count:", runtime.NumGoroutine())
			INFO("GC Summary:", GCSummary())
			INFO("Sysroutine MQ size:", len(sess.MQ))
			timer.Add(0, time.Now().Unix()+GC_INTERVAL, gc_timer)
		}
	}
}
Exemplo n.º 5
0
Arquivo: sys.go Projeto: hycxa/gonet
//---------------------------------------------------------- 系统routine
func SysRoutine() {
	// timer
	gc_timer := make(chan int32, 1)
	timer.Add(0, time.Now().Unix()+GC_INTERVAL, gc_timer)

	for {
		select {
		case <-gc_timer:
			runtime.GC()
			log.Println("GC executed")
			log.Println("NumGoroutine", runtime.NumGoroutine())
			log.Println("GC Summary:", helper.GCSummary())
			timer.Add(0, time.Now().Unix()+GC_INTERVAL, gc_timer)
		}
	}
}
Exemplo n.º 6
0
//---------------------------------------------------------- Load a timeout event at startup
func Load(event_id int32, Type int16, user_id int32, timeout int64, params []byte) {
	timer.Add(event_id, timeout, _event_ch)
	event := &Event{EventId: event_id, Type: Type, UserId: user_id, Timeout: timeout, Params: params}
	_events[event_id] = event

	return
}
Exemplo n.º 7
0
func Raid(id int32) bool {
	_lock_players.RLock()
	player := _players[id]
	_lock_players.RUnlock()

	if player != nil {
		player.Lock()
		defer player.Unlock()

		switch player.State {
		case OFF_FREE:
			timeout := time.Now().Unix() + RAID_TIME
			event_id := atomic.AddInt32(&_event_id_gen, 1)
			timer.Add(event_id, timeout, _waits_ch) // generate timer

			player.State = OFF_RAID
			player.RaidTimeout = timeout
			player.WaitEventId = event_id

			_waits_lock.Lock()
			_waits[event_id] = player
			_waits_lock.Unlock()
		default:
			return false
		}
		return true
	}
	return false
}
Exemplo n.º 8
0
Arquivo: main.go Projeto: hycxa/gonet
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()
		}
	}
}
Exemplo n.º 9
0
func init() {
	_all = make(map[int32]*Collector)
	CH = make(chan int32, 5)
	go _writer()

	config := cfg.Get()
	trigger, err := strconv.Atoi(config["collect_time"])
	if err != nil {
		log.Println("cannot parse collect_time from config", err)
	}

	// 寻找最近的触发点
	now := time.Now().Unix()
	passed := now % DAY_SEC
	if passed < int64(trigger) {
		timer.Add(-1, now-passed+int64(trigger), CH)
	} else {
		timer.Add(-1, now-passed+int64(trigger)+DAY_SEC, CH)
	}
}
Exemplo n.º 10
0
//---------------------------------------------------------- Add a timeout event
func Add(Type int16, user_id int32, timeout int64, params []byte) int32 {
	event_id := db.NextVal(EVENTID_GEN)
	timer.Add(event_id, timeout, _event_ch)

	event := &Event{Type: Type, UserId: user_id, EventId: event_id, Timeout: timeout, Params: params}
	_events_lock.Lock()
	_events[event_id] = event
	_events_lock.Unlock()

	// store to db
	event_tbl.Add(event)

	return event_id
}
Exemplo n.º 11
0
Arquivo: agent.go Projeto: hycxa/gonet
//------------------------------------------------ Stats Server Agent
func StatsAgent(incoming chan []byte, conn net.Conn) {
	queue_timer := make(chan int32, 1)
	queue_timer <- 1

	for {
		select {
		case sample := <-incoming:
			reader := packet.Reader(sample)
			HandleRequest(reader)
		case <-queue_timer:
			log.Println("============== STATS QUEUE SIZE:", len(incoming), "===================")
			timer.Add(1, time.Now().Unix()+PRINT_INTERVAL, queue_timer)
		}
	}
}
Exemplo n.º 12
0
Arquivo: fsm.go Projeto: kingpro/gonet
//------------------------------------------------ add a user to finite state machine manager
func _add_fsm(user *User) {
	player := &PlayerInfo{Id: user.Id}
	player.ProtectTimeout = user.ProtectTimeout

	if user.ProtectTimeout > time.Now().Unix() { // 有保护时间
		player.State = OFF_PROT

		_lock_players.Lock()
		_players[player.Id] = player
		_lock_players.Unlock()

		timer.Add(user.Id, user.ProtectTimeout, _waits_ch)
	} else {
		player.State = OFF_FREE

		_lock_players.Lock()
		_players[user.Id] = player
		_lock_players.Unlock()
	}
}
Exemplo n.º 13
0
Arquivo: fsm.go Projeto: kingpro/gonet
func Raid(id int32) bool {
	_lock_players.Lock()
	player := _players[id]
	_lock_players.Unlock()

	if player != nil {
		player.Lock()
		defer player.Unlock()

		switch player.State {
		case OFF_FREE:
			player.State = OFF_RAID
			player.RaidStart = time.Now().Unix()
			timeout := time.Now().Unix() + AUTO_EXPIRE // automatic expire when in raid
			timer.Add(player.Id, timeout, _waits_ch)
		default:
			return false
		}
		return true
	}
	return false
}
Exemplo n.º 14
0
//------------------------------------------------ 统计数据定时汇总写入
func _writer() {
	for {
		// 时钟信号
		<-CH

		// 复制map已进行费事操作,不阻塞collect
		_all_lock.Lock()
		snapshot := make(map[int32]*Collector)
		for k, v := range _all {
			snapshot[k] = v
		}
		_all_lock.Unlock()

		// 创建每个玩家的报表
		c := StatsCollection()
		for userid, collector := range snapshot {
			if collector != nil {
				archive := _archive(userid, collector)
				c.Upsert(bson.M{"userid": userid}, archive)
			}
		}

		now := time.Now().Unix()
		log.Printf("stats flush finished at %v\n", now)

		// 明天同一时刻再见
		passed := now % DAY_SEC
		config := cfg.Get()
		trigger, err := strconv.Atoi(config["collect_time"])
		if err != nil {
			log.Println("cannot parse collect_time from config", err)
		}

		timer.Add(-1, now-passed+int64(trigger)+DAY_SEC, CH)
		snapshot = nil
	}
}
Exemplo n.º 15
0
//----------------------------------------------- Start Agent when a client is connected
func StartAgent(in chan []byte, conn net.Conn) {
	defer helper.PrintPanicStack()

	config := cfg.Get()
	if config["profile"] == "true" {
		helper.SetMemProfileRate(1)
		defer func() {
			helper.GC()
			helper.DumpHeap()
			helper.PrintGCSummary()
		}()
	}

	var sess Session
	sess.IP = net.ParseIP(conn.RemoteAddr().String())
	sess.MQ = make(chan IPCObject, DEFAULT_MQ_SIZE)
	sess.ConnectTime = time.Now()
	sess.LastPacketTime = time.Now().Unix()
	sess.KickOut = false

	// standard 1-sec timer
	std_timer := make(chan int32, 1)
	timer.Add(1, time.Now().Unix()+1, std_timer)

	// write buffer
	bufctrl := make(chan bool)
	buf := NewBuffer(&sess, conn, bufctrl)
	go buf.Start()

	// max # of operartions allowed before flushing
	flush_ops, err := strconv.Atoi(config["flush_ops"])
	if err != nil {
		log.Println("cannot parse flush_ops from config", err)
		flush_ops = DEFAULT_FLUSH_OPS
	}

	// cleanup work
	defer func() {
		close_work(&sess)
		close(bufctrl)
	}()

	// the main message loop
	for {
		select {
		case msg, ok := <-in:
			if !ok {
				return
			}

			if result := UserRequestProxy(&sess, msg); result != nil {
				err := buf.Send(result)
				if err != nil {
					return
				}
			}
			sess.LastPacketTime = time.Now().Unix()

		case msg, ok := <-sess.MQ: // async
			if !ok {
				return
			}

			if result := IPCRequestProxy(&sess, &msg); result != nil {
				err := buf.Send(result)
				if err != nil {
					return
				}
			}

		case <-std_timer:
			timer_work(&sess)
			if session_timeout(&sess) {
				return
			}
			timer.Add(1, time.Now().Unix()+1, std_timer)
		}

		// 持久化逻辑#1: 超过一定的操作数量,刷入数据库
		if sess.OpCount > flush_ops {
			_flush(&sess)
		}

		// 是否被逻辑踢出
		if sess.KickOut {
			return
		}
	}
}