guanhailong il y a 2 ans
Parent
commit
61875d7537

+ 8 - 0
AnsjerPush/cn_config/cn_formal_config.py

@@ -172,4 +172,12 @@ APNS_CONFIG = {
 
 XMPUSH_CONFIG = {
     'com.ansjer.zccloud_ab': 'fXAdAwGDum3FKgQtAiW9hg=='
+}
+
+VIVOPUSH_CONFIG = {
+    'com.ansjer.zccloud_ab':{
+        'ID':'102227506',
+        'Key':'531bf5befece8840d31b654a166db91c',
+        'Secret':'9d6f19ef-5cdb-47ee-9433-d74c7d11fa50'
+    }
 }

+ 8 - 0
AnsjerPush/dev_config/local_config.py

@@ -155,5 +155,13 @@ XMPUSH_CONFIG = {
     'com.ansjer.zccloud_ab': 'fXAdAwGDum3FKgQtAiW9hg=='
 }
 
+VIVOPUSH_CONFIG = {
+    'com.ansjer.zccloud_ab':{
+        'ID':'102227506',
+        'Key':'531bf5befece8840d31b654a166db91c',
+        'Secret':'9d6f19ef-5cdb-47ee-9433-d74c7d11fa50'
+    }
+}
+
 APNS_MODE = 'dev'
 REDIS_ADDRESS = '127.0.0.1'

+ 8 - 0
AnsjerPush/eur_config/eur_formal_config.py

@@ -172,4 +172,12 @@ APNS_CONFIG = {
 
 XMPUSH_CONFIG = {
     'com.ansjer.zccloud_ab': 'fXAdAwGDum3FKgQtAiW9hg=='
+}
+
+VIVOPUSH_CONFIG = {
+    'com.ansjer.zccloud_ab':{
+        'ID':'102227506',
+        'Key':'531bf5befece8840d31b654a166db91c',
+        'Secret':'9d6f19ef-5cdb-47ee-9433-d74c7d11fa50'
+    }
 }

+ 8 - 0
AnsjerPush/test_config/test_config.py

@@ -149,4 +149,12 @@ APNS_CONFIG = {
 
 XMPUSH_CONFIG = {
     'com.ansjer.zccloud_ab': 'fXAdAwGDum3FKgQtAiW9hg=='
+}
+
+VIVOPUSH_CONFIG = {
+    'com.ansjer.zccloud_ab':{
+        'ID':'102227506',
+        'Key':'531bf5befece8840d31b654a166db91c',
+        'Secret':'9d6f19ef-5cdb-47ee-9433-d74c7d11fa50'
+    }
 }

+ 8 - 0
AnsjerPush/us_config/formal_config.py

@@ -172,4 +172,12 @@ APNS_CONFIG = {
 
 XMPUSH_CONFIG = {
     'com.ansjer.zccloud_ab': 'fXAdAwGDum3FKgQtAiW9hg=='
+}
+
+VIVOPUSH_CONFIG = {
+    'com.ansjer.zccloud_ab':{
+        'ID':'102227506',
+        'Key':'531bf5befece8840d31b654a166db91c',
+        'Secret':'9d6f19ef-5cdb-47ee-9433-d74c7d11fa50'
+    }
 }

+ 2 - 0
Controller/AiController.py

@@ -185,6 +185,8 @@ class AiView(View):
                         PushObject.android_jpush(**kwargs)
                     elif push_type == 4:  # android 小米推送
                         PushObject.android_xmpush(**kwargs)
+                    elif push_type == 5:  # android vivo推送
+                        PushObject.android_vivopush(**kwargs)
                 except Exception as e:
                     LOGGING.info('ai推送消息异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
                     continue

+ 3 - 0
Controller/ComboCron/ComboCronPushController.py

@@ -232,6 +232,9 @@ class ComboCronPushView(View):
             # android 小米推送
             elif push_type == 4:
                 PushObject.android_xmpush(**kwargs)
+            # android vivo推送
+            elif push_type == 5:
+                PushObject.android_vivopush(**kwargs)
             return True
         except Exception as e:
             logger.info('流量预警推送异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))

+ 2 - 0
Controller/PowerWarningController.py

@@ -93,6 +93,8 @@ class PowerWarningView(View):
                         PushObject.android_jpush(**kwargs)
                     elif push_type == 4:  # android 小米推送
                         PushObject.android_xmpush(**kwargs)
+                    elif push_type == 5:  # android vivo推送
+                        PushObject.android_vivopush(**kwargs)
                 except Exception as e:
                     logger.info('低电量推送消息异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
                     continue

+ 4 - 0
Controller/gatewayController.py

@@ -175,6 +175,8 @@ class GatewayView(View):
                             PushObject.android_jpush(**kwargs)
                         elif push_type == 4:  # android 小米推送
                             PushObject.android_xmpush(**kwargs)
+                        elif push_type == 5:  # android vivo推送
+                            PushObject.android_vivopush(**kwargs)
                     except Exception as e:
                         logger.info('网关推送消息异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
                         continue
@@ -262,6 +264,8 @@ class GatewayView(View):
                                 PushObject.android_jpush(**kwargs)
                             elif push_type == 4:  # android 小米推送
                                 PushObject.android_xmpush(**kwargs)
+                            elif push_type == 5:  # android vivo推送
+                                PushObject.android_vivopush(**kwargs)
                         except Exception as e:
                             logger.info('场景日志推送消息异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
                             continue

+ 11 - 2
Service/DevicePushService.py

@@ -160,13 +160,14 @@ class DevicePushService:
         """
         try:
             kwag_args = param['kwag_args']
-            result = {'do_apns_code': '', 'do_fcm_code': '', 'do_jpush_code': '', 'do_xmpush_code': ''}
+            result = {'do_apns_code': '', 'do_fcm_code': '', 'do_jpush_code': '', 'do_xmpush_code': '',
+                      'do_vivopush_code': ''}
             # 判断是否进行APP消息推送,如app_push不为空,则不进行推送
             if not param['app_push']:
                 LOGGING.info('APP准备推送:{}, {}'.format(param['uid'], param))
                 # 推送显示图片
                 if (param['is_st'] == 1 or param['is_st'] == 3) and \
-                        (push_type == 0 or push_type == 1 or push_type == 3 or push_type == 4):
+                        (push_type == 0 or push_type == 1 or push_type == 3 or push_type == 4 or push_type == 5):
                     if param['is_st'] == 1:
                         key = '{}/{}/{}.jpeg'.format(param['uid'], param['channel'], param['n_time'])
                     else:
@@ -185,6 +186,9 @@ class DevicePushService:
                         result['do_jpush_code'] = cls.do_jpush(**kwag_args)
                     elif push_type == 4:  # android xmpush
                         result['do_xmpush_code'] = cls.do_xmpush(**kwag_args)
+                    elif push_type == 5:
+                        kwag_args['app_bundle_id'] = kwag_args.pop('appBundleId')
+                        result['do_vivopush_code'] = PushObject.android_vivopush(**kwag_args)
             return result
         except Exception as e:
             LOGGING.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
@@ -411,6 +415,9 @@ class DevicePushService:
             elif push_type == 4:
                 PushObject.android_xmpush(uid, appBundleId, token_val, n_time, event_type, msg_title,
                                           msg_text, uid, channel, image_url)
+            elif push_type == 5:
+                PushObject.android_vivopush(uid, appBundleId, token_val, n_time, event_type, msg_title,
+                                            msg_text, uid, channel, image_url)
         except Exception as e:
             LOGGING.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
 
@@ -432,6 +439,8 @@ class DevicePushService:
                     up['do_jpush_code'] = params['code_dict']['code_date']['do_jpush_code']
                 elif up['push_type'] == 4:  # android jpush
                     up['do_xmpush_code'] = params['code_dict']['code_date']['do_xmpush_code']
+                elif up['push_type'] == 5:  # android jpush
+                    up['do_vivopush_code'] = params['code_dict']['code_date']['do_xmpush_code']
                 del up['push_type']
                 del up['userID_id']
                 del up['userID__NickName']

+ 71 - 1
Service/PushService.py

@@ -13,8 +13,12 @@ import jpush
 import requests
 from pyfcm import FCMNotification
 
-from AnsjerPush.config import APP_BUNDLE_DICT, APNS_MODE, BASE_DIR, APNS_CONFIG, FCM_CONFIG, JPUSH_CONFIG, XMPUSH_CONFIG
+from AnsjerPush.config import APP_BUNDLE_DICT, APNS_MODE, BASE_DIR, APNS_CONFIG, FCM_CONFIG, JPUSH_CONFIG, XMPUSH_CONFIG\
+    , VIVOPUSH_CONFIG
+from Object.RedisObject import RedisObject
 from Service.CommonService import CommonService
+from Service.VivoPushService.push_admin.APIMessage import PushMessage
+from Service.VivoPushService.push_admin.APISender import APISender
 
 
 class PushObject:
@@ -243,3 +247,69 @@ class PushObject:
             assert response.status_code == 200
         except Exception as e:
             return repr(e)
+
+    @staticmethod
+    def android_vivopush(app_bundle_id, token_val, n_time, event_type, msg_title, msg_text,
+                         uid='', channel='1', image='', skip_type='1', nickname=''):
+        """
+        vivo 推送
+        @param app_bundle_id: app包id
+        @param token_val: 推送token
+        @param event_type: 消息类型 (0:运营类消息,1:系统类消息。默认为 0)
+        @param msg_title: 推送标题
+        @param msg_text: 推送内容
+        @param push_mode: 推送模式 (0:正式推送;1:测试推送,默认为0)
+        @param m_code: 用户请求唯一标识 最大 64 字符
+        @param skip_type: 跳转类型(1:打开 APP 首页 2:打开链接 3:自定义 4:打开 app 内指定页面)
+        @param n_time: 当前时间
+        @param nickname: 设备昵称
+        @param uid: uid
+        @param image: 推送图片链接
+        @param channel: 通道
+        @return: None
+        """
+        logger = logging.getLogger('info')
+        try:
+            authToken = 'authToken_' + app_bundle_id
+            redisObj = RedisObject()
+            # 获取redis里面的authToken
+            redis_authToken = redisObj.get_data(key=authToken)
+            if redis_authToken is not False:
+                app_secret = VIVOPUSH_CONFIG[app_bundle_id]['Secret']
+                sender_send = APISender(app_secret)
+                sender_send.set_token(redis_authToken)
+            else:
+                skip_type = int(skip_type)
+                app_id = VIVOPUSH_CONFIG[app_bundle_id]['ID']
+                app_key = VIVOPUSH_CONFIG[app_bundle_id]['Key']
+                app_secret = VIVOPUSH_CONFIG[app_bundle_id]['Secret']
+                sender = APISender(app_secret)
+                rec = sender.get_token(app_id, app_key)
+                # 存放authToken,有效期3个小时
+                redisObj = RedisObject()
+                redisObj.set_data(key=authToken, val=rec['authToken'], expire=10800)
+                sender_send = APISender(app_secret)
+                sender_send.set_token(rec['authToken'])
+            push_data = {'alert': 'Motion', 'msg': '', 'sound': 'sound.aif', 'zpush': '1', 'image': image,
+                         'received_at': n_time, 'event_time': n_time, 'event_type': event_type, 'nickname': nickname,
+                         'uid': uid, 'channel': channel
+                         }
+            # 推送
+            message = PushMessage() \
+                .reg_id(token_val) \
+                .title(msg_title) \
+                .content(msg_text) \
+                .push_mode(1) \
+                .notify_type(1) \
+                .network_type(-1) \
+                .skip_type(skip_type) \
+                .skip_content('') \
+                .time_to_live(1000) \
+                .request_id('123456') \
+                .classification(1) \
+                .client_custom_map(**push_data) \
+                .message_dict()
+            rec2 = sender_send.send(message)
+            logger.info('vivo推送结果:{}'.format(rec2))
+        except Exception as e:
+            logger.info('vivo推送异常:{}'.format(e))

+ 91 - 0
Service/VivoPushService/push_admin/APIConstants.py

@@ -0,0 +1,91 @@
+# coding=utf-8
+class Constants(object):
+    def __init__(self):
+        pass
+
+    def enum(**self):
+        return type('Enum', (), self)
+
+    __VERSION__ = '1.0'
+    __HTTP_GET__ = 0
+    __HTTP_POST__ = 1
+
+    _METHOD_MAP = {'GET': __HTTP_GET__, 'POST': __HTTP_POST__}
+
+    http_server = "https://api-push.vivo.com.cn"
+
+    '''
+        targetMessage parameter name
+    '''
+
+    http_param_reg_ids = "regIds"
+    http_param_aliases = "aliases"
+    http_param_task_id = "taskId"
+
+    '''
+        pushMessage parameter name
+    '''
+    http_param_tag_expression = "tagExpression"
+    http_param_or_tags = "orTags"
+    http_param_and_tags = "andTags"
+    http_param_not_tags = "notTags"
+    http_param_segment_name = "segmentName"
+    http_param_reg_id = "regId"
+    http_param_content = "content"
+    http_param_title = "title"
+    http_param_ali_as = "alias"
+    http_param_notify_type = "notifyType"
+    http_param_time_to_live = "timeToLive"
+    http_param_skip_type = "skipType"
+    http_param_skip_content = "skipContent"
+    http_param_network_type = "networkType"
+    http_param_client_custom_map = "clientCustomMap"
+    http_param_extra = "extra"
+    http_param_callback = "callback"
+    http_param_callback_param = "callback.param"
+
+    http_param_request_id = "requestId"
+
+    http_param_classification = "classification"
+
+    http_param_push_mode = "pushMode"
+
+
+    http_param_task_ids = "taskIds"
+
+    '''
+        tagMessage parameter name
+    '''
+    http_param_name = "name"
+    http_param_old_name = "oldName"
+    http_param_new_name = "newName"
+    http_param_desc = "desc"
+    http_param_group = "group"
+    http_param_type = "type"
+    http_param_ids = "ids"
+
+    http_param_tag_list = "tagList"
+
+    http_param_expression = "expression"
+
+    request_path = enum(
+        GET_TOKEN=["/message/auth"],
+        PUSH_TO_SINGLE=['/message/send'],
+        SAVE_LIST_PAYLOAD=['/message/saveListPayload '],
+        PUSH_TO_LIST=['/message/pushToList'],
+        PUSH_TO_ALL=['/message/all'],
+        PUSH_TO_TAG=['/message/tagPush'],
+        GET_STATISTICS=['/report/getStatistics'],
+
+        ADD_TAG=['/tag/add'],
+        UPDATE_TAG=['/tag/update'],
+        ADD_MEMBERS=['/tag/addMembers'],
+        REMOVE_MEMBERS=['/tag/removeMembers'],
+
+        ADD_TAG_GROUP=['/tagGroup/add'],
+        UPDATE_TAG_GROUP=['/tagGroup/update'],
+        ADD_TAG_TO_GROUP=['/tagGroup/addToGroup'],
+
+        ADD_TAG_SEGMENT=['/tagSegment/add'],
+        UPDATE_TAG_SEGMENT=['/tagSegment/update'],
+    )

+ 13 - 0
Service/VivoPushService/push_admin/APIError.py

@@ -0,0 +1,13 @@
+
+class APIError(Exception):
+    """
+    raise APIError if receiving json message indicating failure.
+    """
+    def __init__(self, error_code, error, request):
+        self.error_code = error_code
+        self.error = error
+        self.request = request
+        Exception.__init__(self, error)
+
+    def __str__(self):
+        return 'APIError: %s: %s, request: %s' % (self.error_code, self.error, self.request)

+ 103 - 0
Service/VivoPushService/push_admin/APIMessage.py

@@ -0,0 +1,103 @@
+# coding=utf-8
+from Service.VivoPushService.push_admin.APIConstants import Constants
+
+
+class MessageDict(dict):
+    def __getattr__(self, item):
+        try:
+            return self[item]
+        except KeyError:
+            raise AttributeError(r"'message' object has no attribute %s'" % item)
+
+    def __setattr__(self, key, value):
+        self[key] = value
+
+class PushMessage(object):
+    tag_expression={}
+
+    def __init__(self):
+        self.__message_dict = MessageDict()
+
+    def or_tags(self,or_tags):
+        PushMessage.tag_expression[Constants.http_param_or_tags]=or_tags
+        self.__message_dict[Constants.http_param_tag_expression] = PushMessage.tag_expression
+        return self
+
+    def and_tags(self,and_tags):
+        PushMessage.tag_expression[Constants.http_param_and_tags]=and_tags
+        self.__message_dict[Constants.http_param_tag_expression] = PushMessage.tag_expression
+        return self
+
+    def not_tags(self,not_tags):
+        PushMessage.tag_expression[Constants.http_param_not_tags]=not_tags
+        self.__message_dict[Constants.http_param_tag_expression] = PushMessage.tag_expression
+        return self
+
+    def segment_name(self, segment_name):
+        self.__message_dict[Constants.http_param_segment_name] = segment_name
+        self.__message_dict[Constants.http_param_tag_expression] = PushMessage.tag_expression
+        return self
+
+    def reg_id(self, reg_id):
+        self.__message_dict[Constants.http_param_reg_id] = reg_id
+        return self
+
+    def ali_as(self, ali_as):
+        self.__message_dict[Constants.http_param_ali_as] = ali_as
+        return self
+
+    def content(self, content):
+        self.__message_dict[Constants.http_param_content] = content
+        return self
+
+    def title(self, title):
+        self.__message_dict[Constants.http_param_title] = title
+        return self
+
+    def notify_type(self, notify_type):
+        self.__message_dict[Constants.http_param_notify_type] = notify_type
+        return self
+
+    def time_to_live(self, time_to_live):
+        self.__message_dict[Constants.http_param_time_to_live] = time_to_live
+        return self
+
+    def skip_type(self, skip_type):
+        self.__message_dict[Constants.http_param_skip_type] = skip_type
+        return self
+
+    def skip_content(self, skip_content):
+        self.__message_dict[Constants.http_param_skip_content] = skip_content
+        return self
+
+    def network_type(self, network_type=-1):
+        self.__message_dict[Constants.http_param_network_type] = network_type
+        return self
+
+    def request_id(self, request_id):
+        self.__message_dict[Constants.http_param_request_id] = request_id
+        return self
+
+    def classification(self, classification):
+        self.__message_dict[Constants.http_param_classification] = classification
+        return self
+
+    def push_mode(self, push_mode):
+        self.__message_dict[Constants.http_param_push_mode] = push_mode
+        return self
+
+    def client_custom_map(self, **client_custom_map):
+        self.__message_dict[Constants.http_param_client_custom_map] = client_custom_map
+        return self
+
+    def extra(self, value1, value2):
+        extra = {Constants.http_param_callback: value1, Constants.http_param_callback_param: value2}
+        self.__message_dict[Constants.http_param_extra] = extra
+        return self
+
+    '''
+        message params build method
+    '''
+
+    def message_dict(self):
+        return self.__message_dict

+ 73 - 0
Service/VivoPushService/push_admin/APISender.py

@@ -0,0 +1,73 @@
+# coding=utf-8
+import time
+
+from Service.VivoPushService.push_admin.APIConstants import Constants
+from Service.VivoPushService.push_admin.APISenderBase import Base
+from Service.VivoPushService.push_admin.APISignUtil import SignUtil
+
+_BROADCAST_TOPIC_MAX = 5
+_TOPIC_SPLITTER = ';$;'
+
+
+class APISender(Base):
+    """
+    发送消息API(send push message class)
+    构造方法接收两个参数:
+    @:param secret 必填 - APP_SECRET
+    @:param token 可选 - authToken,发送消息时需带该参数以进行鉴权操作,调用鉴权接口获得
+    """
+
+    def get_token(self, app_id, app_key):
+        timestamp = int(round(time.time() * 1000))
+        sign = SignUtil(app_id, app_key, self.secret).sign_util(timestamp)
+        get_token = {'appId': app_id, 'appKey': app_key, 'timestamp': timestamp, 'sign': sign}
+        return self._try_http_request(Constants.request_path.GET_TOKEN, retry_times=3, **get_token)
+
+    def send(self, push_message, retry_times=3):
+        """
+        发送单推消息
+        :param push_message: 消息体(请求参数对象)
+        :param retry_times: 重试次数
+        """
+        return self._try_http_request(Constants.request_path.PUSH_TO_SINGLE, retry_times, **push_message)
+
+    def save_list_payload(self, push_message, retry_times=3):
+        """
+        保存群推消息
+        :param push_message: 消息体(请求参数对象)
+        :param retry_times: 重试次数
+        """
+        return self._try_http_request(Constants.request_path.SAVE_LIST_PAYLOAD, retry_times, **push_message)
+
+    def send_to_list(self, target_push_message, retry_times=3):
+        """
+        推送群推消息
+        :param target_push_message: 消息体(请求参数对象)
+        :param retry_times: 重试次数
+        """
+        return self._try_http_request(Constants.request_path.PUSH_TO_LIST, retry_times, **target_push_message)
+
+    def send_to_all(self, push_message, retry_times=3):
+        """
+        发送全推消息
+        :param push_message: 消息体(请求参数对象)
+        :param retry_times: 重试次数
+        """
+        return self._try_http_request(Constants.request_path.PUSH_TO_ALL, retry_times, **push_message)
+
+    def send_to_tag(self, push_message, retry_times=3):
+        """
+        发送标签推消息
+        :param push_message: 消息体(请求参数对象)
+        :param retry_times: 重试次数
+        """
+        return self._try_http_request(Constants.request_path.PUSH_TO_TAG,retry_times,**push_message)
+
+    def get_statistics(self, taskids_message, retry_times=3):
+        """
+        发送全推消息
+        :param taskids_message: 消息体(请求参数对象)
+        :param retry_times: 重试次数
+        """
+        return self._try_http_request(Constants.request_path.GET_STATISTICS, retry_times, Constants.__HTTP_GET__,
+                                      **taskids_message)

+ 131 - 0
Service/VivoPushService/push_admin/APISenderBase.py

@@ -0,0 +1,131 @@
+import logging
+import time
+import json
+import urllib.request, urllib.parse, urllib.error
+import urllib.request, urllib.error, urllib.parse
+
+from Service.VivoPushService.push_admin.APIConstants import Constants
+from Service.VivoPushService.push_admin.APIError import APIError
+
+_MAX_BACKOFF_DELAY = 1024000
+
+
+class JsonDict(dict):
+    def __getattr__(self, item):
+        try:
+            return self[item]
+        except KeyError:
+            raise AttributeError(r"'JsonDict' object has no attribute %s'" % item)
+
+    def __setattr__(self, key, value):
+        self[key] = value
+
+
+def _parse_json(body):
+    """
+    convert json object to python object
+    :param body: response data
+    """
+    def _obj_hook(pairs):
+        o = JsonDict()
+        for k, v in pairs.items():
+            o[str(k)] = v
+        return o
+
+    return json.loads(body, object_hook=_obj_hook)
+
+
+def _build_request_url(request_path):
+    return Constants.http_server + request_path[0]
+
+
+def _http_call(url, method, token, **message):
+    """
+    :param url: http request url
+    :param method: http request method
+    :param message: params
+    """
+    params = _encode_params(message) if method == Constants.__HTTP_GET__ else ''
+    http_url = '%s?%s' % (url, params) if method == Constants.__HTTP_GET__ else url
+    http_body = None if method == Constants.__HTTP_GET__ else message
+    req = urllib.request.Request(http_url, data=json.dumps(http_body).encode("utf-8"))
+    if token:
+        req.add_header('authToken', token)
+    req.add_header('Content-Type', 'application/json;charset=UTF-8')
+    try:
+        resp = urllib.request.urlopen(req, timeout=5)
+        r = _parse_json(resp.read().decode())
+        return r
+    except urllib.error.URLError as e:
+        raise APIError('-5', e.reason, 'http error ' + str(e.code))
+    except BaseException as e:
+        raise e
+
+def _encode_params(kw):
+    """
+    splic get request url
+    :param kw: params
+    """
+    args = ''
+    s = ''
+    for k, v in kw.items():
+        for t in v:
+            s = s+ str(t) + ','
+        args = '%s=%s' %(k, s[:-1])
+    return args
+
+class Base(object):
+    def __init__(self, secret, token=None):
+        self.secret = secret
+        self.token = token
+
+    def set_token(self, token):
+        self.token = token
+
+    def _http_request(self, request_path, method, **message):
+        """
+        :param request_path: http interface
+        :param method: GET|POST
+        :param message: params
+        """
+        request_url = _build_request_url(request_path)
+        try:
+            ret = _http_call(request_url, method, self.token, **message)
+            return ret
+        except APIError as ex:
+            logging.error("%s request: [%s] error [%s]" % (Constants.http_server, request_url, ex))
+            raise ex
+
+    def http_post(self, request_path, **message):
+        logging.info("POST %s" % request_path[0])
+        return self._http_request(request_path, Constants.__HTTP_POST__, **message)
+
+    def http_get(self, request_path, **message):
+        logging.info("GET %s" % request_path[0])
+        return self._http_request(request_path, Constants.__HTTP_GET__, **message)
+
+    def _try_http_request(self, request_path, retry_times, method=Constants.__HTTP_POST__, **message):
+        is_fail, try_time, result, sleep_time = True, 0, None, 1
+        while is_fail and try_time < retry_times:
+            try:
+                if method == Constants.__HTTP_POST__:
+                    result = self.http_post(request_path, **message)
+                elif method == Constants.__HTTP_GET__:
+                    result = self.http_get(request_path, **message)
+                else:
+                    raise APIError('-2', 'not support %s http request' % method, 'http error')
+                is_fail = False
+            except APIError as ex:
+                '''
+                    failure retry
+                '''
+                if ex.error_code == '-5':
+                    is_fail = True
+                try_time += 1
+                logging.error('code:[%s] - description:[%s] - reason:[%s] - try_time:[%s]' % (ex.error_code, ex.error, ex.request, try_time))
+                time.sleep(sleep_time)
+                if 2 * sleep_time < _MAX_BACKOFF_DELAY:
+                    sleep_time *= 2
+        if not result:
+            raise APIError('-3', 'retry %s time failure' % retry_times, 'request error')
+        return result

+ 17 - 0
Service/VivoPushService/push_admin/APISignUtil.py

@@ -0,0 +1,17 @@
+# coding=utf-8
+import  hashlib
+
+
+class SignUtil:
+    def __init__(self, app_id, app_key, app_secret):
+        self.app_id = app_id
+        self.app_key = app_key
+        self.app_secret = app_secret
+
+    def sign_util(self, timestamp):
+        m = hashlib.md5()
+        m.update(self.app_id.encode("UTF-8"))
+        m.update(self.app_key.encode("UTF-8"))
+        m.update(str(timestamp).encode("UTF-8"))
+        m.update(self.app_secret.encode("UTF-8"))
+        return m.hexdigest()

+ 0 - 0
Service/VivoPushService/push_admin/__init__.py