예제 #1
0
 def log_error(self, message='message push fail'):
     self.rds.hincrby("fail_counter", self.app_key)
     log.error(message)
     type, value, tb = sys.exc_info()
     error_message = traceback.format_exception(type, value, tb)
     log.debug(type)
     log.error(error_message)
예제 #2
0
 def log_error(self, message='message push fail'):
     self.rds.hincrby("fail_counter", self.app_key)
     log.error(message)
     type, value, tb = sys.exc_info()
     error_message = traceback.format_exception(type, value, tb)
     log.debug(type)
     log.error(error_message)
예제 #3
0
    def _send_message(self, message):
        real_message = simplejson.loads(message['data'])
        badge = real_message.get('badge', None)
        sound = real_message.get('sound', None)
        alert = real_message.get('alert', None)
        custom = real_message.get('custom', {})

        if self.rds.sismember(
                '%s:%s' % (constants.INVALID_TOKENS, self.app_key),
                real_message['token']):
            # the token is invalid,do nothing
            return
        try:
            payload = Payload(sound=sound,
                              badge=badge,
                              alert=alert,
                              custom=custom)

        except PayloadTooLargeError:
            # 在内存保留100条缩短后消息,避免批量发送时,每条都要缩短的损耗
            if not alert:
                log.error('push meta data too long to trim, discard')
                payload = None
            if isinstance(alert, dict):
                log.error('payload too long to trim, discard')
                payload = None

            log.debug('try to trime large alert')
            payload = SafePayload(sound=sound,
                                  badge=badge,
                                  alert=alert,
                                  custom=custom)
            l_payload = len(payload.json())
            l_alert = len(alert.encode('unicode_escape'))
            l_allow = 256 - (l_payload - l_alert) - 3  # 允许提示长度

            ec_alert = alert.encode('unicode_escape')
            t_alert = re.sub(r'([^\\])\\(u|$)[0-9a-f]{0,3}$', r'\1',
                             ec_alert[:l_allow])
            alert = t_alert.decode('unicode_escape') + u'...'

            log.debug('payload is : %s' % alert)

            payload.alert = alert
            log.debug('how long dest it after trim %d' % len(payload.json()))
            payload = payload.as_payload()

        if not payload:
            return

        log.debug('will sent a meesage to token %s', real_message['token'])
        now = datetime.now()
        if (now - self.last_sent_time).seconds > 300:
            log.debug('idle for a long time , reconnect now.')
            self.reconnect()
        self.apns.gateway_server.send_notification(real_message['token'],
                                                   payload)
        self.last_sent_time = datetime.now()
        self.rds.hincrby("counter", self.app_key)
예제 #4
0
    def _send_message(self, message):
        real_message = simplejson.loads(message['data'])
        badge = real_message.get('badge', None)
        sound = real_message.get('sound', None)
        alert = real_message.get('alert', None)
        custom = real_message.get('custom', {})

        if self.rds.sismember('%s:%s' % (constants.INVALID_TOKENS,
                                             self.app_key),
                                  real_message['token']):
            # the token is invalid,do nothing
            return
        try:
            payload = Payload(sound=sound, badge=badge, alert=alert,
                              custom=custom)

        except PayloadTooLargeError:
            # 在内存保留100条缩短后消息,避免批量发送时,每条都要缩短的损耗
            if not alert:
                log.error('push meta data too long to trim, discard')
                payload = None
            if isinstance(alert, dict):
                log.error('payload too long to trim, discard')
                payload = None

            log.debug('try to trime large alert')
            payload = SafePayload(sound=sound, badge=badge, alert=alert,
                                  custom=custom)
            l_payload = len(payload.json())
            l_alert = len(alert.encode('unicode_escape'))
            l_allow = 256 - (l_payload - l_alert) - 3  # 允许提示长度

            ec_alert = alert.encode('unicode_escape')
            t_alert = re.sub(r'([^\\])\\(u|$)[0-9a-f]{0,3}$', r'\1',
                             ec_alert[:l_allow])
            alert = t_alert.decode('unicode_escape') + u'...'

            log.debug('payload is : %s' % alert)

            payload.alert = alert
            log.debug('how long dest it after trim %d' % len(payload.json()))
            payload = payload.as_payload()

        if not payload:
            return

        log.debug('will sent a meesage to token %s', real_message['token'])
        now = datetime.now()
        if (now - self.last_sent_time).seconds > 300:
            log.debug('idle for a long time , reconnect now.')
            self.reconnect()
        self.apns.gateway_server.send_notification(real_message['token'],
                                                   payload)
        self.last_sent_time = datetime.now()
        self.rds.hincrby("counter", self.app_key)
