瀏覽代碼

V2接口代码优化

zhangdongming 2 年之前
父節點
當前提交
a595908715
共有 2 個文件被更改,包括 528 次插入261 次删除
  1. 83 261
      Controller/DetectControllerV2.py
  2. 445 0
      Service/DevicePushService.py

+ 83 - 261
Controller/DetectControllerV2.py

@@ -1,28 +1,22 @@
 import json
 import json
 import logging
 import logging
 import os
 import os
-import threading
-import time
 
 
 import apns2
 import apns2
 import boto3
 import boto3
 import botocore
 import botocore
 import jpush as jpush
 import jpush as jpush
 from botocore import client
 from botocore import client
+from django.db import transaction
 from django.http import JsonResponse
 from django.http import JsonResponse
 from django.views.generic.base import View
 from django.views.generic.base import View
 from pyfcm import FCMNotification
 from pyfcm import FCMNotification
 
 
 from AnsjerPush.config import AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
 from AnsjerPush.config import AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
 from AnsjerPush.config import JPUSH_CONFIG, FCM_CONFIG, APNS_CONFIG, BASE_DIR, APNS_MODE
 from AnsjerPush.config import JPUSH_CONFIG, FCM_CONFIG, APNS_CONFIG, BASE_DIR, APNS_MODE
-from AnsjerPush.config import SERVER_TYPE
-from Model.models import UidPushModel, SysMsgModel
-from Object.ETkObject import ETkObject
 from Object.RedisObject import RedisObject
 from Object.RedisObject import RedisObject
-from Object.UidTokenObject import UidTokenObject
-from Object.utils import LocalDateTimeUtil
 from Service.CommonService import CommonService
 from Service.CommonService import CommonService
-from Service.EquipmentInfoService import EquipmentInfoService
+from Service.DevicePushService import DevicePushService
 from Service.GatewayService import GatewayPushService
 from Service.GatewayService import GatewayPushService
 
 
 
 
@@ -38,6 +32,17 @@ class NotificationV2View(View):
         return self.validation(request.POST)
         return self.validation(request.POST)
 
 
     def validation(self, request_dict):
     def validation(self, request_dict):
+        """
+        设备触发报警消息推送
+        @param request_dict:uidToken 加密uid
+        @param request_dict:etk 加密uid
+        @param request_dict:channel 设备通道号
+        @param request_dict:n_time 设备触发报警时间
+        @param request_dict:event_type 设备事件类型
+        @param request_dict:is_st 文件类型(0:无,1:图片,2:视频)
+        @param request_dict:region 文件存储区域(1:国外,2国内)
+        @param request_dict:electricity 电量值
+        """
         logger = logging.getLogger('info')
         logger = logging.getLogger('info')
         logger.info("移动侦测V2接口参数:{}".format(request_dict))
         logger.info("移动侦测V2接口参数:{}".format(request_dict))
         uidToken = request_dict.get('uidToken', None)
         uidToken = request_dict.get('uidToken', None)
@@ -57,250 +62,71 @@ class NotificationV2View(View):
             return JsonResponse(status=200, data={'code': 404, 'msg': 'no region or is_st'})
             return JsonResponse(status=200, data={'code': 404, 'msg': 'no region or is_st'})
 
 
         try:
         try:
