示例#1
0
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