예제 #5
0
    def run(self):
        """
        - 监听redis队列,发送push消息
        - 从apns获取feedback service,处理无效token
        """
        log.debug('starting a thread')

        self.rds = redis.Redis(**self.server_info)
        if self.job == 'push':
            self.push()
        elif self.job == 'feedback':
            self.feedback()

        log.debug('leaving a thread')
예제 #6
0
    def run(self):
        """
        - 监听redis队列,发送push消息
        - 从apns获取feedback service,处理无效token
        """
        log.debug('starting a thread')

        self.rds = redis.Redis(**self.server_info)
        if self.job == 'push':
            self.push()
        elif self.job == 'feedback':
            self.feedback()

        log.debug('leaving a thread')
예제 #7
0
    def feedback(self):
        """
        从apns获取feedback,处理无效token
        """
        while(self.alive):
            try:
                self.reconnect()
                for (token, fail_time) in self.apns.feedback_server.items():
                    log.debug('push message fail to send to %s.' % token)
                    # send a empty msg to confirm the token is valid
                    self.client.push(token, enhance=True)
            except:
                self.log_error('get feedback fail')
            time.sleep(10)

        log.debug('i am leaving feedback')
예제 #8
0
 def handle_error(self, identifier, errorcode):
     """处理推送错误
     """
     log.debug('apns sent back an error: %s %d', identifier, errorcode)
     if errorcode == 8:
         # add token to invalid token set
         sent = self.rds.smembers('ENHANCE_SENT:%s' % self.app_key)
         for s in sent:
             data = simplejson.loads(s)
             if data['id'] != identifier:
                 continue
             token = data['token']
             self.rds.sadd(
                 '%s:%s' % (constants.INVALID_TOKENS, self.app_key), token)
     else:
         log.debug('not invalid token, ignore error')
예제 #9
0
    def feedback(self):
        """
        从apns获取feedback,处理无效token
        """
        while (self.alive):
            try:
                self.reconnect()
                for (token, fail_time) in self.apns.feedback_server.items():
                    log.debug('push message fail to send to %s.' % token)
                    # send a empty msg to confirm the token is valid
                    self.client.push(token, enhance=True)
            except:
                self.log_error('get feedback fail')
            time.sleep(10)

        log.debug('i am leaving feedback')
예제 #10
0
 def handle_error(self, identifier, errorcode):
     """处理推送错误
     """
     log.debug('apns sent back an error: %s %d', identifier, errorcode)
     if errorcode == 8:
         # add token to invalid token set
         sent = self.rds.smembers('ENHANCE_SENT:%s' % self.app_key)
         for s in sent:
             data = simplejson.loads(s)
             if data['id'] != identifier:
                 continue
             token = data['token']
             self.rds.sadd('%s:%s' % (constants.INVALID_TOKENS,
                                      self.app_key),
                           token)
     else:
         log.debug('not invalid token, ignore error')
예제 #11
0
 def send_message(self, message):
     """
     发送消息,如果发生异常失败,重新连接再试一次,再失败则丢失
     """
     log.debug('get a message from channel')
     log.debug(message)
     try:
         if message['type'] != 'message':
             return
         self._send_message(message)
     except SSLError:
         self.log_error()
         self.resend(message)
     except socket.error:
         self.log_error()
         self.resend(message)
     except:
         self.log_error()
예제 #12
0
 def send_message(self, message):
     """
     发送消息,如果发生异常失败,重新连接再试一次,再失败则丢失
     """
     log.debug('get a message from channel')
     log.debug(message)
     try:
         if message['type'] != 'message':
             return
         self._send_message(message)
     except SSLError:
         self.log_error()
         self.resend(message)
     except socket.error:
         self.log_error()
         self.resend(message)
     except:
         self.log_error()