-            is_st = int(is_st)
-            region = int(region)
-
-            # 解密获取uid
-            if etk:
-                eto = ETkObject(etk)
-                uid = eto.uid
-            else:
-                uto = UidTokenObject(uidToken)
-                uid = uto.UID
-            # uid = request_dict.get('uid', None)     # 调试
-            # 判断uid长度
-            if len(uid) != 20 and len(uid) != 14:
-                return JsonResponse(status=200, data={'code': 404, 'msg': 'wrong uid'})
-            logger.info('调用推送接口的uid:{}'.format(uid))
-
-            pkey = '{uid}_{channel}_{event_type}_ptl'.format(uid=uid, channel=channel, event_type=event_type)
-            ykey = '{uid}_redis_qs'.format(uid=uid)
-            is_sys_msg = self.is_sys_msg(int(event_type))
-            if is_sys_msg:
-                dkey = '{uid}_{channel}_{event_type}_flag'.format(uid=uid, channel=channel, event_type=event_type)
-            else:
-                dkey = '{uid}_{channel}_flag'.format(uid=uid, channel=channel)
-
-            redisObj = RedisObject(db=6)
-            have_ykey = redisObj.get_data(key=ykey)  # uid_set 数据库缓存
-            have_pkey = redisObj.get_data(key=pkey)  # 一分钟限制key
-            have_dkey = redisObj.get_data(key=dkey)  # 推送消息时间间隔
-            logger.info('ykey:{}, pkey: {}, dkey: {}'.format(have_ykey, have_pkey, have_dkey))
-            # 一分钟内不推送
-            if have_pkey:
-                return JsonResponse(status=200, data={'code': 0, 'msg': 'Push again in one minute'})
-            redisObj.set_data(key=pkey, val=1, expire=60)
-
-            # 查询推送数据
-            uid_push_qs = UidPushModel.objects.filter(uid_set__uid=uid, uid_set__detect_status=1). \
-                values('token_val', 'app_type', 'appBundleId', 'm_code', 'push_type', 'userID_id', 'userID__NickName',
-                       'lang', 'm_code', 'tz', 'uid_set__nickname', 'uid_set__detect_interval', 'uid_set__detect_group',
-                       'uid_set__channel', 'uid_set__ai_type', 'uid_set__new_detect_interval')
-            if not uid_push_qs.exists():
-                logger.info('uid_push 数据不存在')
-                return JsonResponse(status=200, data={'code': 176, 'msg': 'no uid_push data'})
-            ai_type = uid_push_qs.first()['uid_set__ai_type']
-            event_type = self.get_combo_msg_type(ai_type, int(event_type))
-            redis_list = []
-            for qs in uid_push_qs:
-                redis_list.append(qs)
-            # 修改redis数据,并设置过期时间为10分钟
-            redisObj.set_data(key=ykey, val=str(redis_list), expire=600)
-
-            nickname = redis_list[0]['uid_set__nickname']
-            detect_interval = redis_list[0]['uid_set__detect_interval']
-            if not nickname:
-                nickname = uid
-            if not have_dkey:
-                # 设置推送消息的时间间隔
-                if SERVER_TYPE != 'Ansjer.cn_formal_settings':
-                    new_detect_interval = redis_list[0]['uid_set__new_detect_interval']
-                    detect_interval = new_detect_interval if new_detect_interval > 0 else detect_interval
-                    detect_interval = 60 if detect_interval < 60 else detect_interval
-                redisObj.set_data(key=dkey, val=1, expire=detect_interval - 5)
-                logger.info('APP消息推送间隔:{}s'.format(detect_interval))
-
-            if is_st == 1 or is_st == 3:  # 使用aws s3
-                aws_s3_client = s3_client(region=region)
-                bucket = 'foreignpush' if region == 1 else 'push'
-            kwag_args = {
-                'uid': uid,
-                'channel': channel,
-                'event_type': event_type,
-                'n_time': n_time,
-            }
-            sys_msg_list = []
-            userID_ids = []
-            do_apns_code = ''
-            do_fcm_code = ''
-            do_jpush_code = ''
-            logger.info('进入手机推送------')
-            logger.info('uid={}'.format(uid))
-            logger.info(redis_list)
-            new_device_info_list = []
-            local_date_time = ''
-            for up in redis_list:
-                push_type = up['push_type']
-                appBundleId = up['appBundleId']
-                token_val = up['token_val']
-                lang = up['lang']
-                tz = up['tz']
-                if tz is None or tz == '':
-                    tz = 0
-                # 发送标题
-                msg_title = self.get_msg_title(appBundleId=appBundleId, nickname=nickname)
-                # 发送内容
-                msg_text = self.get_msg_text(channel=channel, n_time=n_time, lang=lang, tz=tz,
-                                             event_type=event_type, electricity=electricity)
-                kwag_args['appBundleId'] = appBundleId
-                kwag_args['token_val'] = token_val
-                kwag_args['msg_title'] = msg_title
-                kwag_args['msg_text'] = msg_text
-                logger.info('推送要的数据: {}'.format(kwag_args))
-                local_date_time = CommonService.get_now_time_str(n_time=n_time, tz=tz, lang='cn')
-                logger.info('<<<<<根据时区计算后日期={},时区={}'.format(local_date_time, tz))
-                local_date_time = local_date_time[0:10]
-                logger.info('<<<<<切片后的日期={}'.format(local_date_time))
-                # 以下是存库
-                userID_id = up["userID_id"]
-                if userID_id not in userID_ids:
-                    now_time = int(time.time())
-                    if is_sys_msg:
-                        sys_msg_text = self.get_msg_text(channel=channel, n_time=n_time, lang=lang, tz=tz,
-                                                         event_type=event_type, electricity=electricity, is_sys=1)
-                        sys_msg_list.append(SysMsgModel(
-                            userID_id=userID_id,
-                            msg=sys_msg_text,
-                            addTime=now_time,
-                            updTime=now_time,
-                            uid=uid,
-                            eventType=event_type))
-                    else:
-                        # start 根据设备侦测时间为准进行分表存储数据
-                        logger.info('分表存数据start------')
-                        new_device_info_list.append(EquipmentInfoService.get_equipment_info_obj(
-                            local_date_time,
-                            device_user_id=userID_id,
-                            event_time=n_time,
-                            event_type=event_type,
-                            device_uid=uid,
-                            device_nick_name=nickname,
-                            channel=channel,
-                            alarm='Motion \tChannel:{channel}'.format(channel=channel),
-                            is_st=is_st,
-                            receive_time=n_time,
-                            add_time=now_time,
-                            storage_location=2,
-                            border_coords='',
-                        ))
-                        # end
-                    userID_ids.append(userID_id)
-                try:
-                    # 推送消息
-                    if not have_dkey:
-                        logger.info('APP准备推送:{}, {}'.format(uid, request_dict))
-                        if (is_st == 1 or is_st == 3) and (push_type == 0 or push_type == 1):  # 推送显示图片
-                            if is_st == 1:
-                                key = '{}/{}/{}.jpeg'.format(uid, channel, n_time)
-                            else:
-                                key = '{}/{}/{}_0.jpeg'.format(uid, channel, n_time)
-                            push_thread = threading.Thread(target=self.push_thread_test, args=(
-                                push_type, aws_s3_client, bucket, key, uid, appBundleId, token_val, event_type, n_time,
-                                msg_title, msg_text, channel))
-                            push_thread.start()
-                        else:
-                            if push_type == 0:  # ios apns
-                                do_apns_code = self.do_apns(**kwag_args)
-                            elif push_type == 1:  # android gcm
-                                do_fcm_code = self.do_fcm(**kwag_args)
-                            elif push_type == 2:  # android jpush
-                                do_jpush_code = self.do_jpush(**kwag_args)
-                except Exception as e:
-                    logger.info(
-                        "errLine={errLine}, errMsg={errMsg}".format(errLine=e.__traceback__.tb_lineno, errMsg=repr(e)))
-                    continue
-            if is_sys_msg:
-                SysMsgModel.objects.bulk_create(sys_msg_list)
-            else:
-                # new 分表批量存储 设备信息
-                if new_device_info_list and len(new_device_info_list) > 0:
-                    # 根据日期获得星期几
-                    week = LocalDateTimeUtil.date_to_week(local_date_time)
-                    EquipmentInfoService.equipment_info_bulk_create(week, new_device_info_list)
-                    logger.info('设备信息分表批量保存end------')
-
-            if is_st == 0 or is_st == 2:
-                for up in redis_list:
-                    if up['push_type'] == 0:  # ios apns
-                        up['do_apns_code'] = do_apns_code
-                    elif up['push_type'] == 1:  # android gcm
-                        up['do_fcm_code'] = do_fcm_code
-                    elif up['push_type'] == 2:  # android jpush
-                        up['do_jpush_code'] = do_jpush_code
-                    del up['push_type']
-                    del up['userID_id']
-                    del up['userID__NickName']
-                    del up['lang']
-                    del up['tz']
-                    del up['uid_set__nickname']
-                    del up['uid_set__detect_interval']
-                    del up['uid_set__detect_group']
-                return JsonResponse(status=200, data={'code': 0, 'msg': 'success 0 or 2', 're_list': redis_list})
-
-            elif is_st == 1:
-                thumbspng = '{uid}/{channel}/{filename}.jpeg'.format(uid=uid, channel=channel, filename=n_time)
-                Params = {'Key': thumbspng}
-                if region == 2:  # 2:国内
-                    Params['Bucket'] = 'push'
-                else:  # 1:国外
-                    Params['Bucket'] = 'foreignpush'
-                response_url = generate_s3_url(aws_s3_client, Params)
-                for up in redis_list:
-                    up['do_apns_code'] = do_apns_code
-                    up['do_fcm_code'] = do_fcm_code
-                    up['do_jpush_code'] = do_jpush_code
-                    del up['push_type']
-                    del up['userID_id']
-                    del up['userID__NickName']
-                    del up['lang']
-                    del up['tz']
-                    del up['uid_set__nickname']
-                    del up['uid_set__detect_interval']
-                    del up['uid_set__detect_group']
-                res_data = {'code': 0, 'img_push': response_url, 'msg': 'success'}
-                return JsonResponse(status=200, data=res_data)
-
-            elif is_st == 3:
-                img_url_list = []
-                if region == 2:  # 2:国内
-                    Params = {'Bucket': 'push'}
-                else:  # 1:国外
-                    Params = {'Bucket': 'foreignpush'}
-                for i in range(is_st):
-                    thumbspng = '{uid}/{channel}/{filename}_{st}.jpeg'. \
-                        format(uid=uid, channel=channel, filename=n_time, st=i)
-                    Params['Key'] = thumbspng
-                    response_url = generate_s3_url(aws_s3_client, Params)
-                    img_url_list.append(response_url)
-
-                for up in redis_list:
-                    up['do_apns_code'] = do_apns_code
-                    up['do_fcm_code'] = do_fcm_code
-                    up['do_jpush_code'] = do_jpush_code
-                    del up['push_type']
-                    del up['userID_id']
-                    del up['userID__NickName']
-                    del up['lang']
-                    del up['tz']
-                    del up['uid_set__nickname']
-                    del up['uid_set__detect_interval']
-                    del up['uid_set__detect_group']
-                res_data = {'code': 0, 'img_url_list': img_url_list, 'msg': 'success 3'}
-                return JsonResponse(status=200, data=res_data)
+            with transaction.atomic():
+                is_st = int(is_st)
+                region = int(region)
+                uid = DevicePushService.decode_uid(etk, uidToken)  # 解密uid
+                if len(uid) != 20 and len(uid) != 14:
+                    return JsonResponse(status=200, data={'code': 404, 'msg': 'wrong uid'})
+                req_limiting = '{uid}_{channel}_{event_type}_ptl' \
+                    .format(uid=uid, channel=channel, event_type=event_type)
+                is_sys_msg = self.is_sys_msg(int(event_type))  # 判断事件类型是否是系统消息
+                if is_sys_msg:
+                    push_interval = '{uid}_{channel}_{event_type}_flag' \
+                        .format(uid=uid, channel=channel, event_type=event_type)
+                else:
+                    push_interval = '{uid}_{channel}_flag'.format(uid=uid, channel=channel)
+                redisObj = RedisObject(db=6)
+                cache_req_limiting = redisObj.get_data(key=req_limiting)  # 获取请求限流缓存数据
+                cache_app_push = redisObj.get_data(key=push_interval)  # 获取APP推送消息时间间隔缓存数据
+                logger.info('消息推送- 限流key: {}, 推送间隔key: {}'.
+                            format(cache_req_limiting, cache_app_push))
+                if cache_req_limiting:  # 限流存在则直接返回
+                    return JsonResponse(status=200, data={'code': 0, 'msg': 'Push again in one minute'})
+                redisObj.set_data(key=req_limiting, val=1, expire=60)  # 当缓存不存在限流数据 重新设置一分钟请求一次
+                uid_push_qs = DevicePushService.query_uid_push(uid)  # 查询uid_set与push数据列表
+                if not uid_push_qs.exists():
+                    logger.info('消息推送-uid_push 数据不存在')
+                    return JsonResponse(status=200, data={'code': 176, 'msg': 'no uid_push data'})
+                ai_type = uid_push_qs.first()['uid_set__ai_type']
+                event_type = self.get_combo_msg_type(ai_type, int(event_type))  # 解析消息事件类型看是否多类型组合
+                # 将uid_set以及uid_push 转数组列表
+                uid_set_push_list = DevicePushService.cache_uid_push(uid_push_qs)
+                nickname = uid_set_push_list[0]['uid_set__nickname']
+                nickname = uid if not nickname else nickname
+                # APP消息提醒推送间隔
+                detect_interval = uid_set_push_list[0]['uid_set__detect_interval']
+                if not cache_app_push:
+                    # 缓存APP提醒推送间隔 默认1分钟提醒一次
+                    DevicePushService.cache_push_detect_interval(redisObj, push_interval, detect_interval,
+                                                                 uid_set_push_list[0]['uid_set__new_detect_interval'])
+                bucket = ''
+                aws_s3_client = ''
+                if is_st == 1 or is_st == 3:  # 使用aws s3
+                    aws_s3_client = s3_client(region=region)
+                    bucket = 'foreignpush' if region == 1 else 'push'
+                kwag_args = {
+                    'uid': uid,
+                    'channel': channel,
+                    'event_type': event_type,
+                    'n_time': n_time,
+                }
+                params = {'nickname': nickname, 'uid': uid, 'kwag_args': kwag_args, 'is_st': is_st, 'region': region,
+                          'is_sys_msg': is_sys_msg, 'channel': channel, 'event_type': event_type, 'n_time': n_time,
+                          'electricity': electricity, 'bucket': bucket, 'aws_s3_client': aws_s3_client,
+                          'app_push': cache_app_push}
+                # APP消息推送与获取报警消息数据列表
+                result = DevicePushService.save_msg_push(uid_set_push_list, **params)
+                # 批量系统消息&报警消息数据存库
+                DevicePushService.save_sys_msg(is_sys_msg, result['local_date_time'],
+                                               result['sys_msg_list'], result['new_device_info_list'])
+                params['aws_s3_client'] = aws_s3_client
+                params['uid_set_push_list'] = uid_set_push_list
+                params['code_dict'] = result
+                result_dict = DevicePushService.get_push_url(**params)  # 获取S3对象上传链接
+                return JsonResponse(status=200, data=result_dict)
         except Exception as e:
         except Exception as e:
