Example #1
0
func (self *apnsPushService) pushListProcess(pool *connpool.Pool) {
	for push := range self.pushRet {
		if push.action == 1 {
			// add send finish mid
			p, ok := self.pushList[push.connId]
			if ok {
				self.pushList[push.connId].list = append(p.list, push.msgId)
				self.pushList[push.connId].timestamp = time.Now()
			} else {
				pushinfo := new(pushInfo)
				pushinfo.list = make([]uint32, 0)
				pushinfo.list = append(pushinfo.list, push.msgId)
				pushinfo.timestamp = time.Now()
				self.pushList[push.connId] = pushinfo
			}
		} else if push.action == 8 {
			// process mistack mid
			req, reqOk := self.midReqMap[push.msgId]
			if reqOk {
				req.fialPush++
			} else {
				self.logChan <- NewInfof("act:8 find req fail, mid:%v cid:%v", push.msgId, push.connId)
			}

			pool.SetUnable(push.connId)
			_, ok := self.pushList[push.connId]
			if ok {
				flag := 0
				for _, mid := range self.pushList[push.connId].list {
					self.cleanMap(self.midReqMap, self.midTokenMap, mid)
					flag++
					if mid == push.msgId {
						break
					}
				}
				self.logChan <- NewInfof("receive unavailable token, mid:%v cid:%v, mid size:%v flag:%v", push.msgId, push.connId, len(self.pushList[push.connId].list), flag)

				self.pushList[push.connId].list = self.pushList[push.connId].list[flag:]
			} else {
				self.logChan <- NewInfof("pushList find cid err cid:%v mid:%v", push.connId, push.msgId)
			}
		} else if push.action == 0 {
			// process disconn conn
			_, ok := self.pushList[push.connId]
			if ok {
				if pool.IsUnable(push.connId) {
					if len(self.pushList[push.connId].list) > 0 {
						reSendToken := make([]*midTokenReq, 0)

						self.logChan <- NewInfof("resend size:%v cid:%v", len(self.pushList[push.connId].list), push.connId)
						for _, mid := range self.pushList[push.connId].list {
							token, tOk := self.midTokenMap[mid]
							if tOk {
								//self.logChan <- NewInfof("resend token:%v cid:%v ", hex.EncodeToString(token), push.connId)
								req, reqOk := self.midReqMap[mid]
								if reqOk {
									midtr := new(midTokenReq)
									midtr.mid = mid
									midtr.req = req
									midtr.token = token
									reSendToken = append(reSendToken, midtr)
									//go self.singlePush(req.payload, token, req.expiry, mid, pool)
								} else {
									self.logChan <- NewInfof("act:0 find req fail, mid:%v cid:%v", mid, push.connId)
								}
							} else {
								self.logChan <- NewInfof("find token err mid:%v cid:%v", mid, push.connId)
							}
						}

						go self.resendPush(reSendToken, pool)
					}
				} else {
					for _, mid := range self.pushList[push.connId].list {
						self.logChan <- NewInfof("abnormal conn, cid:%v mid:%v", push.connId, mid)
						self.cleanMap(self.midReqMap, self.midTokenMap, mid)
					}
					pool.SetUnable(push.connId)
				}
				delete(self.pushList, push.connId)
			} else {
				pool.SetUnable(push.connId)
				self.logChan <- NewInfof("find conn cid err, cid:%v mid:%v ", push.connId, push.msgId)
			}
		} else if push.action == 2 {
			//	tick process pushList
			if pool.IsConn() == 0 {
				isTimeout := true
				for _, push := range self.pushList {
					if time.Now().Sub(push.timestamp) < time.Duration(self.apnstimeout)*time.Second {
						isTimeout = false
						break
					}
				}

				if isTimeout {
					for connId, push := range self.pushList {
						self.logChan <- NewInfof("conn free, conn size:%v cid:%v cid size:%v", len(self.pushList), connId, len(push.list))
						for _, mid := range push.list {
							self.cleanMap(self.midReqMap, self.midTokenMap, mid)
						}
						delete(self.pushList, connId)
					}
				}
			}
		} else if push.action == 3 {
			//	delete msg id
			req, reqOk := self.midReqMap[push.msgId]
			if reqOk {
				req.fialPush++
			} else {
				self.logChan <- NewInfof("act:3 find req fail, mid:%v cid:%v", push.msgId, push.connId)
			}
			self.logChan <- NewInfof("mid:%v send fail cid:%v", push.msgId, push.connId)

			self.cleanMap(self.midReqMap, self.midTokenMap, push.msgId)
		}
	}
}
Example #2
0
func (self *apnsPushService) singlePush(payload, token []byte, expiry uint32, mid uint32, pool *connpool.Pool) {
	conn, err := pool.Get()
	if err != nil {
		for i := 0; i < 3; i++ {
			conn, err = pool.Get()
			if err != nil {
				self.logChan <- NewInfof("singlePush pool get err:%v token:%v", err, hex.EncodeToString(token))
				continue
			}
			break
		}
		if err != nil {
			clearRequest(self.pushRet, 3, mid, 0)
			self.logChan <- NewInfof("Alas helpless... err:%v token:%v", err, hex.EncodeToString(token))
			return
		}
	}

	// Total size for each notification:
	//
	// - command: 1
	// - identifier: 4
	// - expiry: 4
	// - device token length: 2
	// - device token: 32 (vary)
	// - payload length: 2
	// - payload: vary (256 max)
	//
	// In total, 301 bytes (max)
	var dataBuffer [2048]byte

	buffer := bytes.NewBuffer(dataBuffer[:0])
	// command
	binary.Write(buffer, binary.BigEndian, uint8(1))
	// transaction id
	binary.Write(buffer, binary.BigEndian, mid)

	// Expiry
	binary.Write(buffer, binary.BigEndian, expiry)

	// device token
	binary.Write(buffer, binary.BigEndian, uint16(len(token)))
	buffer.Write(token)

	// payload
	binary.Write(buffer, binary.BigEndian, uint16(len(payload)))
	buffer.Write(payload)

	pdu := buffer.Bytes()

	deadline := time.Now().Add(time.Duration(maxWaitTime) * time.Second)
	conn.SetWriteDeadline(deadline)

	err = writen(conn, pdu)

	//self.logChan <- NewInfof("writen token::%v err:%v LocalAddr:%v cid:%v mid:%v pdu:%v", hex.EncodeToString(token), err, conn.LocalAddr(), conn.Id(), mid, len(pdu))
	//fmt.Println("writen token:", hex.EncodeToString(token), " err:", err, " LocalAddr:", conn.LocalAddr(), " cid", conn.Id(), " mid:", mid)

	sleepTime := time.Duration(maxWaitTime) * time.Second
	for nrRetries := 0; err != nil && nrRetries < 3; nrRetries++ {
		self.logChan <- NewInfof("error on connection with %v. Will retry within %v   %v", err, sleepTime, hex.EncodeToString(token))

		conn.Close()
		time.Sleep(sleepTime)
		// randomly wait more time
		sleepTime += time.Duration(rand.Int63n(int64(sleepTime)))
		// Let's try another connection to see if we can recover this error
		conn, err = pool.Get()

		if err != nil {
			self.logChan <- NewInfof("We are unable to get a connection: %v", err)
			if conn != nil {
				conn.Close()
			}
			return
		}
		deadline := time.Now().Add(sleepTime)
		conn.SetWriteDeadline(deadline)
		err = writen(conn, pdu)
	}

	if err != nil {
		clearRequest(self.pushRet, 3, mid, 0)
		self.logChan <- NewInfof("token send fail: %v  err:%v LocalAddr:%v", hex.EncodeToString(token), err, conn.LocalAddr())
	} else {
		clearRequest(self.pushRet, 1, mid, conn.Id())
	}

	conn.SetWriteDeadline(time.Time{})
	conn.Close()
}