class _APNConn(object): def __init__(self, prev_buffers, cert_file, svr_tuple, encode_func): """ :param cert_file: 证书文件路径 :param prev_buffers: 之前残留的推送链表 按照苹果的尿性推送协议 谁也不知道到底有没有成功 F**K JOBS! """ self.__io_loop = IOLoop.instance() self.__cert = path.join(CERT_ROOT, cert_file) self.__svr_addr = svr_tuple self.__encode_func = encode_func self.__stream = None self.__connected = False #list自身的索引作为 self.sending_buffer = [] if prev_buffers and isinstance(prev_buffers, (list, tuple)): self.sending_buffer.extend(prev_buffers) self.__recv_buf = '' self.__connection_close_ts = None #从read读到的错误消息id,便于 self.__recv_err_msgid = None self.critical = False def force_close(self): self.__connected = False self.__stream.close_fd() self.__stream = None self.critical = True def connect(self): self.__stream = SSLIOStream( socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0), io_loop=self.__io_loop, ssl_options={ 'ssl_version': ssl.PROTOCOL_TLSv1, # 'ca_certs': path.join(CERT_ROOT, 'entrust_root_ca.pem'), 'certfile': self.__cert, # 'cert_reqs': ssl.CERT_REQUIRED }) self.__stream.set_close_callback(self._on_close) self.__stream.connect(self.__svr_addr, self.__on_connect) def __on_connect(self): self.__connected = True self.__stream.set_nodelay(True) self.__stream.read_until_close(self._last_closd_recv, self._on_recv) self.__send_batch() def __do_check(self, sent_len): if self.__recv_err_msgid: logger.debug('CHECK: %r' % self.__recv_err_msgid) if self.__recv_err_msgid is None: self.sending_buffer = self.sending_buffer[sent_len:] self.__send_batch() return self.sending_buffer = self.sending_buffer[self.__recv_err_msgid:] self.__recv_err_msgid = None self.__stream.close_fd() self.__stream = None self.critical = True def __send_batch(self): """ 连接断开后就停了 """ if not self.__connected: return if not self.__stream: return l = self.sending_buffer[:QUEUE_CAPACITY] for i, b in enumerate(l): self.__stream.write(self.__encode_func(i, *b)) logger.debug('>> %d - %s' % (i, b)) self.__io_loop.add_timeout(timedelta(seconds=CHECK_TIMESPAN), partial(self.__do_check, len(l))) def append(self, device_token, payload): """ :param device_token: app从apns服务器获取的64字节串 :param payload: 报文dict """ self.sending_buffer.append((device_token, payload)) def _last_closd_recv(self, buf): """ socket关闭时最后几个字节 """ if not buf: return self._on_recv(buf) def _on_recv(self, buf): logger.debug('<< %r' % buf) self.__recv_buf = self.__recv_buf + buf _ = err_resp(self.__recv_buf) if _ is None: return self.__recv_buf = '' errno, self.__recv_err_msgid = _ logger.fatal('apns err: %d - %d - %s' % (self.__recv_err_msgid, errno, resp_errno.get(errno))) def _on_close(self): self.critical = True logger.warn('closed') self.__connected = False self.__stream = None