예제 #13
0
    def consume_message(self, channel):
        # 再订阅消息队列
        try:
            pubsub = self.rds.pubsub()
            pubsub.subscribe('%s:%s' % (channel, self.app_key))
            log.debug('subscribe push job channel successfully')
            redis_channel = pubsub.listen()

            for message in redis_channel:
                self.retry_time = 0
                if 'kill' == message['data']:
                    break
                else:
                    self.send_message(message)
        except:
            # 连接redis不上, 睡眠几秒钟重试连接
            if self.retry_time <= self.retry_time_max:
                time.sleep(10)
                self.retry_time = self.retry_time + 1
                log.debug(u'redis cannot connect, retry %d' % self.retry_time)
                self.consume_message(channel)
            else:
                # 这时,需要Email通知管理员了
                log.error(u'retry time up, redis gone! help!')

        log.debug('i am leaving push')
예제 #14
0
    def consume_message(self, channel):
        # 再订阅消息队列
        try:
            pubsub = self.rds.pubsub()
            pubsub.subscribe('%s:%s' % (channel, self.app_key))
            log.debug('subscribe push job channel successfully')
            redis_channel = pubsub.listen()

            for message in redis_channel:
                self.retry_time = 0
                if 'kill' == message['data']:
                    break
                else:
                    self.send_message(message)
        except:
            # 连接redis不上, 睡眠几秒钟重试连接
            if self.retry_time <= self.retry_time_max:
                time.sleep(10)
                self.retry_time = self.retry_time + 1
                log.debug(u'redis cannot connect, retry %d' % self.retry_time)
                self.consume_message(channel)
            else:
                # 这时,需要Email通知管理员了
                log.error(u'retry time up, redis gone! help!')

        log.debug('i am leaving push')
예제 #15
0
 def push_fallback(self, fallback):
     log.debug('handle fallback messages')
     old_msg = self.rds.spop('%s:%s' % (fallback, self.app_key))
     while (old_msg):
         log.debug('handle message:%s' % old_msg)
         try:
             simplejson.loads(old_msg)
             self.send_message({'type': 'message', 'data': old_msg})
         except:
             log.debug('message is not a json object')
         finally:
             old_msg = self.rds.spop('%s:%s' % (fallback, self.app_key))
예제 #16
0
 def push_fallback(self, fallback):
     log.debug('handle fallback messages')
     old_msg = self.rds.spop('%s:%s' % (fallback, self.app_key))
     while(old_msg):
         log.debug('handle message:%s' % old_msg)
         try:
             simplejson.loads(old_msg)
             self.send_message({'type': 'message', 'data': old_msg})
         except:
             log.debug('message is not a json object')
         finally:
             old_msg = self.rds.spop('%s:%s' % (fallback, self.app_key))
예제 #17
0
 def resend(self, message):
     log.debug('resending')
     self.reconnect()
     self._send_message(message)