-            logger.info('移动侦测接口异常: {}'.format(e))
-            logger.info('错误文件', e.__traceback__.tb_frame.f_globals['__file__'])
-            logger.info('错误行号', e.__traceback__.tb_lineno)
+            logger.info('消息推送-异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
             data = {
             data = {
                 'errLine': e.__traceback__.tb_lineno,
                 'errLine': e.__traceback__.tb_lineno,
                 'errMsg': repr(e),
                 'errMsg': repr(e),
@@ -387,7 +213,12 @@ class NotificationV2View(View):
         else:
         else:
             return nickname
             return nickname
 
 
-    def is_sys_msg(self, event_type):
+    @staticmethod
+    def is_sys_msg(event_type):
+        """
+        判断是否属于系统消息
+        @return: True | False
+        """
         event_type_list = [702, 703, 704]
         event_type_list = [702, 703, 704]
         if event_type in event_type_list:
         if event_type in event_type_list:
             return True
             return True
@@ -521,12 +352,3 @@ def s3_client(region):
             region_name='us-east-1'
             region_name='us-east-1'
         )
         )
     return aws_s3_client
     return aws_s3_client
-
-
-def generate_s3_url(aws_s3_client, Params):
-    response_url = aws_s3_client.generate_presigned_url(
-        ClientMethod='put_object',
-        Params=Params,
-        ExpiresIn=3600
-    )
-    return response_url

+ 445 - 0
Service/DevicePushService.py

@@ -0,0 +1,445 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : DevicePushService.py
+@Time    : 2022/11/23 11:40
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+import logging
+import os
+import threading
+import time
+
+import apns2
+import jpush as jpush
+from pyfcm import FCMNotification
+
+from AnsjerPush.config import JPUSH_CONFIG, FCM_CONFIG, APNS_CONFIG, BASE_DIR, APNS_MODE
+from AnsjerPush.config import SERVER_TYPE
+from Model.models import UidPushModel, SysMsgModel
+from Object.ETkObject import ETkObject
+from Object.UidTokenObject import UidTokenObject
+from Object.utils import LocalDateTimeUtil
+from Service.CommonService import CommonService
+from Service.EquipmentInfoService import EquipmentInfoService
+from Service.GatewayService import GatewayPushService
+
+LOGGING = logging.getLogger('info')
+
+
+class DevicePushService:
+
+    @staticmethod
+    def decode_uid(etk, uidToken):
+        """
+        解密UID,优先解密etk 否则判断uidToken
+        """
+        # 解密获取uid
+        if etk:
+            eto = ETkObject(etk)
+            uid = eto.uid
+        else:
+            uto = UidTokenObject(uidToken)
+            uid = uto.UID
+        LOGGING.info('消息推送-当前UID:{}'.format(uid))
+        return uid
+
+    @classmethod
+    def query_uid_push(cls, uid):
+        """
+        查询uid_set与push数据列表
+        """
+        uid_push_qs = UidPushModel.objects.filter(uid_set__uid=uid, uid_set__detect_status=1). \
+            values('token_val', 'app_type', 'appBundleId', 'm_code', 'push_type', 'userID_id', 'userID__NickName',
+                   'lang', 'm_code', 'tz', 'uid_set__nickname', 'uid_set__detect_interval', 'uid_set__detect_group',
+                   'uid_set__channel', 'uid_set__ai_type', 'uid_set__new_detect_interval')
+        return uid_push_qs
+
+    @staticmethod
+    def cache_uid_push(uid_push_qs):
+        """
+        将uid_push 信息进行缓存
+        @param uid_push_qs: uid_set & uid_push 列表对象
+        @return: uid_set_list
+        """
+        uid_set_list = []
+        for qs in uid_push_qs:
+            uid_set_list.append(qs)
+        # redis_obj.set_data(key=name, val=str(redis_list), expire=expire)
+        return uid_set_list
+
+    @staticmethod
+    def cache_push_detect_interval(redis_obj, name, detect_interval, new_detect_interval):
+        """
+        缓存设置推送消息的时间间隔
+        @param redis_obj: redis对象
+        @param name: redis key
+        @param detect_interval: 原推送时间间隔
+        @param new_detect_interval: 新推送时间间隔
+        """
+        if SERVER_TYPE != 'Ansjer.cn_formal_settings':
+            detect_interval = new_detect_interval if new_detect_interval > 0 else detect_interval
+            detect_interval = 60 if detect_interval < 60 else detect_interval
+        redis_obj.set_data(key=name, val=1, expire=detect_interval - 5)
+        LOGGING.info('消息推送-缓存设置APP推送间隔:{}s'.format(detect_interval))
+
+    @classmethod
+    def save_msg_push(cls, uid_set_push_list, **params):
+        """
+        APP消息推送以及报警消息存库
+        @nickname 设备名称
+        @channel 通道
+        @event_type 事件类型
+        """
+        new_device_info_list = []
+        sys_msg_list = []
+        userID_ids = []
+        kwag_args = params['kwag_args']
+        code_data = {'do_apns_code': '', 'do_fcm_code': '', 'do_jpush_code': ''}
+        local_date_time = ''
+        for up in uid_set_push_list:
+            appBundleId = up['appBundleId']
+            token_val = up['token_val']
+            lang = up['lang']
+            tz = up['tz']
+            if tz is None or tz == '':
+                tz = 0
+            # 发送标题
+            msg_title = cls.get_msg_title(appBundleId=appBundleId, nickname=params['nickname'])
+            # 发送内容
+            msg_text = cls.get_msg_text(channel=params['channel'], n_time=params['n_time'], lang=lang,
+                                        tz=tz, event_type=params['event_type'],
+                                        electricity=params['electricity'])
+            kwag_args['appBundleId'] = appBundleId
+            kwag_args['token_val'] = token_val
+            kwag_args['msg_title'] = msg_title
+            kwag_args['msg_text'] = msg_text
+            LOGGING.info('推送要的数据: {}'.format(kwag_args))
+            local_date_time = CommonService.get_now_time_str(n_time=params['n_time'], tz=tz, lang='cn')
+            LOGGING.info('<<<<<根据时区计算后日期={},时区={}'.format(local_date_time, tz))
+            local_date_time = local_date_time[0:10]
+            LOGGING.info('<<<<<切片后的日期={}'.format(local_date_time))
+            # 以下是存库
+            userID_id = up["userID_id"]
+            if userID_id not in userID_ids:
+                now_time = int(time.time())
+                if params['is_sys_msg']:
+                    sys_msg_text = cls.get_msg_text(channel=params['channel'], n_time=params['n_time'], lang=lang,
+                                                    tz=tz,
+                                                    event_type=params['event_type'], electricity=params['electricity'],
+                                                    is_sys=1)
+                    sys_msg_list.append(SysMsgModel(userID_id=userID_id, msg=sys_msg_text, addTime=now_time,
+                                                    updTime=now_time, uid=params['uid'],
+                                                    eventType=params['event_type']))
+                else:
+                    LOGGING.info('分表存数据start------')
+                    params['userID_id'] = userID_id
+                    new_device_info_list.append(cls.created_device_vo(local_date_time, **params))
+                userID_ids.append(userID_id)
+            params['appBundleId'] = appBundleId
+            params['token_val'] = token_val
+            params['lang'] = lang
+            params['tz'] = tz
+            params['kwag_args'] = kwag_args
+            code_data = cls.send_app_msg_push(up['push_type'], **params)
+        return {'code_date': code_data, 'new_device_info_list': new_device_info_list, 'sys_msg_list': sys_msg_list,
+                'local_date_time': local_date_time}
+
+    @classmethod
+    def send_app_msg_push(cls, push_type, **param):
+        """
+        发送app消息推送
+        """
+        try:
+            kwag_args = param['kwag_args']
+            result = {'do_apns_code': '', 'do_fcm_code': '', 'do_jpush_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):  # 推送显示图片
+                    if param['is_st'] == 1:
+                        key = '{}/{}/{}.jpeg'.format(param['uid'], param['channel'], param['n_time'])
+                    else:
+                        key = '{}/{}/{}_0.jpeg'.format(param['uid'], param['channel'], param['n_time'])
+                    push_thread = threading.Thread(target=cls.async_send_picture_push, args=(
+                        push_type, param['aws_s3_client'], param['bucket'], key, param['uid'], param['appBundleId'],
+                        param['token_val'], param['event_type'], param['n_time'],
+                        param['msg_title'], param['msg_text'], param['channel']))
+                    push_thread.start()
+                else:
+                    if push_type == 0:  # ios apns
+                        result['do_apns_code'] = cls.do_apns(**kwag_args)
+                    elif push_type == 1:  # android gcm
+                        result['do_fcm_code'] = cls.do_fcm(**kwag_args)
+                    elif push_type == 2:  # android jpush
+                        result['do_jpush_code'] = cls.do_jpush(**kwag_args)
+            return result
+        except Exception as e:
+            LOGGING.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return None
+
+    @classmethod
+    def save_sys_msg(cls, is_sys_msg, local_date_time, sys_msg_list, new_device_info_list):
+        """
+        保存系统消息&设备推送消息存库
+        """
+        if is_sys_msg:
+            SysMsgModel.objects.bulk_create(sys_msg_list)
+        else:
+            # new 分表批量存储 设备信息
+            if new_device_info_list and len(new_device_info_list) > 0:
+                # 根据日期获得星期几
+                week = LocalDateTimeUtil.date_to_week(local_date_time)
+                EquipmentInfoService.equipment_info_bulk_create(week, new_device_info_list)
+                LOGGING.info('设备信息分表批量保存end------')
+        return True
+
+    @classmethod
+    def created_device_vo(cls, local_date_time, **params):
+        """
+        获取设备推送表对象
+        """
+        return EquipmentInfoService.get_equipment_info_obj(
+            local_date_time,
+            device_user_id=params['userID_id'],
+            event_time=params['n_time'],
+            event_type=params['event_type'],
+            device_uid=params['uid'],
+            device_nick_name=params['nickname'],
+            channel=params['channel'],
+            alarm='Motion \tChannel:{channel}'.format(channel=params['channel']),
+            is_st=params['is_st'],
+            receive_time=params['n_time'],
+            add_time=int(time.time()),
+            storage_location=2,
+            border_coords='',
+        )
+
+    @staticmethod
+    def get_msg_title(appBundleId, nickname):
+        """
+        获取消息标题
+        """""
+        package_title_config = {
+            'com.ansjer.customizedd_a': 'DVS',
+            'com.ansjer.zccloud_a': 'ZosiSmart',
+            'com.ansjer.zccloud_ab': '周视',
+            'com.ansjer.adcloud_a': 'ADCloud',
+            'com.ansjer.adcloud_ab': 'ADCloud',
+            'com.ansjer.accloud_a': 'ACCloud',
+            'com.ansjer.loocamccloud_a': 'Loocam',
+            'com.ansjer.loocamdcloud_a': 'Anlapus',
+            'com.ansjer.customizedb_a': 'COCOONHD',
+            'com.ansjer.customizeda_a': 'Guardian365',
+            'com.ansjer.customizedc_a': 'PatrolSecure',
+        }
+        if appBundleId in package_title_config.keys():
+            return package_title_config[appBundleId] + '(' + nickname + ')'
+        else:
+            return nickname
+
+    @staticmethod
+    def get_msg_text(channel, n_time, lang, tz, event_type, electricity='', is_sys=0):
+        """
+        获取消息文本
+        """
+        n_date = CommonService.get_now_time_str(n_time=n_time, tz=tz, lang=lang)
+        etype = int(event_type)
+        if lang == 'cn':
+            if etype == 704:
+                msg_type = '剩余电量:' + electricity
+            elif etype == 702:
+                msg_type = '摄像头休眠'
+            elif etype == 703:
+                msg_type = '摄像头唤醒'
+            else:
+                msg_type = ''
+            if is_sys:
+                send_text = '{msg_type} 通道:{channel}'.format(msg_type=msg_type, channel=channel)
+            else:
+                send_text = '{msg_type} 通道:{channel} 日期:{date}'.format(msg_type=msg_type, channel=channel, date=n_date)
+        else:
+            if etype == 704:
+                msg_type = 'Battery remaining:' + electricity
+            elif etype == 702:
+                msg_type = 'Camera sleep'
+            elif etype == 703:
+                msg_type = 'Camera wake'
+            else:
+                msg_type = ''
+            if is_sys:
+                send_text = '{msg_type} channel:{channel}'. \
+                    format(msg_type=msg_type, channel=channel)
+            else:
+                send_text = '{msg_type} channel:{channel} date:{date}'. \
+                    format(msg_type=msg_type, channel=channel, date=n_date)
+        return send_text
+
+    @staticmethod
+    def do_jpush(uid, channel, appBundleId, token_val, event_type, n_time,
+                 msg_title, msg_text):
+        """
+        android 国内极光APP消息提醒推送
+        """
+        app_key = JPUSH_CONFIG[appBundleId]['Key']
+        master_secret = JPUSH_CONFIG[appBundleId]['Secret']
+        _jpush = jpush.JPush(app_key, master_secret)
+        push = _jpush.create_push()
+        push.audience = jpush.registration_id(token_val)
+        push_data = {"alert": "Motion ", "event_time": n_time, "event_type": event_type, "msg": "",
+                     "received_at": n_time, "sound": "sound.aif", "uid": uid, "zpush": "1", "channel": channel}
+        android = jpush.android(alert=msg_text, priority=1, style=1, alert_type=7,
+                                big_text=msg_text, title=msg_title,
+                                extras=push_data)
+        push.notification = jpush.notification(android=android)
+        push.platform = jpush.all_
+        res = push.send()
+        print(res)
+        return res.status_code
+
+    @staticmethod
+    def do_fcm(uid, channel, appBundleId, token_val, event_type, n_time, msg_title, msg_text):
+        """
+        android 谷歌APP消息提醒推送
+        """
+        try:
+            serverKey = FCM_CONFIG[appBundleId]
+        except Exception as e:
+            LOGGING.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return 'serverKey abnormal'
+        push_service = FCMNotification(api_key=serverKey)
+        data = {"alert": "Motion ", "event_time": n_time, "event_type": event_type, "msg": "",
+                "received_at": n_time, "sound": "sound.aif", "uid": uid, "zpush": "1", "channel": channel}
+        result = push_service.notify_single_device(registration_id=token_val, message_title=msg_title,
+                                                   message_body=msg_text, data_message=data,
+                                                   extra_kwargs={
+                                                       'default_vibrate_timings': True,
+                                                       'default_sound': True,
+                                                       'default_light_settings': True
+                                                   })
+        return result
+
+    @staticmethod
+    def do_apns(uid, channel, appBundleId, token_val, event_type, n_time, msg_title,
+                msg_text):
+        """
+        ios 消息提醒推送
+        """
+        LOGGING.info("进来do_apns函数了")
+        LOGGING.info(token_val)
+        LOGGING.info(APNS_MODE)
+        LOGGING.info(os.path.join(BASE_DIR, APNS_CONFIG[appBundleId]['pem_path']))
+        try:
+            cli = apns2.APNSClient(
+                mode=APNS_MODE, client_cert=os.path.join(BASE_DIR, APNS_CONFIG[appBundleId]['pem_path']))
+
+            push_data = {"alert": "Motion ", "event_time": n_time, "event_type": event_type, "msg": "",
+                         "received_at": n_time, "sound": "", "uid": uid, "zpush": "1", "channel": channel}
+            alert = apns2.PayloadAlert(body=msg_text, title=msg_title)
+            payload = apns2.Payload(alert=alert, custom=push_data, sound="default")
+
+            # return uid, channel, appBundleId, str(token_val), event_type, n_time, msg_title,msg_text
+            n = apns2.Notification(payload=payload, priority=apns2.PRIORITY_LOW)
+            res = cli.push(n=n, device_token=token_val, topic=appBundleId)
+            print(res.status_code)
+            LOGGING.info("apns_推送状态:")
+            LOGGING.info(res.status_code)
+
+            if res.status_code == 200:
+                return res.status_code
+            else:
+                print('apns push fail')
+                print(res.reason)
+                LOGGING.info('apns push fail')
+                LOGGING.info(res.reason)
+                return res.status_code
+        except (ValueError, ArithmeticError):
+            return 'The program has a numeric format exception, one of the arithmetic exceptions'
+        except Exception as e:
+            print(repr(e))
+            print('do_apns函数错误行号', e.__traceback__.tb_lineno)
+            LOGGING.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return repr(e)
+
+    @classmethod
+    def async_send_picture_push(cls, push_type, aws_s3_client, bucket, key, uid, appBundleId,
+                                token_val, event_type, n_time, msg_title, msg_text, channel):
+        """
+        异步APP图片推送
+        """
+        try:
+            image_url = aws_s3_client.generate_presigned_url('get_object', Params={'Bucket': bucket, 'Key': key},
+                                                             ExpiresIn=300)
+            LOGGING.info('推送图片url:{}'.format(image_url))
+            if push_type == 0:
+                GatewayPushService.ios_apns_push(uid, appBundleId, token_val, n_time, event_type, msg_title, msg_text,
+                                                 uid, channel, image_url)
+            elif push_type == 1:
+                GatewayPushService.android_fcm_push(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)))
+
+    @staticmethod
+    def get_push_url(**params):
+        """
+        获取推送URL,设备根本当前返回结果进行数据上传
+        @return: re_data
+        """
+        re_data = {'code': 0, 'msg': 'success'}
+        if params['is_st'] == 0 or params['is_st'] == 2:
+            re_data['msg'] = 'success 0 or 2'
+            for up in params['uid_set_push_list']:
+                if up['push_type'] == 0:  # ios apns
+                    up['do_apns_code'] = params['code_dict']['do_apns_code']
+                elif up['push_type'] == 1:  # android gcm
+                    up['do_fcm_code'] = params['code_dict']['do_fcm_code']
+                elif up['push_type'] == 2:  # android jpush
+                    up['do_jpush_code'] = params['code_dict']['do_jpush_code']
+                del up['push_type']
+                del up['userID_id']
+                del up['userID__NickName']
+                del up['lang']
+                del up['tz']
+                del up['uid_set__nickname']
+                del up['uid_set__detect_interval']
+                del up['uid_set__detect_group']
+            re_data['re_list'] = params['uid_set_push_list']
+        elif params['is_st'] == 1:
+            key_name = '{uid}/{channel}/{filename}.jpeg' \
+                .format(uid=params['uid'], channel=params['channel'], filename=params['n_time'])
+            re_args = {'Key': key_name}
+            if params['region'] == 2:  # 2:国内
+                re_args['Bucket'] = 'push'
+            else:  # 1:国外
+                re_args['Bucket'] = 'foreignpush'
+            response_url = DevicePushService.generate_s3_url(params['aws_s3_client'], re_args)
+            re_data['img_push'] = response_url
+        elif params['is_st'] == 3:
+            img_url_list = []
+            if params['region'] == 2:  # 2:国内
+                re_args = {'Bucket': 'push'}
+            else:  # 1:国外
+                re_args = {'Bucket': 'foreignpush'}
+            for i in range(params['is_st']):
+                key_name = '{uid}/{channel}/{filename}_{st}.jpeg'. \
+                    format(uid=params['uid'], channel=params['channel'], filename=params['n_time'], st=i)
+                re_args['Key'] = key_name
+                response_url = DevicePushService.generate_s3_url(params['aws_s3_client'], re_args)
+                img_url_list.append(response_url)
+            re_data['img_url_list'] = img_url_list
+            re_data['msg'] = 'success 3'
+        return re_data
+
+    @staticmethod
+    def generate_s3_url(aws_s3_client, params):
+        """
+        获取S3对象URL
+        """
+        response_url = aws_s3_client.generate_presigned_url(
+            ClientMethod='put_object',
+            Params=params,
+            ExpiresIn=3600
+        )
+        return response_url