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) } } }
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() }