예제 #18
0
    def enhance_push(self):
        """
        使用增强版协议推送消息
        """
        self.host = 'localhost'
        index = self.rds.incr('ENHANCE_THREAD', 1)
        self.port = 9527 + index - 1
        self.rds.hset('ENHANCE_PORT',
                      ':'.join((self.app_key,
                                'dev' if self.develop else 'pro')),
                      self.port)

        srv_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        srv_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        srv_sock.bind((self.host, self.port))
        srv_sock.listen(5)
        srv_sock.setblocking(0)

        self.apns.gateway_server._connect()
        cli_sock = self.apns.gateway_server._ssl

        rlist = [srv_sock, cli_sock]
        wlist = []
        xlist = []

        while self.alive:
            rl, wl, xl = select.select(rlist, wlist, xlist, 10)
            if rl:
                for r in rl:
                    if r == srv_sock:
                        # connection from client!
                        try:
                            new_sock, addr = srv_sock.accept()
                            rlist.append(new_sock)
                            continue
                        except socket.error:
                            pass
                    elif r == cli_sock:
                        # message from apns, some error eccour!
                        error = self.apns.gateway_server.get_error()
                        if not error:
                            log.debug('apns drop the connection, reconnect!')
                            rlist.remove(r)
                            self.apns.gateway_server._disconnect()
                            self.apns._gateway_connection = None
                            continue
                        else:
                            self.handle_error(error[0], error[1])
                    else:
                        # message from client
                        buf = ''
                        try:
                            buf = r.recv(4096)
                        except socket.error:
                            rlist.remove(r)
                            r.close()
                            continue

                        if not buf:
                            # client close the socket.
                            rlist.remove(r)
                            r.close()
                            continue

                        try:
                            # 如果还没有连接,或闲置时间过长
                            now = datetime.now()
                            if not self.apns._gateway_connection:
                                log.debug('无连接,重连')
                                self.apns.gateway_server._connect()
                                cli_sock = self.apns.gateway_server._ssl
                                rlist.append(cli_sock)
                            elif (now - self.last_sent_time).seconds > 300:
                                log.debug('闲置时间过长,重连')
                                self.apns.gateway_server._disconnect()
                                self.apns._gateway_connection = None
                                rlist.remove(cli_sock)
                                self.apns.gateway_server._connect()
                                cli_sock = self.apns.gateway_server._ssl
                                rlist.append(cli_sock)
                            log.debug('推送消息%s' % buf)
                            self.send_enhance_message(buf)
                            self.last_sent_time = now
                        except socket.error:
                            log.debug('send notification fail, reconnect')
예제 #19
0
    def enhance_push(self):
        """
        使用增强版协议推送消息
        """
        self.host = 'localhost'
        index = self.rds.incr('ENHANCE_THREAD', 1)
        self.port = 9527 + index - 1
        self.rds.hset(
            'ENHANCE_PORT', ':'.join(
                (self.app_key, 'dev' if self.develop else 'pro')), self.port)

        srv_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        srv_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        srv_sock.bind((self.host, self.port))
        srv_sock.listen(5)
        srv_sock.setblocking(0)

        self.apns.gateway_server._connect()
        cli_sock = self.apns.gateway_server._ssl

        rlist = [srv_sock, cli_sock]
        wlist = []
        xlist = []

        while self.alive:
            rl, wl, xl = select.select(rlist, wlist, xlist, 10)
            if rl:
                for r in rl:
                    if r == srv_sock:
                        # connection from client!
                        try:
                            new_sock, addr = srv_sock.accept()
                            rlist.append(new_sock)
                            continue
                        except socket.error:
                            pass
                    elif r == cli_sock:
                        # message from apns, some error eccour!
                        error = self.apns.gateway_server.get_error()
                        if not error:
                            log.debug('apns drop the connection, reconnect!')
                            rlist.remove(r)
                            self.apns.gateway_server._disconnect()
                            self.apns._gateway_connection = None
                            continue
                        else:
                            self.handle_error(error[0], error[1])
                    else:
                        # message from client
                        buf = ''
                        try:
                            buf = r.recv(4096)
                        except socket.error:
                            rlist.remove(r)
                            r.close()
                            continue

                        if not buf:
                            # client close the socket.
                            rlist.remove(r)
                            r.close()
                            continue

                        try:
                            # 如果还没有连接,或闲置时间过长
                            now = datetime.now()
                            if not self.apns._gateway_connection:
                                log.debug('无连接,重连')
                                self.apns.gateway_server._connect()
                                cli_sock = self.apns.gateway_server._ssl
                                rlist.append(cli_sock)
                            elif (now - self.last_sent_time).seconds > 300:
                                log.debug('闲置时间过长,重连')
                                self.apns.gateway_server._disconnect()
                                self.apns._gateway_connection = None
                                rlist.remove(cli_sock)
                                self.apns.gateway_server._connect()
                                cli_sock = self.apns.gateway_server._ssl
                                rlist.append(cli_sock)
                            log.debug('推送消息%s' % buf)
                            self.send_enhance_message(buf)
                            self.last_sent_time = now
                        except socket.error:
                            log.debug('send notification fail, reconnect')
예제 #20
0
 def resend(self, message):
     log.debug('resending')
     self.reconnect()
     self._send_message(message)