func (c *client) waitOnline(msg *define.Msg) (err error) { // Push the online msg glog.Info("Get a online msg") // Check the msg time if msg.Expired > 0 { if time.Now().UTC().Unix() > msg.Expired { // cancel send the msg glog.Info("Out of time") return } } // Add the msg into cache if msg == nil { err = errors.New("onlines has been close") return } if len(c.onlineCache) > Conf.MaxCacheMsg && Conf.MaxCacheMsg != 0 { err = fmt.Errorf("Online msg is out of range:%v", len(c.onlineCache)) return } mid := c.getOnlineMsgId() if mid == -1 { return } msg.Msg_id = mid msg.Typ = define.ONLINE c.onlineCache[msg.Msg_id] = msg err = c.pushMsg(msg) c.counter++ return }
func (c *Comet_RPC) WriteMsg(msg *define.Msg, r *myrpc.Reply) (err error) { msg.Dup = 0 // Fix the Expired if msg.Expired > 0 { msg.Expired = time.Now().UTC().Add(time.Duration(msg.Expired)).Unix() } // Check the user whether online. b, addr, err := redis.IsExist(msg.To_id) if !b { if err != nil { glog.Error(err) } // User is offline. err = store.Manager.InsertOfflineMsg(msg, Conf.RPC_addr, Conf.Etcd_addr) if err != nil { glog.Error(err) } else { // nil error. r.IsOk = true } return err } // User is online. if addr == Conf.RPC_addr { // Call local comet. return c.WriteOnlineMsg(msg, r) } else { // RPC. c, err := rpc.DialHTTP("tcp", addr) if err != nil { return err } reply := new(myrpc.Reply) if err = c.Call("Comet_RPC.WriteOnlineMsg", msg, reply); err != nil { return err } r.IsRe = reply.IsRe r.IsOk = reply.IsOk return nil } }
func (*Comet_RPC) WriteOnlineMsg(msg *define.Msg, r *myrpc.Reply) (err error) { defer func() { if err == nil { r.IsOk = true } else { glog.Error(err) } }() glog.Info("Get a Write Online msg RPC") c := Users.Get(msg.To_id) if c == nil { msg.Typ = define.OFFLINE // Get the offline msg id err = store.Manager.InsertOfflineMsg(msg, Conf.RPC_addr, Conf.Etcd_addr) return } c.lock.Lock() if len(c.onlines) == Conf.MaxCacheMsg { c.lock.Unlock() msg.Typ = define.OFFLINE err = store.Manager.InsertOfflineMsg(msg, Conf.RPC_addr, Conf.Etcd_addr) return } else { c.lock.Unlock() } c.lock.Lock() if c.isStop { c.lock.Unlock() msg.Typ = define.OFFLINE err = store.Manager.InsertOfflineMsg(msg, Conf.RPC_addr, Conf.Etcd_addr) } else { msg.Typ = define.ONLINE c.onlines <- msg c.lock.Unlock() } return }
func (c *client) waitOffline(msg *define.Msg) (err error) { // Check the msg time if msg.Expired > 0 { if time.Now().UTC().Unix() > msg.Expired { // cancel send the msg glog.Info("Out of time.") // TODO Del the offline msg store.Manager.DelOfflineMsg(msg.Id) return } } msg.Msg_id = c.getOnlineMsgId() if msg.Msg_id == -1 { return } c.offline_map[msg.Msg_id] = msg.Id // Push the offline msg glog.Info("Get a offline msg") // Set the msg id err = c.pushOfflineMsg(msg) c.counter++ return }
func writeOfflineMsg(msg *define.Msg) error { msg.Typ = define.OFFLINE return store.Manager.InsertOfflineMsg(msg, Conf.Listen_addr, Conf.Etcd_addr) }
// Push the msg and response the heart beat func (c *client) listen_loop() (e error) { defer func() { err := redis.Logout(c.id, Conf.RPC_addr) if err != nil { err = redis.Logout(c.id, Conf.RPC_addr) if err != nil { glog.Errorf("Redis conn error:%v", err) } Users.Del(c.id) if c.isSendClose { c.closeChan <- 0 } } }() var ( err error msg *define.Msg pAndErr *packAndErr noticeFin = make(chan byte, 2) // wg = new(sync.WaitGroup) findEndChan <-chan byte ) // Start the write queue go c.queue.writeLoop() c.offlines, findEndChan = store.Manager.GetOfflineMsg(c.id, noticeFin) c.readChan = c.queue.ReadPackInLoop(noticeFin) // Start push loop: for { if c.counter < math.MaxUint16 { select { case <-findEndChan: if err = c.offlineEnd(); err != nil { glog.Error(err) break loop } case msg := <-c.offlines: if err = c.waitOffline(msg); err != nil { glog.Error(err) break loop } case msg = <-c.onlines: if err = c.waitOnline(msg); err != nil { glog.Error(err) break loop } case pAndErr = <-c.readChan: if err = c.waitPack(pAndErr); err != nil { glog.Error("Get a connection error , will break(%v)", err) break loop } case <-c.closeChan: c.waitQuit() break loop } } else { select { case <-findEndChan: if err = c.offlineEnd(); err != nil { glog.Error(err) break loop } case pAndErr = <-c.readChan: if err = c.waitPack(pAndErr); err != nil { glog.Error(err) break loop } case <-c.closeChan: c.waitQuit() break loop } } } c.lock.Lock() c.isStop = true c.lock.Unlock() // Wrte the onlines msg to the db // Free resources // Close channels for i := 0; i < 2; i++ { noticeFin <- 1 } close(noticeFin) // Write the onlines msg to the db for _, v := range c.onlineCache { // Add the offline msg id v.Typ = define.OFFLINE store.Manager.InsertOfflineMsg(v, Conf.RPC_addr, Conf.Etcd_addr) } // Flush the channel. for len(c.onlines) > 0 { msg := <-c.onlines msg.Typ = define.OFFLINE store.Manager.InsertOfflineMsg(msg, Conf.RPC_addr, Conf.Etcd_addr) } glog.Info("Cleaned the online msgs channel.") // Close the online msg channel close(c.onlines) close(c.closeChan) glog.Info("Groutine will esc.") return }