//------------------------------------------------ 登陆后的数据加载 func LoginProc(sess *Session) bool { if sess.User == nil { return false } // 载入建筑表 if !data_tbl.Get(estates.COLLECTION, sess.User.Id, &sess.Estates) { // 创建默认的建筑表 e := &estates.Manager{} e.UserId = sess.User.Id sess.Estates = e } else { // 创建Grid sess.Grid = CreateGrid(sess.Estates) } if !data_tbl.Get(samples.COLLECTION, sess.User.Id, &sess.LatencySamples) { s := &samples.Samples{} s.UserId = sess.User.Id s.Init() sess.LatencySamples = s } // if sess.User.CountryCode == "" { sess.User.CountryCode = geoip.Query(sess.IP) } if sess.User.CreatedAt == 0 { sess.User.CreatedAt = time.Now().Unix() } // 开始计算Flush时间 sess.LastFlushTime = time.Now().Unix() // 注册为在线 gsdb.RegisterOnline(sess, sess.User.Id) // 最后, 载入离线消息,并push到MQ, 这里小心MQ的buffer长度, // 不能直接调用,有可能消息超过MQ被永远阻塞 go LoadIPCObjects(sess.User.Id, sess.MQ) // 标记在线 //sess.LoggedIn = true return true }
//------------------------------------------------ 登陆后的数据加载 func LoginProc(sess *Session) bool { if sess.User == nil { return false } // TODO: init data structure for session, such as builds // set countrycode if sess.User.CountryCode == "" { sess.User.CountryCode = geoip.Query(sess.IP) } // register as online gsdb.RegisterOnline(sess, sess.User.Id) // load messages go LoadIPCObjects(sess.User.Id, sess.MQ) return true }
//----------------------------------------------- cleanup work after disconnection func close_work(sess *Session) { defer PrintPanicStack() if sess.Flag&SESS_LOGGED_IN == 0 { return } // must flush user data _flush(sess) // notify hub hub_client.Logout(sess.User.Id) // unregister online at this server gsdb.UnregisterOnline(sess.User.Id) // close MQ, and save the queue to db close(sess.MQ) for ipcobject := range sess.MQ { forward_tbl.Push(&ipcobject) NOTICE("re-pushed ipcobject back to db, userid:", sess.User.Id) } NOTICE(sess.User.Name, "disconnected from", sess.IP, "country:", geoip.Query(sess.IP)) }
//----------------------------------------------- start a goroutine when a new connection is accepted func handleClient(conn *net.TCPConn) { defer func() { if x := recover(); x != nil { ERR("caught panic in handleClient", x) } }() // input buffer config := cfg.Get() inqueue_size, err := strconv.Atoi(config["inqueue_size"]) if err != nil { inqueue_size = DEFAULT_INQUEUE_SIZE WARN("cannot parse inqueue_size from config", err, "using default:", inqueue_size) } // init header := make([]byte, 2) in := make(chan []byte, inqueue_size) bufctrl := make(chan bool) defer func() { close(bufctrl) close(in) }() // create new session var sess Session sess.IP = net.ParseIP(strings.Split(conn.RemoteAddr().String(), ":")[0]) NOTICE("new connection from:", sess.IP, "country:", geoip.Query(sess.IP)) // create write buffer out := NewBuffer(&sess, conn, bufctrl) go out.Start() // start agent!! wg.Add(1) go StartAgent(&sess, in, out) for { // header conn.SetReadDeadline(time.Now().Add(TCP_TIMEOUT * time.Second)) n, err := io.ReadFull(conn, header) if err != nil { WARN("error receiving header, bytes:", n, "reason:", err) break } // data size := binary.BigEndian.Uint16(header) data := make([]byte, size) n, err = io.ReadFull(conn, data) if err != nil { WARN("error receiving msg, bytes:", n, "reason:", err) break } // NOTICE: slice is passed by reference; don't re-use a single buffer. select { case in <- data: case <-time.After(MAX_DELAY_IN * time.Second): WARN("server busy or agent closed, session flag:", sess.Flag) return } } }