pengzhibo168 пре 5 година
комит
c2e3e6a2cc
49 измењених фајлова са 5199 додато и 0 уклоњено
  1. 16 0
      .gitignore
  2. 0 0
      AnsjerPush/__init__.py
  3. 191 0
      AnsjerPush/config.py
  4. 3 0
      AnsjerPush/file/alipay/alipay_private_2048.pem
  5. 3 0
      AnsjerPush/file/alipay/alipay_public_2048.pem
  6. 3 0
      AnsjerPush/file/alipay/zosi_alipay_private_2048.pem
  7. 3 0
      AnsjerPush/file/alipay/zosi_alipay_public_2048.pem
  8. 64 0
      AnsjerPush/file/apns_pem/accloud-dev.pem
  9. 67 0
      AnsjerPush/file/apns_pem/accloud.pem
  10. 64 0
      AnsjerPush/file/apns_pem/customizeda-dev.pem
  11. 68 0
      AnsjerPush/file/apns_pem/customizeda.pem
  12. 64 0
      AnsjerPush/file/apns_pem/customizedb-dev.pem
  13. 68 0
      AnsjerPush/file/apns_pem/customizedb.pem
  14. 68 0
      AnsjerPush/file/apns_pem/lcc-dev.pem
  15. 68 0
      AnsjerPush/file/apns_pem/lcc.pem
  16. 64 0
      AnsjerPush/file/apns_pem/zccloud-dev.pem
  17. 67 0
      AnsjerPush/file/apns_pem/zccloud.pem
  18. 64 0
      AnsjerPush/file/apns_pem/zosidcloud-dev.pem
  19. 67 0
      AnsjerPush/file/apns_pem/zosidcloud.pem
  20. BIN
      AnsjerPush/file/font/simhei.ttf
  21. 184 0
      AnsjerPush/file/log type .txt
  22. 69 0
      AnsjerPush/file/后台管理系统说明.txt
  23. BIN
      AnsjerPush/file/表文档.doc
  24. 149 0
      AnsjerPush/formal_config.py
  25. 179 0
      AnsjerPush/formal_settings.py
  26. 16 0
      AnsjerPush/formal_wsgi.py
  27. 148 0
      AnsjerPush/local_config.py
  28. 196 0
      AnsjerPush/local_settings.py
  29. 16 0
      AnsjerPush/local_wsgi.py
  30. 145 0
      AnsjerPush/settings.py
  31. 146 0
      AnsjerPush/test_config.py
  32. 180 0
      AnsjerPush/test_settings.py
  33. 16 0
      AnsjerPush/test_wsgi.py
  34. 27 0
      AnsjerPush/urls.py
  35. 16 0
      AnsjerPush/wsgi.py
  36. 651 0
      Controller/DetectController.py
  37. 132 0
      Controller/ShadowController.py
  38. 708 0
      Controller/TestDetectController.py
  39. 365 0
      Model/models.py
  40. 68 0
      Object/ETkObject.py
  41. 82 0
      Object/RedisObject.py
  42. 134 0
      Object/ResponseObject.py
  43. 48 0
      Object/UidTokenObject.py
  44. 207 0
      Service/CommonService.py
  45. 22 0
      formal_manage.py
  46. 22 0
      local_manage.py
  47. 15 0
      manage.py
  48. 224 0
      requirements.txt
  49. 22 0
      test_manage.py

+ 16 - 0
.gitignore

@@ -0,0 +1,16 @@
+/.idea
+/static
+/Model/migrations
+/Ansjer/__pycache__
+/Controller/__pycache__
+/Model/__pycache__
+/Object/__pycache__
+/Service/__pycache__
+/Object/AWS/__pycache__
+*.log
+*/__pycache__
+/Ansjer/test/__pycache__
+/Ansjer/test/__init__.py
+/sdk_install
+/DB/mydata4vipday2.ipdb
+/__pycache__/*.pyc

+ 0 - 0
AnsjerPush/__init__.py


+ 191 - 0
AnsjerPush/config.py

@@ -0,0 +1,191 @@
+#!/usr/bin/env python3  
+# -*- coding: utf-8 -*-  
+"""
+@Copyright (C) ansjer cop Video Technology Co.,Ltd.All rights reserved.
+@AUTHOR: ASJRD018
+@NAME: Ansjer
+@software: PyCharm
+@DATE: 2018/7/2 14:06
+@Version: python3.6
+@MODIFY DECORD:ansjer dev
+@file: Conf.py
+@Contact: chanjunkai@163.com
+"""
+# 主要静态变量配置文件
+import datetime, os
+
+
+DEBUG_MODE = 'DEV'
+# MODE = 'PRO'
+# 阿里云发邮箱
+ALY_SES_ACCESS_NAME = 'message@dvema.com'
+ALY_SES_ACCESS_PAW = 'SMtp123456'
+ALY_SES_ACCESS_REPLYTO = '***'
+
+# 发送邮件邮箱
+SES_COMPANY_EMAIL = 'user_server@nsst.com'
+AWS_SES_ACCESS_ID = 'AKIAJKPU23EU5QWHFPKQ'
+AWS_SES_ACCESS_SECRET = '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'
+AWS_SES_ACCESS_REGION = 'us-east-1'
+AWS_BUCKET = 'ansjertest'
+# 设定离线时间为5分钟
+OFF_LINE_TIME_DELTA = 5
+
+# token的secret
+OAUTH_ACCESS_TOKEN_SECRET = 'a+jbgnw%@1%zy^=@dn62%'
+OAUTH_REFRESH_TOKEN_SECRET = 'r+jbgnw%@1%zy^=@dn62%'
+# access_token超时
+# OAUTH_ACCESS_TOKEN_TIME = datetime.timedelta(hours=1)
+OAUTH_ACCESS_TOKEN_TIME = datetime.timedelta(days=30)
+# refresh_token超时
+OAUTH_REFRESH_TOKEN_TIME = datetime.timedelta(days=30)
+# 腾讯验证,短信发送
+TX_PHONE_APP_ID = '1400052907'
+TX_PHONE_APP_KEY = '7705976ca6e85fe7b86d6bc2d11f7783'
+
+# 验证码超时时间
+AuthCode_Expire = 600
+
+# 根路径
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+# uid token key
+UID_TOKEN_KEY = 'c+565*j@%^'
+
+# oss param
+OSS_STS_ACCESS_KEY = 'LTAIyMkGfEdogyL9'
+OSS_STS_ACCESS_SECRET = '71uIjpsqVOmF7DAITRyRuc259jHOjO'
+OSS_ROLE_ARN = 'acs:ram::1901342792446414:role/stsoss'
+
+
+NGINX_RTMP_STAT = 'http://www.dvema.com/stat'
+SERVER_DOMAIN = 'http://www.dvema.com/'
+SERVER_DOMAIN_SSL = 'https://www.dvema.com/'
+DOMAIN_HOST = 'www.dvema.com'
+# SERVER_HOST = 'localhost'
+PAYPAL_CRD = {
+    "mode": "live",  # sandbox or live
+    "client_id": "AdSRd6WBn-qLl9OiQHQuNYTDFSx0ZX0RUttqa58au8bPzoGYQUrt8bc6591RmH8_pEAIPijdvVYSVXyI",
+    "client_secret": "ENT-J08N3Fw0B0uAokg4RukljAwO9hFHPf8whE6-Dwd8oBWJO8AWMgpdTKpfB1pOy89t4bsFEzMWDowm"
+}
+DETECT_PUSH_DOMAIN = 'http://push.dvema.com/'
+
+
+JPUSH_CONFIG = {
+    'com.ansjer.accloud_ab': {
+        'Key': 'f0dc047e5e53fd14199de5b0',
+        'Secret': 'aa7f7db33e9f0a7f3871aa1c'},
+    'com.ansjer.adcloud_ab': {
+        'Key': '76d97b535185114985608234',
+        'Secret': 'c9a92b301043cc9c52778692'},
+    'com.ansjer.zccloud_ab': {
+        'Key': 'd9924f56d3cc7c6017965130',
+        'Secret': '869d832d126a232f158b5987'},
+    'com.ansjer.loocamccloud_ab': {
+        'Key': 'd1cc44797b4642b0e05304fe',
+        'Secret': 'c3e8b4ca8c576de61401e56a'},
+    'com.ansjer.loocamdcloud_ab': {
+        'Key': '76d97b535185114985608234',
+        'Secret': 'c9a92b301043cc9c52778692'},
+    'com.ansjer.zccloud_a': {
+        'Key': '57de2a80d68bf270fd6bdf5a',
+        'Secret': '3d354eb6a0b49c2610decf42'},
+    'com.ansjer.accloud_a': {
+        'Key': 'ff95ee685f49c0dc4013347b',
+        'Secret': 'de2c20959f5516fdeeafe78e'},
+    'com.ansjer.adcloud_a': {
+        'Key': '2e47eb1aee9b164460df3668',
+        'Secret': 'b9137d8d684bc248f1809b6d'},
+    'com.ansjer.loocamccloud_a': {
+        'Key': '23c9213215c7ca0ec945629b',
+        'Secret': '81e4b1e859cc8387e2e6c431'},
+    'com.ansjer.loocamdcloud_a': {
+        'Key': '1dbdd60a16e9892d6f68a073',
+        'Secret': '80a97690e7e043109059b403'},
+    'com.ansjer.customizedb_a': {
+        'Key': '9d79630aa49adfa291fe2568',
+        'Secret': '4d8ff52f88136561875a0212'},
+    'com.ansjer.customizedd_a': {
+        'Key': '8fc4f495685bde53341ee25d',
+        'Secret': 'f1da11fa466509fa2670fb66',
+    }
+}
+# type =1
+FCM_CONFIG = {
+    'com.ansjer.zccloud_a': 'AAAAb9YP3rk:APA91bHu8u-CTpcd0g6lKPo0WNVqCi8jZub1cPPbSAY9AucT1HxlF65ZDUko9iG8q2ch17bwu9YWHpK1xI1gHSRXCslLvZlXEmHZC0AG3JKg15XuUvlFKACIajUFV-pOeGRT8tM6-31I',
+    'com.ansjer.loocamccloud_a': 'AAAAb9YP3rk:APA91bFCgd-kbVmpK4EVpfdHH_PJZQCYTkOGnTZdIuBWEz2r7aMRsJYHOH3sB-rwcbaRWgnufTyjX9nGQxb6KxQbWVk4ah_H-M3IqGh6Mb60WQQAuR33V6g_Jes5pGL6ViuIxGHqVMaR',
+    'com.ansjer.loocamdcloud_a': 'AAAAb9YP3rk:APA91bGw2I2KMD4i-5T7nZO_wB8kuAOuqgyqe5rxmY-W5qkpYEx9IL2IfmC_qf6B_xOyjIDDSjckvMo-RauN__SEoxvAkis7042GRkoKpw7cjZ_H8lC-d50PC0GclPzccrOGFusyKbFY',
+    'com.ansjer.customizedb_a': 'AAAAb9YP3rk:APA91bE7kI4vcm-9h_CJNFlOZfc-xwP4Btn6AnjOrwoKV6fgYN7fdarkO76sYxVZiAbDnxsFfOJyP7vQfwyan6mdjuyD5iHdt_XgO22VqniC0vA1V4GJiCS8Tp7LxIX8JVKZl9I_Powt',
+    'com.ansjer.customizeda_a': 'AAAAb9YP3rk:APA91bF0HzizVWDc6dKzobY9fsaKDK4veqkOZehDXshVXs8pEEvNWjR_YWbhP60wsRYCHCal8fWN5cECVOWNMMzDsfU88Ty2AUl8S5FtZsmeDTkoGntQOswBr8Ln7Fm_LAp1VqTf9CpM',
+    'com.ansjer.customizedd_a': 'AAAAb9YP3rk:APA91bHkxOozJWBrlv3eNT0PgwosYENI9aM4Zuzd418cX-iKkpa1zFNC5MkNDKApx1KH4fhmAfaJ6IMRZ0nj5GIxCpstDYCaZWwgC7-etqfSxG5JAq8LOwJx0o_1tUZqwjIic8ztsg0o',
+    'com.ansjer.adcloud_a': 'AAAAb9YP3rk:APA91bFm06w8b9OKQ0gz0iaWFuRqRIkvgAz6z7Gp3dBU_X-LNGJQd1hc1QR2W7QzBglF8SHtERA45a2lbdLRa5qv7hxfd6W_sJLBK7dA8jklsOQBvy505oUzTwMKWy4TwH-exps9KrhO',
+    'com.ansjer.accloud_a': 'AAAAb9YP3rk:APA91bFm06w8b9OKQ0gz0iaWFuRqRIkvgAz6z7Gp3dBU_X-LNGJQd1hc1QR2W7QzBglF8SHtERA45a2lbdLRa5qv7hxfd6W_sJLBK7dA8jklsOQBvy505oUzTwMKWy4TwH-exps9KrhO',
+    'com.ansjer.zccloud_ab': 'AAAAb9YP3rk:APA91bHu8u-CTpcd0g6lKPo0WNVqCi8jZub1cPPbSAY9AucT1HxlF65ZDUko9iG8q2ch17bwu9YWHpK1xI1gHSRXCslLvZlXEmHZC0AG3JKg15XuUvlFKACIajUFV-pOeGRT8tM6-31I',
+}
+SERVER_TYPE = os.environ.get('DJANGO_SETTINGS_MODULE')
+
+APNS_CONFIG = {
+    'com.ansjer.loocamccloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/lcc-dev.pem',
+    },
+    'com.ansjer.zosidcloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/zosidcloud-dev.pem',
+    },
+    'com.ansjer.customizedb': {
+        'pem_path': 'AnsjerPush/file/apns_pem/customizedb-dev.pem',
+    },
+    'com.ansjer.customizeda': {
+        'pem_path': 'AnsjerPush/file/apns_pem/customizeda-dev.pem',
+    },
+    'com.ansjer.zccloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/zccloud-dev.pem',
+    },
+    'com.ansjer.accloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/accloud-dev.pem',
+    }
+}
+APNS_MODE = 'dev'
+REDIS_ADDRESS = '192.168.136.45'
+
+if SERVER_TYPE == 'AnsjerPush.local_settings':
+    from AnsjerPush.local_config import *
+elif SERVER_TYPE == 'AnsjerPush.test_settings':
+    from AnsjerPush.test_config import *
+elif SERVER_TYPE == 'AnsjerPush.formal_settings':
+    from AnsjerPush.formal_config import *
+
+APNS_CODE = {
+    -1: '只库存不推送',
+    200: '推送成功',
+    400: '请求有问题',
+    403: '证书或Token有问题',
+    405: '请求方式不正确, 只支持POST请求',
+    410: '设备的Token与证书不一致'
+}
+
+JPUSH_CODE = {
+    -1: '只库存不推送',
+    200: '推送成功',
+    400: '错误请求',
+    401: '没有验证信息或者验证失败',
+    403: '请求被拒绝',
+    404: '资源不存在,请求的用户的不存在,请求的格式不被支持',
+    405: '请求方法不合适',
+    410: '请求的资源已下线',
+    429: '请求超出了频率限制',
+    500: '极光内部服务错误',
+    502: '业务服务器下线了或者正在升级。请稍后重试',
+    503: '服务暂时失效',
+    504: '代理超时'
+}
+
+FCM_CODE = {
+    -1: '只库存不推送',
+    200: '推送成功',
+    400: '无效数据',
+    401: '没有验证信息或者验证失败'
+}
+
+APP_TYPE = {
+    1: 'ios',
+    2: 'android'
+}

+ 3 - 0
AnsjerPush/file/alipay/alipay_private_2048.pem

@@ -0,0 +1,3 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCkSf9JD/HprSulQiE6zHkcYX1f5nnDfaM5SCB8iVz/C7ClX+o4fj446kkq74BkB3k40S6RhttQRiRIkRinsR4/ZxgtwWOaUFCPrZebIqm5CBKp6UHCq8aiYFzBomrUWLLvtqfuwMiUh6J+0LLr1lVocQqu2aCCt/D62ac21bAD1WkDQzcDNVoeRAvsnvkyQj2ftN+BdR423/jzWabmNGATBvjk+dzuGMMl8jYDQcJ0nhpOXy3R0ytWMny1OT94VxVX7CwAJt0nzA9aw/f11wfYNqBt33/PuchzHb/Nond/OjIQ2Hg+vVeXnTjoK/FN4Qw5cM0apiHJU2ea7QxhzTZ7AgMBAAECggEBAKPrBOB0HU2mr46Crb8J9qjfiIVf4wuvVmU31toLABOlKUnHql1VcGW/NOO29SZY4pVS+SDQKhAs+9S/mJbwPJrMFS7J7sQv8EF61XI/IpJwQJbxGeDPHTAz7zhwAiD+owJT/7hS945iyjm3p11xi+PaLeuJTgI+3xyaf6FRkf4vnSf1oAicP1Ufg/eHr1BKPpL5BdtSVxtTKwOZpl4IkvvjBTvTVqzl/nHqOJXEew/H2EL48KDMhrZ9IfFCCUgMtowoIys/xcGmcuFbwo1+YIETDCEat4XnGBW/q81C/+l/KtP9scbT17AMBaH0dxLcJHPR1IVn8cVTw+1uctbRRUkCgYEA2wX2cpqGWnfTwb5gPchRr4hTzZx/EpDmNkOiGe1mgwoEH09ucRCAU54IOIWJnlUGO4rs4wwreIA/kO0DQkjM8Q5Xho/Wob/vjLemvgAx1ZaxspIp2fKDd/+Mk1ksXuK9RTASI46uAfQVx4S6vQGAOVnCQd3yHgyeplE9m21X+l0CgYEAwAZ1PqilcjjbhKnIBGbgPNuEGS3MrHanUAEYnb3AAxBjFLioAsgEYCsvE6l2MWz4ZSXLkG7qvNGqndUPY3sxltd9csrYRoTR7wiM1SJ/BVZGS7Bv9DeVlyxVg6WYgjKfDia4+UAIYyJjlB1n4+vmNScnTTzdpHa6CRC0WIAmVrcCgYBkJ+Df3VvM6PjTowv9lKoN++heoM7XHZ24eMsa0h3LlHv4GWmmmGYmVqDpv98DoVvdRJU46mrCitsGmeuglwvou6c4qHP8uXmAvsaoIgyn4GZYA1DSEn0eFaUiCGgq58KnbekNi4R07jo7Z63BGnuZPjt/xU+fgCPYaFQkzCasHQKBgQCoSsCkqq9dXOFe8mG/Id5y17x9SLtxhwf5wQwu6ycGSG1dsrxku6HCGvbGV6WjiaplE2vF6L/HvkW20A0NleGPHsruOUK1AyDuSmMLRJFoPwWavkZQFgr/k7Zai14O9YiaoWtJ30m6gGAfZmovwgZfHTJ/qdFimz9ORJqaWa3AHwKBgH2kjJx5D8c/IuNMQ3yErKj8a41u7852d04W65ZxlhaX3cFGpJVR4REA548U8K9Fy89Z7Xzf6ByI80e9clmy/I71vQfPEpxOGkI/1JnUjHdBDyk6Owqg4zOTUPlF2nUeJfi78G53W/gbqb6kKB2v0cxfk0QElvAPBZGsT9ptZbti
+-----END RSA PRIVATE KEY-----

+ 3 - 0
AnsjerPush/file/alipay/alipay_public_2048.pem

@@ -0,0 +1,3 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6WSh//F8thrOf8Zm5CwIr9+HYy3+K4uRQtZoOolCRkbO47k++4da5/uBJz/vEoyX2/YwyqbdzIRbpwZlSyTKrRJpf5JwUE26dSVIjZ+2FOOUoRqf9MTDHhMEtvRvW2nSD3u4gDSz2vTuQPdiFzpJamuszR9ONdeIIYttoC//BR5TO3aDPHD1Q0D1WVnaBvWWnFUNaaW0BLjqLa3gtxWeUgMSePjusG28EX+aMomqSMReMRC87Hoan0TeQYU35Mgq6ZHGQ8RFBGAPfueHcvvtBLmiuL+UmJS5FyAq6QLCMSd74NnUAJwdQOi4e5vXeQX772DEyA/19RBXA4PESwJ0lwIDAQAB
+-----END PUBLIC KEY-----

+ 3 - 0
AnsjerPush/file/alipay/zosi_alipay_private_2048.pem

@@ -0,0 +1,3 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCAtJ/+dopwzLOA6yq4yDiOIWRs1z1vJicOZF/O1xZOs+UN+B5yJvCsyyInEY9kWFRPoZoYjuZ5x8of23zELozZuebt1cbJOikRhMYQ8HiIZfPX+v9Uqve+j7qDcOAzJJwRz26eak8WA6+au6BVTyOKQa35oY3tbOQWN+Nu7zxqMjxrLmy/+af6WuQhhOY+EYjEMqMpc5iDRJzkSjPuWWzvD9PE5/AJiYsUs0lb9z1s2+O15eKp1nwEOJp3rOwfowin8MjR2BbGZ8SuugK3cU49X84sAsNXo0Anv/htV9Pp6QgAPs0b1E3F3NrHJifl/GAd/hpLby0tsoHKY8d7He+3AgMBAAECggEAEPe/IA0As15JS/W07Cd5TUOZub+mmcCt5XfWKa6xgi61Q+IyIVqA4Ebneb8W6GO8ucLUTeiI+gUc4JZPHI4Gg62+hBxq2JySTXzzn8gUG+dU/mRYxRDFGJpaPHnlFNj+ulpeewQI6R4TSJLz0EtepBuElCR4UZTJfSRhF37yuA03aqp2WVTDmvdLxY8ZIZcbovPA34VIs91Bs+s7UmgQKIT5YkMRUG7En5dgGB0Uce0JeoN35P9U+DrplX0YP51qwf7APQxEeKY/ifaDdGf69tm86wz188/HWOVUeBXKNbcPN/CtreLgb0zR8OLji/FKMIIW3JMrAlQEu3H6t3HIAQKBgQDDufBDF2fn+DmpyggNsKbS/L8M4n9Ak7W/5r3L9vh0RQ+fbqGMazURoqQOt6e+rjnPuoTB42Yk9XEUzZcXF65klq+kY+PVNKOuvVXMJpO+kb71aP6heJ5CQ0KHUsQ2zMxrxl0xdcj8WkBP5mLyz6gdNX8Ypfgq7Rn9YVddYtpPUQKBgQCoVxzyjbEhM5WmhhlUQ+2i/fz0hVmNPC52FN5xhI11VAqT4rS+EBr2LPaWJz0bsVCsaPshePNc/yNwUbWpg4VmdIc9NLHXOyq3mI9uLt4Nzwtm15UrVGuJA2c9CEIBRsrsX89tO1xvOPeHJ0GnX6rV0WByg/uGWyw4Ga3kIG1chwKBgC3t7S6hSHXL7yQjz73+rTcnrmGEqR3rS6QrrnA1lVobdq4QFQLRiZOI2fzGJiv90H0ppMum5CpaGl4qXIFDwl3CapcmBanbf2ma7o5IozT+GJSYPeCAYIrmI6+DwZ2mc3X7B5V6sV5eg2b8hk26YxXvntKW5+SS3R1zgT/d2aLxAoGAMq3XJyaFFuvCt9lTMs0oc5NnXe3vYdemXSI3PZGcTKA6dv8fTsDmfQpYSigR+45MLTuFrzQMgAjHkH7o49mWhZu7Qy/kAlnrqE4jkBZH/3w/gHySifLmVN9Ta0pbJKs9WCAYAFiIoWtTCbtFxq/EbI6WLKOTS4WTMGh6s10Xz20CgYEAmLF68mrO7Noq6w5jy7P2Gb6SvmriUW1jSwcpgq/jC/u83iMg2+++TYmGp01CCxZVPQ+pU8VOuMLoKlm4mn0Im4gxXU6GeGerVb/LO2WkYn7aFMNRV05bgg7nCM5Df1vV6UzYsU4uzM/VC8FFm7/bRTqKv0u3pv+sYGB0YrlZaHs=
+-----END RSA PRIVATE KEY-----

+ 3 - 0
AnsjerPush/file/alipay/zosi_alipay_public_2048.pem

@@ -0,0 +1,3 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1usde7ybZRkDB0cx2a1QAgoVqwV+3HLOmB/f2lmqvWGhT9Kv2T09yu5+HuckQIr7EXIsyd+8gxv483xXkSdzVgm4UKD5QrVSaSs0s0iKOUAc2QOWF/rmzZ8/hDLHteNcYzyOYkr7ws7woCw0aN76oABzpBuch070mvTS7XNvV64YHtBeDo0iAGRaLu7OuHOOUJwQqFGzgaTtZz+TGXNk6ZonfYTcWbTw5Pc4kG9PjweBPpcsJXoCB0Ul9t/V66grhjnJ1TcYqzO0wY1Lr6J3p/0PtKVaG4Ijf6iGfmkOPBMy3lV9NPf/t20nuGLeBPkMMlGTytXVH5DkSB/6INytcQIDAQAB
+-----END PUBLIC KEY-----

+ 64 - 0
AnsjerPush/file/apns_pem/accloud-dev.pem

@@ -0,0 +1,64 @@
+Bag Attributes
+    friendlyName: Apple Development IOS Push Services: com.ansjer.accloud
+    localKeyID: 21 EE 16 12 6C 1D DA 58 D2 49 C0 CC ED FB BC 39 42 F4 CE 08 
+subject=/UID=com.ansjer.accloud/CN=Apple Development IOS Push Services: com.ansjer.accloud/OU=66PK439G56/C=CN
+issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIFiTCCBHGgAwIBAgIIQ5R/pnWDUpgwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
+ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
+aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMjAwNTA3MDAzMDU1WhcNMjEwNTA3MDAzMDU1WjCBiDEiMCAGCgmSJomT8ixk
+AQEMEmNvbS5hbnNqZXIuYWNjbG91ZDFAMD4GA1UEAww3QXBwbGUgRGV2ZWxvcG1l
+bnQgSU9TIFB1c2ggU2VydmljZXM6IGNvbS5hbnNqZXIuYWNjbG91ZDETMBEGA1UE
+CwwKNjZQSzQzOUc1NjELMAkGA1UEBhMCQ04wggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDgFCcND3LLOEj0jxcLQMTrT7CcrNV6M4+UMwbTBKe/U7zkUsW0
+N4GFaMQeRkq9bZgtPpqdq9cqW4ItsNTZpccXyLwBt7hJLMrpOtXFVjfcBflU93Yt
+q1an7jvtUWIKssbNsBjOW4hXeIe+zuvl1mmdr0JKpusFn07uBVB58UMhTyHLNSjy
+F84Gp/EQbi1jLW3uJWnjvoPkp72TBotViN6YWzQyrHSq3LLngHodxVeEj/vJjj3B
+mCfUcKct+DO25pUkyvaZe17fAVlLUKK0jVEyXAhabPc4Ho2Ifh4oIcGVC6CC/0r9
+S0JeD8g18e8zVJTbdH0aB/qReq0EMJD/R4vXAgMBAAGjggHlMIIB4TAJBgNVHRME
+AjAAMB8GA1UdIwQYMBaAFIgnFwmpthhgi+zruvZHWcVSVKO3MIIBDwYDVR0gBIIB
+BjCCAQIwgf8GCSqGSIb3Y2QFATCB8TCBwwYIKwYBBQUHAgIwgbYMgbNSZWxpYW5j
+ZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2Vw
+dGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGljeSBhbmQgY2VydGlm
+aWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjApBggrBgEFBQcCARYdaHR0cDov
+L3d3dy5hcHBsZS5jb20vYXBwbGVjYS8wEwYDVR0lBAwwCgYIKwYBBQUHAwIwTQYD
+VR0fBEYwRDBCoECgPoY8aHR0cDovL2RldmVsb3Blci5hcHBsZS5jb20vY2VydGlm
+aWNhdGlvbmF1dGhvcml0eS93d2RyY2EuY3JsMB0GA1UdDgQWBBQh7hYSbB3aWNJJ
+wMzt+7w5QvTOCDALBgNVHQ8EBAMCB4AwEAYKKoZIhvdjZAYDAQQCBQAwDQYJKoZI
+hvcNAQEFBQADggEBAD0oroTnPITJgN8lwY0oLlVtjVfgcDjSx8lEbTAplLRlCfmm
+3xAgycRlKT4m03di++uvAX53UXOKxq0d5vgDziD6GL7iS9MwZJxfEnNFoAdiwTYP
+zWWpUR57ZeXRSIPaWaDaLSeUeOI6GeZy7v3FeWS+s398FtpFXpJonmFOwEFfMiGN
+OB9Q1jO8rDRlYklHwEjWjE5FIxK3ijApzXFf6xVDBybWggflghPObvxgIUS4Fb+X
+x62NAo/C0EzoA1ZT1YerYgNTiLVxvDsv8SAPZdwdpQ1xix02iKgxoIdHN9RLq8M8
+9OXTJXoJuGYZ+hVoG4IQ/dYYTmoZMCRxRZWh0TM=
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA4BQnDQ9yyzhI9I8XC0DE60+wnKzVejOPlDMG0wSnv1O85FLF
+tDeBhWjEHkZKvW2YLT6anavXKluCLbDU2aXHF8i8Abe4SSzK6TrVxVY33AX5VPd2
+LatWp+477VFiCrLGzbAYzluIV3iHvs7r5dZpna9CSqbrBZ9O7gVQefFDIU8hyzUo
+8hfOBqfxEG4tYy1t7iVp476D5Ke9kwaLVYjemFs0Mqx0qtyy54B6HcVXhI/7yY49
+wZgn1HCnLfgztuaVJMr2mXte3wFZS1CitI1RMlwIWmz3OB6NiH4eKCHBlQuggv9K
+/UtCXg/INfHvM1SU23R9Ggf6kXqtBDCQ/0eL1wIDAQABAoIBAQDEcuaJnLGXWJEd
+VxVs2CvL4OGFekDuEaYe1110QvCN3GwOAEMz7DWxMFg/8oAz8pEnmWsUMENC71cB
+l7YD2kLhpyqsltUJ0itSrjIb/6qZSuN8ijchcsVWFJaVSHQbzQBd87TLtZOinBjm
+P6KwrXmKtMv5hr0lALXCFwam4c1otMNFXi2jl1YQl/sXRyqQRlbUVo7vOveoHAFl
+NIei4sE7Zx1yIiM0ksAPiUIJwDfhuYWiBwZbiatC213t+sE1b4Lo1Dk4xe/IlXXm
+9YiQljxwIs8CdR/wDJ8AEmDf5utb5LhcJrmComHXyxsmNEJJuTEsfVqkAA78TH+w
+wT2HMqYBAoGBAPf/rbZINMZmYslaAO2nvuMU6rrGvaYrOaYpggxYJDKZwFhhdkR6
+CzWlzLl1e5PfQLjgTzcnT6Kl/TGOHWwtPINC1Sm+44IWfVgCEpdp0aW4wWYOu9ZB
+sYFPOiUcgRkcPldSqCoU9A3h4YqBOOoqZydwgeMR4LsTyTwltyY6EYZxAoGBAOdO
+6KxULMVvKRYbgUXms04P/beSKK+oYCXOppYgNRqAUHbm0G9AebYiplfZQP0GZkFK
+ki7epk6EnDvEYyjYytNlYsrfBFOhEbwmwjd2y5SiUEhymPN0+tiyPMS1ea8W2ZmZ
+bMZ4k8fv99WL4GejEzvGax7EPPpbR87XMtko8arHAoGBAPT7mbqLsbabxdJqGqiq
+IKNqMka3tPjFknlWX6WaHIfv4lZsUMxsU053rrk2GRGGZQU8cIRnTP+7QVcGsIIA
+Xdq81p4ad9w2IzQhOARjADrZPBN5Uozg8Fxwy1uFwPHxOJRCjuSjNkPQc2DDLloD
+8UrAlU6ehoXHke7cwwP8MPvBAoGAFuRSVqvF+owzzsJOGvLoD/O5Mm++oxPQ4C0B
+g54QY10LmZjiTABfi00GlW8k5WW6vP96VDUo1GB/bdLT1XkPKbjA/D7yGKy6KprT
+YdXZ9A3UUDc3N/D92nBZX0Zukot6YZ8zirjoN0NijbnYLamP/7x1YYgeWNCr3Kaj
+m6ZXtIUCgYB3HRwiY6rv+4GZfxcHolTeZuV+38uogK65/mntMJrQHDW/CAOER+sj
+sddGGic7UhFeXg8pePqZ9pu091AI40iYSCnap+tnIAby7pPC6GeDhzXdy0Kt3PKL
+K9JU7kNg2TUCje/YJgyhFIFNwIkeAorGjFpoN2ok5W2dTARGcT9+7w==
+-----END RSA PRIVATE KEY-----

+ 67 - 0
AnsjerPush/file/apns_pem/accloud.pem

@@ -0,0 +1,67 @@
+Bag Attributes
+    friendlyName: Apple Push Services: com.ansjer.accloud
+    localKeyID: 21 EE 16 12 6C 1D DA 58 D2 49 C0 CC ED FB BC 39 42 F4 CE 08 
+subject=/UID=com.ansjer.accloud/CN=Apple Push Services: com.ansjer.accloud/OU=66PK439G56/O=side zhang/C=US
+issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIGFTCCBP2gAwIBAgIIa8UIpVRjdUswDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
+ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
+aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMjAwNTA3MDIyMzExWhcNMjEwNjA2MDIyMzExWjCBjTEiMCAGCgmSJomT8ixk
+AQEMEmNvbS5hbnNqZXIuYWNjbG91ZDEwMC4GA1UEAwwnQXBwbGUgUHVzaCBTZXJ2
+aWNlczogY29tLmFuc2plci5hY2Nsb3VkMRMwEQYDVQQLDAo2NlBLNDM5RzU2MRMw
+EQYDVQQKDApzaWRlIHpoYW5nMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAOAUJw0Pcss4SPSPFwtAxOtPsJys1Xozj5QzBtMEp79T
+vORSxbQ3gYVoxB5GSr1tmC0+mp2r1ypbgi2w1NmlxxfIvAG3uEksyuk61cVWN9wF
++VT3di2rVqfuO+1RYgqyxs2wGM5biFd4h77O6+XWaZ2vQkqm6wWfTu4FUHnxQyFP
+Ics1KPIXzgan8RBuLWMtbe4laeO+g+SnvZMGi1WI3phbNDKsdKrcsueAeh3FV4SP
++8mOPcGYJ9Rwpy34M7bmlSTK9pl7Xt8BWUtQorSNUTJcCFps9zgejYh+HighwZUL
+oIL/Sv1LQl4PyDXx7zNUlNt0fRoH+pF6rQQwkP9Hi9cCAwEAAaOCAmwwggJoMAwG
+A1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUiCcXCam2GGCL7Ou69kdZxVJUo7cwggEc
+BgNVHSAEggETMIIBDzCCAQsGCSqGSIb3Y2QFATCB/TCBwwYIKwYBBQUHAgIwgbYM
+gbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1
+bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0
+ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGljeSBh
+bmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjA1BggrBgEFBQcC
+ARYpaHR0cDovL3d3dy5hcHBsZS5jb20vY2VydGlmaWNhdGVhdXRob3JpdHkwEwYD
+VR0lBAwwCgYIKwYBBQUHAwIwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL2NybC5h
+cHBsZS5jb20vd3dkcmNhLmNybDAdBgNVHQ4EFgQUIe4WEmwd2ljSScDM7fu8OUL0
+zggwDgYDVR0PAQH/BAQDAgeAMBAGCiqGSIb3Y2QGAwEEAgUAMBAGCiqGSIb3Y2QG
+AwIEAgUAMH0GCiqGSIb3Y2QGAwYEbzBtDBJjb20uYW5zamVyLmFjY2xvdWQwBQwD
+YXBwDBdjb20uYW5zamVyLmFjY2xvdWQudm9pcDAGDAR2b2lwDB9jb20uYW5zamVy
+LmFjY2xvdWQuY29tcGxpY2F0aW9uMA4MDGNvbXBsaWNhdGlvbjANBgkqhkiG9w0B
+AQsFAAOCAQEAxVbw8gXMQ/bb/X9uwJ+mqM0PTzfyh21Rzkr40IKJQQaf/dY/Rl07
+mk889Rm6ksQBwTRMeyZghAmfQripZJO+XRRWCjgEX9FxjIatpiYaA46A5N0Qwj+P
+E4564uAF3yYq0xwhJx7SSwSBd00Bc4B7WSgDWCkuJ05kbQe+i4lhcTmDPz5jc/qJ
+4lOZHMZ3JhAQJ4+EhT29BNb/YMBte/S5brAIqjVTZVnfTAtPj9S9A26l0Buor51i
+YXphJJZWDLV9nerkLCVW5/kwcGt1tzuecCHKD0fgkxMfmyaibavEOzWDDsJSOL8R
+m43aKy9xPVw+wvGxv0UbSv3YFwsUYMS+yA==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA4BQnDQ9yyzhI9I8XC0DE60+wnKzVejOPlDMG0wSnv1O85FLF
+tDeBhWjEHkZKvW2YLT6anavXKluCLbDU2aXHF8i8Abe4SSzK6TrVxVY33AX5VPd2
+LatWp+477VFiCrLGzbAYzluIV3iHvs7r5dZpna9CSqbrBZ9O7gVQefFDIU8hyzUo
+8hfOBqfxEG4tYy1t7iVp476D5Ke9kwaLVYjemFs0Mqx0qtyy54B6HcVXhI/7yY49
+wZgn1HCnLfgztuaVJMr2mXte3wFZS1CitI1RMlwIWmz3OB6NiH4eKCHBlQuggv9K
+/UtCXg/INfHvM1SU23R9Ggf6kXqtBDCQ/0eL1wIDAQABAoIBAQDEcuaJnLGXWJEd
+VxVs2CvL4OGFekDuEaYe1110QvCN3GwOAEMz7DWxMFg/8oAz8pEnmWsUMENC71cB
+l7YD2kLhpyqsltUJ0itSrjIb/6qZSuN8ijchcsVWFJaVSHQbzQBd87TLtZOinBjm
+P6KwrXmKtMv5hr0lALXCFwam4c1otMNFXi2jl1YQl/sXRyqQRlbUVo7vOveoHAFl
+NIei4sE7Zx1yIiM0ksAPiUIJwDfhuYWiBwZbiatC213t+sE1b4Lo1Dk4xe/IlXXm
+9YiQljxwIs8CdR/wDJ8AEmDf5utb5LhcJrmComHXyxsmNEJJuTEsfVqkAA78TH+w
+wT2HMqYBAoGBAPf/rbZINMZmYslaAO2nvuMU6rrGvaYrOaYpggxYJDKZwFhhdkR6
+CzWlzLl1e5PfQLjgTzcnT6Kl/TGOHWwtPINC1Sm+44IWfVgCEpdp0aW4wWYOu9ZB
+sYFPOiUcgRkcPldSqCoU9A3h4YqBOOoqZydwgeMR4LsTyTwltyY6EYZxAoGBAOdO
+6KxULMVvKRYbgUXms04P/beSKK+oYCXOppYgNRqAUHbm0G9AebYiplfZQP0GZkFK
+ki7epk6EnDvEYyjYytNlYsrfBFOhEbwmwjd2y5SiUEhymPN0+tiyPMS1ea8W2ZmZ
+bMZ4k8fv99WL4GejEzvGax7EPPpbR87XMtko8arHAoGBAPT7mbqLsbabxdJqGqiq
+IKNqMka3tPjFknlWX6WaHIfv4lZsUMxsU053rrk2GRGGZQU8cIRnTP+7QVcGsIIA
+Xdq81p4ad9w2IzQhOARjADrZPBN5Uozg8Fxwy1uFwPHxOJRCjuSjNkPQc2DDLloD
+8UrAlU6ehoXHke7cwwP8MPvBAoGAFuRSVqvF+owzzsJOGvLoD/O5Mm++oxPQ4C0B
+g54QY10LmZjiTABfi00GlW8k5WW6vP96VDUo1GB/bdLT1XkPKbjA/D7yGKy6KprT
+YdXZ9A3UUDc3N/D92nBZX0Zukot6YZ8zirjoN0NijbnYLamP/7x1YYgeWNCr3Kaj
+m6ZXtIUCgYB3HRwiY6rv+4GZfxcHolTeZuV+38uogK65/mntMJrQHDW/CAOER+sj
+sddGGic7UhFeXg8pePqZ9pu091AI40iYSCnap+tnIAby7pPC6GeDhzXdy0Kt3PKL
+K9JU7kNg2TUCje/YJgyhFIFNwIkeAorGjFpoN2ok5W2dTARGcT9+7w==
+-----END RSA PRIVATE KEY-----

+ 64 - 0
AnsjerPush/file/apns_pem/customizeda-dev.pem

@@ -0,0 +1,64 @@
+Bag Attributes
+    friendlyName: Apple Development IOS Push Services: com.ansjer.customizeda
+    localKeyID: 70 A0 2E 70 8B E6 88 0C F6 4D 4E 9F D8 21 23 3F 4A E7 87 86 
+subject=/UID=com.ansjer.customizeda/CN=Apple Development IOS Push Services: com.ansjer.customizeda/OU=47V9C97WG7/C=AU
+issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIFkTCCBHmgAwIBAgIIBpjLEWeGlpowDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
+ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
+aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMTkxMTA4MDk0MjUwWhcNMjAxMTA3MDk0MjUwWjCBkDEmMCQGCgmSJomT8ixk
+AQEMFmNvbS5hbnNqZXIuY3VzdG9taXplZGExRDBCBgNVBAMMO0FwcGxlIERldmVs
+b3BtZW50IElPUyBQdXNoIFNlcnZpY2VzOiBjb20uYW5zamVyLmN1c3RvbWl6ZWRh
+MRMwEQYDVQQLDAo0N1Y5Qzk3V0c3MQswCQYDVQQGEwJBVTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAKcXmdal9BeTF5liE+sIwHVleH3ElolMN2A1qsHI
+rfAeXc+DkHvjqk9W+1+BSln2jkfn0/8UBpIt9WG1Jusj9R4fn5mT0nP81BKL/c64
+qrWGFG4THELiT6Sz9JFYh7co2WFCmLFM7tDStiIWGmWbVKgVs8Vq9tE9zscuyeyo
+W/JfV5Ab7L30qkmpv0dq7S5sQUBBFu+Vs9IshUA/SgoVfutPBSCLrGD+/URAa3p6
+qtnEMxaRXKlxJfrMn6Pxlc8Eyhx/0a1Bn/TJBbGxdvc0+Pxw95hNGhRXwOVN43IL
+q5pepm0UQyri8SPm33/o+9oaJqNzC1gS94e5zqafMdvOb+MCAwEAAaOCAeUwggHh
+MAkGA1UdEwQCMAAwHwYDVR0jBBgwFoAUiCcXCam2GGCL7Ou69kdZxVJUo7cwggEP
+BgNVHSAEggEGMIIBAjCB/wYJKoZIhvdjZAUBMIHxMIHDBggrBgEFBQcCAjCBtgyB
+s1JlbGlhbmNlIG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3Vt
+ZXMgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRl
+cm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFu
+ZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMCkGCCsGAQUFBwIB
+Fh1odHRwOi8vd3d3LmFwcGxlLmNvbS9hcHBsZWNhLzATBgNVHSUEDDAKBggrBgEF
+BQcDAjBNBgNVHR8ERjBEMEKgQKA+hjxodHRwOi8vZGV2ZWxvcGVyLmFwcGxlLmNv
+bS9jZXJ0aWZpY2F0aW9uYXV0aG9yaXR5L3d3ZHJjYS5jcmwwHQYDVR0OBBYEFHCg
+LnCL5ogM9k1On9ghIz9K54eGMAsGA1UdDwQEAwIHgDAQBgoqhkiG92NkBgMBBAIF
+ADANBgkqhkiG9w0BAQUFAAOCAQEAURmmauUmkpMpaXbIAvgXMJwXkjKI0GT9aXLM
+bnwstmVMNZtGNMHzb2U2x81TlEoSdH4+F+9n7DkcrUzrY1Gcr4Q9jkBJ48SrLrq4
+yMmcmz/7Gasph8td19JUP7+wnYrRDQfDynntmkQvnfLhttMUvI0XADcdunui8u9T
+CxZxX300PqHCXW4/D7gOVUuW/PSazxvqN6cTHfAavhbBJqwNP4idNpCUL+D5XSrS
+3OYlyBsvwYFGMcwIa6rmKJCPqBJv71ewk3iK1eRfckZk9imHwRVAfsekQ3VlpFZV
+DZcFTFAjMuvPOYG90ge+lTU6XACctgkbT5y5fBz3Jd/snkpshA==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEApxeZ1qX0F5MXmWIT6wjAdWV4fcSWiUw3YDWqwcit8B5dz4OQ
+e+OqT1b7X4FKWfaOR+fT/xQGki31YbUm6yP1Hh+fmZPSc/zUEov9zriqtYYUbhMc
+QuJPpLP0kViHtyjZYUKYsUzu0NK2IhYaZZtUqBWzxWr20T3Oxy7J7Khb8l9XkBvs
+vfSqSam/R2rtLmxBQEEW75Wz0iyFQD9KChV+608FIIusYP79REBrenqq2cQzFpFc
+qXEl+syfo/GVzwTKHH/RrUGf9MkFsbF29zT4/HD3mE0aFFfA5U3jcgurml6mbRRD
+KuLxI+bff+j72homo3MLWBL3h7nOpp8x285v4wIDAQABAoIBAEqx+TqEa27SeZ0+
+w+qwueCBIPEQHb94y9R9iT0hqegKmyM2DDPl3W+kUbErCgLXfllUoGeKGznjw6sP
+ITvCkkQKHP25oD3rix5TaH2t/dox+xYOAvc/Vh0puS30Zo8ResPI0puH6cZ+O59X
+RCuh2aFeOkQJghady78tAmWCCcB593j4e63pds1dcoCO5TnysQwntwdgpBMvo5yH
+QuazSIHCu1YAmFrz5SwDAqq35hqYGlPpDzStRjTYmNg68ubbOeFGSKknEOzYhKGV
+TnCftDEAkePDBoNT5Mx7mJ+LV4JHBvXMyXSOJX07Wm1yZNMAkibjdxzrcRxtfTpU
+7rYKxZkCgYEA2QLVZZ3JEqqdEI+/5f307ExnGuIR5Z81p7xta81Z50dHQ0w+FglX
+62U9evZQ4iW3+/aoPP/kX22xrjf463wP/ou7f9Jhim7AFqdHud4tEqKubljde6dF
+Hh3CVpwtZLII768GQYHl+DlVVPg/NFhVy4EkfOXxfG4+R8SLsy9ugMcCgYEAxRzO
+z2vVCz7J2s0U6NNn+GZkfZOoAOGtIo/YMxEnf04E5iEy7JmfgGQyKboZOhNnndLI
+6f7G7/f9yWcdYbQUPLXyL8OMCBpF18UugL6OK8cBc4xXOnoE48Un+oYFFRhR27b8
+4Kl9Xpkju4I6y12dMwExXMirBKoedd8hSH0WtAUCgYA9KndLdPW/tScgC+RixvnJ
+wJ8vDJlOx1kwNgQBZpf4gDat2UeGnouRZa+2gMa7dzYsZpF04AtWemyiVlRqy0UW
+0fu/Q2UKx7yMpgmpcd3yargPkiybNcJdgrXMA6knwKaUKBjzTdGr7T0H/hCSiHNm
+MLhAG++8yrXzNIrLrorO8QKBgExoz26usWZrj5om180tbmdnYdsgKwc0dIYqVrft
+FW+PEe0Xv4LiRmdh7+QnBPJzZT5T4Jh8sCeD7bhuJYCjaxjhuyFy30ygyqRLBqzX
+sYsc2N4u7/12IYEeA1JlM4Eq7UiL1dlNOpE6MhTU9e+xuWd1Nepuy4TCYY510ZQl
+EXD1AoGAU19qzaVNhV8I3bnzyQ0m80ouvvRQFiLbxC32QQMyrk7fOfi9p+w3ImHn
+2sYj1p5V1yMx9I4nRoLhLMRyX+Nm5uiVCQLAjE9qd3ES9QKAWhvbSAU2t/RSw0pa
+EYxBc50Xw8vE9x6OI6g9yONgxaXwezhXUsb6uASSZ95SFQQIEBc=
+-----END RSA PRIVATE KEY-----

+ 68 - 0
AnsjerPush/file/apns_pem/customizeda.pem

@@ -0,0 +1,68 @@
+Bag Attributes
+    friendlyName: Apple Push Services: com.ansjer.customizeda
+    localKeyID: 41 CD F5 C7 FD 58 97 EA 6B 33 76 8B A7 8F 42 62 B9 12 E5 44 
+subject=/UID=com.ansjer.customizeda/CN=Apple Push Services: com.ansjer.customizeda/OU=47V9C97WG7/O=UNIDEN AUSTRALIA PTY. LIMITED/C=AU
+issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIGPTCCBSWgAwIBAgIIPFtx2BfR7BYwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
+ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
+aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMjAwMjEwMDEyODUzWhcNMjEwMzExMDEyODUzWjCBqDEmMCQGCgmSJomT8ixk
+AQEMFmNvbS5hbnNqZXIuY3VzdG9taXplZGExNDAyBgNVBAMMK0FwcGxlIFB1c2gg
+U2VydmljZXM6IGNvbS5hbnNqZXIuY3VzdG9taXplZGExEzARBgNVBAsMCjQ3VjlD
+OTdXRzcxJjAkBgNVBAoMHVVOSURFTiBBVVNUUkFMSUEgUFRZLiBMSU1JVEVEMQsw
+CQYDVQQGEwJBVTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJcGaIX
+kGE5BasQkg+gg+G6h29kVyS1i57JasNUbvEA5hJyF2c21/2PAxNs7c9UE4aoDtFs
+i9E5o10gQ2hZK8Gpznbx5m5cby0226/BzMgmgVw+MP9y/QrV/RQdF29XbvxldF24
+PW5d1ym3Mqf4Rh1+I3P2zHoAI0M1dccSZHBXpN08nGeuqBka0I7vXAdUaBBWT4Ls
+TTj4/XdNF80JTG8GCovVlnQlGGYSccVBGXtA0E/syNkn6KWuj54ZdDbhLg61a8jt
+Tda6rApAJv2/FUYIZCzMjKXlOti42V1su5KzVAUMvjm+l2DMQUlrB5wMbLbagEuv
+E88Zr4u2axshCIsCAwEAAaOCAnkwggJ1MAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgw
+FoAUiCcXCam2GGCL7Ou69kdZxVJUo7cwggEcBgNVHSAEggETMIIBDzCCAQsGCSqG
+SIb3Y2QFATCB/TCBwwYIKwYBBQUHAgIwgbYMgbNSZWxpYW5jZSBvbiB0aGlzIGNl
+cnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhl
+IHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBv
+ZiB1c2UsIGNlcnRpZmljYXRlIHBvbGljeSBhbmQgY2VydGlmaWNhdGlvbiBwcmFj
+dGljZSBzdGF0ZW1lbnRzLjA1BggrBgEFBQcCARYpaHR0cDovL3d3dy5hcHBsZS5j
+b20vY2VydGlmaWNhdGVhdXRob3JpdHkwEwYDVR0lBAwwCgYIKwYBBQUHAwIwMAYD
+VR0fBCkwJzAloCOgIYYfaHR0cDovL2NybC5hcHBsZS5jb20vd3dkcmNhLmNybDAd
+BgNVHQ4EFgQUQc31x/1Yl+prM3aLp49CYrkS5UQwDgYDVR0PAQH/BAQDAgeAMBAG
+CiqGSIb3Y2QGAwEEAgUAMBAGCiqGSIb3Y2QGAwIEAgUAMIGJBgoqhkiG92NkBgMG
+BHsweQwWY29tLmFuc2plci5jdXN0b21pemVkYTAFDANhcHAMG2NvbS5hbnNqZXIu
+Y3VzdG9taXplZGEudm9pcDAGDAR2b2lwDCNjb20uYW5zamVyLmN1c3RvbWl6ZWRh
+LmNvbXBsaWNhdGlvbjAODAxjb21wbGljYXRpb24wDQYJKoZIhvcNAQELBQADggEB
+AE9Kl2OX9Ba4YsBzVzE9k4FKiXtPvxSl+M4ratIgyiHYvOP0e5ekUjZlZDe2NiFc
+pcMG9sQ873GNsSY8QZCwrKYYaDapBcTF8Yy678GPsVBDDyjXyN/9Lmrc9LI1BZuH
+1eWHAOn17Em2vtjWF7Su6p2x7ju4lhuquwUdAWNe4R2S9b2JQAPnmkXR+5QLyxxM
+GyNprcyJnwq2JGq0kq33Io3ffezI5PE5wZVrAXpAqt/hrrdkMo9OZlmhmWJrp2IV
+pmtr16oEdbnsEZsELQIh6Jl4nLo2cjIpqiDq9PKjee27rN08HvVmgTce4ZJ2z5iR
+G3STaZCv9dCxRXvDTdaYIWw=
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAslwZoheQYTkFqxCSD6CD4bqHb2RXJLWLnslqw1Ru8QDmEnIX
+ZzbX/Y8DE2ztz1QThqgO0WyL0TmjXSBDaFkrwanOdvHmblxvLTbbr8HMyCaBXD4w
+/3L9CtX9FB0Xb1du/GV0Xbg9bl3XKbcyp/hGHX4jc/bMegAjQzV1xxJkcFek3Tyc
+Z66oGRrQju9cB1RoEFZPguxNOPj9d00XzQlMbwYKi9WWdCUYZhJxxUEZe0DQT+zI
+2Sfopa6Pnhl0NuEuDrVryO1N1rqsCkAm/b8VRghkLMyMpeU62LjZXWy7krNUBQy+
+Ob6XYMxBSWsHnAxsttqAS68Tzxmvi7ZrGyEIiwIDAQABAoIBAH+3E2POG8SCYFyt
+8Ojft4/bUT+iSgQvO1roP1q/CvHoAtcSe0+dJeyai0lNprvfKFwz2uh7IWMgMqps
+f9gogfya6wyhCq/b4IAv1/9ydoCbkeXLYqqIXEl2EVJlwnIn2YFB5KF3XAW7jGaC
+l/NPBGX5/Mj84E476wQlM8DomqMV6/tk+0uWMsoMepk3zbYe22xSykYQlYruxYmx
+WNd94WdzY2SHHNklA6wXOO9IGuDly369exOy8jVxpTm1TD7MaJdblfviwxinExoE
+dkewlTV4yv6v/o/nZGtaSWxNpPIHSWLS+mHIAti8etlr2O88YCQ/pmPPb77isxkA
+pYDhswECgYEA6Q03+Uu246JyOMmWvmpIY96f0UYqVgnXIe7c+4hrtyl+aAEerpml
+Zw5SwY5E4mwk/S3AnTScRKMZr6CkEZ/EB7L3b08bDNFHDhIjTGc0EtsOU07wcV33
+xLsMsK2+KNhB8qiEhuASubzeSOW26OJnm8JAIyHyBsGr2nJ+njXK9mMCgYEAw+w0
+hNGuoij7Iwr8Durr+ajGsRMm42U5VYIHW3/uW7knNzpxxTNt/eI0+ANO51IjWcku
+vEN/eeTiaTlG6xP31v92Ksg9ngCYeTec+7BtswuAISXO2seW8NIBaHQ0MjIKaWxv
+94VMs9PwTq4IKQ0k81dod62XPPrTEciMYqoeibkCgYB3l8f0j00gDXmt+Iz51BKn
+5VOAEhChrFUQ3cHa9kvIZ2uttX1oPgJqGyiOmRJyWuq0XaktQxU6B7SjsrzfKmxv
+QwDExwRrlG1xJA+nIoLPdkgoqiarFnySISbG97HQxgE5pA62JACX/frXz8IISj6+
+6HT/Umkf3HzzEbQ2PgaUXwKBgQCuhVd7AHS4yhx66KwCdczhxS/ISDEZ2e8qdfsr
+zFd8qP9/uLXjXZ6aysc4LWo5r/cBYa4Z0V5aLEJqTLUZbd4VS9Xs4hXRCuLHB3z0
+zgHJvXLTFCSgya1wswDCFNDx7ZVMt2U9bSYYAbBLxcZLGwRRJwlNofnYPe2KJ8S1
+lqhBMQKBgQCl853It5ykvk7pSzqC2N+kKV9k2YJE+hNAz2gseSyNi/570l6r4C8D
+VSaSjYJoWSu4T/P8R90pqLrZTm7wDkI5F9kCAfp0hz2AKeL91KksawhD2Tr6OXBQ
+r92aaisJK3Azn8m70ss9GuoB+b35KIaCGfo9XJXyH/0hGZr7/7ZVNA==
+-----END RSA PRIVATE KEY-----

+ 64 - 0
AnsjerPush/file/apns_pem/customizedb-dev.pem

@@ -0,0 +1,64 @@
+Bag Attributes
+    friendlyName: Apple Development IOS Push Services: com.ansjer.customizedb
+    localKeyID: 53 D0 A7 6B CF E9 9C 46 ED 44 01 01 01 14 02 52 A6 45 AB C5 
+subject=/UID=com.ansjer.customizedb/CN=Apple Development IOS Push Services: com.ansjer.customizedb/OU=485ZBTNP7J/C=AU
+issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIFkTCCBHmgAwIBAgIIFWKl1P6fRqAwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
+ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
+aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMTkxMTA4MDgzNzI3WhcNMjAxMTA3MDgzNzI3WjCBkDEmMCQGCgmSJomT8ixk
+AQEMFmNvbS5hbnNqZXIuY3VzdG9taXplZGIxRDBCBgNVBAMMO0FwcGxlIERldmVs
+b3BtZW50IElPUyBQdXNoIFNlcnZpY2VzOiBjb20uYW5zamVyLmN1c3RvbWl6ZWRi
+MRMwEQYDVQQLDAo0ODVaQlROUDdKMQswCQYDVQQGEwJBVTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBANOI0TfZ1x5kwSw7/Sdr+oNxgPeJxZq7Khib9IvQ
+5ZW0hqEXgnm9dyDjpAc2FDjL/FzMUtCviJmxQrISW3dzcwtkKzY//vlQ58ZhlNVG
+m6COjzeJKnP2kdmXipzt9kwPK6tfNxhrNFqUXMH889soFL49W0AykK/hrUKD++0c
+IwXed4lRAxXJORePI27ErhRT8+B5yTjLnZOa+4kwwS2RstGioKHTjpVKDZwYuaM0
+72P4QK+fetFv9dl049sM+1oJ7Z0sT5wvWV0l2TLGTkoma+GR+JCU5GGAmtLyvrco
+NlKLw8JGqSBstZbp1dQFA7BAIuyEt+Jxjkzgu4s+2FROvnUCAwEAAaOCAeUwggHh
+MAkGA1UdEwQCMAAwHwYDVR0jBBgwFoAUiCcXCam2GGCL7Ou69kdZxVJUo7cwggEP
+BgNVHSAEggEGMIIBAjCB/wYJKoZIhvdjZAUBMIHxMIHDBggrBgEFBQcCAjCBtgyB
+s1JlbGlhbmNlIG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3Vt
+ZXMgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRl
+cm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFu
+ZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMCkGCCsGAQUFBwIB
+Fh1odHRwOi8vd3d3LmFwcGxlLmNvbS9hcHBsZWNhLzATBgNVHSUEDDAKBggrBgEF
+BQcDAjBNBgNVHR8ERjBEMEKgQKA+hjxodHRwOi8vZGV2ZWxvcGVyLmFwcGxlLmNv
+bS9jZXJ0aWZpY2F0aW9uYXV0aG9yaXR5L3d3ZHJjYS5jcmwwHQYDVR0OBBYEFFPQ
+p2vP6ZxG7UQBAQEUAlKmRavFMAsGA1UdDwQEAwIHgDAQBgoqhkiG92NkBgMBBAIF
+ADANBgkqhkiG9w0BAQUFAAOCAQEAIvlmy2VPFbbY0BdmA1LjoGfUOtcJd8B6gpav
+n0oVzohIT1t8TBe/GPvgMFmGgPDJkuyJnI7lwvsxUoIJ/eJu+We2Y0iF8BvE3hPx
+VU+epvzOmxFnsxg+2go3pZEGv2eRgmbarYai5N37x0ERES3F4dQDzsnr1gxAO1QH
+fZr39DL0wU9gJUEq1wNsAt6CDyCdsdQPuwuB6X0iVeCiRs5SnjR4x7HDC4DlzC8q
+5Azej615Nel88V6+Cvu7evc7kyT8iAXsUCJSiL8ioxaLfHLZ7HjO567+aWidcG6e
+E5wHJ8wvVe+SCgSrCz1z+LU+7VaYrr+0hw/coxUtlZ/U/LJerg==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA04jRN9nXHmTBLDv9J2v6g3GA94nFmrsqGJv0i9DllbSGoReC
+eb13IOOkBzYUOMv8XMxS0K+ImbFCshJbd3NzC2QrNj/++VDnxmGU1UaboI6PN4kq
+c/aR2ZeKnO32TA8rq183GGs0WpRcwfzz2ygUvj1bQDKQr+GtQoP77RwjBd53iVED
+Fck5F48jbsSuFFPz4HnJOMudk5r7iTDBLZGy0aKgodOOlUoNnBi5ozTvY/hAr596
+0W/12XTj2wz7WgntnSxPnC9ZXSXZMsZOSiZr4ZH4kJTkYYCa0vK+tyg2UovDwkap
+IGy1lunV1AUDsEAi7IS34nGOTOC7iz7YVE6+dQIDAQABAoIBAATziOIjyTM+7H6a
+kNxhXKXC/F/O678pblzRGbJEG3ublCMlJ7qtwqIUcfxxOZvyul95sN6NnUbrrUH5
+yAZNv32exJwqd09io2ozUoaDdpUVgSitnz7DoLpVH7t4nnE9UapbOjDqIXmVS26G
++zZAA+xIB2DDTjuvrpyF9lmgdPloJsA3Q+X3nFfNgbt8Z8xGF2xs8a3R/83k8y+F
+UueDV56v/ivIebPULSOsktEQXtKDgYLNIuMXDztJSflTr0M+Uq9qPIs6fQl55ssk
+o7G55vAzlTBlwSWiOSubecAmiyFeWY3E16uVAYcTKXYEjSpFTqAyNjBTElsgSiuh
+kSODACkCgYEA898WP5Edd9tUgJCr0OQcxdCmXhTZI2fcAqEcjfCyxKHRXAzDwrKN
+Dpx5Es+Ymn2bRGoLCYpeXpxHZTnuRakrO8zM34PbCWWul14oAKzB5vn7TRuNJXOE
+HeOeztF8FEao3YAQlmDR8SqgG0+Z0fkU0/668r0nxz87NQhVmryF8csCgYEA3g4G
+AmULfpRebUyNIn+rtyd2R6IqR3S3HYrfZNRcPPN4V6T5hRN9Fbg+xu3HvY4xl2ww
+XTa5Fq48+K+Hahq+VLyG1FCQWKaJkcKwhUsE811SWVqBUDiFiE+t0+xMdiuuWA2+
+WBnxXJuRZjX7Lz3uvyhkPYvg3GGl+gIe2UhTCL8CgYBO/BAOoodyzFzADxs22sre
+3scjbYkuSHMffuLqreyYdviB4bh9lKrO8qrcBtScJNZnABl3C5Oo/OC6zlp3wWS5
+R4mLUv9cOcykReCa51kd4BUeUjAS0ykVLSXAQmT3hDMpGlNFATK981pLvipJsWyn
+hLcz60O46qfYc0yWgzy2pQKBgDZbgncVmzG6Sj9BTQ9T54onW9n/RZBGbwkJVNRO
+8+FrzFrQJNDBy44Ek0GJNaseYt9peZFn8vktX/mUpnZ/43XEzNCuhBdfdS+8VA/d
+JHIatyzubddgbrfGoYvOPY1z9fLSMnVIrH/6CSbXMg0HgSlETv2N/1aThNjlqf2Q
+qdrrAoGBAO7cE80xgQaZxu3x9ZtM4PeiE2thVjdZEGAyQlRyS6BO0iGMGWjpeUZq
+2ZJvm8AurRv7Wtmjf9EsoIJKbnGI3wBH0Sbs8LZ8ksI4Dtcx8UPeqzeUwfM/VQdH
+qARGkCRJD/nBbZIy+sOfBysnYVr099kEoGFW8XA0IoGveVkGv8p9
+-----END RSA PRIVATE KEY-----

+ 68 - 0
AnsjerPush/file/apns_pem/customizedb.pem

@@ -0,0 +1,68 @@
+Bag Attributes
+    friendlyName: Apple Push Services: com.ansjer.customizedb
+    localKeyID: 53 D0 A7 6B CF E9 9C 46 ED 44 01 01 01 14 02 52 A6 45 AB C5 
+subject=/UID=com.ansjer.customizedb/CN=Apple Push Services: com.ansjer.customizedb/OU=485ZBTNP7J/O=Winplus Australasia PTY LTD/C=AU
+issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIGOzCCBSOgAwIBAgIIGg1yKiemRoEwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
+ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
+aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMTkxMTA4MDgzODA0WhcNMjAxMjA3MDgzODA0WjCBpjEmMCQGCgmSJomT8ixk
+AQEMFmNvbS5hbnNqZXIuY3VzdG9taXplZGIxNDAyBgNVBAMMK0FwcGxlIFB1c2gg
+U2VydmljZXM6IGNvbS5hbnNqZXIuY3VzdG9taXplZGIxEzARBgNVBAsMCjQ4NVpC
+VE5QN0oxJDAiBgNVBAoMG1dpbnBsdXMgQXVzdHJhbGFzaWEgUFRZIExURDELMAkG
+A1UEBhMCQVUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTiNE32dce
+ZMEsO/0na/qDcYD3icWauyoYm/SL0OWVtIahF4J5vXcg46QHNhQ4y/xczFLQr4iZ
+sUKyElt3c3MLZCs2P/75UOfGYZTVRpugjo83iSpz9pHZl4qc7fZMDyurXzcYazRa
+lFzB/PPbKBS+PVtAMpCv4a1Cg/vtHCMF3neJUQMVyTkXjyNuxK4UU/Pgeck4y52T
+mvuJMMEtkbLRoqCh046VSg2cGLmjNO9j+ECvn3rRb/XZdOPbDPtaCe2dLE+cL1ld
+Jdkyxk5KJmvhkfiQlORhgJrS8r63KDZSi8PCRqkgbLWW6dXUBQOwQCLshLficY5M
+4LuLPthUTr51AgMBAAGjggJ5MIICdTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaA
+FIgnFwmpthhgi+zruvZHWcVSVKO3MIIBHAYDVR0gBIIBEzCCAQ8wggELBgkqhkiG
+92NkBQEwgf0wgcMGCCsGAQUFBwICMIG2DIGzUmVsaWFuY2Ugb24gdGhpcyBjZXJ0
+aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2NlcHRhbmNlIG9mIHRoZSB0
+aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2Yg
+dXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRpZmljYXRpb24gcHJhY3Rp
+Y2Ugc3RhdGVtZW50cy4wNQYIKwYBBQUHAgEWKWh0dHA6Ly93d3cuYXBwbGUuY29t
+L2NlcnRpZmljYXRlYXV0aG9yaXR5MBMGA1UdJQQMMAoGCCsGAQUFBwMCMDAGA1Ud
+HwQpMCcwJaAjoCGGH2h0dHA6Ly9jcmwuYXBwbGUuY29tL3d3ZHJjYS5jcmwwHQYD
+VR0OBBYEFFPQp2vP6ZxG7UQBAQEUAlKmRavFMA4GA1UdDwEB/wQEAwIHgDAQBgoq
+hkiG92NkBgMBBAIFADAQBgoqhkiG92NkBgMCBAIFADCBiQYKKoZIhvdjZAYDBgR7
+MHkMFmNvbS5hbnNqZXIuY3VzdG9taXplZGIwBQwDYXBwDBtjb20uYW5zamVyLmN1
+c3RvbWl6ZWRiLnZvaXAwBgwEdm9pcAwjY29tLmFuc2plci5jdXN0b21pemVkYi5j
+b21wbGljYXRpb24wDgwMY29tcGxpY2F0aW9uMA0GCSqGSIb3DQEBCwUAA4IBAQA7
+mHftwMQj6bfXVzXMf6qsvM1gc/842e1/4aPiM4A+09dgJFUXz6Zq7Zw7JkcMWJdx
+bJsDcH4FoNR0Z24RM8wKjaYsPUQz6I3CBgSC5Zj5OnbSDuYLLciqDPWdVqtZD0EK
+/oMt7O8H4H640ZvzNOpfa+WPTBlyWWoYJvQJtFmPNajmaMKGj5BIxgmxW+bAGbdN
+IOiIgebFn0vcXiybptS6nthvBf7qqs5y0Z9ZwOh2Z/e3ognHv35Qa5fBfjuDf0Gb
+mUa7fAoI/MVdu2TwvdmZQ6Ob1IPL9z1yPHBeUwt8qGDqaqeoXo7uVg/qQCAHEz+n
+b4AM1a7aHD1YTAnbk+FH
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA04jRN9nXHmTBLDv9J2v6g3GA94nFmrsqGJv0i9DllbSGoReC
+eb13IOOkBzYUOMv8XMxS0K+ImbFCshJbd3NzC2QrNj/++VDnxmGU1UaboI6PN4kq
+c/aR2ZeKnO32TA8rq183GGs0WpRcwfzz2ygUvj1bQDKQr+GtQoP77RwjBd53iVED
+Fck5F48jbsSuFFPz4HnJOMudk5r7iTDBLZGy0aKgodOOlUoNnBi5ozTvY/hAr596
+0W/12XTj2wz7WgntnSxPnC9ZXSXZMsZOSiZr4ZH4kJTkYYCa0vK+tyg2UovDwkap
+IGy1lunV1AUDsEAi7IS34nGOTOC7iz7YVE6+dQIDAQABAoIBAATziOIjyTM+7H6a
+kNxhXKXC/F/O678pblzRGbJEG3ublCMlJ7qtwqIUcfxxOZvyul95sN6NnUbrrUH5
+yAZNv32exJwqd09io2ozUoaDdpUVgSitnz7DoLpVH7t4nnE9UapbOjDqIXmVS26G
++zZAA+xIB2DDTjuvrpyF9lmgdPloJsA3Q+X3nFfNgbt8Z8xGF2xs8a3R/83k8y+F
+UueDV56v/ivIebPULSOsktEQXtKDgYLNIuMXDztJSflTr0M+Uq9qPIs6fQl55ssk
+o7G55vAzlTBlwSWiOSubecAmiyFeWY3E16uVAYcTKXYEjSpFTqAyNjBTElsgSiuh
+kSODACkCgYEA898WP5Edd9tUgJCr0OQcxdCmXhTZI2fcAqEcjfCyxKHRXAzDwrKN
+Dpx5Es+Ymn2bRGoLCYpeXpxHZTnuRakrO8zM34PbCWWul14oAKzB5vn7TRuNJXOE
+HeOeztF8FEao3YAQlmDR8SqgG0+Z0fkU0/668r0nxz87NQhVmryF8csCgYEA3g4G
+AmULfpRebUyNIn+rtyd2R6IqR3S3HYrfZNRcPPN4V6T5hRN9Fbg+xu3HvY4xl2ww
+XTa5Fq48+K+Hahq+VLyG1FCQWKaJkcKwhUsE811SWVqBUDiFiE+t0+xMdiuuWA2+
+WBnxXJuRZjX7Lz3uvyhkPYvg3GGl+gIe2UhTCL8CgYBO/BAOoodyzFzADxs22sre
+3scjbYkuSHMffuLqreyYdviB4bh9lKrO8qrcBtScJNZnABl3C5Oo/OC6zlp3wWS5
+R4mLUv9cOcykReCa51kd4BUeUjAS0ykVLSXAQmT3hDMpGlNFATK981pLvipJsWyn
+hLcz60O46qfYc0yWgzy2pQKBgDZbgncVmzG6Sj9BTQ9T54onW9n/RZBGbwkJVNRO
+8+FrzFrQJNDBy44Ek0GJNaseYt9peZFn8vktX/mUpnZ/43XEzNCuhBdfdS+8VA/d
+JHIatyzubddgbrfGoYvOPY1z9fLSMnVIrH/6CSbXMg0HgSlETv2N/1aThNjlqf2Q
+qdrrAoGBAO7cE80xgQaZxu3x9ZtM4PeiE2thVjdZEGAyQlRyS6BO0iGMGWjpeUZq
+2ZJvm8AurRv7Wtmjf9EsoIJKbnGI3wBH0Sbs8LZ8ksI4Dtcx8UPeqzeUwfM/VQdH
+qARGkCRJD/nBbZIy+sOfBysnYVr099kEoGFW8XA0IoGveVkGv8p9
+-----END RSA PRIVATE KEY-----

+ 68 - 0
AnsjerPush/file/apns_pem/lcc-dev.pem

@@ -0,0 +1,68 @@
+Bag Attributes
+    friendlyName: Apple Push Services: com.ansjer.loocamccloud
+    localKeyID: 81 BA F8 2E C5 58 9A A4 86 A9 47 F6 EF B7 16 48 1C 7A 1E E9
+subject=/UID=com.ansjer.loocamccloud/CN=Apple Push Services: com.ansjer.loocamccloud/OU=JCHT67XT68/O=Loocam Technology LLC/C=US
+issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIGOjCCBSKgAwIBAgIIEh/B+Kd1dVowDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
+ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
+aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMTkxMDE1MDk0OTQ4WhcNMjAxMTEzMDk0OTQ4WjCBojEnMCUGCgmSJomT8ixk
+AQEMF2NvbS5hbnNqZXIubG9vY2FtY2Nsb3VkMTUwMwYDVQQDDCxBcHBsZSBQdXNo
+IFNlcnZpY2VzOiBjb20uYW5zamVyLmxvb2NhbWNjbG91ZDETMBEGA1UECwwKSkNI
+VDY3WFQ2ODEeMBwGA1UECgwVTG9vY2FtIFRlY2hub2xvZ3kgTExDMQswCQYDVQQG
+EwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMIfC7vgq2k1bNRW
+4/Ix+W5CYWLzlbZJ3WS+A4X8GEZVkpcuQhADCs/fxMk/KMzl3XvX8YiNQoItKGzK
+Gd0wEtwdjmQvsXwjZG47v7OGE0qj9beQRMYo0gq6SOK7J7r7/8QW9ggmZJXfTqu2
+kQimrpTLeEQdKERbZLxV4i5oOTaAwyzHChNDmvcg2LCjkYaHuOMKtuQHOcMd8RQ4
+DybXkCyPbItIRxuAksMSem2TBHyHoO6Agx3epPgU+9nTbze7eU0OpAiAl7lFqc3i
+80llb8N23q4WUK+1u/5KEVlZjXHvdmOYldVpUK2GUgc4gcBbZoda3DIQ/F8nddTI
+gczwXRMCAwEAAaOCAnwwggJ4MAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUiCcX
+Cam2GGCL7Ou69kdZxVJUo7cwggEcBgNVHSAEggETMIIBDzCCAQsGCSqGSIb3Y2QF
+ATCB/TCBwwYIKwYBBQUHAgIwgbYMgbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmlj
+YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4g
+YXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2Us
+IGNlcnRpZmljYXRlIHBvbGljeSBhbmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBz
+dGF0ZW1lbnRzLjA1BggrBgEFBQcCARYpaHR0cDovL3d3dy5hcHBsZS5jb20vY2Vy
+dGlmaWNhdGVhdXRob3JpdHkwEwYDVR0lBAwwCgYIKwYBBQUHAwIwMAYDVR0fBCkw
+JzAloCOgIYYfaHR0cDovL2NybC5hcHBsZS5jb20vd3dkcmNhLmNybDAdBgNVHQ4E
+FgQUgbr4LsVYmqSGqUf277cWSBx6HukwDgYDVR0PAQH/BAQDAgeAMBAGCiqGSIb3
+Y2QGAwEEAgUAMBAGCiqGSIb3Y2QGAwIEAgUAMIGMBgoqhkiG92NkBgMGBH4wfAwX
+Y29tLmFuc2plci5sb29jYW1jY2xvdWQwBQwDYXBwDBxjb20uYW5zamVyLmxvb2Nh
+bWNjbG91ZC52b2lwMAYMBHZvaXAMJGNvbS5hbnNqZXIubG9vY2FtY2Nsb3VkLmNv
+bXBsaWNhdGlvbjAODAxjb21wbGljYXRpb24wDQYJKoZIhvcNAQELBQADggEBABr9
+dM8BvrJVSwYRGw39JU7kiGV+dOhcJ59XwOdo2xO05dv1iQJeVDRSpni9yfeHX/pu
+rycGgEm40IQxqTNs851KUqBiLjEwRjkX6MZQMbWnTZY8xiLFKm7lhY6mFUsxfkXH
+/dygY9uZkNCzYfzs8JbWRU8p2uNwF3ZRvZiXITncNWImkdtneSHgF3IQtq/6flc5
+aA89zIH8P7V5/Rvye7JFuM98AXNUHO8XznwgGru6kZCpi4e+83AAXhD9JQmHv/wN
+iHCDWHq1TFS8KgbxfvgGkB2r5vlGkWSo2E3xnxGZu6tiRYgNyNqNsJoMeAtH/352
+xQQMuMMfCP/eKBojC+8=
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAwh8Lu+CraTVs1Fbj8jH5bkJhYvOVtkndZL4DhfwYRlWSly5C
+EAMKz9/EyT8ozOXde9fxiI1Cgi0obMoZ3TAS3B2OZC+xfCNkbju/s4YTSqP1t5BE
+xijSCrpI4rsnuvv/xBb2CCZkld9Oq7aRCKaulMt4RB0oRFtkvFXiLmg5NoDDLMcK
+E0Oa9yDYsKORhoe44wq25Ac5wx3xFDgPJteQLI9si0hHG4CSwxJ6bZMEfIeg7oCD
+Hd6k+BT72dNvN7t5TQ6kCICXuUWpzeLzSWVvw3berhZQr7W7/koRWVmNce92Y5iV
+1WlQrYZSBziBwFtmh1rcMhD8Xyd11MiBzPBdEwIDAQABAoIBAAi22BIBDfDVIyON
+GwJ+V9IpTLHieXALdNLW7NWQ8Y4GvWPoAbMyT8PxKaZXHX/FOeIbWY5luPybBluL
+3wlc5RvYf9HjijYmaJXCPOLUO/13ysoIwe2bW4J7xlXXTPtJ4LtuxHCtOIq50ZBH
+y871nJS1ZZq5LFuVNrp1qIeoyhi2LuMdkzjpA5MujOhr9vEgI2P2wBazgL2XZ/i/
+2FTJBWp13wSCj6usohni+Ppm77+/Ax9kj0K2vXTjy/fRDIcmkAHdfzifd3oGHtIs
+zc5m1i5GnKXhUB87GrCSvZ1gqJII2ZgXCroprp1TzrWOtH0mzDtzuqYsT8aUpAuG
+Fbnj0sECgYEA+78DbnEAWfzjQXjUytgE2FVSWINsl0zUyr0mIh85r0QY+eQc3LX6
+RDPQq1qndhwXPGY5Nv+hGncAIP0o6eldT1D6LuAcyTzff025aTMLxAswtj1qSfNL
+vVEA+V8Q45TqKIC+CfzJysx5xk53S3DFesCxGfHk5ozmg8ILQSblUlECgYEAxWbD
+OwEW1Wi9UmQcGfKjM7tN22EpY4qid0BJsib/qqfI++42BAuytFKZyyAnaOaNCEKx
+ktaKGZcTCjtstathMiB+3sjJbqOXV+WntrVb4eu35N+IhhRd/ltdyXqx9PwMeMpC
+i73JZZhw9Wn4M7aAC/M37vw3Ztecx5hiTKixXCMCgYAFb3dcgBYY20vw0vINOyLH
+pPf1L0k97wu9IN5c6D2vmhHL+2/gGBHCPTgpKvjopOyfgjmEBXrt/lnDXJPwkPhR
+yRbNwkr80VKmBgCV0+NSJUe095h+5kDhYolZ2QKdV07C9xyjTJDyzv1mGbWbrGCn
+KNfqDn35uFsVxy/FBVj4MQKBgQCkwCyGzVTqTh1ca1MM0PYm0decFg5+FpGb55ra
+RjQxkRFsOhb47255k0rqPe7GXU0trMQZolbmHrF0Y75KLTvUo0xf0cJURdKlOHXu
+RpTmDF6RdYKzLMJ57HVtF6r4pXgfQ+egS4iP81era4MMXe+miZqQKg5vFdqyttqr
+0ksccwKBgQC0jmQ6/KCE2hvNcNIKJzXDZ+4C5LGn6f6hSe5G2yzyt0KVUuUd1gk9
+/IbwSYbNR5SO8KmHoL3yjhBnv+eVE5VFTgy5Gc+J+ON9pPjvYqpwMjlqBCzhUWZN
+gm9kUGZQPYOvuweViXECMZntcVNxG2bKodaMFHKda3xD2fTSeB6OCg==
+-----END RSA PRIVATE KEY-----

+ 68 - 0
AnsjerPush/file/apns_pem/lcc.pem

@@ -0,0 +1,68 @@
+Bag Attributes
+    friendlyName: Apple Push Services: com.ansjer.loocamccloud
+    localKeyID: 81 BA F8 2E C5 58 9A A4 86 A9 47 F6 EF B7 16 48 1C 7A 1E E9 
+subject=/UID=com.ansjer.loocamccloud/CN=Apple Push Services: com.ansjer.loocamccloud/OU=JCHT67XT68/O=Loocam Technology LLC/C=US
+issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIGOjCCBSKgAwIBAgIIEh/B+Kd1dVowDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
+ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
+aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMTkxMDE1MDk0OTQ4WhcNMjAxMTEzMDk0OTQ4WjCBojEnMCUGCgmSJomT8ixk
+AQEMF2NvbS5hbnNqZXIubG9vY2FtY2Nsb3VkMTUwMwYDVQQDDCxBcHBsZSBQdXNo
+IFNlcnZpY2VzOiBjb20uYW5zamVyLmxvb2NhbWNjbG91ZDETMBEGA1UECwwKSkNI
+VDY3WFQ2ODEeMBwGA1UECgwVTG9vY2FtIFRlY2hub2xvZ3kgTExDMQswCQYDVQQG
+EwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMIfC7vgq2k1bNRW
+4/Ix+W5CYWLzlbZJ3WS+A4X8GEZVkpcuQhADCs/fxMk/KMzl3XvX8YiNQoItKGzK
+Gd0wEtwdjmQvsXwjZG47v7OGE0qj9beQRMYo0gq6SOK7J7r7/8QW9ggmZJXfTqu2
+kQimrpTLeEQdKERbZLxV4i5oOTaAwyzHChNDmvcg2LCjkYaHuOMKtuQHOcMd8RQ4
+DybXkCyPbItIRxuAksMSem2TBHyHoO6Agx3epPgU+9nTbze7eU0OpAiAl7lFqc3i
+80llb8N23q4WUK+1u/5KEVlZjXHvdmOYldVpUK2GUgc4gcBbZoda3DIQ/F8nddTI
+gczwXRMCAwEAAaOCAnwwggJ4MAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUiCcX
+Cam2GGCL7Ou69kdZxVJUo7cwggEcBgNVHSAEggETMIIBDzCCAQsGCSqGSIb3Y2QF
+ATCB/TCBwwYIKwYBBQUHAgIwgbYMgbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmlj
+YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4g
+YXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2Us
+IGNlcnRpZmljYXRlIHBvbGljeSBhbmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBz
+dGF0ZW1lbnRzLjA1BggrBgEFBQcCARYpaHR0cDovL3d3dy5hcHBsZS5jb20vY2Vy
+dGlmaWNhdGVhdXRob3JpdHkwEwYDVR0lBAwwCgYIKwYBBQUHAwIwMAYDVR0fBCkw
+JzAloCOgIYYfaHR0cDovL2NybC5hcHBsZS5jb20vd3dkcmNhLmNybDAdBgNVHQ4E
+FgQUgbr4LsVYmqSGqUf277cWSBx6HukwDgYDVR0PAQH/BAQDAgeAMBAGCiqGSIb3
+Y2QGAwEEAgUAMBAGCiqGSIb3Y2QGAwIEAgUAMIGMBgoqhkiG92NkBgMGBH4wfAwX
+Y29tLmFuc2plci5sb29jYW1jY2xvdWQwBQwDYXBwDBxjb20uYW5zamVyLmxvb2Nh
+bWNjbG91ZC52b2lwMAYMBHZvaXAMJGNvbS5hbnNqZXIubG9vY2FtY2Nsb3VkLmNv
+bXBsaWNhdGlvbjAODAxjb21wbGljYXRpb24wDQYJKoZIhvcNAQELBQADggEBABr9
+dM8BvrJVSwYRGw39JU7kiGV+dOhcJ59XwOdo2xO05dv1iQJeVDRSpni9yfeHX/pu
+rycGgEm40IQxqTNs851KUqBiLjEwRjkX6MZQMbWnTZY8xiLFKm7lhY6mFUsxfkXH
+/dygY9uZkNCzYfzs8JbWRU8p2uNwF3ZRvZiXITncNWImkdtneSHgF3IQtq/6flc5
+aA89zIH8P7V5/Rvye7JFuM98AXNUHO8XznwgGru6kZCpi4e+83AAXhD9JQmHv/wN
+iHCDWHq1TFS8KgbxfvgGkB2r5vlGkWSo2E3xnxGZu6tiRYgNyNqNsJoMeAtH/352
+xQQMuMMfCP/eKBojC+8=
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAwh8Lu+CraTVs1Fbj8jH5bkJhYvOVtkndZL4DhfwYRlWSly5C
+EAMKz9/EyT8ozOXde9fxiI1Cgi0obMoZ3TAS3B2OZC+xfCNkbju/s4YTSqP1t5BE
+xijSCrpI4rsnuvv/xBb2CCZkld9Oq7aRCKaulMt4RB0oRFtkvFXiLmg5NoDDLMcK
+E0Oa9yDYsKORhoe44wq25Ac5wx3xFDgPJteQLI9si0hHG4CSwxJ6bZMEfIeg7oCD
+Hd6k+BT72dNvN7t5TQ6kCICXuUWpzeLzSWVvw3berhZQr7W7/koRWVmNce92Y5iV
+1WlQrYZSBziBwFtmh1rcMhD8Xyd11MiBzPBdEwIDAQABAoIBAAi22BIBDfDVIyON
+GwJ+V9IpTLHieXALdNLW7NWQ8Y4GvWPoAbMyT8PxKaZXHX/FOeIbWY5luPybBluL
+3wlc5RvYf9HjijYmaJXCPOLUO/13ysoIwe2bW4J7xlXXTPtJ4LtuxHCtOIq50ZBH
+y871nJS1ZZq5LFuVNrp1qIeoyhi2LuMdkzjpA5MujOhr9vEgI2P2wBazgL2XZ/i/
+2FTJBWp13wSCj6usohni+Ppm77+/Ax9kj0K2vXTjy/fRDIcmkAHdfzifd3oGHtIs
+zc5m1i5GnKXhUB87GrCSvZ1gqJII2ZgXCroprp1TzrWOtH0mzDtzuqYsT8aUpAuG
+Fbnj0sECgYEA+78DbnEAWfzjQXjUytgE2FVSWINsl0zUyr0mIh85r0QY+eQc3LX6
+RDPQq1qndhwXPGY5Nv+hGncAIP0o6eldT1D6LuAcyTzff025aTMLxAswtj1qSfNL
+vVEA+V8Q45TqKIC+CfzJysx5xk53S3DFesCxGfHk5ozmg8ILQSblUlECgYEAxWbD
+OwEW1Wi9UmQcGfKjM7tN22EpY4qid0BJsib/qqfI++42BAuytFKZyyAnaOaNCEKx
+ktaKGZcTCjtstathMiB+3sjJbqOXV+WntrVb4eu35N+IhhRd/ltdyXqx9PwMeMpC
+i73JZZhw9Wn4M7aAC/M37vw3Ztecx5hiTKixXCMCgYAFb3dcgBYY20vw0vINOyLH
+pPf1L0k97wu9IN5c6D2vmhHL+2/gGBHCPTgpKvjopOyfgjmEBXrt/lnDXJPwkPhR
+yRbNwkr80VKmBgCV0+NSJUe095h+5kDhYolZ2QKdV07C9xyjTJDyzv1mGbWbrGCn
+KNfqDn35uFsVxy/FBVj4MQKBgQCkwCyGzVTqTh1ca1MM0PYm0decFg5+FpGb55ra
+RjQxkRFsOhb47255k0rqPe7GXU0trMQZolbmHrF0Y75KLTvUo0xf0cJURdKlOHXu
+RpTmDF6RdYKzLMJ57HVtF6r4pXgfQ+egS4iP81era4MMXe+miZqQKg5vFdqyttqr
+0ksccwKBgQC0jmQ6/KCE2hvNcNIKJzXDZ+4C5LGn6f6hSe5G2yzyt0KVUuUd1gk9
+/IbwSYbNR5SO8KmHoL3yjhBnv+eVE5VFTgy5Gc+J+ON9pPjvYqpwMjlqBCzhUWZN
+gm9kUGZQPYOvuweViXECMZntcVNxG2bKodaMFHKda3xD2fTSeB6OCg==
+-----END RSA PRIVATE KEY-----

+ 64 - 0
AnsjerPush/file/apns_pem/zccloud-dev.pem

@@ -0,0 +1,64 @@
+Bag Attributes
+    friendlyName: Apple Development IOS Push Services: com.ansjer.zccloud
+    localKeyID: 25 54 61 DA 6A 7C CD 2D 6A 1E 45 64 96 7A 4B 28 89 15 73 D4 
+subject=/UID=com.ansjer.zccloud/CN=Apple Development IOS Push Services: com.ansjer.zccloud/OU=772N5HXAR2/C=US
+issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIFiTCCBHGgAwIBAgIIdGAeNPi1q4YwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
+ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
+aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMjAwNDI0MDYwODU4WhcNMjEwNDI0MDYwODU4WjCBiDEiMCAGCgmSJomT8ixk
+AQEMEmNvbS5hbnNqZXIuemNjbG91ZDFAMD4GA1UEAww3QXBwbGUgRGV2ZWxvcG1l
+bnQgSU9TIFB1c2ggU2VydmljZXM6IGNvbS5hbnNqZXIuemNjbG91ZDETMBEGA1UE
+CwwKNzcyTjVIWEFSMjELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDQXWXsPbUk9HO3JqA6FbJU7iphv28RK2fEnyryzQPLyp/uGOiV
+uxP7xbOV/3vbEcqSoEvZx4xzMh3xb9LKPpSK1OPr9D+KwbNzh0H7C/n17YdsG6v3
+NWIVsfx6iVK6TUNQYCTvwntao6sij/9ctrLJItBOgwuvne5pHozXLAV49CGHW6Yq
+oAf9hmUCm9WJT/y0aZNlsD1nQUA8vfahBcnDKvEgew53UkAeDTYU9r/TWNWw4r44
+D5momf+vE+rDonUi3gwVrEFRGr+G66CYvGP5F20Xqwlxpw717Oz9gae1fyqkbgEx
+blUq+mv5Xh1yMCmDpeqowVgcyA4Oz1us0OnLAgMBAAGjggHlMIIB4TAJBgNVHRME
+AjAAMB8GA1UdIwQYMBaAFIgnFwmpthhgi+zruvZHWcVSVKO3MIIBDwYDVR0gBIIB
+BjCCAQIwgf8GCSqGSIb3Y2QFATCB8TCBwwYIKwYBBQUHAgIwgbYMgbNSZWxpYW5j
+ZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2Vw
+dGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGljeSBhbmQgY2VydGlm
+aWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjApBggrBgEFBQcCARYdaHR0cDov
+L3d3dy5hcHBsZS5jb20vYXBwbGVjYS8wEwYDVR0lBAwwCgYIKwYBBQUHAwIwTQYD
+VR0fBEYwRDBCoECgPoY8aHR0cDovL2RldmVsb3Blci5hcHBsZS5jb20vY2VydGlm
+aWNhdGlvbmF1dGhvcml0eS93d2RyY2EuY3JsMB0GA1UdDgQWBBQlVGHaanzNLWoe
+RWSWeksoiRVz1DALBgNVHQ8EBAMCB4AwEAYKKoZIhvdjZAYDAQQCBQAwDQYJKoZI
+hvcNAQEFBQADggEBAMTfpZRXJpz8/1wkWYT2zSxGJcdmtB6oEUmVzjlYod5rDuTl
+yFSJPl/Sy41/anW88UgC231AF3h78q54vdFuQ7rd8ORF3nEDGzib4+7d4QCcguFP
+2Lz27r2goLQhKRIY/isjAUrLFHwcX9hjG9TuhMO+e8a6Vu5gXpXU6/QA1HTqO3ei
+kvfw/MoaAOQuRNofFPNCVO+nOndK61oTHovDcMfU1LG6siJGkVn3VhPAQOd7VbOQ
+eXqd1+LWkBMrJbsdJElKKKl0mQpXHUf4yW2k8Eg2AdZkMOSQKm8IaLXGHzrqg+fk
+sPUfBL2JEaGpAlD56fZYLPRMEdIV4SG8m6BOw4M=
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA0F1l7D21JPRztyagOhWyVO4qYb9vEStnxJ8q8s0Dy8qf7hjo
+lbsT+8Wzlf972xHKkqBL2ceMczId8W/Syj6UitTj6/Q/isGzc4dB+wv59e2HbBur
+9zViFbH8eolSuk1DUGAk78J7WqOrIo//XLayySLQToMLr53uaR6M1ywFePQhh1um
+KqAH/YZlApvViU/8tGmTZbA9Z0FAPL32oQXJwyrxIHsOd1JAHg02FPa/01jVsOK+
+OA+ZqJn/rxPqw6J1It4MFaxBURq/huugmLxj+RdtF6sJcacO9ezs/YGntX8qpG4B
+MW5VKvpr+V4dcjApg6XqqMFYHMgODs9brNDpywIDAQABAoIBAF4aMFPXMp40AKaw
+vSA+eEG/JkjrCiA4+C5mrCDn0lURd9UyTqiAyu+kRAz0S12O1WwPFPKQGrBT7A4E
+MLDCPpfMufrwXlouTPtaFMRqjkMxOT3r6WhGJbwinCJDLqeRCVudcFEQBmHTFREQ
+84VNxcTtAiLTME3qB6hV8cmjyfzrg9HgVd/g0/7UmMBlyHeEj8yAbGuTmzndvtYS
+9ADVri+rVo4dVSYo0tlGNmSbz2j+F680ghu8EVqpV1LOOmo54UIWeCqeSY7KskKI
+kLyGZmchUF0AqZnY2/jTJ9DO/opaTFkp6PFwVH4enamWAHFDqKzpj5C8cFnnO55+
+SkdD0LECgYEA9VzVyyyNumOC3I4BHtZ9iGIp7mwrt7lPFDMdtA7MhClI4HCILWcs
+cVahCyphb9u0mpGxZfu2iz6IbiVAsoZL1IiS98xNxn1oarbmqmtHBfu0V0YfprgU
+C26PWO9/5DCwhTD22ZJlKkvy+Yf6NMWgoCkZ7nHbtMsQRgxiQQqoyccCgYEA2WXx
+Fz29tvgy5lw552rD3EIxlxET9EF+Vd3qJCCyVcN0lMzoSBRwHPwJCHNgtSOeV/bn
+KFEfLvslFNCu+AYVpDfm5tEbL+67Xop9XYJZeVe9SKfuy3IGGh+Qo0uDYwQrJwVt
+e+etqL+NuDkjeMs/Toiyc+8/KlkbodWJloL3f90CgYBva+4GasAdsUze3XmyyFKP
+WYyTIfokX3mCwceuWb4UEi9vBItCmwS6n01YpbFDu7DjNGAr4Me/qfEIm9AqggPz
+iuW6s8Np7M87Dr3nC/pfxDLcIxMCgbtQia99Ap3AQUAX6+ldWjaoo36+RDqiNlDA
+CoolFv1ft4s3VC5WPQHzRwKBgCo2DgLaPRzqwk9SNvgFFfSNcb2IVlyF3vbjONQ8
++QOICPnfc3aTaVVnZoWaiXuCZ/tieG2umqRvpTqObnrAC7GwHQhSL7o123G26DKg
+3aie7aTO3qHoCOFHobjjL6apJ4vTFPgK+wAZ+XV8urN4m1kvV58FJDmfxaq9oJJ1
+6YKNAoGAWULDkYaRAklSkM9lGV/OWcBgH/rYZycqwRKaLRdluKoWzYqnpcF5Vj8l
+ENI854Luqo7NpoHfAhyB3TH7CFocTL6BXMO0Naf5q7nmQMqQmcHuPBhyaVCiMXBy
+4aKyiWNMt4Rn54VDbgyYklCZkg3o0kV70yAdWm5blnxnbVpOe+g=
+-----END RSA PRIVATE KEY-----

+ 67 - 0
AnsjerPush/file/apns_pem/zccloud.pem

@@ -0,0 +1,67 @@
+Bag Attributes
+    friendlyName: Apple Push Services: com.ansjer.zccloud
+    localKeyID: 25 54 61 DA 6A 7C CD 2D 6A 1E 45 64 96 7A 4B 28 89 15 73 D4 
+subject=/UID=com.ansjer.zccloud/CN=Apple Push Services: com.ansjer.zccloud/OU=772N5HXAR2/O=ZOSI Technology Co. , Ltd/C=US
+issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIGJDCCBQygAwIBAgIIPgEkIypNo/cwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
+ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
+aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMjAwNDI0MDYxMzU0WhcNMjEwNTI0MDYxMzU0WjCBnDEiMCAGCgmSJomT8ixk
+AQEMEmNvbS5hbnNqZXIuemNjbG91ZDEwMC4GA1UEAwwnQXBwbGUgUHVzaCBTZXJ2
+aWNlczogY29tLmFuc2plci56Y2Nsb3VkMRMwEQYDVQQLDAo3NzJONUhYQVIyMSIw
+IAYDVQQKDBlaT1NJIFRlY2hub2xvZ3kgQ28uICwgTHRkMQswCQYDVQQGEwJVUzCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANBdZew9tST0c7cmoDoVslTu
+KmG/bxErZ8SfKvLNA8vKn+4Y6JW7E/vFs5X/e9sRypKgS9nHjHMyHfFv0so+lIrU
+4+v0P4rBs3OHQfsL+fXth2wbq/c1YhWx/HqJUrpNQ1BgJO/Ce1qjqyKP/1y2sski
+0E6DC6+d7mkejNcsBXj0IYdbpiqgB/2GZQKb1YlP/LRpk2WwPWdBQDy99qEFycMq
+8SB7DndSQB4NNhT2v9NY1bDivjgPmaiZ/68T6sOidSLeDBWsQVEav4broJi8Y/kX
+bRerCXGnDvXs7P2Bp7V/KqRuATFuVSr6a/leHXIwKYOl6qjBWBzIDg7PW6zQ6csC
+AwEAAaOCAmwwggJoMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUiCcXCam2GGCL
+7Ou69kdZxVJUo7cwggEcBgNVHSAEggETMIIBDzCCAQsGCSqGSIb3Y2QFATCB/TCB
+wwYIKwYBBQUHAgIwgbYMgbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5
+IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGlj
+YWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRp
+ZmljYXRlIHBvbGljeSBhbmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1l
+bnRzLjA1BggrBgEFBQcCARYpaHR0cDovL3d3dy5hcHBsZS5jb20vY2VydGlmaWNh
+dGVhdXRob3JpdHkwEwYDVR0lBAwwCgYIKwYBBQUHAwIwMAYDVR0fBCkwJzAloCOg
+IYYfaHR0cDovL2NybC5hcHBsZS5jb20vd3dkcmNhLmNybDAdBgNVHQ4EFgQUJVRh
+2mp8zS1qHkVklnpLKIkVc9QwDgYDVR0PAQH/BAQDAgeAMBAGCiqGSIb3Y2QGAwEE
+AgUAMBAGCiqGSIb3Y2QGAwIEAgUAMH0GCiqGSIb3Y2QGAwYEbzBtDBJjb20uYW5z
+amVyLnpjY2xvdWQwBQwDYXBwDBdjb20uYW5zamVyLnpjY2xvdWQudm9pcDAGDAR2
+b2lwDB9jb20uYW5zamVyLnpjY2xvdWQuY29tcGxpY2F0aW9uMA4MDGNvbXBsaWNh
+dGlvbjANBgkqhkiG9w0BAQsFAAOCAQEAhbsEWfOwoRPz9wgTlWycYrqKbF/QblbA
+yB7rCsR+d1EM9JbpHl7SuS0GMHUbFr7XR5INiDG+a2IKcLlfLyasKvcycuUs/sW0
+NoCI1726d7F0TEtKN3tUx+rAMi4+dQeg40NfmB1Cg1HkpewT7v5LzuRv6+/sx3bH
+ZSfrKe5ervaYlww79mrTzcR3xzt6aXnHa7zVgi6DaCg6jA4Q/IC3XbTlJK/sk0aG
+taA1utdChItuuy2dLyQjnzqzvMAOLSjD0fDVImFAJ3eMqR5gT3jwNn/GLbws+2F7
+AYN72N8HuPWgfy+PteJWbD07Mf3ODjpRbw9tlltuCJ6nhbRkFI6fCA==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA0F1l7D21JPRztyagOhWyVO4qYb9vEStnxJ8q8s0Dy8qf7hjo
+lbsT+8Wzlf972xHKkqBL2ceMczId8W/Syj6UitTj6/Q/isGzc4dB+wv59e2HbBur
+9zViFbH8eolSuk1DUGAk78J7WqOrIo//XLayySLQToMLr53uaR6M1ywFePQhh1um
+KqAH/YZlApvViU/8tGmTZbA9Z0FAPL32oQXJwyrxIHsOd1JAHg02FPa/01jVsOK+
+OA+ZqJn/rxPqw6J1It4MFaxBURq/huugmLxj+RdtF6sJcacO9ezs/YGntX8qpG4B
+MW5VKvpr+V4dcjApg6XqqMFYHMgODs9brNDpywIDAQABAoIBAF4aMFPXMp40AKaw
+vSA+eEG/JkjrCiA4+C5mrCDn0lURd9UyTqiAyu+kRAz0S12O1WwPFPKQGrBT7A4E
+MLDCPpfMufrwXlouTPtaFMRqjkMxOT3r6WhGJbwinCJDLqeRCVudcFEQBmHTFREQ
+84VNxcTtAiLTME3qB6hV8cmjyfzrg9HgVd/g0/7UmMBlyHeEj8yAbGuTmzndvtYS
+9ADVri+rVo4dVSYo0tlGNmSbz2j+F680ghu8EVqpV1LOOmo54UIWeCqeSY7KskKI
+kLyGZmchUF0AqZnY2/jTJ9DO/opaTFkp6PFwVH4enamWAHFDqKzpj5C8cFnnO55+
+SkdD0LECgYEA9VzVyyyNumOC3I4BHtZ9iGIp7mwrt7lPFDMdtA7MhClI4HCILWcs
+cVahCyphb9u0mpGxZfu2iz6IbiVAsoZL1IiS98xNxn1oarbmqmtHBfu0V0YfprgU
+C26PWO9/5DCwhTD22ZJlKkvy+Yf6NMWgoCkZ7nHbtMsQRgxiQQqoyccCgYEA2WXx
+Fz29tvgy5lw552rD3EIxlxET9EF+Vd3qJCCyVcN0lMzoSBRwHPwJCHNgtSOeV/bn
+KFEfLvslFNCu+AYVpDfm5tEbL+67Xop9XYJZeVe9SKfuy3IGGh+Qo0uDYwQrJwVt
+e+etqL+NuDkjeMs/Toiyc+8/KlkbodWJloL3f90CgYBva+4GasAdsUze3XmyyFKP
+WYyTIfokX3mCwceuWb4UEi9vBItCmwS6n01YpbFDu7DjNGAr4Me/qfEIm9AqggPz
+iuW6s8Np7M87Dr3nC/pfxDLcIxMCgbtQia99Ap3AQUAX6+ldWjaoo36+RDqiNlDA
+CoolFv1ft4s3VC5WPQHzRwKBgCo2DgLaPRzqwk9SNvgFFfSNcb2IVlyF3vbjONQ8
++QOICPnfc3aTaVVnZoWaiXuCZ/tieG2umqRvpTqObnrAC7GwHQhSL7o123G26DKg
+3aie7aTO3qHoCOFHobjjL6apJ4vTFPgK+wAZ+XV8urN4m1kvV58FJDmfxaq9oJJ1
+6YKNAoGAWULDkYaRAklSkM9lGV/OWcBgH/rYZycqwRKaLRdluKoWzYqnpcF5Vj8l
+ENI854Luqo7NpoHfAhyB3TH7CFocTL6BXMO0Naf5q7nmQMqQmcHuPBhyaVCiMXBy
+4aKyiWNMt4Rn54VDbgyYklCZkg3o0kV70yAdWm5blnxnbVpOe+g=
+-----END RSA PRIVATE KEY-----

+ 64 - 0
AnsjerPush/file/apns_pem/zosidcloud-dev.pem

@@ -0,0 +1,64 @@
+Bag Attributes
+    friendlyName: Apple Development IOS Push Services: com.ansjer.zosidcloud
+    localKeyID: 53 D0 A7 6B CF E9 9C 46 ED 44 01 01 01 14 02 52 A6 45 AB C5 
+subject=/UID=com.ansjer.zosidcloud/CN=Apple Development IOS Push Services: com.ansjer.zosidcloud/OU=66PK439G56/C=CN
+issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIFjzCCBHegAwIBAgIIAV1gZ5yODtEwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
+ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
+aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMTkxMTA4MDgyNTAzWhcNMjAxMTA3MDgyNTAzWjCBjjElMCMGCgmSJomT8ixk
+AQEMFWNvbS5hbnNqZXIuem9zaWRjbG91ZDFDMEEGA1UEAww6QXBwbGUgRGV2ZWxv
+cG1lbnQgSU9TIFB1c2ggU2VydmljZXM6IGNvbS5hbnNqZXIuem9zaWRjbG91ZDET
+MBEGA1UECwwKNjZQSzQzOUc1NjELMAkGA1UEBhMCQ04wggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDTiNE32dceZMEsO/0na/qDcYD3icWauyoYm/SL0OWV
+tIahF4J5vXcg46QHNhQ4y/xczFLQr4iZsUKyElt3c3MLZCs2P/75UOfGYZTVRpug
+jo83iSpz9pHZl4qc7fZMDyurXzcYazRalFzB/PPbKBS+PVtAMpCv4a1Cg/vtHCMF
+3neJUQMVyTkXjyNuxK4UU/Pgeck4y52TmvuJMMEtkbLRoqCh046VSg2cGLmjNO9j
++ECvn3rRb/XZdOPbDPtaCe2dLE+cL1ldJdkyxk5KJmvhkfiQlORhgJrS8r63KDZS
+i8PCRqkgbLWW6dXUBQOwQCLshLficY5M4LuLPthUTr51AgMBAAGjggHlMIIB4TAJ
+BgNVHRMEAjAAMB8GA1UdIwQYMBaAFIgnFwmpthhgi+zruvZHWcVSVKO3MIIBDwYD
+VR0gBIIBBjCCAQIwgf8GCSqGSIb3Y2QFATCB8TCBwwYIKwYBBQUHAgIwgbYMgbNS
+ZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVz
+IGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJt
+cyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGljeSBhbmQg
+Y2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjApBggrBgEFBQcCARYd
+aHR0cDovL3d3dy5hcHBsZS5jb20vYXBwbGVjYS8wEwYDVR0lBAwwCgYIKwYBBQUH
+AwIwTQYDVR0fBEYwRDBCoECgPoY8aHR0cDovL2RldmVsb3Blci5hcHBsZS5jb20v
+Y2VydGlmaWNhdGlvbmF1dGhvcml0eS93d2RyY2EuY3JsMB0GA1UdDgQWBBRT0Kdr
+z+mcRu1EAQEBFAJSpkWrxTALBgNVHQ8EBAMCB4AwEAYKKoZIhvdjZAYDAQQCBQAw
+DQYJKoZIhvcNAQEFBQADggEBABYBkephyibIPt7nur9eY0bmqEuPQKNg94ZteOFm
+Fo/8Er9tFYndAqXm7Zr7dhdA9dcL9VYrt+qGAPpOLmfnTPdDXBbB59GXWSrBMio6
+5VU9T3bb/4kVzA54SLbMZAjhgEQDULfYK5KSvDgdJQBJLcQu1OMyNntwrF8Xebmt
+AbpyJcv/HOaaQ2gYC+pQ9ye6eGYEZ9BT0BRp61cXnyiii1sUkOCnaamDWMVKIa2W
+8Ii0k6UIXtS+RIOI9mbN1xKDwIAtjZvldd2AS7802R4Ls1Lklf8tcOlt9VcAN0Xs
+EUf4zCneaB6x/CyjXaqCEmE7mmETNs6UcHNqMv3jJRi1wMI=
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA04jRN9nXHmTBLDv9J2v6g3GA94nFmrsqGJv0i9DllbSGoReC
+eb13IOOkBzYUOMv8XMxS0K+ImbFCshJbd3NzC2QrNj/++VDnxmGU1UaboI6PN4kq
+c/aR2ZeKnO32TA8rq183GGs0WpRcwfzz2ygUvj1bQDKQr+GtQoP77RwjBd53iVED
+Fck5F48jbsSuFFPz4HnJOMudk5r7iTDBLZGy0aKgodOOlUoNnBi5ozTvY/hAr596
+0W/12XTj2wz7WgntnSxPnC9ZXSXZMsZOSiZr4ZH4kJTkYYCa0vK+tyg2UovDwkap
+IGy1lunV1AUDsEAi7IS34nGOTOC7iz7YVE6+dQIDAQABAoIBAATziOIjyTM+7H6a
+kNxhXKXC/F/O678pblzRGbJEG3ublCMlJ7qtwqIUcfxxOZvyul95sN6NnUbrrUH5
+yAZNv32exJwqd09io2ozUoaDdpUVgSitnz7DoLpVH7t4nnE9UapbOjDqIXmVS26G
++zZAA+xIB2DDTjuvrpyF9lmgdPloJsA3Q+X3nFfNgbt8Z8xGF2xs8a3R/83k8y+F
+UueDV56v/ivIebPULSOsktEQXtKDgYLNIuMXDztJSflTr0M+Uq9qPIs6fQl55ssk
+o7G55vAzlTBlwSWiOSubecAmiyFeWY3E16uVAYcTKXYEjSpFTqAyNjBTElsgSiuh
+kSODACkCgYEA898WP5Edd9tUgJCr0OQcxdCmXhTZI2fcAqEcjfCyxKHRXAzDwrKN
+Dpx5Es+Ymn2bRGoLCYpeXpxHZTnuRakrO8zM34PbCWWul14oAKzB5vn7TRuNJXOE
+HeOeztF8FEao3YAQlmDR8SqgG0+Z0fkU0/668r0nxz87NQhVmryF8csCgYEA3g4G
+AmULfpRebUyNIn+rtyd2R6IqR3S3HYrfZNRcPPN4V6T5hRN9Fbg+xu3HvY4xl2ww
+XTa5Fq48+K+Hahq+VLyG1FCQWKaJkcKwhUsE811SWVqBUDiFiE+t0+xMdiuuWA2+
+WBnxXJuRZjX7Lz3uvyhkPYvg3GGl+gIe2UhTCL8CgYBO/BAOoodyzFzADxs22sre
+3scjbYkuSHMffuLqreyYdviB4bh9lKrO8qrcBtScJNZnABl3C5Oo/OC6zlp3wWS5
+R4mLUv9cOcykReCa51kd4BUeUjAS0ykVLSXAQmT3hDMpGlNFATK981pLvipJsWyn
+hLcz60O46qfYc0yWgzy2pQKBgDZbgncVmzG6Sj9BTQ9T54onW9n/RZBGbwkJVNRO
+8+FrzFrQJNDBy44Ek0GJNaseYt9peZFn8vktX/mUpnZ/43XEzNCuhBdfdS+8VA/d
+JHIatyzubddgbrfGoYvOPY1z9fLSMnVIrH/6CSbXMg0HgSlETv2N/1aThNjlqf2Q
+qdrrAoGBAO7cE80xgQaZxu3x9ZtM4PeiE2thVjdZEGAyQlRyS6BO0iGMGWjpeUZq
+2ZJvm8AurRv7Wtmjf9EsoIJKbnGI3wBH0Sbs8LZ8ksI4Dtcx8UPeqzeUwfM/VQdH
+qARGkCRJD/nBbZIy+sOfBysnYVr099kEoGFW8XA0IoGveVkGv8p9
+-----END RSA PRIVATE KEY-----

+ 67 - 0
AnsjerPush/file/apns_pem/zosidcloud.pem

@@ -0,0 +1,67 @@
+Bag Attributes
+    friendlyName: Apple Push Services: com.ansjer.zosidcloud
+    localKeyID: 53 D0 A7 6B CF E9 9C 46 ED 44 01 01 01 14 02 52 A6 45 AB C5 
+subject=/UID=com.ansjer.zosidcloud/CN=Apple Push Services: com.ansjer.zosidcloud/OU=66PK439G56/O=side zhang/C=CN
+issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIGJTCCBQ2gAwIBAgIIGmaRz2bBpE8wDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
+ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
+aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMTkxMTA4MDgyNTQ1WhcNMjAxMjA3MDgyNTQ1WjCBkzElMCMGCgmSJomT8ixk
+AQEMFWNvbS5hbnNqZXIuem9zaWRjbG91ZDEzMDEGA1UEAwwqQXBwbGUgUHVzaCBT
+ZXJ2aWNlczogY29tLmFuc2plci56b3NpZGNsb3VkMRMwEQYDVQQLDAo2NlBLNDM5
+RzU2MRMwEQYDVQQKDApzaWRlIHpoYW5nMQswCQYDVQQGEwJDTjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBANOI0TfZ1x5kwSw7/Sdr+oNxgPeJxZq7Khib
+9IvQ5ZW0hqEXgnm9dyDjpAc2FDjL/FzMUtCviJmxQrISW3dzcwtkKzY//vlQ58Zh
+lNVGm6COjzeJKnP2kdmXipzt9kwPK6tfNxhrNFqUXMH889soFL49W0AykK/hrUKD
+++0cIwXed4lRAxXJORePI27ErhRT8+B5yTjLnZOa+4kwwS2RstGioKHTjpVKDZwY
+uaM072P4QK+fetFv9dl049sM+1oJ7Z0sT5wvWV0l2TLGTkoma+GR+JCU5GGAmtLy
+vrcoNlKLw8JGqSBstZbp1dQFA7BAIuyEt+Jxjkzgu4s+2FROvnUCAwEAAaOCAnYw
+ggJyMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUiCcXCam2GGCL7Ou69kdZxVJU
+o7cwggEcBgNVHSAEggETMIIBDzCCAQsGCSqGSIb3Y2QFATCB/TCBwwYIKwYBBQUH
+AgIwgbYMgbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0
+eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFu
+ZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBv
+bGljeSBhbmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjA1Bggr
+BgEFBQcCARYpaHR0cDovL3d3dy5hcHBsZS5jb20vY2VydGlmaWNhdGVhdXRob3Jp
+dHkwEwYDVR0lBAwwCgYIKwYBBQUHAwIwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDov
+L2NybC5hcHBsZS5jb20vd3dkcmNhLmNybDAdBgNVHQ4EFgQUU9Cna8/pnEbtRAEB
+ARQCUqZFq8UwDgYDVR0PAQH/BAQDAgeAMBAGCiqGSIb3Y2QGAwEEAgUAMBAGCiqG
+SIb3Y2QGAwIEAgUAMIGGBgoqhkiG92NkBgMGBHgwdgwVY29tLmFuc2plci56b3Np
+ZGNsb3VkMAUMA2FwcAwaY29tLmFuc2plci56b3NpZGNsb3VkLnZvaXAwBgwEdm9p
+cAwiY29tLmFuc2plci56b3NpZGNsb3VkLmNvbXBsaWNhdGlvbjAODAxjb21wbGlj
+YXRpb24wDQYJKoZIhvcNAQELBQADggEBAIN90Bvh4NH8riH5t1EwMQ4MSN+KCLyA
+PZ8ZsF2XX4em+Eap7q/4Dp7K+6bC64+A5RsuXqlWk4LDRVdclCTXuHhY5wjLw5iD
+HhnawtVuV9Cqh1naKwYoza+dQzcxwlyUvFVahJjlbB0C/86g1jU6VgMkat32qahA
+7PqF8TmfBAHJ8AwXnKpccvR+eoa2z2GkJBCVkP1DiIaYIUr590Eg5V+aw0UgKW3v
+/cYslnmfTJt1HEp9DiUQmNclD7KYexs53xGOu1ACnWgNf4o3XEabUPNX/RF0S14J
+3hzChlUQ05ntbN10xvuauUvsTF+7kMk8QOgOEcJUKlJTmWCPLCOsyPw=
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA04jRN9nXHmTBLDv9J2v6g3GA94nFmrsqGJv0i9DllbSGoReC
+eb13IOOkBzYUOMv8XMxS0K+ImbFCshJbd3NzC2QrNj/++VDnxmGU1UaboI6PN4kq
+c/aR2ZeKnO32TA8rq183GGs0WpRcwfzz2ygUvj1bQDKQr+GtQoP77RwjBd53iVED
+Fck5F48jbsSuFFPz4HnJOMudk5r7iTDBLZGy0aKgodOOlUoNnBi5ozTvY/hAr596
+0W/12XTj2wz7WgntnSxPnC9ZXSXZMsZOSiZr4ZH4kJTkYYCa0vK+tyg2UovDwkap
+IGy1lunV1AUDsEAi7IS34nGOTOC7iz7YVE6+dQIDAQABAoIBAATziOIjyTM+7H6a
+kNxhXKXC/F/O678pblzRGbJEG3ublCMlJ7qtwqIUcfxxOZvyul95sN6NnUbrrUH5
+yAZNv32exJwqd09io2ozUoaDdpUVgSitnz7DoLpVH7t4nnE9UapbOjDqIXmVS26G
++zZAA+xIB2DDTjuvrpyF9lmgdPloJsA3Q+X3nFfNgbt8Z8xGF2xs8a3R/83k8y+F
+UueDV56v/ivIebPULSOsktEQXtKDgYLNIuMXDztJSflTr0M+Uq9qPIs6fQl55ssk
+o7G55vAzlTBlwSWiOSubecAmiyFeWY3E16uVAYcTKXYEjSpFTqAyNjBTElsgSiuh
+kSODACkCgYEA898WP5Edd9tUgJCr0OQcxdCmXhTZI2fcAqEcjfCyxKHRXAzDwrKN
+Dpx5Es+Ymn2bRGoLCYpeXpxHZTnuRakrO8zM34PbCWWul14oAKzB5vn7TRuNJXOE
+HeOeztF8FEao3YAQlmDR8SqgG0+Z0fkU0/668r0nxz87NQhVmryF8csCgYEA3g4G
+AmULfpRebUyNIn+rtyd2R6IqR3S3HYrfZNRcPPN4V6T5hRN9Fbg+xu3HvY4xl2ww
+XTa5Fq48+K+Hahq+VLyG1FCQWKaJkcKwhUsE811SWVqBUDiFiE+t0+xMdiuuWA2+
+WBnxXJuRZjX7Lz3uvyhkPYvg3GGl+gIe2UhTCL8CgYBO/BAOoodyzFzADxs22sre
+3scjbYkuSHMffuLqreyYdviB4bh9lKrO8qrcBtScJNZnABl3C5Oo/OC6zlp3wWS5
+R4mLUv9cOcykReCa51kd4BUeUjAS0ykVLSXAQmT3hDMpGlNFATK981pLvipJsWyn
+hLcz60O46qfYc0yWgzy2pQKBgDZbgncVmzG6Sj9BTQ9T54onW9n/RZBGbwkJVNRO
+8+FrzFrQJNDBy44Ek0GJNaseYt9peZFn8vktX/mUpnZ/43XEzNCuhBdfdS+8VA/d
+JHIatyzubddgbrfGoYvOPY1z9fLSMnVIrH/6CSbXMg0HgSlETv2N/1aThNjlqf2Q
+qdrrAoGBAO7cE80xgQaZxu3x9ZtM4PeiE2thVjdZEGAyQlRyS6BO0iGMGWjpeUZq
+2ZJvm8AurRv7Wtmjf9EsoIJKbnGI3wBH0Sbs8LZ8ksI4Dtcx8UPeqzeUwfM/VQdH
+qARGkCRJD/nBbZIy+sOfBysnYVr099kEoGFW8XA0IoGveVkGv8p9
+-----END RSA PRIVATE KEY-----

BIN
AnsjerPush/file/font/simhei.ttf


+ 184 - 0
AnsjerPush/file/log type .txt

@@ -0,0 +1,184 @@
+typedef enum _log_type
+{
+	//系统控制(Control)
+	LOG_TYPE_SYSTEM_CTRL		= 0x00010000,
+	LOG_TYPE_BOOT,							//系统开机
+	LOG_TYPE_SHUTDOWN,						//系统关机
+	LOG_TYPE_REBOOT,						//系统重启
+	LOG_TYPE_FORMAT_SUCC,					//格式化磁盘成功
+	LOG_TYPE_FORMAT_FAIL,					//格式化磁盘失败
+	LOG_TYPE_UPGRADE_SUCC,					//升级成功
+	LOG_TYPE_UPGRADE_FAIL,					//升级失败
+	LOG_TYPE_CLEAR_ALARM,					//清除报警
+	LOG_TYPE_OPEN_ALARM,					//开启报警
+	LOG_TYPE_MANUAL_START,					//开启手动录像
+	LOG_TYPE_MANUAL_STOP,					//停止手动录像
+	LOG_TYPE_PTZ_ENTER,						//开始云台控制
+	LOG_TYPE_PTZ_CTRL,						//云台操作
+	LOG_TYPE_PTZ_EXIT,						//结束云台控制
+	LOG_TYPE_AUDIO_CH_CHANGE,				//改变现场音频通道
+	LOG_TYPE_VOLUME_ADJUST,					//调节音量
+	LOG_TYPE_MUTE_ENABLE,					//开启静音
+	LOG_TYPE_MUTE_DISENABLE,				//关闭静音
+	LOG_TYPE_DWELL_ENABLE,					//开启轮循
+	LOG_TYPE_DWELL_DISENABLE,				//关闭轮循
+	LOG_TYPE_LOG_IN,						//登录
+	LOG_TYPE_LOG_OFF,						//登出
+	LOG_TYPE_CHANGE_TIME,					//修改系统时间
+	LOG_TYPE_MANUAL_SNAP_SUCC,               //手动抓图成功
+	LOG_TYPE_MANUAL_SNAP_FAIL,               //手动抓图失败
+
+	//系统配置(Setup)
+	LOG_TYPE_CONFIG			= 0x00020000,
+	LOG_TYPE_CHGE_VIDEO_FORMAT,				//改变视频制式
+	LOG_TYPE_CHGE_VGA_RESOLUTION,			//改变显示器分辨率
+	LOG_TYPE_CHGE_LANGUAGE,					//调整语言
+	LOG_TYPE_CHGE_NET_USER_NUM,				//调整网络用户数目
+	LOG_TYPE_CHGE_TIME_ZONE,				//调整时区
+	LOG_TYPE_NTP_MANUAL,					//手动网络校时
+	LOG_TYPE_NTP_ON,						//开启自动网络校时
+	LOG_TYPE_NTP_OFF,						//关闭自动网络校时
+	LOG_TYPE_CHGE_NTP_SERVER,				//修改网络时间服务器地址
+	LOG_TYPE_CHGE_DST,						//调整夏令时设置
+	LOG_TYPE_PASSWD_ON,						//开启操作密码
+	LOG_TYPE_PASSWD_OFF,					//关闭操作密码
+
+	LOG_TYPE_CHGE_CAM_NAME,					//调整通道名称
+	LOG_TYPE_MODIFY_COLOR,					//调整图像色彩
+	LOG_TYPE_CHGE_HOST_MONITOR,				//调整主监视器画面设置
+	LOG_TYPE_CHGE_SPOT,						//调整辅助输出画面设置
+	LOG_TYPE_CHGE_OSD,						//调整字符叠加设置
+
+	LOG_TYPE_CHGE_LOCAL_ENCODE,				//调整录像流编码参数
+	LOG_TYPE_CHGE_REC_VIDEO_SWITCH,			//调整录像开关设置
+	LOG_TYPE_CHGE_REC_AUDIO_SWITCH,			//调整录制音频开关设置
+	LOG_TYPE_CHGE_REC_REDU_SWITCH,			//调整冗余录像开关设置
+	LOG_TYPE_CHGE_REC_PRE_TIME,				//调整景前录像时间
+	LOG_TYPE_CHGE_REC_POST_TIME,			//调整景后录像时间
+	LOG_TYPE_CHGE_REC_HOLD_TIME,			//调整录像数据过期时间
+
+	LOG_TYPE_CHGE_SCH_SCHEDULE,				//调整定时录像计划
+	LOG_TYPE_CHGE_SCH_MOTION,				//调整移动侦测录像计划
+	LOG_TYPE_CHGE_SCH_ALARM,				//调整报警录像计划
+
+	LOG_TYPE_CHGE_SENSOR_SWITCH,			//调整报警输入开关设置
+	LOG_TYPE_CHGE_SENSOR_TYPE,				//调整报警输入设备类型
+	LOG_TYPE_CHGE_SENSOR_TRIGGER,			//调整报警输入处理方式设置
+	LOG_TYPE_CHGE_SENSOR_SCH,				//调整报警输入侦测计划
+
+	LOG_TYPE_CHGE_MOTION_SWITCH,			//调整移动侦测开关设置
+	LOG_TYPE_CHGE_MOTION_SENS,				//调整移动侦测灵敏度
+	LOG_TYPE_CHGE_MOTION_AREA,				//调整移动侦测区域设置
+	LOG_TYPE_CHGE_MOTION_TRIGGER,			//调整移动侦测处理方式
+	LOG_TYPE_CHGE_MOTION_SCH,				//调整移动侦测计划
+
+	LOG_TYPE_CHGE_VL_TRIGGER,				//调整视频丢失处理方式设置
+
+	LOG_TYPE_CHGE_RELAY_SWITCH,				//调整报警输出开关设置
+	LOG_TYPE_CHGE_RELAY_SCH,				//调整报警输出计划
+
+	LOG_TYPE_BUZZER_ON,						//开启声音报警设备
+	LOG_TYPE_BUZZER_OFF,					//关闭声音报警设备
+	LOG_TYPE_CHGE_BUZZER_SCH,				//调整声音报警计划
+
+	LOG_TYPE_CHGE_HTTP_PORT,				//修改HTTP服务器端口
+	LOG_TYPE_CHGE_SER_PORT,					//修改网络服务器端口
+	LOG_TYPE_CHGE_IP,						//设置网络地址
+	LOG_TYPE_DHCP_SUCC,						//自动获取网络地址成功
+	LOG_TYPE_DHCP_FAIL,						//自动获取网络地址失败
+	LOG_TYPE_CHGE_PPPOE,					//设置PPPoE
+	LOG_TYPE_CHGE_DDNS,						//设置DDNS
+	LOG_TYPE_NET_STREAM_CFG,				//调整网络流编码设置
+
+	LOG_TYPE_CHGE_SERIAL,					//调整云台串口设置
+	LOG_TYPE_PRESET_MODIFY,					//调整预置点
+	LOG_TYPE_CRUISE_MODIFY,					//调整巡航线
+	LOG_TYPE_TRACK_MODIFY,					//调整轨迹
+
+	LOG_TYPE_USER_ADD,						//增加用户
+	LOG_TYPE_USER_MODIFY,					//调整用户权限
+	LOG_TYPE_USER_DELETE,					//删除用户
+	LOG_TYPE_CHANGE_PASSWD,					//修改用户密码
+
+	LOG_TYPE_LOAD_DEFAULT,					//恢复默认配置
+	LOG_TYPE_IMPORT_CONFIG,					//导入配置
+	LOG_TYPE_EXPORT_CONFIG,					//导出配置
+
+	LOG_TYPE_CHGE_IMAGE_MASK,				//图像遮挡
+	LOG_TYPE_RECYCLE_REC_ON,				//开启循环录像
+	LOG_TYPE_RECYCLE_REC_OFF,				//关闭循环录像
+	LOG_TYPE_CHGE_DISK_ALARM,				//调整磁盘报警空间
+
+	LOG_TYPE_CHGE_SEND_EMAIL,				//设置Email 发送人信息
+	LOG_TYPE_CHGE_RECV_EMAIL,				//设置Email 接收人信息
+	LOG_TYPE_CHGE_SNAP_SETTING,             //调整抓图配置
+
+	//yqf add 2017.12.22
+	LOG_TYPE_CHGE_SCH_PIR,					//调整人体红外感应录像计划
+	LOG_TYPE_CHGE_PIR_SWITCH,				//调整人体红外感应开关设置
+	LOG_TYPE_CHGE_PIR_TRIGGER,				//调整人体红外感应处理方式
+	LOG_TYPE_CHGE_PIR_SCH,					//调整人体红外感应计划
+
+	//录像回放(Playback)
+	LOG_TYPE_PLAYBACK		= 0x00040000,
+	LOG_TYPE_PLAYBACK_PLAY,					//播放
+	LOG_TYPE_PLAYBACK_PAUSE,				//暂停
+	LOG_TYPE_PLAYBACK_RESUME,				//恢复播放
+	LOG_TYPE_PLAYBACK_FF,					//快进
+	LOG_TYPE_PLAYBACK_REW,					//快退
+	LOG_TYPE_PLAYBACK_STOP,					//停止
+	LOG_TYPE_PLAYBACK_NEXT_SECTION,			//下一段
+	LOG_TYPE_PLAYBACK_PREV_SECTION,			//上一段
+
+	//数据备份(Backup)
+	LOG_TYPE_BACKUP			= 0x00080000,
+	LOG_TYPE_BACKUP_START,					//开始备份
+	LOG_TYPE_BACKUP_COMPLETE,				//备份完成
+	LOG_TYPE_BACKUP_CANCEL,					//放弃备份
+	LOG_TYPE_BACKUP_FAIL,					//备份失败
+
+	//录像检索(Search)
+	LOG_TYPE_SEARCH			= 0x00100000,
+	LOG_TYPE_SEARCH_TIME,					//按时间检索
+	LOG_TYPE_SEARCH_EVENT,					//按事件检索
+	LOG_TYPE_SEARCH_FILE_MAN,				//文件管理
+	LOG_TYPE_DELETE_FILE,					//删除文件
+	LOG_TYPE_LOCK_FILE,						//锁定文件
+	LOG_TYPE_UNLOCK_FILE,					//解锁文件
+	LOG_TYPE_DELETE_PICTURE,                //删除图片
+	LOG_TYPE_LOCK_PICTURE,                  //锁定图片
+	LOG_TYPE_UNLOCK_PICTURE,                //解锁图片
+
+
+	//查看信息(View information)
+	LOG_TYPE_VIEW_INFO		= 0x00200000,
+	LOG_TYPE_VIEW_SYSTEM,					//查看系统信息
+	LOG_TYPE_VIEW_EVENT,					//查看事件
+	LOG_TYPE_VIEW_LOG,						//查看日志
+	LOG_TYPE_VIEW_NETWORK,					//查看网络状态
+	LOG_TYPE_VIEW_ONLINE_USER,				//查看在线用户
+	LOG_TYPE_VIEW_EXPORT_LOG,				//导出日志
+	LOG_TYPE_VIEW_EXPORT_EVENT,				//导出事件
+
+	//异常信息(Error)
+	LOG_TYPE_ERROR_INFO		= 0x00400000,
+	LOG_TYPE_IP_CONFLICT,					//网络地址冲突
+	LOG_TYPE_NETWORK_ERR,					//网络异常
+	LOG_TYPE_DDNS_ERR,						//DDNS错误
+	LOG_TYPE_DISK_IO_ERR,					//磁盘读写错误
+	LOG_TYPE_UNKNOWN_OFF,					//异常断电
+	LOG_TYPE_UNKNOWN_ERR,					//未知错误
+	LOG_TYPE_ERR_9A9A9A9A,
+	LOG_TYPE_ERR_9A000001,
+	LOG_TYPE_ERR_9A000002,
+	LOG_TYE_DISK_WARNING,                  //磁盘衰减报警
+	LOG_TYE_DISK_DISCONNECT,                  //磁盘掉线报警
+	//LOG_TYE_DISK_NOTFIND,					//开机无硬盘
+
+    LOG_TYPE_EVENT            = 0x00800000,   //事件信息
+    LOG_TYPE_EVENT_MOTION     = 0x00800001,
+    LOG_TYPE_EVENT_SENSOR     = 0x00800002,
+    LOG_TYPE_EVENT_VIDEO_LOSS = 0x00800004,
+    LOG_TYPE_EVENT_COVER      = 0x00800008,
+    LOG_TYPE_EVENT_PIR		  = 0x00800010,   //yqf add 2017.12.26
+}LOG_TYPE;

+ 69 - 0
AnsjerPush/file/后台管理系统说明.txt

@@ -0,0 +1,69 @@
+一.修改记录
+创建时间: 2017/10/25 版本: 1.0
+
+二.项目说明
+	1.架构概述
+		1).现有模块 :  用户模块(包括用户设备共享模块)  设备信息模块 OTA模块 Token验证模块
+		2).整体说明 :                                  OTA模块
+		                                                 ↗ 
+														 
+			用户注册 -> 用户登录  -> Token验证模块 
+
+				 ↓		          ↓                     ↘
+			 用户模块       用户模块             设备信息模块
+		3).各个模块明细说明
+			1. 用户模块: 
+				用户信息处理模块:用户基本操作
+					用户注册:包括获取验证码,然后通过验证注册用户
+					用户登录:返回Token信息给后续验证用户安全性
+					用户信息完善:修改完善用户个人信息
+					用户修改密码:修改用户密码
+					用户重置密码:重置密码(使用邮箱进行重置)
+					显示用户信息:显示本用户当前信息
+					显示所有用户信息:只有管理员与超级管理员可以调用,显示所有的用户信息
+					用户启用、禁用:只有管理员与超级管理员可以调用,启用、禁用设备用户
+				
+				用户设备共享模块:共享用户设备
+					搜索用户:通过用户的信息搜索用户自身另外的账号
+					共享用户设备:主用户把设备共享给搜索到用户(可以共享一台设备,也可以全部等设备)
+					取消用户设备:主用户取消之前共享给其他账号的设备(可以取消共享一台设备,也可以全部等设备)
+					
+			2.Token验证模块:
+				token获取:在登录时调用获取Token
+				token验证:解密access token,验证有效期,如果有效可以继续访问接口,无效返回错误信息
+				token更新:解密refresh token,验证有效性,如果有效并且没有过期就更新access token,然后返回access token,或者返回错误信息
+				token错误信息:通过上面三个接口返回的错误码,解析出来token错误信息,并返回提示用户
+				
+			3.设备信息模块
+				添加设备信息:添加新设备信息
+				查询设备信息:查询本账户名下所有设备信息
+				修改设备信息:修改本账户名下的相应设备信息
+				删除设备信息:删除本账户名下相应设备信息
+				显示所有用户设备信息:只有管理员与超级管理员可以调用,显示所有的用户名下所有设备信息
+			
+			4.OTA模块
+				升级文件上传:上传升级文件(根据文件名称保存到相应的文件夹下)
+				添加版本信息:把上传的升级文件信息更新到数据库表里面
+				获取最新版本信息:通过输入要查询的设备信息,返回查询到该设备最新版本
+				获取最新版本url链接:通过输入要查询的设备信息,返回查询到该设备升级文件的下载链接
+				下载升级文件:通过获取的url下载升级文件
+
+			5.批量处理模块
+				设备信息批量导入:2种内容格式txt格式, 2种调用Excel文件导入方式
+				
+			6.权限模块
+				模型设计:用户、角色、权限,用户 → 多对多 ← 角色, 用户 → 多对多 ← 权限,角色 → 多对多 ← 权限
+			7.日志模块
+			    中间件middle入口进行统计入库,利用nginx自带module进行统计(更精确)
+			8.APP版本信息模块
+			    对应app版本更新,检测版本详细信息
+			9.语言包模块
+			    所有响应信息增加中英适配
+			10.
+
+
+django常用命令
+python3 mangage.py makemigrations
+python3 manage.py migrate --fake
+python3 manage.py sqlmigrate
+python3 manage.py runserver 0.0.0.0:8222

BIN
AnsjerPush/file/表文档.doc


+ 149 - 0
AnsjerPush/formal_config.py

@@ -0,0 +1,149 @@
+#!/usr/bin/env python3  
+# -*- coding: utf-8 -*-  
+"""
+@Copyright (C) ansjer cop Video Technology Co.,Ltd.All rights reserved.
+@AUTHOR: ASJRD018
+@NAME: Ansjer
+@software: PyCharm
+@DATE: 2018/7/2 14:06
+@Version: python3.6
+@MODIFY DECORD:ansjer dev
+@file: Conf.py
+@Contact: chanjunkai@163.com
+"""
+# 主要静态变量配置文件
+import datetime, os
+
+
+DEBUG_MODE = 'DEV'
+# MODE = 'PRO'
+# 阿里云发邮箱
+ALY_SES_ACCESS_NAME = 'message@dvema.com'
+ALY_SES_ACCESS_PAW = 'SMtp123456'
+ALY_SES_ACCESS_REPLYTO = '***'
+
+# 发送邮件邮箱
+SES_COMPANY_EMAIL = 'user_server@nsst.com'
+AWS_SES_ACCESS_ID = 'AKIAJKPU23EU5QWHFPKQ'
+AWS_SES_ACCESS_SECRET = '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'
+AWS_SES_ACCESS_REGION = 'us-east-1'
+AWS_BUCKET = 'ansjertest'
+# 设定离线时间为5分钟
+OFF_LINE_TIME_DELTA = 5
+
+# token的secret
+OAUTH_ACCESS_TOKEN_SECRET = 'a+jbgnw%@1%zy^=@dn62%'
+OAUTH_REFRESH_TOKEN_SECRET = 'r+jbgnw%@1%zy^=@dn62%'
+# access_token超时
+# OAUTH_ACCESS_TOKEN_TIME = datetime.timedelta(hours=1)
+OAUTH_ACCESS_TOKEN_TIME = datetime.timedelta(days=30)
+# refresh_token超时
+OAUTH_REFRESH_TOKEN_TIME = datetime.timedelta(days=30)
+# 腾讯验证,短信发送
+TX_PHONE_APP_ID = '1400052907'
+TX_PHONE_APP_KEY = '7705976ca6e85fe7b86d6bc2d11f7783'
+
+# 验证码超时时间
+AuthCode_Expire = 600
+
+# 根路径
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+# uid token key
+UID_TOKEN_KEY = 'c+565*j@%^'
+
+# oss param
+OSS_STS_ACCESS_KEY = 'LTAIyMkGfEdogyL9'
+OSS_STS_ACCESS_SECRET = '71uIjpsqVOmF7DAITRyRuc259jHOjO'
+OSS_ROLE_ARN = 'acs:ram::1901342792446414:role/stsoss'
+
+SERVER_TYPE = 'Ansjer.formal_settings'
+
+NGINX_RTMP_STAT = 'http://www.dvema.com/stat'
+SERVER_DOMAIN = 'http://www.dvema.com/'
+SERVER_DOMAIN_SSL = 'https://www.dvema.com/'
+DOMAIN_HOST = 'www.dvema.com'
+SERVER_HOST = 'localhost'
+
+PAYPAL_CRD = {
+    "mode": "live",  # sandbox or live
+    "client_id": "AdSRd6WBn-qLl9OiQHQuNYTDFSx0ZX0RUttqa58au8bPzoGYQUrt8bc6591RmH8_pEAIPijdvVYSVXyI",
+    "client_secret": "ENT-J08N3Fw0B0uAokg4RukljAwO9hFHPf8whE6-Dwd8oBWJO8AWMgpdTKpfB1pOy89t4bsFEzMWDowm"
+}
+DETECT_PUSH_DOMAIN = 'http://push.dvema.com/'
+
+
+JPUSH_CONFIG = {
+    'com.ansjer.accloud_ab': {
+        'Key': 'f0dc047e5e53fd14199de5b0',
+        'Secret': 'aa7f7db33e9f0a7f3871aa1c'},
+    'com.ansjer.adcloud_ab': {
+        'Key': '76d97b535185114985608234',
+        'Secret': 'c9a92b301043cc9c52778692'},
+    'com.ansjer.zccloud_ab': {
+        'Key': 'd9924f56d3cc7c6017965130',
+        'Secret': '869d832d126a232f158b5987'},
+    'com.ansjer.loocamccloud_ab': {
+        'Key': 'd1cc44797b4642b0e05304fe',
+        'Secret': 'c3e8b4ca8c576de61401e56a'},
+    'com.ansjer.loocamdcloud_ab': {
+        'Key': '76d97b535185114985608234',
+        'Secret': 'c9a92b301043cc9c52778692'},
+    'com.ansjer.zccloud_a': {
+        'Key': '57de2a80d68bf270fd6bdf5a',
+        'Secret': '3d354eb6a0b49c2610decf42'},
+    'com.ansjer.accloud_a': {
+        'Key': 'ff95ee685f49c0dc4013347b',
+        'Secret': 'de2c20959f5516fdeeafe78e'},
+    'com.ansjer.adcloud_a': {
+        'Key': '2e47eb1aee9b164460df3668',
+        'Secret': 'b9137d8d684bc248f1809b6d'},
+    'com.ansjer.loocamccloud_a': {
+        'Key': '23c9213215c7ca0ec945629b',
+        'Secret': '81e4b1e859cc8387e2e6c431'},
+    'com.ansjer.loocamdcloud_a': {
+        'Key': '1dbdd60a16e9892d6f68a073',
+        'Secret': '80a97690e7e043109059b403'},
+    'com.ansjer.customizedb_a': {
+        'Key': '9d79630aa49adfa291fe2568',
+        'Secret': '4d8ff52f88136561875a0212'},
+    'com.ansjer.customizedd_a': {
+        'Key': '8fc4f495685bde53341ee25d',
+        'Secret': 'f1da11fa466509fa2670fb66',
+    }
+}
+# type =1
+FCM_CONFIG = {
+    'com.ansjer.zccloud_a': 'AAAAb9YP3rk:APA91bHu8u-CTpcd0g6lKPo0WNVqCi8jZub1cPPbSAY9AucT1HxlF65ZDUko9iG8q2ch17bwu9YWHpK1xI1gHSRXCslLvZlXEmHZC0AG3JKg15XuUvlFKACIajUFV-pOeGRT8tM6-31I',
+    'com.ansjer.loocamccloud_a': 'AAAAb9YP3rk:APA91bFCgd-kbVmpK4EVpfdHH_PJZQCYTkOGnTZdIuBWEz2r7aMRsJYHOH3sB-rwcbaRWgnufTyjX9nGQxb6KxQbWVk4ah_H-M3IqGh6Mb60WQQAuR33V6g_Jes5pGL6ViuIxGHqVMaR',
+    'com.ansjer.loocamdcloud_a': 'AAAAb9YP3rk:APA91bGw2I2KMD4i-5T7nZO_wB8kuAOuqgyqe5rxmY-W5qkpYEx9IL2IfmC_qf6B_xOyjIDDSjckvMo-RauN__SEoxvAkis7042GRkoKpw7cjZ_H8lC-d50PC0GclPzccrOGFusyKbFY',
+    'com.ansjer.customizedb_a': 'AAAAb9YP3rk:APA91bE7kI4vcm-9h_CJNFlOZfc-xwP4Btn6AnjOrwoKV6fgYN7fdarkO76sYxVZiAbDnxsFfOJyP7vQfwyan6mdjuyD5iHdt_XgO22VqniC0vA1V4GJiCS8Tp7LxIX8JVKZl9I_Powt',
+    'com.ansjer.customizeda_a': 'AAAAb9YP3rk:APA91bF0HzizVWDc6dKzobY9fsaKDK4veqkOZehDXshVXs8pEEvNWjR_YWbhP60wsRYCHCal8fWN5cECVOWNMMzDsfU88Ty2AUl8S5FtZsmeDTkoGntQOswBr8Ln7Fm_LAp1VqTf9CpM',
+    'com.ansjer.customizedd_a': 'AAAAb9YP3rk:APA91bHkxOozJWBrlv3eNT0PgwosYENI9aM4Zuzd418cX-iKkpa1zFNC5MkNDKApx1KH4fhmAfaJ6IMRZ0nj5GIxCpstDYCaZWwgC7-etqfSxG5JAq8LOwJx0o_1tUZqwjIic8ztsg0o',
+    'com.ansjer.adcloud_a': 'AAAAb9YP3rk:APA91bFm06w8b9OKQ0gz0iaWFuRqRIkvgAz6z7Gp3dBU_X-LNGJQd1hc1QR2W7QzBglF8SHtERA45a2lbdLRa5qv7hxfd6W_sJLBK7dA8jklsOQBvy505oUzTwMKWy4TwH-exps9KrhO',
+    'com.ansjer.accloud_a': 'AAAAb9YP3rk:APA91bFm06w8b9OKQ0gz0iaWFuRqRIkvgAz6z7Gp3dBU_X-LNGJQd1hc1QR2W7QzBglF8SHtERA45a2lbdLRa5qv7hxfd6W_sJLBK7dA8jklsOQBvy505oUzTwMKWy4TwH-exps9KrhO',
+    'com.ansjer.zccloud_ab': 'AAAAb9YP3rk:APA91bHu8u-CTpcd0g6lKPo0WNVqCi8jZub1cPPbSAY9AucT1HxlF65ZDUko9iG8q2ch17bwu9YWHpK1xI1gHSRXCslLvZlXEmHZC0AG3JKg15XuUvlFKACIajUFV-pOeGRT8tM6-31I',
+}
+
+APNS_CONFIG = {
+    'com.ansjer.loocamccloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/lcc.pem',
+    },
+    'com.ansjer.zosidcloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/zosidcloud.pem',
+    },
+    'com.ansjer.customizedb': {
+        'pem_path': 'AnsjerPush/file/apns_pem/customizedb.pem',
+    },
+    'com.ansjer.customizeda': {
+        'pem_path': 'AnsjerPush/file/apns_pem/customizeda.pem',
+    },
+    'com.ansjer.zccloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/zccloud.pem',
+    },
+    'com.ansjer.accloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/accloud.pem',
+    }
+}
+APNS_MODE = 'prod'
+REDIS_ADDRESS = '127.0.0.1'
+# REDIS_ADDRESS = '192.168.136.45'

+ 179 - 0
AnsjerPush/formal_settings.py

@@ -0,0 +1,179 @@
+import os
+
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+SECRET_KEY = '$2hf5g$a%_^kk0-l25l$!o5)yc=dvtnfpc8(+$rh4fq4twa_xx'
+DEBUG = True
+ALLOWED_HOSTS = ["*"]
+
+INSTALLED_APPS = [
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'corsheaders',
+    'imagekit',
+    'Model'
+]
+
+MIDDLEWARE = [
+    'django.middleware.security.SecurityMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'corsheaders.middleware.CorsMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    # 'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'AnsjerPush.urls'
+
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'DIRS': [os.path.join(BASE_DIR, 'templates')]
+        ,
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = 'AnsjerPush.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
+# formal
+DATABASE_DATA = 'Ansjer81'
+SERVER_HOST = 'azrdsinstance.clraczw4p0yj.us-west-1.rds.amazonaws.com'
+DATABASES_USER = 'azrds'
+DATABASES_PASS = 'azrds.x.x'
+
+DATABASES = {'default': {
+    'ENGINE': 'django.db.backends.mysql',
+    'NAME': DATABASE_DATA,
+    'USER': DATABASES_USER,
+    'PASSWORD': DATABASES_PASS,
+    'HOST': SERVER_HOST,
+    'PORT': '3306',
+    'OPTIONS': {'charset': 'utf8mb4', 'use_unicode': True, 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"},
+    'AUTOCOMMIT': True
+}}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+    {
+        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+    },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/2.1/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/2.1/howto/static-files/
+
+STATIC_URL = '/static/'
+# 跨域增加忽略
+# 跨域增加忽略
+CORS_ALLOW_CREDENTIALS = True
+CORS_ORIGIN_ALLOW_ALL = True
+CORS_ORIGIN_WHITELIST = ()
+
+CORS_ALLOW_METHODS = (
+    'DELETE',
+    'GET',
+    'OPTIONS',
+    'PATCH',
+    'POST',
+    'PUT',
+    'VIEW',
+)
+
+CORS_ALLOW_HEADERS = (
+    'accept',
+    'accept-encoding',
+    'authorization',
+    'content-type',
+    'dnt',
+    'origin',
+    'user-agent',
+    'x-csrftoken',
+    'x-requested-with',
+)
+
+
+# 日志模块
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers': True,
+    'formatters': {
+        'error_format': {
+            # 'format': '{"asctime":"%(asctime)s","thread":"%(threadName)s:%(thread)d","errorline":"%(lineno)d","errorlevel":"%(levelname)s","errorcontent":"%(message)s"}'
+            'format': '%(asctime)s %(threadName)s %(thread)d %(lineno)d %(levelname)s %(message)s'
+        },
+    },
+    'filters': {
+    },
+    'handlers': {
+        'mail_admins': {
+            'level': 'ERROR',
+            'class': 'django.utils.log.AdminEmailHandler',
+            'include_html': True,
+        },
+        'default': {
+            'level': 'ERROR',
+            'class': 'logging.handlers.RotatingFileHandler',
+            'filename': BASE_DIR + '/static/log/error.log',
+            'maxBytes': 1024 * 1024 * 5,  # 5 MB
+            'backupCount': 5,
+            'formatter': 'error_format',
+        },
+        'console': {
+            'level': 'ERROR',
+            'class': 'logging.StreamHandler',
+            'formatter': 'error_format'
+        },
+    },
+    'loggers': {
+        'django': {
+            'handlers': ['default', 'console'],
+            # 'handlers': ['mail_admins','default','console'],
+            'level': 'ERROR',
+            'propagate': False
+        },
+    }
+}

+ 16 - 0
AnsjerPush/formal_wsgi.py

@@ -0,0 +1,16 @@
+"""
+WSGI config for AnsjerPush project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'AnsjerPush.formal_settings')
+
+application = get_wsgi_application()

+ 148 - 0
AnsjerPush/local_config.py

@@ -0,0 +1,148 @@
+#!/usr/bin/env python3  
+# -*- coding: utf-8 -*-  
+"""
+@Copyright (C) ansjer cop Video Technology Co.,Ltd.All rights reserved.
+@AUTHOR: ASJRD018
+@NAME: Ansjer
+@software: PyCharm
+@DATE: 2018/7/2 14:06
+@Version: python3.6
+@MODIFY DECORD:ansjer dev
+@file: Conf.py
+@Contact: chanjunkai@163.com
+"""
+# 主要静态变量配置文件
+import datetime, os
+
+
+DEBUG_MODE = 'DEV'
+# MODE = 'PRO'
+# 阿里云发邮箱
+ALY_SES_ACCESS_NAME = 'message@dvema.com'
+ALY_SES_ACCESS_PAW = 'SMtp123456'
+ALY_SES_ACCESS_REPLYTO = '***'
+
+# 发送邮件邮箱
+SES_COMPANY_EMAIL = 'user_server@nsst.com'
+AWS_SES_ACCESS_ID = 'AKIAJKPU23EU5QWHFPKQ'
+AWS_SES_ACCESS_SECRET = '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'
+AWS_SES_ACCESS_REGION = 'us-east-1'
+AWS_BUCKET = 'ansjertest'
+# 设定离线时间为5分钟
+OFF_LINE_TIME_DELTA = 5
+
+# token的secret
+OAUTH_ACCESS_TOKEN_SECRET = 'a+jbgnw%@1%zy^=@dn62%'
+OAUTH_REFRESH_TOKEN_SECRET = 'r+jbgnw%@1%zy^=@dn62%'
+# access_token超时
+# OAUTH_ACCESS_TOKEN_TIME = datetime.timedelta(hours=1)
+OAUTH_ACCESS_TOKEN_TIME = datetime.timedelta(days=30)
+# refresh_token超时
+OAUTH_REFRESH_TOKEN_TIME = datetime.timedelta(days=30)
+# 腾讯验证,短信发送
+TX_PHONE_APP_ID = '1400052907'
+TX_PHONE_APP_KEY = '7705976ca6e85fe7b86d6bc2d11f7783'
+
+# 验证码超时时间
+AuthCode_Expire = 600
+
+# 根路径
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+# uid token key
+UID_TOKEN_KEY = 'c+565*j@%^'
+
+# oss param
+OSS_STS_ACCESS_KEY = 'LTAIyMkGfEdogyL9'
+OSS_STS_ACCESS_SECRET = '71uIjpsqVOmF7DAITRyRuc259jHOjO'
+OSS_ROLE_ARN = 'acs:ram::1901342792446414:role/stsoss'
+
+SERVER_TYPE = 'Ansjer.local_settings'
+
+NGINX_RTMP_STAT = 'http://www.dvema.com/stat'
+SERVER_DOMAIN = 'http://www.dvema.com/'
+SERVER_DOMAIN_SSL = 'https://www.dvema.com/'
+DOMAIN_HOST = 'www.dvema.com'
+SERVER_HOST = '192.168.136.45'
+# SERVER_HOST = 'localhost'
+PAYPAL_CRD = {
+    "mode": "live",  # sandbox or live
+    "client_id": "AdSRd6WBn-qLl9OiQHQuNYTDFSx0ZX0RUttqa58au8bPzoGYQUrt8bc6591RmH8_pEAIPijdvVYSVXyI",
+    "client_secret": "ENT-J08N3Fw0B0uAokg4RukljAwO9hFHPf8whE6-Dwd8oBWJO8AWMgpdTKpfB1pOy89t4bsFEzMWDowm"
+}
+DETECT_PUSH_DOMAIN = 'http://push.dvema.com/'
+
+
+JPUSH_CONFIG = {
+    'com.ansjer.accloud_ab': {
+        'Key': 'f0dc047e5e53fd14199de5b0',
+        'Secret': 'aa7f7db33e9f0a7f3871aa1c'},
+    'com.ansjer.adcloud_ab': {
+        'Key': '76d97b535185114985608234',
+        'Secret': 'c9a92b301043cc9c52778692'},
+    'com.ansjer.zccloud_ab': {
+        'Key': 'd9924f56d3cc7c6017965130',
+        'Secret': '869d832d126a232f158b5987'},
+    'com.ansjer.loocamccloud_ab': {
+        'Key': 'd1cc44797b4642b0e05304fe',
+        'Secret': 'c3e8b4ca8c576de61401e56a'},
+    'com.ansjer.loocamdcloud_ab': {
+        'Key': '76d97b535185114985608234',
+        'Secret': 'c9a92b301043cc9c52778692'},
+    'com.ansjer.zccloud_a': {
+        'Key': '57de2a80d68bf270fd6bdf5a',
+        'Secret': '3d354eb6a0b49c2610decf42'},
+    'com.ansjer.accloud_a': {
+        'Key': 'ff95ee685f49c0dc4013347b',
+        'Secret': 'de2c20959f5516fdeeafe78e'},
+    'com.ansjer.adcloud_a': {
+        'Key': '2e47eb1aee9b164460df3668',
+        'Secret': 'b9137d8d684bc248f1809b6d'},
+    'com.ansjer.loocamccloud_a': {
+        'Key': '23c9213215c7ca0ec945629b',
+        'Secret': '81e4b1e859cc8387e2e6c431'},
+    'com.ansjer.loocamdcloud_a': {
+        'Key': '1dbdd60a16e9892d6f68a073',
+        'Secret': '80a97690e7e043109059b403'},
+    'com.ansjer.customizedb_a': {
+        'Key': '9d79630aa49adfa291fe2568',
+        'Secret': '4d8ff52f88136561875a0212'},
+    'com.ansjer.customizedd_a': {
+        'Key': '8fc4f495685bde53341ee25d',
+        'Secret': 'f1da11fa466509fa2670fb66',
+    }
+}
+# type =1
+FCM_CONFIG = {
+    'com.ansjer.zccloud_a': 'AAAAb9YP3rk:APA91bHu8u-CTpcd0g6lKPo0WNVqCi8jZub1cPPbSAY9AucT1HxlF65ZDUko9iG8q2ch17bwu9YWHpK1xI1gHSRXCslLvZlXEmHZC0AG3JKg15XuUvlFKACIajUFV-pOeGRT8tM6-31I',
+    'com.ansjer.loocamccloud_a': 'AAAAb9YP3rk:APA91bFCgd-kbVmpK4EVpfdHH_PJZQCYTkOGnTZdIuBWEz2r7aMRsJYHOH3sB-rwcbaRWgnufTyjX9nGQxb6KxQbWVk4ah_H-M3IqGh6Mb60WQQAuR33V6g_Jes5pGL6ViuIxGHqVMaR',
+    'com.ansjer.loocamdcloud_a': 'AAAAb9YP3rk:APA91bGw2I2KMD4i-5T7nZO_wB8kuAOuqgyqe5rxmY-W5qkpYEx9IL2IfmC_qf6B_xOyjIDDSjckvMo-RauN__SEoxvAkis7042GRkoKpw7cjZ_H8lC-d50PC0GclPzccrOGFusyKbFY',
+    'com.ansjer.customizedb_a': 'AAAAb9YP3rk:APA91bE7kI4vcm-9h_CJNFlOZfc-xwP4Btn6AnjOrwoKV6fgYN7fdarkO76sYxVZiAbDnxsFfOJyP7vQfwyan6mdjuyD5iHdt_XgO22VqniC0vA1V4GJiCS8Tp7LxIX8JVKZl9I_Powt',
+    'com.ansjer.customizeda_a': 'AAAAb9YP3rk:APA91bF0HzizVWDc6dKzobY9fsaKDK4veqkOZehDXshVXs8pEEvNWjR_YWbhP60wsRYCHCal8fWN5cECVOWNMMzDsfU88Ty2AUl8S5FtZsmeDTkoGntQOswBr8Ln7Fm_LAp1VqTf9CpM',
+    'com.ansjer.customizedd_a': 'AAAAb9YP3rk:APA91bHkxOozJWBrlv3eNT0PgwosYENI9aM4Zuzd418cX-iKkpa1zFNC5MkNDKApx1KH4fhmAfaJ6IMRZ0nj5GIxCpstDYCaZWwgC7-etqfSxG5JAq8LOwJx0o_1tUZqwjIic8ztsg0o',
+    'com.ansjer.adcloud_a': 'AAAAb9YP3rk:APA91bFm06w8b9OKQ0gz0iaWFuRqRIkvgAz6z7Gp3dBU_X-LNGJQd1hc1QR2W7QzBglF8SHtERA45a2lbdLRa5qv7hxfd6W_sJLBK7dA8jklsOQBvy505oUzTwMKWy4TwH-exps9KrhO',
+    'com.ansjer.accloud_a': 'AAAAb9YP3rk:APA91bFm06w8b9OKQ0gz0iaWFuRqRIkvgAz6z7Gp3dBU_X-LNGJQd1hc1QR2W7QzBglF8SHtERA45a2lbdLRa5qv7hxfd6W_sJLBK7dA8jklsOQBvy505oUzTwMKWy4TwH-exps9KrhO',
+    'com.ansjer.zccloud_ab': 'AAAAb9YP3rk:APA91bHu8u-CTpcd0g6lKPo0WNVqCi8jZub1cPPbSAY9AucT1HxlF65ZDUko9iG8q2ch17bwu9YWHpK1xI1gHSRXCslLvZlXEmHZC0AG3JKg15XuUvlFKACIajUFV-pOeGRT8tM6-31I',
+}
+
+APNS_CONFIG = {
+    'com.ansjer.loocamccloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/lcc-dev.pem',
+    },
+    'com.ansjer.zosidcloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/zosidcloud-dev.pem',
+    },
+    'com.ansjer.customizedb': {
+        'pem_path': 'AnsjerPush/file/apns_pem/customizedb-dev.pem',
+    },
+    'com.ansjer.customizeda': {
+        'pem_path': 'AnsjerPush/file/apns_pem/customizeda-dev.pem',
+    },
+    'com.ansjer.zccloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/zccloud-dev.pem',
+    },
+    'com.ansjer.accloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/accloud-dev.pem',
+    }
+}
+APNS_MODE = 'dev'
+REDIS_ADDRESS = '192.168.136.45'

+ 196 - 0
AnsjerPush/local_settings.py

@@ -0,0 +1,196 @@
+import os
+
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+SECRET_KEY = '$2hf5g$a%_^kk0-l25l$!o5)yc=dvtnfpc8(+$rh4fq4twa_xx'
+DEBUG = True
+ALLOWED_HOSTS = ["*"]
+
+INSTALLED_APPS = [
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'corsheaders',
+    'imagekit',
+    'Model'
+]
+
+MIDDLEWARE = [
+    'django.middleware.security.SecurityMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'corsheaders.middleware.CorsMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    # 'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'AnsjerPush.urls'
+
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'DIRS': [os.path.join(BASE_DIR, 'templates')]
+        ,
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = 'AnsjerPush.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
+# formal
+# DATABASE_DATA = 'Ansjer81'
+# SERVER_HOST = 'localhost'
+# DATABASES_USER = 'ansjer'
+# DATABASES_PASS = '1234'
+# test
+# DATABASE_DATA = 'AnsjerTest'
+# SERVER_HOST = '13.56.215.252'
+# DATABASES_USER = 'ansjer'
+# DATABASES_PASS = '1234'
+DATABASE_DATA = 'AnsjerLocal'
+SERVER_HOST = '192.168.136.45'
+DATABASES_USER = 'ansjer'
+DATABASES_PASS = 'ansjer.x.x'
+
+DATABASES = {'default': {
+    'ENGINE': 'django.db.backends.mysql',
+    'NAME': DATABASE_DATA,
+    'USER': DATABASES_USER,
+    'PASSWORD': DATABASES_PASS,
+    'HOST': SERVER_HOST,
+    'PORT': '3306',
+    'OPTIONS': {'charset': 'utf8mb4', 'use_unicode': True, 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"},
+    'AUTOCOMMIT': True
+}}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+    {
+        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+    },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/2.1/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/2.1/howto/static-files/
+
+STATIC_URL = '/static/'
+# 跨域增加忽略
+# 跨域增加忽略
+CORS_ALLOW_CREDENTIALS = True
+CORS_ORIGIN_ALLOW_ALL = True
+CORS_ORIGIN_WHITELIST = ()
+
+CORS_ALLOW_METHODS = (
+    'DELETE',
+    'GET',
+    'OPTIONS',
+    'PATCH',
+    'POST',
+    'PUT',
+    'VIEW',
+)
+
+CORS_ALLOW_HEADERS = (
+    'accept',
+    'accept-encoding',
+    'authorization',
+    'content-type',
+    'dnt',
+    'origin',
+    'user-agent',
+    'x-csrftoken',
+    'x-requested-with',
+)
+
+
+# 日志模块
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers': True,
+    'formatters': {
+        'error_format': {
+            # 'format': '{"asctime":"%(asctime)s","thread":"%(threadName)s:%(thread)d","errorline":"%(lineno)d","errorlevel":"%(levelname)s","errorcontent":"%(message)s"}'
+            'format': '%(asctime)s %(threadName)s %(thread)d %(lineno)d %(levelname)s %(message)s'
+        },
+    },
+    'filters': {
+    },
+    'handlers': {
+        'mail_admins': {
+            'level': 'ERROR',
+            'class': 'django.utils.log.AdminEmailHandler',
+            'include_html': True,
+        },
+        'default': {
+            'level': 'ERROR',
+            'class': 'logging.handlers.RotatingFileHandler',
+            'filename': BASE_DIR + '/static/log/error.log',
+            'maxBytes': 1024 * 1024 * 5,  # 5 MB
+            'backupCount': 5,
+            'formatter': 'error_format',
+        },
+        'console': {
+            # 'level': 'ERROR',
+            'level': 'DEBUG',
+            'class': 'logging.StreamHandler',
+            'formatter': 'error_format'
+        },
+    },
+    'loggers': {
+        'django': {
+            'handlers': ['default', 'console'],
+            # 'handlers': ['mail_admins','default','console'],
+            # 'level': 'ERROR',
+            'level': 'DEBUG',
+            'propagate': True
+        },
+        # 'django.db.backends': {
+        #     'handlers': ['console'],
+        #     'propagate': True,
+        #     'level': 'DEBUG',
+        # },
+    }
+}
+

+ 16 - 0
AnsjerPush/local_wsgi.py

@@ -0,0 +1,16 @@
+"""
+WSGI config for AnsjerPush project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'AnsjerPush.local_settings')
+
+application = get_wsgi_application()

+ 145 - 0
AnsjerPush/settings.py

@@ -0,0 +1,145 @@
+import os
+
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+SECRET_KEY = '$2hf5g$a%_^kk0-l25l$!o5)yc=dvtnfpc8(+$rh4fq4twa_xx'
+DEBUG = True
+ALLOWED_HOSTS = ["*"]
+
+INSTALLED_APPS = [
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'corsheaders',
+    'imagekit',
+    'Model'
+]
+
+MIDDLEWARE = [
+    'django.middleware.security.SecurityMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'corsheaders.middleware.CorsMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    # 'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'AnsjerPush.urls'
+
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'DIRS': [os.path.join(BASE_DIR, 'templates')]
+        ,
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = 'AnsjerPush.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
+# formal
+# DATABASE_DATA = 'Ansjer81'
+# SERVER_HOST = 'localhost'
+# DATABASES_USER = 'ansjer'
+# DATABASES_PASS = '1234'
+# test
+# DATABASE_DATA = 'AnsjerTest'
+# SERVER_HOST = '13.56.215.252'
+# DATABASES_USER = 'ansjer'
+# DATABASES_PASS = '1234'
+DATABASE_DATA = 'AnsjerLocal'
+SERVER_HOST = '192.168.136.45'
+DATABASES_USER = 'ansjer'
+DATABASES_PASS = 'ansjer.x.x'
+
+DATABASES = {'default': {
+    'ENGINE': 'django.db.backends.mysql',
+    'NAME': DATABASE_DATA,
+    'USER': DATABASES_USER,
+    'PASSWORD': DATABASES_PASS,
+    'HOST': SERVER_HOST,
+    'PORT': '3306',
+    'OPTIONS': {'charset': 'utf8mb4', 'use_unicode': True, 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"},
+    'AUTOCOMMIT': True
+}}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+    {
+        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+    },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/2.1/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/2.1/howto/static-files/
+
+STATIC_URL = '/static/'
+# 跨域增加忽略
+# 跨域增加忽略
+CORS_ALLOW_CREDENTIALS = True
+CORS_ORIGIN_ALLOW_ALL = True
+CORS_ORIGIN_WHITELIST = ()
+
+CORS_ALLOW_METHODS = (
+    'DELETE',
+    'GET',
+    'OPTIONS',
+    'PATCH',
+    'POST',
+    'PUT',
+    'VIEW',
+)
+
+CORS_ALLOW_HEADERS = (
+    'accept',
+    'accept-encoding',
+    'authorization',
+    'content-type',
+    'dnt',
+    'origin',
+    'user-agent',
+    'x-csrftoken',
+    'x-requested-with',
+)

+ 146 - 0
AnsjerPush/test_config.py

@@ -0,0 +1,146 @@
+#!/usr/bin/env python3  
+# -*- coding: utf-8 -*-  
+"""
+@Copyright (C) ansjer cop Video Technology Co.,Ltd.All rights reserved.
+@AUTHOR: ASJRD018
+@NAME: Ansjer
+@software: PyCharm
+@DATE: 2018/7/2 14:06
+@Version: python3.6
+@MODIFY DECORD:ansjer dev
+@file: Conf.py
+@Contact: chanjunkai@163.com
+"""
+# 主要静态变量配置文件
+import datetime, os
+
+
+# MODE = 'PRO'
+# 阿里云发邮箱
+ALY_SES_ACCESS_NAME = 'message@dvema.com'
+ALY_SES_ACCESS_PAW = 'SMtp123456'
+ALY_SES_ACCESS_REPLYTO = '***'
+
+# 发送邮件邮箱
+SES_COMPANY_EMAIL = 'user_server@nsst.com'
+AWS_SES_ACCESS_ID = 'AKIAJKPU23EU5QWHFPKQ'
+AWS_SES_ACCESS_SECRET = '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'
+AWS_SES_ACCESS_REGION = 'us-east-1'
+AWS_BUCKET = 'ansjertest'
+# 设定离线时间为5分钟
+OFF_LINE_TIME_DELTA = 5
+
+# token的secret
+OAUTH_ACCESS_TOKEN_SECRET = 'a+jbgnw%@1%zy^=@dn62%'
+OAUTH_REFRESH_TOKEN_SECRET = 'r+jbgnw%@1%zy^=@dn62%'
+# access_token超时
+# OAUTH_ACCESS_TOKEN_TIME = datetime.timedelta(hours=1)
+OAUTH_ACCESS_TOKEN_TIME = datetime.timedelta(days=30)
+# refresh_token超时
+OAUTH_REFRESH_TOKEN_TIME = datetime.timedelta(days=30)
+# 腾讯验证,短信发送
+TX_PHONE_APP_ID = '1400052907'
+TX_PHONE_APP_KEY = '7705976ca6e85fe7b86d6bc2d11f7783'
+
+# 验证码超时时间
+AuthCode_Expire = 600
+
+# 根路径
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+# uid token key
+UID_TOKEN_KEY = 'c+565*j@%^'
+
+# oss param
+OSS_STS_ACCESS_KEY = 'LTAIyMkGfEdogyL9'
+OSS_STS_ACCESS_SECRET = '71uIjpsqVOmF7DAITRyRuc259jHOjO'
+OSS_ROLE_ARN = 'acs:ram::1901342792446414:role/stsoss'
+
+SERVER_TYPE = 'Ansjer.test_settings'
+
+NGINX_RTMP_STAT = 'http://www.dvema.com/stat'
+SERVER_DOMAIN = 'http://www.dvema.com/'
+SERVER_DOMAIN_SSL = 'https://www.dvema.com/'
+DOMAIN_HOST = 'www.dvema.com'
+SERVER_HOST = 'localhost'
+PAYPAL_CRD = {
+    "mode": "live",  # sandbox or live
+    "client_id": "AdSRd6WBn-qLl9OiQHQuNYTDFSx0ZX0RUttqa58au8bPzoGYQUrt8bc6591RmH8_pEAIPijdvVYSVXyI",
+    "client_secret": "ENT-J08N3Fw0B0uAokg4RukljAwO9hFHPf8whE6-Dwd8oBWJO8AWMgpdTKpfB1pOy89t4bsFEzMWDowm"
+}
+DETECT_PUSH_DOMAIN = 'http://push.dvema.com/'
+
+
+JPUSH_CONFIG = {
+    'com.ansjer.accloud_ab': {
+        'Key': 'f0dc047e5e53fd14199de5b0',
+        'Secret': 'aa7f7db33e9f0a7f3871aa1c'},
+    'com.ansjer.adcloud_ab': {
+        'Key': '76d97b535185114985608234',
+        'Secret': 'c9a92b301043cc9c52778692'},
+    'com.ansjer.zccloud_ab': {
+        'Key': 'd9924f56d3cc7c6017965130',
+        'Secret': '869d832d126a232f158b5987'},
+    'com.ansjer.loocamccloud_ab': {
+        'Key': 'd1cc44797b4642b0e05304fe',
+        'Secret': 'c3e8b4ca8c576de61401e56a'},
+    'com.ansjer.loocamdcloud_ab': {
+        'Key': '76d97b535185114985608234',
+        'Secret': 'c9a92b301043cc9c52778692'},
+    'com.ansjer.zccloud_a': {
+        'Key': '57de2a80d68bf270fd6bdf5a',
+        'Secret': '3d354eb6a0b49c2610decf42'},
+    'com.ansjer.accloud_a': {
+        'Key': 'ff95ee685f49c0dc4013347b',
+        'Secret': 'de2c20959f5516fdeeafe78e'},
+    'com.ansjer.adcloud_a': {
+        'Key': '2e47eb1aee9b164460df3668',
+        'Secret': 'b9137d8d684bc248f1809b6d'},
+    'com.ansjer.loocamccloud_a': {
+        'Key': '23c9213215c7ca0ec945629b',
+        'Secret': '81e4b1e859cc8387e2e6c431'},
+    'com.ansjer.loocamdcloud_a': {
+        'Key': '1dbdd60a16e9892d6f68a073',
+        'Secret': '80a97690e7e043109059b403'},
+    'com.ansjer.customizedb_a': {
+        'Key': '9d79630aa49adfa291fe2568',
+        'Secret': '4d8ff52f88136561875a0212'},
+    'com.ansjer.customizedd_a': {
+        'Key': '8fc4f495685bde53341ee25d',
+        'Secret': 'f1da11fa466509fa2670fb66',
+    }
+}
+# type =1
+FCM_CONFIG = {
+    'com.ansjer.zccloud_a': 'AAAAb9YP3rk:APA91bHu8u-CTpcd0g6lKPo0WNVqCi8jZub1cPPbSAY9AucT1HxlF65ZDUko9iG8q2ch17bwu9YWHpK1xI1gHSRXCslLvZlXEmHZC0AG3JKg15XuUvlFKACIajUFV-pOeGRT8tM6-31I',
+    'com.ansjer.loocamccloud_a': 'AAAAb9YP3rk:APA91bFCgd-kbVmpK4EVpfdHH_PJZQCYTkOGnTZdIuBWEz2r7aMRsJYHOH3sB-rwcbaRWgnufTyjX9nGQxb6KxQbWVk4ah_H-M3IqGh6Mb60WQQAuR33V6g_Jes5pGL6ViuIxGHqVMaR',
+    'com.ansjer.loocamdcloud_a': 'AAAAb9YP3rk:APA91bGw2I2KMD4i-5T7nZO_wB8kuAOuqgyqe5rxmY-W5qkpYEx9IL2IfmC_qf6B_xOyjIDDSjckvMo-RauN__SEoxvAkis7042GRkoKpw7cjZ_H8lC-d50PC0GclPzccrOGFusyKbFY',
+    'com.ansjer.customizedb_a': 'AAAAb9YP3rk:APA91bE7kI4vcm-9h_CJNFlOZfc-xwP4Btn6AnjOrwoKV6fgYN7fdarkO76sYxVZiAbDnxsFfOJyP7vQfwyan6mdjuyD5iHdt_XgO22VqniC0vA1V4GJiCS8Tp7LxIX8JVKZl9I_Powt',
+    'com.ansjer.customizeda_a': 'AAAAb9YP3rk:APA91bF0HzizVWDc6dKzobY9fsaKDK4veqkOZehDXshVXs8pEEvNWjR_YWbhP60wsRYCHCal8fWN5cECVOWNMMzDsfU88Ty2AUl8S5FtZsmeDTkoGntQOswBr8Ln7Fm_LAp1VqTf9CpM',
+    'com.ansjer.customizedd_a': 'AAAAb9YP3rk:APA91bHkxOozJWBrlv3eNT0PgwosYENI9aM4Zuzd418cX-iKkpa1zFNC5MkNDKApx1KH4fhmAfaJ6IMRZ0nj5GIxCpstDYCaZWwgC7-etqfSxG5JAq8LOwJx0o_1tUZqwjIic8ztsg0o',
+    'com.ansjer.adcloud_a': 'AAAAb9YP3rk:APA91bFm06w8b9OKQ0gz0iaWFuRqRIkvgAz6z7Gp3dBU_X-LNGJQd1hc1QR2W7QzBglF8SHtERA45a2lbdLRa5qv7hxfd6W_sJLBK7dA8jklsOQBvy505oUzTwMKWy4TwH-exps9KrhO',
+    'com.ansjer.accloud_a': 'AAAAb9YP3rk:APA91bFm06w8b9OKQ0gz0iaWFuRqRIkvgAz6z7Gp3dBU_X-LNGJQd1hc1QR2W7QzBglF8SHtERA45a2lbdLRa5qv7hxfd6W_sJLBK7dA8jklsOQBvy505oUzTwMKWy4TwH-exps9KrhO',
+    'com.ansjer.zccloud_ab': 'AAAAb9YP3rk:APA91bHu8u-CTpcd0g6lKPo0WNVqCi8jZub1cPPbSAY9AucT1HxlF65ZDUko9iG8q2ch17bwu9YWHpK1xI1gHSRXCslLvZlXEmHZC0AG3JKg15XuUvlFKACIajUFV-pOeGRT8tM6-31I',
+}
+
+APNS_CONFIG = {
+    'com.ansjer.loocamccloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/lcc-dev.pem',
+    },
+    'com.ansjer.zosidcloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/zosidcloud-dev.pem',
+    },
+    'com.ansjer.customizedb': {
+        'pem_path': 'AnsjerPush/file/apns_pem/customizedb-dev.pem',
+    },
+    'com.ansjer.customizeda': {
+        'pem_path': 'AnsjerPush/file/apns_pem/customizeda-dev.pem',
+    },
+    'com.ansjer.zccloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/zccloud-dev.pem',
+    },
+    'com.ansjer.accloud': {
+        'pem_path': 'AnsjerPush/file/apns_pem/accloud-dev.pem',
+    }
+}
+APNS_MODE = 'dev'
+REDIS_ADDRESS = '127.0.0.1'

+ 180 - 0
AnsjerPush/test_settings.py

@@ -0,0 +1,180 @@
+import os
+
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+SECRET_KEY = '$2hf5g$a%_^kk0-l25l$!o5)yc=dvtnfpc8(+$rh4fq4twa_xx'
+DEBUG = True
+ALLOWED_HOSTS = ["*"]
+
+INSTALLED_APPS = [
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'corsheaders',
+    'imagekit',
+    'Model'
+]
+
+MIDDLEWARE = [
+    'django.middleware.security.SecurityMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'corsheaders.middleware.CorsMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    # 'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'AnsjerPush.urls'
+
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'DIRS': [os.path.join(BASE_DIR, 'templates')]
+        ,
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = 'AnsjerPush.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
+
+# test
+DATABASE_DATA = 'AnsjerTest'
+SERVER_HOST = 'azrdsinstance.clraczw4p0yj.us-west-1.rds.amazonaws.com'
+DATABASES_USER = 'azrds'
+DATABASES_PASS = 'azrds.x.x'
+
+
+DATABASES = {'default': {
+    'ENGINE': 'django.db.backends.mysql',
+    'NAME': DATABASE_DATA,
+    'USER': DATABASES_USER,
+    'PASSWORD': DATABASES_PASS,
+    'HOST': SERVER_HOST,
+    'PORT': '3306',
+    'OPTIONS': {'charset': 'utf8mb4', 'use_unicode': True, 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"},
+    'AUTOCOMMIT': True
+}}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+    {
+        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+    },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/2.1/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/2.1/howto/static-files/
+
+STATIC_URL = '/static/'
+# 跨域增加忽略
+# 跨域增加忽略
+CORS_ALLOW_CREDENTIALS = True
+CORS_ORIGIN_ALLOW_ALL = True
+CORS_ORIGIN_WHITELIST = ()
+
+CORS_ALLOW_METHODS = (
+    'DELETE',
+    'GET',
+    'OPTIONS',
+    'PATCH',
+    'POST',
+    'PUT',
+    'VIEW',
+)
+
+CORS_ALLOW_HEADERS = (
+    'accept',
+    'accept-encoding',
+    'authorization',
+    'content-type',
+    'dnt',
+    'origin',
+    'user-agent',
+    'x-csrftoken',
+    'x-requested-with',
+)
+
+# 日志模块
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers': True,
+    'formatters': {
+        'error_format': {
+            # 'format': '{"asctime":"%(asctime)s","thread":"%(threadName)s:%(thread)d","errorline":"%(lineno)d","errorlevel":"%(levelname)s","errorcontent":"%(message)s"}'
+            'format': '%(asctime)s %(threadName)s %(thread)d %(lineno)d %(levelname)s %(message)s'
+        },
+    },
+    'filters': {
+    },
+    'handlers': {
+        'mail_admins': {
+            'level': 'ERROR',
+            'class': 'django.utils.log.AdminEmailHandler',
+            'include_html': True,
+        },
+        'default': {
+            'level': 'ERROR',
+            'class': 'logging.handlers.RotatingFileHandler',
+            'filename': BASE_DIR + '/static/log/error.log',
+            'maxBytes': 1024 * 1024 * 5,  # 5 MB
+            'backupCount': 5,
+            'formatter': 'error_format',
+        },
+        'console': {
+            'level': 'ERROR',
+            'class': 'logging.StreamHandler',
+            'formatter': 'error_format'
+        },
+    },
+    'loggers': {
+        'django': {
+            'handlers': ['default', 'console'],
+            # 'handlers': ['mail_admins','default','console'],
+            'level': 'ERROR',
+            'propagate': True
+        },
+    }
+}

+ 16 - 0
AnsjerPush/test_wsgi.py

@@ -0,0 +1,16 @@
+"""
+WSGI config for AnsjerPush project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'AnsjerPush.test_settings')
+
+application = get_wsgi_application()

+ 27 - 0
AnsjerPush/urls.py

@@ -0,0 +1,27 @@
+"""AnsjerPush URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/2.1/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  path('', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
+Including another URLconf
+    1. Import the include() function: from django.urls import include, path
+    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
+"""
+from django.contrib import admin
+from django.urls import path
+from Controller import DetectController, ShadowController, TestDetectController
+
+
+urlpatterns = [
+    path('admin/', admin.site.urls),
+    path('notify/push', DetectController.NotificationView.as_view()),
+    path('deviceShadow/update', ShadowController.update_device_shadow),
+    path('deviceShadow/generateUTK', ShadowController.generate_utk),
+    path('test/notify/push', TestDetectController.NotificationView.as_view()),
+]

+ 16 - 0
AnsjerPush/wsgi.py

@@ -0,0 +1,16 @@
+"""
+WSGI config for AnsjerPush project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'AnsjerPush.settings')
+
+application = get_wsgi_application()

+ 651 - 0
Controller/DetectController.py

@@ -0,0 +1,651 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+@Copyright (C) ansjer cop Video Technology Co.,Ltd.All rights reserved.
+@AUTHOR: ASJRD018
+@NAME: AnsjerFormal
+@software: PyCharm
+@DATE: 2019/1/14 15:57
+@Version: python3.6
+@MODIFY DECORD:ansjer dev
+@file: DetectController.py
+@Contact: chanjunkai@163.com
+"""
+import os
+import time
+
+import apns2
+import jpush as jpush
+import oss2
+from django.http import JsonResponse
+from django.views.generic.base import View
+from pyfcm import FCMNotification
+from AnsjerPush.config import SERVER_TYPE
+from AnsjerPush.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET, DETECT_PUSH_DOMAIN, JPUSH_CONFIG, FCM_CONFIG, \
+    APNS_CONFIG, BASE_DIR, APNS_MODE
+from Model.models import Equipment_Info, UidPushModel, SysMsgModel
+from Object.ETkObject import ETkObject
+from Object.RedisObject import RedisObject
+from Object.UidTokenObject import UidTokenObject
+from Service.CommonService import CommonService
+
+'''
+http://push.dvema.com/notify/push?etk=Y2lTRXhMTjBWS01sWlpURTVJU0ZWTlJ6RXhNVUU9T3o=&n_time=1526845794&channel=1&event_type=704&is_st=0
+http://push.dvema.com/deviceShadow/generateUTK?username=debug_user&password=debug_password&uid=VVDHCVBYDKFMJRWA111A
+'''
+
+
+# 移动侦测接口
+class NotificationView(View):
+
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        return self.validation(request.GET)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        return self.validation(request.POST)
+
+    def validation(self, request_dict):
+        uidToken = request_dict.get('uidToken', None)
+        etk = request_dict.get('etk', None)
+        channel = request_dict.get('channel', '1')
+        n_time = request_dict.get('n_time', None)
+        event_type = request_dict.get('event_type', None)
+        is_st = request_dict.get('is_st', None)
+        # print("aaa")
+        # return JsonResponse(0,safe=False)
+        if not all([channel, n_time]):
+            return JsonResponse(status=200, data={
+                'code': 444,
+                'msg': 'param is wrong'})
+        if etk:
+            eto = ETkObject(etk)
+            uid = eto.uid
+            if len(uid) != 20:
+                return JsonResponse(status=200, data={'code': 404, 'msg': 'data is not exist'})
+        else:
+            utko = UidTokenObject(uidToken)
+            uid = utko.UID
+        pkey = '{uid}_{channel}_ptl'.format(uid=uid, channel=channel)
+        # ykey = 'MUJ887NLR8K8GBM9111A_redis_qs'.format(uid=uid)
+        ykey = '{uid}_redis_qs'.format(uid=uid)
+        dkey = '{uid}_{channel}_{event_type}_flag'.format(uid=uid, event_type=event_type, channel=channel)
+        # 判断redisObj.get_data(key=pkey):不为空
+        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)  # 推送类型限制
+
+        # 一分钟外,推送开启状态
+        detect_med_type = 0  # 0推送旧机制 1存库不推送,2推送存库
+        # 暂时注销
+        if have_pkey:
+            if SERVER_TYPE != "Ansjer.formal_settings":
+                res_data = {'code': 0, 'msg': 'Push once every 10 seconds'}
+            else:
+                res_data = {'code': 0, 'msg': 'Push it once a minute'}
+            return JsonResponse(status=200, data=res_data)
+
+        # 数据库读取数据
+        if have_ykey:
+            redis_list = eval(redisObj.get_data(key=ykey))
+        else:
+            # 从数据库查询出来
+            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')
+            # 新建一个list接收数据
+            redis_list = []
+            # 把数据库数据追加进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)
+            if not redis_list:
+                res_data = {'code': 404, 'msg': 'error !'}
+                return JsonResponse(status=200, data=res_data)
+
+            # 此时应该更新一下redis里面的dkey的有效时间
+            detect_interval = redis_list[0]['uid_set__detect_interval']
+            channel = redis_list[0]['uid_set__channel']
+            self.do_update_detect_interval(uid, channel, redisObj, detect_interval)
+
+        if not redis_list:
+            print("没有redi_list")
+            res_data = {'code': 0, 'msg': 'no redi_list success!'}
+            return JsonResponse(status=200, data=res_data)
+
+        is_sys_msg = self.is_sys_msg(int(event_type))
+        nickname = redis_list[0]['uid_set__nickname']
+        detect_interval = redis_list[0]['uid_set__detect_interval']
+        detect_group = redis_list[0]['uid_set__detect_group']
+        now_time = int(time.time())
+        if not nickname:
+            nickname = uid
+        if detect_group:
+            if have_dkey:
+                detect_med_type = 1  # 1为存库不推送
+            else:
+                detect_med_type = 2  # 为2的话,既推送,又存库
+                # detect_group=0允许全部推送的时候
+                if detect_group == '0':
+                    redisObj.set_data(key=dkey, val=1, expire=detect_interval)
+                else:
+                    detect_group_list = detect_group.split(',')
+                    if event_type in detect_group_list:
+                        if detect_interval < 60:
+                            detect_interval = 60
+                        redisObj.set_data(key=dkey, val=1, expire=detect_interval)
+                # 改为1秒
+                # 如果不是正式
+                if SERVER_TYPE!="Ansjer.formal_settings":
+                    redisObj.set_data(key=pkey, val=1, expire=10)
+                else:
+                    redisObj.set_data(key=pkey, val=1, expire=60)
+
+            # 打印have_ykey
+        # return JsonResponse(status=200, data={'pkey': 0, 'have_ykey': have_ykey, 'have_pkey': have_pkey, 'have_ykey': have_dkey})
+
+        # 旧模式并且没有pkey,重新创建一个
+        if not detect_group and not have_pkey:
+            # 设置推送时间为60秒一次
+            # 如果不是正式
+            if SERVER_TYPE != "Ansjer.formal_settings":
+                redisObj.set_data(key=pkey, val=1, expire=10)
+            else:
+                redisObj.set_data(key=pkey, val=1, expire=60)
+        auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)
+        bucket = oss2.Bucket(auth, 'oss-cn-shenzhen.aliyuncs.com', 'apg')
+        kwag_args = {
+            'uid': uid,
+            'channel': channel,
+            'event_type': event_type,
+            'n_time': n_time,
+            # 'appBundleId': appBundleId,
+            # 'token_val': token_val,
+            # 'msg_title': msg_title,
+            # 'msg_text': msg_text
+        }
+        eq_list = []
+        sys_msg_list = []
+        userID_ids = []
+        do_apns_code = ''
+        do_fcm_code = ''
+        do_jpush_code = ''
+        for up in redis_list:
+            push_type = up['push_type']
+            appBundleId = up['appBundleId']
+            token_val = up['token_val']
+            lang = up['lang']
+            tz = up['tz']
+            # 发送标题
+            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)
+            kwag_args['appBundleId'] = appBundleId
+            kwag_args['token_val'] = token_val
+            kwag_args['msg_title'] = msg_title
+            kwag_args['msg_text'] = msg_text
+            #推送
+            if detect_med_type == 2 or detect_med_type == 0:
+                if push_type == 0:  # ios apns
+                    print('do_apns')
+                    # self.do_apns(**kwag_args)
+                    do_apns_code = self.do_apns(**kwag_args)
+                elif push_type == 1:  # android gcm
+                    print('do_fcm')
+                    do_fcm_code = self.do_fcm(**kwag_args)
+                elif push_type == 2:  # android jpush
+                    print('do_jpush')
+                    do_jpush_code = self.do_jpush(**kwag_args)
+                    # return JsonResponse(status=200, data={'code': 0, '状态:': self.do_jpush(**kwag_args)})
+            if detect_med_type == 1:
+                do_apns_code = '只存库不推送'
+                do_fcm_code = '只存库不推送'
+                do_jpush_code = '只存库不推送'
+            # 以下是存库
+            userID_id = up["userID_id"]
+            int_is_st = int(is_st)
+            if userID_id not in userID_ids:
+                eq_list.append(Equipment_Info(
+                    userID_id=userID_id,
+                    eventTime=n_time,
+                    eventType=event_type,
+                    devUid=uid,
+                    devNickName=nickname,
+                    Channel=channel,
+                    alarm='Motion \tChannel:{channel}'.format(channel=channel),
+                    is_st=int_is_st,
+                    receiveTime=n_time,
+                    addTime=now_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, 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))
+                userID_ids.append(userID_id)
+        if is_sys_msg:
+            SysMsgModel.objects.bulk_create(sys_msg_list)
+        Equipment_Info.objects.bulk_create(eq_list)
+
+        if is_st == '0' or is_st == '2':
+            print("is_st=0or2")
+            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
+                up['test_or_www'] = SERVER_TYPE
+                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':
+            print("is_st=1")
+            # Endpoint以杭州为例,其它Region请按实际情况填写。
+            obj = '{uid}/{channel}/{filename}.jpeg'.format(uid=uid, channel=channel, filename=n_time)
+            # 设置此签名URL在60秒内有效。
+            url = bucket.sign_url('PUT', obj, 7200)
+            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
+                up['test_or_www'] = SERVER_TYPE
+                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']
+                # 不是正式服务器
+            if SERVER_TYPE != "Ansjer.formal_settings":
+                res_data = {'code': 0, 'img_push': url, 'msg': 'success', 're_list': redis_list}
+            else:
+                # 是正式服务器的时候
+                res_data = {'code': 0, 'img_push': url, 'msg': 'success'}
+
+            return JsonResponse(status=200, data=res_data)
+
+        elif is_st == '3':
+            print("is_st=3")
+            # 人形检测带动图
+            # Endpoint以杭州为例,其它Region请按实际情况填写。
+            img_url_list = []
+            for i in range(int(is_st)):
+                obj = '{uid}/{channel}/{filename}_{st}.jpeg'. \
+                    format(uid=uid, channel=channel, filename=n_time, st=i)
+                # 设置此签名URL在60秒内有效。
+                url = bucket.sign_url('PUT', obj, 7200)
+                img_url_list.append(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
+                up['test_or_www'] = SERVER_TYPE
+                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']
+
+            # 不是正式服务器
+            if SERVER_TYPE != "Ansjer.formal_settings":
+                res_data = {'code': 0, 'img_url_list': img_url_list, 'msg': 'success 3', 're_list': redis_list}
+            else:
+                # 是正式服务器的时候
+                res_data = {'code': 0, 'img_url_list': img_url_list, 'msg': 'success 3'}
+            return JsonResponse(status=200, data=res_data)
+
+
+    def get_msg_title(self, 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
+
+    def is_sys_msg(self, event_type):
+        event_type_list = [702, 703, 704]
+        if event_type in event_type_list:
+            return True
+        return False
+
+    def get_msg_text(self, channel, n_time, lang, tz, event_type, 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 = '电量过低'
+            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)
+                # send_text = '{msg_type} 通道:{channel} 日期:{date}'.format(msg_type=msg_type, channel=channel, date=n_date)
+        else:
+            if etype == 704:
+                msg_type = 'Low battery'
+            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
+
+    def do_jpush(self, uid, channel, appBundleId, token_val, event_type, n_time,
+                 msg_title, msg_text):
+        app_key = JPUSH_CONFIG[appBundleId]['Key']
+        master_secret = JPUSH_CONFIG[appBundleId]['Secret']
+        # 此处换成各自的app_key和master_secre
+        _jpush = jpush.JPush(app_key, master_secret)
+        push = _jpush.create_push()
+        # if you set the logging level to "DEBUG",it will show the debug logging.
+        # _jpush.set_logging("DEBUG")
+        # push.audience = jpush.all_
+        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
+        # try:
+        #     res = push.send()
+        #     print(res)
+        # except Exception as e:
+        #     print("jpush fail")
+        #     print("Exception")
+        #     print(repr(e))
+        #     return
+        # else:
+        #     print("jpush success")
+        #     return
+
+    def do_fcm(self, uid, channel, appBundleId, token_val, event_type, n_time, msg_title, msg_text):
+        try:
+            serverKey = FCM_CONFIG[appBundleId]
+        except Exception as 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
+                                                   })
+        print('fcm push ing')
+        print(result)
+        return result
+
+    def do_apns(self, uid, channel, appBundleId, token_val, event_type, n_time, msg_title,
+                msg_text):
+        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": "sound.aif", "uid": uid, "zpush": "1", "channel": channel}
+            alert = apns2.PayloadAlert(body=msg_text, title=msg_title)
+            payload = apns2.Payload(alert=alert, custom=push_data)
+
+            # 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)
+
+            #     200, 推送成功。
+            #   400, 请求有问题。
+            #   403, 证书或Token有问题。
+            #   405, 请求方式不正确, 只支持POST请求
+            #   410, 设备的Token与证书不一致
+            if res.status_code == 200:
+                return res.status_code
+            else:
+                print('apns push fail')
+                print(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))
+            return repr(e)
+
+    def do_update_detect_interval(self, uid, channel, redisObject, detect_interval):
+        if channel == 0:
+            channel = 17
+        else:
+            channel += 1
+        for i in range(1, channel):
+            tmpDKey = '{uid}_{channel}_{event_type}_flag'.format(uid=uid, event_type=51, channel=i)
+            if tmpDKey is not False:
+                llt = redisObject.get_ttl(tmpDKey)
+                if llt > detect_interval:
+                    redisObject.set_data(key=tmpDKey, val=1, expire=detect_interval)
+
+            tmpDKey = '{uid}_{channel}_{event_type}_flag'.format(uid=uid, event_type=54, channel=i)
+            if tmpDKey is not False:
+                llt = redisObject.get_ttl(tmpDKey)
+                if llt > detect_interval:
+                    redisObject.set_data(key=tmpDKey, val=1, expire=detect_interval)
+
+
+# http://test.dvema.com/detect/add?uidToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiJQMldOR0pSRDJFSEE1RVU5MTExQSJ9.xOCI5lerk8JOs5OcAzunrKCfCrtuPIZ3AnkMmnd-bPY&n_time=1526845794&channel=1&event_type=51&is_st=0
+# 移动侦测接口
+class PushNotificationView(View):
+
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        # operation = kwargs.get('operation')
+        return self.validation(request.GET)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        # operation = kwargs.get('operation')
+        return self.validation(request.POST)
+
+    def validation(self, request_dict):
+        etk = request_dict.get('etk', None)
+        channel = request_dict.get('channel', '1')
+        n_time = request_dict.get('n_time', None)
+        event_type = request_dict.get('event_type', None)
+        is_st = request_dict.get('is_st', None)
+        eto = ETkObject(etk)
+        uid = eto.uid
+        if len(uid) == 20:
+            redisObj = RedisObject(db=6)
+            # pkey = '{uid}_{channel}_ptl'.format(uid=uid, channel=channel)
+            pkey = '{uid}_ptl'.format(uid=uid)
+            ykey = '{uid}_redis_qs'.format(uid=uid)
+            if redisObj.get_data(key=pkey):
+                res_data = {'code': 0, 'msg': 'success,!33333333333'}
+                return JsonResponse(status=200, data=res_data)
+            else:
+                redisObj.set_data(key=pkey, val=1, expire=60)
+            ##############
+            redis_data = redisObj.get_data(key=ykey)
+            if redis_data:
+                redis_list = eval(redis_data)
+            else:
+                # 设置推送时间为60秒一次
+                redisObj.set_data(key=pkey, val=1, expire=60)
+                print("从数据库查到数据")
+                # 从数据库查询出来
+                uid_push_qs = UidPushModel.objects.filter(uid_set__uid=uid, uid_set__detect_status=1). \
+                    values('token_val', 'app_type', 'appBundleId',
+                           'push_type', 'userID_id', 'lang','m_code',
+                           'tz', 'uid_set__nickname')
+                # 新建一个list接收数据
+                redis_list = []
+                # 把数据库数据追加进redis_list
+                for qs in uid_push_qs:
+                    redis_list.append(qs)
+                # 修改redis数据,并设置过期时间为10分钟
+            if redis_list:
+                redisObj.set_data(key=ykey, val=str(redis_list), expire=600)
+                auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)
+                bucket = oss2.Bucket(auth, 'oss-cn-shenzhen.aliyuncs.com', 'apg')
+                self.do_bulk_create_info(redis_list, n_time, channel, event_type, is_st, uid)
+                if is_st == '0' or is_st == '2':
+                    return JsonResponse(status=200, data={'code': 0, 'msg': 'success44444444444444444'})
+                elif is_st == '1':
+                    # Endpoint以杭州为例,其它Region请按实际情况填写。
+                    obj = '{uid}/{channel}/{filename}.jpeg'.format(uid=uid, channel=channel, filename=n_time)
+                    # 设置此签名URL在60秒内有效。
+                    url = bucket.sign_url('PUT', obj, 7200)
+                    res_data = {'code': 0, 'img_push': url, 'msg': 'success'}
+                    return JsonResponse(status=200, data=res_data)
+                elif is_st == '3':
+                    # 人形检测带动图
+                    img_url_list = []
+                    for i in range(int(is_st)):
+                        obj = '{uid}/{channel}/{filename}_{st}.jpeg'. \
+                            format(uid=uid, channel=channel, filename=n_time, st=i)
+                        # 设置此签名URL在60秒内有效。
+                        url = bucket.sign_url('PUT', obj, 7200)
+                        img_url_list.append(url)
+                    res_data = {'code': 0, 'img_url_list': img_url_list, 'msg': 'success'}
+                    return JsonResponse(status=200, data=res_data)
+            else:
+                return JsonResponse(status=200, data={'code': 404, 'msg': 'data is not exist'})
+        else:
+            return JsonResponse(status=200, data={'code': 404, 'msg': 'wrong etk'})
+
+    def do_bulk_create_info(self, uaqs, n_time, channel, event_type, is_st, uid):
+        now_time = int(time.time())
+        # 设备昵称
+        userID_ids = []
+        sys_msg_list = []
+        is_sys_msg = self.is_sys_msg(int(event_type))
+        is_st = int(is_st)
+        eq_list = []
+        nickname = uaqs[0]['uid_set__nickname']
+        if not nickname:
+            nickname = uid
+        for ua in uaqs:
+            lang = ua['lang']
+            tz = ua['tz']
+            userID_id = ua["userID_id"]
+            if userID_id not in userID_ids:
+                eq_list.append(Equipment_Info(
+                    userID_id=userID_id,
+                    eventTime=n_time,
+                    eventType=event_type,
+                    devUid=uid,
+                    devNickName=nickname,
+                    Channel=channel,
+                    alarm='Motion \tChannel:{channel}'.format(channel=channel),
+                    is_st=is_st,
+                    receiveTime=n_time,
+                    addTime=now_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, 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))
+        if eq_list:
+            print('eq_list')
+            Equipment_Info.objects.bulk_create(eq_list)
+        if is_sys_msg:
+            print('sys_msg')
+            SysMsgModel.objects.bulk_create(sys_msg_list)
+        return True
+
+    def is_sys_msg(self, event_type):
+        event_type_list = [702, 703, 704]
+        if event_type in event_type_list:
+            return True
+        return False
+
+    def get_msg_text(self, channel, n_time, lang, tz, event_type, is_sys=0):
+        n_date = CommonService.get_now_time_str(n_time=n_time, tz=tz)
+        etype = int(event_type)
+        if lang == 'cn':
+            if etype == 704:
+                msg_type = '电量过低'
+            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 = 'Low battery'
+            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

+ 132 - 0
Controller/ShadowController.py

@@ -0,0 +1,132 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+@Copyright (C) ansjer cop Video Technology Co.,Ltd.All rights reserved.
+@AUTHOR: ASJRD018
+@NAME: AnsjerPush
+@software: PyCharm
+@DATE: 2020/2/14 13:54
+@Version: python3.6
+@MODIFY DECORD:ansjer dev
+@file: ShadowController.py
+@Contact: chanjunkai@163.com
+"""
+# 测试环境
+# test.shadow.dvema.com
+# 生产环境
+# shadow.dvema.com
+# 设备影子更新
+from Object.ResponseObject import ResponseObject
+from Object.ETkObject import ETkObject
+import time
+from Model.models import Device_Info,UidSetModel
+from Service.CommonService import CommonService
+from django.http import JsonResponse
+from Object.UidTokenObject import UidTokenObject
+
+def generate_utk(request):
+    request.encoding = 'utf-8'
+    response = ResponseObject()
+    if request.method == 'GET':
+        request_dict = request.GET
+    elif request.method == 'POST':
+        request_dict = request.POST
+    else:
+        return response.json(444,'wrong method')
+    username = request_dict.get('username',None)
+    password = request_dict.get('password',None)
+    uid = request_dict.get('uid',None)
+    if username and password:
+        if username == 'debug_user' and password == 'debug_password':
+            # utko = UidTokenObject()
+            # # right
+            # utko.generate(data={'uid': uid})
+            etkObj = ETkObject(etk='')
+            etk = etkObj.encrypt(uid)
+            return response.json(0, {'etk': etk})
+        else:
+            return response.json(404)
+    else:
+        return response.json(444,'username password')
+
+
+# 设备影子更新
+def update_device_shadow(request):
+    request.encoding = 'utf-8'
+    response = ResponseObject()
+    if request.method == 'POST':
+        request_dict = request.POST
+    elif request.method == 'GET':
+        request_dict = request.GET
+    else:
+        return response.json(444)
+    etk = request_dict.get('etk', None)
+    eto = ETkObject(etk)
+    uid = eto.uid
+    if uid:
+        # 重置按钮
+        is_reset = request_dict.get('is_reset', None)
+        # 传1则重置设备信息
+        if is_reset == '1':
+            UidSetModel.objects.filter(uid=uid).delete()
+            # 重置设备,判断设备为已删除
+            Device_Info.objects.filter(UID=uid).update(isExist=2)
+        ucode = request_dict.get('ucode', None)
+        version = request_dict.get('version', None)
+        p2p_region = request_dict.get('p2p_region', None)
+        tz = request_dict.get('tz', None)
+        video_code = request_dict.get('video_code', None)
+        ip = CommonService.get_ip_address(request)
+        channel = request_dict.get('channel', None)
+        cloud_vod = request_dict.get('cloud_vod', None)
+        push_status = request_dict.get('push_status', None)
+        pwd = request_dict.get('pwd', None)
+        resetTime = request_dict.get('resetTime', None)
+        is_alexa = request_dict.get('is_alexa', None)
+
+        us_qs = UidSetModel.objects.filter(uid=uid)
+        # 更新
+        nowTime = int(time.time())
+
+        print('-------')
+        print(resetTime)
+        print('-------')
+        qs_dict = {
+            'updTime': nowTime,
+            'ip': ip
+        }
+        if channel:
+            qs_dict['channel'] = channel
+        if p2p_region:
+            qs_dict['p2p_region'] = p2p_region
+        if ucode:
+            qs_dict['ucode'] = ucode
+        if version:
+            qs_dict['version'] = version
+        if tz:
+            qs_dict['tz'] = tz
+        if video_code:
+            qs_dict['video_code'] = video_code
+        if cloud_vod:
+            qs_dict['cloud_vod'] = cloud_vod
+        if push_status:
+            qs_dict['detect_status'] = push_status
+        if pwd:
+            qs_dict['pwd'] = pwd
+        if us_qs.exists():
+            if is_alexa and us_qs[0].is_alexa == 0:
+                qs_dict['is_alexa'] = is_alexa
+            us_qs.update(**qs_dict)
+            # 如果推送状态开启,返回推送url
+            return JsonResponse(status=200, data={'code': 0, 'msg': 'success', 'data': {}})
+        # 新增
+        else:
+            if is_alexa:
+                qs_dict['is_alexa'] = is_alexa
+            qs_dict['uid'] = uid
+            qs_dict['addTime'] = nowTime
+            UidSetModel.objects.create(**qs_dict)
+            # 如果推送状态开启,返回推送url
+            return JsonResponse(status=200, data={'code': 0, 'msg': 'success', 'data': {}})
+    else:
+        return JsonResponse(status=200, data={'code': 403, 'msg': 'error etk'})

+ 708 - 0
Controller/TestDetectController.py

@@ -0,0 +1,708 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+@Copyright (C) ansjer cop Video Technology Co.,Ltd.All rights reserved.
+@AUTHOR: ASJRD018
+@NAME: AnsjerFormal
+@software: PyCharm
+@DATE: 2019/1/14 15:57
+@Version: python3.6
+@MODIFY DECORD:ansjer dev
+@file: DetectController.py
+@Contact: chanjunkai@163.com
+"""
+import os
+import time
+
+import apns2
+import jpush as jpush
+import oss2
+from django.http import JsonResponse, HttpResponse
+from django.views.generic.base import View
+from pyfcm import FCMNotification
+from AnsjerPush.config import SERVER_TYPE, JPUSH_CODE, APNS_CODE, APP_TYPE
+from AnsjerPush.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET, DETECT_PUSH_DOMAIN, JPUSH_CONFIG, FCM_CONFIG, \
+    APNS_CONFIG, BASE_DIR, APNS_MODE
+from Model.models import Equipment_Info, UidPushModel, SysMsgModel
+from Object.ETkObject import ETkObject
+from Object.RedisObject import RedisObject
+from Object.UidTokenObject import UidTokenObject
+from Service.CommonService import CommonService
+import json
+
+'''
+http://push.dvema.com/notify/push?etk=Y2lTRXhMTjBWS01sWlpURTVJU0ZWTlJ6RXhNVUU9T3o=&n_time=1526845794&channel=1&event_type=704&is_st=0
+http://push.dvema.com/deviceShadow/generateUTK?username=debug_user&password=debug_password&uid=VVDHCVBYDKFMJRWA111A
+'''
+
+
+# 移动侦测接口
+class NotificationView(View):
+
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        return self.validation(request.GET, 0)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        return self.validation(request.POST, 1)
+
+    def validation(self, request_dict, request_type):
+        uidToken = request_dict.get('uidToken', None)
+        etk = request_dict.get('etk', None)
+        channel = request_dict.get('channel', '1')
+        n_time = request_dict.get('n_time', None)
+        event_type = request_dict.get('event_type', None)
+        is_st = request_dict.get('is_st', None)
+        # print("aaa")
+        # return JsonResponse(0,safe=False)
+        if not all([channel, n_time]):
+            return JsonResponse(status=200, data={
+                'code': 444,
+                'msg': 'param is wrong'})
+        if etk:
+            eto = ETkObject(etk)
+            uid = eto.uid
+            if len(uid) != 20:
+                return JsonResponse(status=200, data={'code': 404, 'msg': 'data is not exist'})
+        else:
+            utko = UidTokenObject(uidToken)
+            uid = utko.UID
+        pkey = '{uid}_{channel}_ptl'.format(uid=uid, channel=channel)
+        # ykey = 'MUJ887NLR8K8GBM9111A_redis_qs'.format(uid=uid)
+        ykey = '{uid}_redis_qs'.format(uid=uid)
+        dkey = '{uid}_{channel}_{event_type}_flag'.format(uid=uid, event_type=event_type, channel=channel)
+        # 判断redisObj.get_data(key=pkey):不为空
+        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)  # 推送类型限制
+
+        # 一分钟外,推送开启状态
+        detect_med_type = 0  # 0推送旧机制 1存库不推送,2推送存库
+        # 暂时注销
+        if have_pkey:
+            if SERVER_TYPE != "Ansjer.formal_settings":
+                res_data = {'code': 0, 'msg': 'Push once every 10 seconds'}
+            else:
+                res_data = {'code': 0, 'msg': 'Push it once a minute'}
+            return JsonResponse(status=200, data=res_data)
+
+        # 数据库读取数据
+        if have_ykey:
+            redis_list = eval(redisObj.get_data(key=ykey))
+        else:
+            # 从数据库查询出来
+            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', 'userID__username',
+                       'lang', 'm_code', 'tz', 'uid_set__nickname', 'uid_set__detect_interval', 'uid_set__detect_group',
+                       'uid_set__channel')
+            # 新建一个list接收数据
+            redis_list = []
+            # 把数据库数据追加进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)
+            if not redis_list:
+                res_data = {'code': 404, 'msg': 'error !'}
+                return JsonResponse(status=200, data=res_data)
+
+            # 此时应该更新一下redis里面的dkey的有效时间
+            detect_interval = redis_list[0]['uid_set__detect_interval']
+            channel = redis_list[0]['uid_set__channel']
+            self.do_update_detect_interval(uid, channel, redisObj, detect_interval)
+
+
+        if not redis_list:
+            print("没有redi_list")
+            res_data = {'code': 0, 'msg': 'no redi_list success!'}
+            return JsonResponse(status=200, data=res_data)
+
+        is_sys_msg = self.is_sys_msg(int(event_type))
+        nickname = redis_list[0]['uid_set__nickname']
+        detect_interval = redis_list[0]['uid_set__detect_interval']
+        detect_group = redis_list[0]['uid_set__detect_group']
+        now_time = int(time.time())
+        if not nickname:
+            nickname = uid
+        print('detect_group')
+        print(detect_group)
+        print(detect_interval)
+        if detect_group:
+            if have_dkey:
+                detect_med_type = 1  # 1为存库不推送
+            else:
+                detect_med_type = 2  # 为2的话,既推送,又存库
+                # detect_group=0允许全部推送的时候
+                if detect_group == '0':
+                    redisObj.set_data(key=dkey, val=1, expire=detect_interval)
+                else:
+                    detect_group_list = detect_group.split(',')
+                    if event_type in detect_group_list:
+                        if detect_interval < 60:
+                            detect_interval = 60
+                        redisObj.set_data(key=dkey, val=1, expire=detect_interval)
+                # 改为1秒
+                # 如果不是正式
+                if SERVER_TYPE!="Ansjer.formal_settings":
+                    redisObj.set_data(key=pkey, val=1, expire=10)
+                else:
+                    redisObj.set_data(key=pkey, val=1, expire=60)
+
+            # 打印have_ykey
+        # return JsonResponse(status=200, data={'pkey': 0, 'have_ykey': have_ykey, 'have_pkey': have_pkey, 'have_ykey': have_dkey})
+
+        # 旧模式并且没有pkey,重新创建一个
+        if not detect_group and not have_pkey:
+            # 设置推送时间为60秒一次
+            # 如果不是正式
+            if SERVER_TYPE != "Ansjer.formal_settings":
+                redisObj.set_data(key=pkey, val=1, expire=10)
+            else:
+                redisObj.set_data(key=pkey, val=1, expire=60)
+        auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)
+        bucket = oss2.Bucket(auth, 'oss-cn-shenzhen.aliyuncs.com', 'apg')
+        kwag_args = {
+            'uid': uid,
+            'channel': channel,
+            'event_type': event_type,
+            'n_time': n_time,
+            # 'appBundleId': appBundleId,
+            # 'token_val': token_val,
+            # 'msg_title': msg_title,
+            # 'msg_text': msg_text
+        }
+        eq_list = []
+        sys_msg_list = []
+        userID_ids = []
+        do_apns_code = ''
+        do_fcm_code = ''
+        do_jpush_code = ''
+        for up in redis_list:
+            push_type = up['push_type']
+            appBundleId = up['appBundleId']
+            token_val = up['token_val']
+            lang = up['lang']
+            tz = up['tz']
+            # 发送标题
+            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)
+            kwag_args['appBundleId'] = appBundleId
+            kwag_args['token_val'] = token_val
+            kwag_args['msg_title'] = msg_title
+            kwag_args['msg_text'] = msg_text
+            #推送
+            if detect_med_type == 2 or detect_med_type == 0:
+                if push_type == 0:  # ios apns
+                    print('do_apns')
+                    # self.do_apns(**kwag_args)
+                    do_apns_code = self.do_apns(**kwag_args)
+                    up['push_code'] = do_apns_code
+                elif push_type == 1:  # android gcm
+                    print('do_fcm')
+                    do_fcm_code = self.do_fcm(**kwag_args)
+                    up['push_code'] = do_fcm_code
+                elif push_type == 2:  # android jpush
+                    print('do_jpush')
+                    do_jpush_code = self.do_jpush(**kwag_args)
+                    up['push_code'] = do_jpush_code
+                    # return JsonResponse(status=200, data={'code': 0, '状态:': self.do_jpush(**kwag_args)})
+
+            if detect_med_type == 1:
+                do_apns_code = '只存库不推送'
+                do_fcm_code = '只存库不推送'
+                do_jpush_code = '只存库不推送'
+                up['push_code'] = -1
+
+            # 以下是存库
+            userID_id = up["userID_id"]
+            int_is_st = int(is_st)
+            if userID_id not in userID_ids:
+                eq_list.append(Equipment_Info(
+                    userID_id=userID_id,
+                    eventTime=n_time,
+                    eventType=event_type,
+                    devUid=uid,
+                    devNickName=nickname,
+                    Channel=channel,
+                    alarm='Motion \tChannel:{channel}'.format(channel=channel),
+                    is_st=int_is_st,
+                    receiveTime=n_time,
+                    addTime=now_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, 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))
+                userID_ids.append(userID_id)
+        if is_sys_msg:
+            SysMsgModel.objects.bulk_create(sys_msg_list)
+        Equipment_Info.objects.bulk_create(eq_list)
+
+        if is_st == '0' or is_st == '2':
+            print("is_st=0or2")
+            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
+
+                try:
+
+                    code = up['push_code']
+                    print("push_code is ")
+                    print(code)
+                    if up['push_type'] == 0:
+                        up['push_res'] = '{code} {desc}'.format(code=code, desc=APNS_CODE[code])
+                        up['push_type'] = '苹果推送'
+                    elif up['push_type'] == 1:
+                        up['push_res'] = code
+                        up['push_type'] = '谷歌推送'
+                    elif up['push_type'] == 2:
+                        up['push_res'] = '{code} {desc}'.format(code=code, desc=JPUSH_CODE[code])
+                        up['push_type'] = '极光推送'
+
+
+                except KeyError as ke:
+                    print(ke)
+                else:
+                    del up['push_code']
+
+                #up['test_or_www'] = SERVER_TYPE
+                if SERVER_TYPE == 'Ansjer.formal_settings':
+                    up['server_type'] = '正式服务器'
+                else:
+                    up['server_type'] = '测试服务器'
+
+                up['app_type'] = APP_TYPE[up['app_type']]
+
+                # 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']
+
+                if request_type == 0:
+                    data = ""
+                    for up in redis_list:
+                        data += ("<p>" + repr(up) + "</p>")
+                    return HttpResponse(repr(data))
+                else:
+                    return JsonResponse(status=200, data={'code': 0, 'msg': 'success 0 or 2', 're_list': redis_list})
+
+        elif is_st == '1':
+            print("is_st=1")
+            # Endpoint以杭州为例,其它Region请按实际情况填写。
+            obj = '{uid}/{channel}/{filename}.jpeg'.format(uid=uid, channel=channel, filename=n_time)
+            # 设置此签名URL在60秒内有效。
+            url = bucket.sign_url('PUT', obj, 7200)
+            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
+                up['test_or_www'] = SERVER_TYPE
+                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']
+                # 不是正式服务器
+            if SERVER_TYPE != "Ansjer.formal_settings":
+                res_data = {'code': 0, 'img_push': url, 'msg': 'success', 're_list': redis_list}
+            else:
+                # 是正式服务器的时候
+                res_data = {'code': 0, 'img_push': url, 'msg': 'success'}
+
+            return JsonResponse(status=200, data=res_data)
+
+        elif is_st == '3':
+            print("is_st=3")
+            # 人形检测带动图
+            # Endpoint以杭州为例,其它Region请按实际情况填写。
+            img_url_list = []
+            for i in range(int(is_st)):
+                obj = '{uid}/{channel}/{filename}_{st}.jpeg'. \
+                    format(uid=uid, channel=channel, filename=n_time, st=i)
+                # 设置此签名URL在60秒内有效。
+                url = bucket.sign_url('PUT', obj, 7200)
+                img_url_list.append(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
+                up['test_or_www'] = SERVER_TYPE
+                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']
+
+            # 不是正式服务器
+            if SERVER_TYPE != "Ansjer.formal_settings":
+                res_data = {'code': 0, 'img_url_list': img_url_list, 'msg': 'success 3', 're_list': redis_list}
+            else:
+                # 是正式服务器的时候
+                res_data = {'code': 0, 'img_url_list': img_url_list, 'msg': 'success 3'}
+            return JsonResponse(status=200, data=res_data)
+
+
+    def get_msg_title(self, 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
+
+    def is_sys_msg(self, event_type):
+        event_type_list = [702, 703, 704]
+        if event_type in event_type_list:
+            return True
+        return False
+
+    def get_msg_text(self, channel, n_time, lang, tz, event_type, 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 = '电量过低'
+            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)
+                # send_text = '{msg_type} 通道:{channel} 日期:{date}'.format(msg_type=msg_type, channel=channel, date=n_date)
+        else:
+            if etype == 704:
+                msg_type = 'Low battery'
+            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
+
+    def do_jpush(self, uid, channel, appBundleId, token_val, event_type, n_time,
+                 msg_title, msg_text):
+        app_key = JPUSH_CONFIG[appBundleId]['Key']
+        master_secret = JPUSH_CONFIG[appBundleId]['Secret']
+        # 此处换成各自的app_key和master_secre
+        _jpush = jpush.JPush(app_key, master_secret)
+        push = _jpush.create_push()
+        # if you set the logging level to "DEBUG",it will show the debug logging.
+        # _jpush.set_logging("DEBUG")
+        # push.audience = jpush.all_
+        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
+        # try:
+        #     res = push.send()
+        #     print(res)
+        # except Exception as e:
+        #     print("jpush fail")
+        #     print("Exception")
+        #     print(repr(e))
+        #     return
+        # else:
+        #     print("jpush success")
+        #     return
+
+    def do_fcm(self, uid, channel, appBundleId, token_val, event_type, n_time, msg_title, msg_text):
+        try:
+            serverKey = FCM_CONFIG[appBundleId]
+        except Exception as 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
+                                                   })
+        print('fcm push ing')
+        print(result)
+        return result
+
+    def do_apns(self, uid, channel, appBundleId, token_val, event_type, n_time, msg_title,
+                msg_text):
+        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": "sound.aif", "uid": uid, "zpush": "1", "channel": channel}
+            alert = apns2.PayloadAlert(body=msg_text, title=msg_title)
+            payload = apns2.Payload(alert=alert, custom=push_data)
+
+            # 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)
+
+            #     200, 推送成功。
+            #   400, 请求有问题。
+            #   403, 证书或Token有问题。
+            #   405, 请求方式不正确, 只支持POST请求
+            #   410, 设备的Token与证书不一致
+            if res.status_code == 200:
+                return res.status_code
+            else:
+                print('apns push fail')
+                print(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))
+            return repr(e)
+
+
+    def getJPushReport(self, msg_id, appBundleId):
+        app_key = JPUSH_CONFIG[appBundleId]['Key']
+        master_secret = JPUSH_CONFIG[appBundleId]['Secret']
+        _jpush = jpush.JPush(app_key, master_secret)
+        report = _jpush.create_report()
+        res = report.get_received_detail(msg_id)
+        print("getJPushReport")
+        print(res)
+
+    def do_update_detect_interval(self, uid, channel, redisObject, detect_interval):
+        if channel == 0:
+            channel = 17
+        else:
+            channel += 1
+        for i in range(1, channel):
+            tmpDKey = '{uid}_{channel}_{event_type}_flag'.format(uid=uid, event_type=51, channel=i)
+            if tmpDKey is not False:
+                llt = redisObject.get_ttl(tmpDKey)
+                if llt > detect_interval:
+                    redisObject.set_data(key=tmpDKey, val=1, expire=detect_interval)
+
+            tmpDKey = '{uid}_{channel}_{event_type}_flag'.format(uid=uid, event_type=54, channel=i)
+            if tmpDKey is not False:
+                llt = redisObject.get_ttl(tmpDKey)
+                if llt > detect_interval:
+                    redisObject.set_data(key=tmpDKey, val=1, expire=detect_interval)
+
+
+
+# http://test.dvema.com/detect/add?uidToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiJQMldOR0pSRDJFSEE1RVU5MTExQSJ9.xOCI5lerk8JOs5OcAzunrKCfCrtuPIZ3AnkMmnd-bPY&n_time=1526845794&channel=1&event_type=51&is_st=0
+# 移动侦测接口
+class PushNotificationView(View):
+
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        # operation = kwargs.get('operation')
+        return self.validation(request.GET)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        # operation = kwargs.get('operation')
+        return self.validation(request.POST)
+
+    def validation(self, request_dict):
+        etk = request_dict.get('etk', None)
+        channel = request_dict.get('channel', '1')
+        n_time = request_dict.get('n_time', None)
+        event_type = request_dict.get('event_type', None)
+        is_st = request_dict.get('is_st', None)
+        eto = ETkObject(etk)
+        uid = eto.uid
+        if len(uid) == 20:
+            redisObj = RedisObject(db=6)
+            # pkey = '{uid}_{channel}_ptl'.format(uid=uid, channel=channel)
+            pkey = '{uid}_ptl'.format(uid=uid)
+            ykey = '{uid}_redis_qs'.format(uid=uid)
+            if redisObj.get_data(key=pkey):
+                res_data = {'code': 0, 'msg': 'success,!33333333333'}
+                return JsonResponse(status=200, data=res_data)
+            else:
+                redisObj.set_data(key=pkey, val=1, expire=60)
+            ##############
+            redis_data = redisObj.get_data(key=ykey)
+            if redis_data:
+                redis_list = eval(redis_data)
+            else:
+                # 设置推送时间为60秒一次
+                redisObj.set_data(key=pkey, val=1, expire=60)
+                print("从数据库查到数据")
+                # 从数据库查询出来
+                uid_push_qs = UidPushModel.objects.filter(uid_set__uid=uid, uid_set__detect_status=1). \
+                    values('token_val', 'app_type', 'appBundleId',
+                           'push_type', 'userID_id', 'lang','m_code',
+                           'tz', 'uid_set__nickname')
+                # 新建一个list接收数据
+                redis_list = []
+                # 把数据库数据追加进redis_list
+                for qs in uid_push_qs:
+                    redis_list.append(qs)
+                # 修改redis数据,并设置过期时间为10分钟
+            if redis_list:
+                redisObj.set_data(key=ykey, val=str(redis_list), expire=600)
+                auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)
+                bucket = oss2.Bucket(auth, 'oss-cn-shenzhen.aliyuncs.com', 'apg')
+                self.do_bulk_create_info(redis_list, n_time, channel, event_type, is_st, uid)
+                if is_st == '0' or is_st == '2':
+                    return JsonResponse(status=200, data={'code': 0, 'msg': 'success44444444444444444'})
+                elif is_st == '1':
+                    # Endpoint以杭州为例,其它Region请按实际情况填写。
+                    obj = '{uid}/{channel}/{filename}.jpeg'.format(uid=uid, channel=channel, filename=n_time)
+                    # 设置此签名URL在60秒内有效。
+                    url = bucket.sign_url('PUT', obj, 7200)
+                    res_data = {'code': 0, 'img_push': url, 'msg': 'success'}
+                    return JsonResponse(status=200, data=res_data)
+                elif is_st == '3':
+                    # 人形检测带动图
+                    img_url_list = []
+                    for i in range(int(is_st)):
+                        obj = '{uid}/{channel}/{filename}_{st}.jpeg'. \
+                            format(uid=uid, channel=channel, filename=n_time, st=i)
+                        # 设置此签名URL在60秒内有效。
+                        url = bucket.sign_url('PUT', obj, 7200)
+                        img_url_list.append(url)
+                    res_data = {'code': 0, 'img_url_list': img_url_list, 'msg': 'success'}
+                    return JsonResponse(status=200, data=res_data)
+            else:
+                return JsonResponse(status=200, data={'code': 404, 'msg': 'data is not exist'})
+        else:
+            return JsonResponse(status=200, data={'code': 404, 'msg': 'wrong etk'})
+
+    def do_bulk_create_info(self, uaqs, n_time, channel, event_type, is_st, uid):
+        now_time = int(time.time())
+        # 设备昵称
+        userID_ids = []
+        sys_msg_list = []
+        is_sys_msg = self.is_sys_msg(int(event_type))
+        is_st = int(is_st)
+        eq_list = []
+        nickname = uaqs[0]['uid_set__nickname']
+        if not nickname:
+            nickname = uid
+        for ua in uaqs:
+            lang = ua['lang']
+            tz = ua['tz']
+            userID_id = ua["userID_id"]
+            if userID_id not in userID_ids:
+                eq_list.append(Equipment_Info(
+                    userID_id=userID_id,
+                    eventTime=n_time,
+                    eventType=event_type,
+                    devUid=uid,
+                    devNickName=nickname,
+                    Channel=channel,
+                    alarm='Motion \tChannel:{channel}'.format(channel=channel),
+                    is_st=is_st,
+                    receiveTime=n_time,
+                    addTime=now_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, 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))
+        if eq_list:
+            print('eq_list')
+            Equipment_Info.objects.bulk_create(eq_list)
+        if is_sys_msg:
+            print('sys_msg')
+            SysMsgModel.objects.bulk_create(sys_msg_list)
+        return True
+
+    def is_sys_msg(self, event_type):
+        event_type_list = [702, 703, 704]
+        if event_type in event_type_list:
+            return True
+        return False
+
+    def get_msg_text(self, channel, n_time, lang, tz, event_type, is_sys=0):
+        n_date = CommonService.get_now_time_str(n_time=n_time, tz=tz)
+        etype = int(event_type)
+        if lang == 'cn':
+            if etype == 704:
+                msg_type = '电量过低'
+            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 = 'Low battery'
+            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

+ 365 - 0
Model/models.py

@@ -0,0 +1,365 @@
+from itertools import chain
+
+from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
+from django.db import models
+# from django.utils import six
+# from django.utils.encoding import python_2_unicode_compatible
+from six import python_2_unicode_compatible
+from imagekit.models import ProcessedImageField
+from imagekit.processors import ResizeToFill
+import six
+from AnsjerPush.config import SERVER_DOMAIN
+
+
+class PermissionsManager(models.Manager):
+    use_in_migrations = True
+
+    def get_by_natural_key(self, permName):
+        return self.get(
+            permName=permName
+        )
+
+
+class RoleManager(models.Manager):
+    """
+    The manager for the auth's Role model.
+    """
+    use_in_migrations = True
+
+    def get_by_natural_key(self, roleName):
+        return self.get(roleName=roleName)
+
+
+class UserManager(BaseUserManager):
+
+    def create_user(self, username, password, userID, is_active,
+                    user_isValid, **extra_fields):
+        user = self.model(
+            username=username,
+            userID=userID,
+            is_active=is_active,
+            user_isValid=user_isValid,
+            **extra_fields
+        )
+        user.set_password(password)
+        user.save(using=self._db)
+
+        role = Role.objects.get(rid=1)
+        user.role.add(role)
+        return user
+
+    def create_superuser(self, username, password, userID, is_active,
+                         user_isValid, **extra_fields):
+        # extra_fields.setdefault('is_superuser', is_superuser)
+        is_superuser = extra_fields.get('is_superuser', None)
+        if is_superuser != 100 and is_superuser != 1:
+            raise ValueError('Superuser must have is_superuser=1 or 100.')
+
+        return self.create_user(username, password, userID, is_active,
+                                user_isValid, **extra_fields)
+
+
+@python_2_unicode_compatible
+class Permissions(models.Model):
+    permName = models.CharField(blank=True, null=True, max_length=32, unique=True, verbose_name=u'权限名称')
+    description = models.CharField(blank=True, null=True, max_length=128, verbose_name=u'描述信息', default='')
+    objects = PermissionsManager()
+
+    def __str__(self):
+        return "%s" % (
+            six.text_type(self.description))
+
+    class Meta:
+        ordering = ['permName']
+        db_table = 'permissions'
+        verbose_name = u'role permission'
+        verbose_name_plural = verbose_name
+        unique_together = (('permName'),)
+
+    def natural_key(self):
+        return (self.permName)
+
+
+class Role(models.Model):
+    rid = models.SmallIntegerField(primary_key=True, unique=True, verbose_name=u'用户角色组ID')
+    roleName = models.CharField(max_length=32, unique=True,
+                                default='User', verbose_name=u'角色名称')
+    permission = models.ManyToManyField(to='Permissions', blank=True, verbose_name=u'权限', db_table='role_permissions')
+    Description = models.TextField(blank=True, default='', verbose_name=u'描述信息')
+
+    objects = RoleManager()
+
+    class Meta:
+        ordering = ['roleName']
+        db_table = 'role'
+        verbose_name = u'用户角色'
+        verbose_name_plural = verbose_name
+
+    def __str__(self):
+        return self.roleName
+
+    def natural_key(self):
+        return (self.roleName,)
+
+    def get_all_permission(self):
+        perms = self.permission.all()
+
+        permslist = []
+        if self.rid == 100:
+            perms = Permissions.objects.all()
+            for perm in perms:
+                permslist.append(perm.permName)
+            return permslist
+        else:
+            permlist_tmp = []
+            for perm in perms:
+                permlist_tmp.append(perm.permName)
+            permSet = set(permlist_tmp)
+            permslist = list(permSet)
+            permslist.sort()
+            return permslist
+
+
+class Device_User(AbstractBaseUser):
+    userID = models.CharField(blank=True, max_length=32, primary_key=True,
+                              verbose_name=u'用户ID', unique=True)
+    role = models.ManyToManyField(to='Role', blank=True, verbose_name=u'用户角色', db_table='user_role')
+
+    username = models.CharField(max_length=64, verbose_name=u'用户名', default='', blank=True)
+    password = models.CharField(max_length=128, verbose_name=u'密码')
+    userEmail = models.EmailField(max_length=64, verbose_name=u'邮箱', default='', blank=True)
+    # 实际的路径就是 MEDIA_ROOT/Image/filename,所以可用upload_to来指定文件存放的前缀路径
+    userIconPath = ProcessedImageField(blank=True, upload_to='User/Images/', default='static/User/default.png',
+                                       verbose_name=u'头像',
+                                       # 图片将处理成85x85的尺寸
+                                       processors=[ResizeToFill(85, 85)], )
+    userIconUrl = models.URLField(blank=True, max_length=128, default=SERVER_DOMAIN
+                                                                      + 'account/getAvatar/User/defaultUser.png')
+    NickName = models.CharField(blank=True, max_length=64, default='', verbose_name=u'用户昵称')
+    is_superuser = models.IntegerField(blank=True, default=0, verbose_name=u'用户类型')
+    is_active = models.BooleanField(blank=True, default=False, verbose_name=u'用户活动状态')
+    data_joined = models.DateTimeField(blank=True, verbose_name=u'加入时间', auto_now_add=True)
+    last_login = models.DateTimeField(blank=True, verbose_name='u最后登录时间', auto_now=True)
+    user_isValid = models.BooleanField(blank=True, default=False, verbose_name=u'用户有效性', help_text=u'是否是认证通过的用户')
+    online = models.BooleanField(blank=True, default=False, verbose_name=u'用户登录状态')
+    machine_code = models.CharField(blank=True, max_length=128, default='', verbose_name=u'机械码')
+
+    language = models.CharField(blank=True, max_length=16, default='en', verbose_name=u'语言地区')
+    # 手机注册增加字段
+    phone = models.CharField(max_length=16, verbose_name=u'手机号', default='', blank=True)
+
+    objects = UserManager()
+
+    USERNAME_FIELD = 'userID'  # 必须有一个唯一标识
+    REQUIRED_FIELDS = ['is_superuser']  # 创建superuser时的必须字段
+
+    class Meta:
+        ordering = ('-data_joined',)
+        verbose_name = u'用户信息'
+        db_table = 'device_user'
+        get_latest_by = 'last_login'
+
+    def __str__(self):
+        return self.username
+
+    def get_role_id(self):
+        rids = []
+        roles = self.role.all()
+        for role in roles:
+            rids.append(role.rid)
+        return rids
+
+    def get_all_permission(self):
+        roles = self.role.all()
+        perms = self.permission.all()
+
+        permslist = []
+        for role in roles:
+            if role.rid == 100:
+                perms = Permissions.objects.all()
+                for perm in perms:
+                    permslist.append(perm.permName)
+                return permslist
+
+        for perm in perms:
+            permslist.append(perm.permName)
+
+        permSet = set(permslist)
+        for role in roles:
+            permlist_tmp = []
+            for perm in role.permission.all():
+                permlist_tmp.append(perm.permName)
+
+            permSet_tmp = set(permlist_tmp)
+            permSet = permSet.union(permSet_tmp)
+            permslist = list(permSet)
+            permslist.sort()
+            return permslist
+
+    @property
+    def is_staff(self):
+        return self.is_superuser
+
+
+class Device_Info(models.Model):
+    id = models.CharField(blank=True, max_length=32, primary_key=True)
+    userID = models.ForeignKey(Device_User, blank=True, to_field='userID', on_delete=models.CASCADE)
+    NickName = models.CharField(blank=True, max_length=32, verbose_name=u'设备名称')
+    UID = models.CharField(blank=True, max_length=32, verbose_name=u'设备UID', default='')
+    SID = models.CharField(blank=True, max_length=32, verbose_name=u'服务器ID', default='')
+    View_Account = models.CharField(blank=True, max_length=32, verbose_name=u'设备用户名称', default='')
+    View_Password = models.CharField(blank=True, max_length=32, verbose_name=u'设备密码', default='')
+    AudioFormat = models.IntegerField(blank=True, default=1, verbose_name=u'初始化影像')
+    EventNotification = models.IntegerField(blank=True, verbose_name=u'报警类型', default=0)
+    ChannelIndex = models.IntegerField(blank=True, verbose_name=u'通道号', default=0)
+    Online = models.BooleanField(blank=True, default=False, verbose_name=u'设备是否在线')
+    mMonitorIndex = models.IntegerField(blank=True, default=-1)
+    Type = models.IntegerField(blank=True, verbose_name='设备类型')
+    DebugMode = models.IntegerField(blank=True, verbose_name=u'调试模式', default=0)
+    NotificationMode = models.IntegerField(blank=True, verbose_name=u'是否报警', default=0)
+    qvgaLevel = models.BooleanField(blank=True, verbose_name=u'SD与HD画面', default=0,
+                                    help_text=u'0代表:SD、1代表:HD')
+    isShare = models.BooleanField(blank=True, verbose_name=u'共享设备',
+                                  help_text=u'是否为共享获取的设备', default=False)
+    primaryUserID = models.CharField(blank=True, verbose_name='主用户id', max_length=32, default='')
+    primaryMaster = models.CharField(max_length=64, verbose_name=u'主用户名', default='')
+    data_joined = models.DateTimeField(blank=True, verbose_name=u'设备添加时间', auto_now_add=True)
+    update_time = models.DateTimeField(blank=True, verbose_name=u'更新时间', auto_now=True, null=True)
+
+    ip = models.CharField(blank=True, max_length=20, default='', verbose_name=u'设备区域ip')
+    area = models.CharField(blank=True, max_length=100, default='', verbose_name=u'设备区域area')
+    # ios要求新增字段
+    version = models.CharField(blank=True, max_length=20, default='', verbose_name=u'版本号')
+    SpaceUsable = models.CharField(blank=True, max_length=20, default='', verbose_name=u'可用空间')
+    SpaceSum = models.CharField(blank=True, max_length=20, default='', verbose_name=u'总空间')
+    WIFIName = models.CharField(blank=True, max_length=50, default='', verbose_name=u'无线名称')
+    WIFIIP = models.CharField(blank=True, max_length=20, default='', verbose_name=u'无线ip')
+    WIFIPwd = models.CharField(blank=True, max_length=50, default='', verbose_name=u'无线密码')
+    isDetector = models.BooleanField(blank=True, verbose_name=u'侦测开关0:关闭,1:开启)', default=False)
+    DetectorRank = models.IntegerField(blank=True, default=0, verbose_name=u'侦测灵敏度 1:低,2:中,3:高4:最高')
+    iSNotification = models.BooleanField(blank=True, verbose_name=u'报警通知 0:关闭,1:开启)', default=False)
+    MirrorType = models.IntegerField(blank=True, default=0, verbose_name=u'镜像类型 0:关闭镜像,1:上下镜像,2:左右镜像,3:上下左右镜像')
+    RecordType = models.IntegerField(blank=True, default=0, verbose_name=u'录像模式(0:关闭,1:全是录像,3:报警录像)')
+    TimeZone = models.CharField(blank=True, max_length=50, default='', verbose_name=u'时区')
+    isVod = models.SmallIntegerField(blank=True, default=0, verbose_name='是否支持云存')  # 是否支持云存设备
+    isExist = models.SmallIntegerField(blank=True, default=1, verbose_name='是否被删除')  # 是否被删除了(需主用户交互) 1存在,0不存在,2设备被重置
+    ###
+    REQUIRED_FIELDS = []
+
+    def __str__(self):
+        return self.NickName
+
+    def model_to_dict(self, fields=None, exclude=None):
+        opts = self._meta
+        data = {}
+        for f in chain(opts.concrete_fields, opts.private_fields, opts.many_to_many):
+            if not getattr(f, 'editable', False):
+                continue
+            if fields and f.name not in fields:
+                continue
+            if exclude and f.name in exclude:
+                continue
+            data[f.name] = f.value_from_object(self)
+        return data
+
+    class Meta:
+        db_table = 'device_info'
+        ordering = ('-data_joined',)
+        verbose_name = u'用户设备信息表'
+        verbose_name_plural = verbose_name
+
+
+class Equipment_Info(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    devUid = models.CharField(default='', blank=True, max_length=32, verbose_name=u'设备ID')
+    devNickName = models.CharField(blank=True, max_length=32, default='', verbose_name=u'设备昵称')
+    Channel = models.IntegerField(default=1, blank=True, verbose_name=u'设备通道')
+    eventType = models.IntegerField(default=0, blank=True, verbose_name=u'事件类型')
+    status = models.BooleanField(blank=True, default=False, verbose_name=u'事件状态')
+    alarm = models.CharField(blank=True, max_length=256, verbose_name=u'报警信息')
+    eventTime = models.CharField(blank=True, default='', max_length=16, verbose_name=u'设备报警时间')
+    receiveTime = models.CharField(blank=True, default='', max_length=16, verbose_name=u'接收到报警时间')
+    userID = models.ForeignKey(Device_User, null=True, blank=True, to_field='userID', on_delete=models.CASCADE)
+    is_st = models.SmallIntegerField(default=0, verbose_name='是否截图')  # 0 否,1 是图,2,视频
+    addTime = models.IntegerField(verbose_name='添加时间', default=0)
+
+    def __str__(self):
+        return self.id
+
+    class Meta:
+        db_table = 'equipment_info'
+        verbose_name = u'设备信息推送表'
+        verbose_name_plural = verbose_name
+        ordering = ('-id',)
+
+
+# 系统发送信息新到用户
+class SysMsgModel(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增id')
+    userID = models.ForeignKey(Device_User, to_field='userID', on_delete=models.CASCADE)  # 用户信息
+    msg = models.TextField(blank=True, default='', verbose_name=u'发送内容')
+    status = models.SmallIntegerField(verbose_name='是否已读', default=0)  # 0:否,1:是
+    addTime = models.IntegerField(verbose_name='添加时间', default=0)
+    updTime = models.IntegerField(verbose_name='更新时间', default=0)
+    eventType = models.IntegerField(verbose_name='消息类型', default=0) # 默认系统消息类型,0系统消息,1 ipcamera消息
+    uid = models.CharField(default='', max_length=20, db_index=True, verbose_name='设备UID')
+
+    class Meta:
+        db_table = 'sys_msg'
+        verbose_name = '系统消息'
+        verbose_name_plural = verbose_name
+        ordering = ('-id',)
+
+# 设备推送重构
+# 设备配置表,新
+class UidSetModel(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    uid = models.CharField(max_length=20, db_index=True, unique=True, verbose_name='设备UID')
+    channel = models.SmallIntegerField(default=0, verbose_name='通道数量')  #
+    detect_status = models.SmallIntegerField(default=0, verbose_name='推送开关')  # 状态[0:关闭,1:开启,2:用户解绑]
+    detect_interval = models.IntegerField(verbose_name='推送间隔', default=60)  # 秒
+    addTime = models.IntegerField(verbose_name='添加时间', default=0)
+    updTime = models.IntegerField(verbose_name='更新时间', default=0)
+    ucode = models.CharField(max_length=32, verbose_name='设备产品码', default='')
+    version = models.CharField(max_length=32, verbose_name='设备版本', default='')
+    p2p_region = models.CharField(max_length=16, verbose_name='设备区域', default='ALL')  # ALL CN EU US
+    cloud_vod = models.SmallIntegerField(default=2, verbose_name='云存开关')  # 0,关闭,1开启,2,不支持
+    tz = models.CharField(default='', max_length=16, verbose_name='设备时区')  # +8
+    video_code = models.SmallIntegerField(default=0, verbose_name='编码类型')  # 0:264,1:265
+    nickname = models.CharField(default='', max_length=64, verbose_name='设备昵称')
+    ip = models.CharField(max_length=20, default='', verbose_name=u'设备ip')
+    pwd = models.CharField(max_length=32, default='', verbose_name=u'设备密码')
+    # 设备重置后第一次启动时间
+    resetTime = models.IntegerField(default=0, verbose_name='设备重置时间')
+    is_alexa = models.IntegerField(default=0, verbose_name='会否支持alexa') # 0:否,1:是
+    detect_group = models.CharField(default='', max_length=32, verbose_name=u'检测类型')
+    region_alexa = models.CharField(max_length=8, verbose_name='设备alexa区域', default='ALL')  # ALL CN EU US
+
+    class Meta:
+        db_table = 'uid_set'
+        verbose_name = u'设备配置表'
+        verbose_name_plural = verbose_name
+        ordering = ('id',)
+
+
+# 设备关联用户推送
+class UidPushModel(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增id')
+    userID = models.ForeignKey(Device_User, to_field='userID', on_delete=models.CASCADE)
+    uid_set = models.ForeignKey(UidSetModel, to_field='id', on_delete=models.CASCADE)
+    appBundleId = models.CharField(blank=True, max_length=32, verbose_name=u'appID')
+    app_type = models.IntegerField(default=0, verbose_name=u'app类型 1:ios,2:安卓')
+    push_type = models.IntegerField(default=0, verbose_name=u'推送类型')  # 0,apns 1,安卓gcm 2,极光
+    token_val = models.CharField(default='', max_length=160, verbose_name=u'设备验证令牌')
+    m_code = models.CharField(default='', max_length=64, verbose_name='手机唯一标识')
+    addTime = models.IntegerField(verbose_name='添加时间', default=0)
+    updTime = models.IntegerField(verbose_name='更新时间', default=0)
+    lang = models.CharField(max_length=8, verbose_name='推送语言类型', default='en')  # en英文 cn中文
+    tz = models.CharField(max_length=8, verbose_name='utc时区', default='0')
+
+    class Meta:
+        db_table = 'uid_push'
+        verbose_name = '设备绑定'
+        verbose_name_plural = verbose_name
+        ordering = ('-id',)
+

+ 68 - 0
Object/ETkObject.py

@@ -0,0 +1,68 @@
+#!/usr/bin/env python3  
+# -*- coding: utf-8 -*-  
+"""
+@Copyright (C) ansjer cop Video Technology Co.,Ltd.All rights reserved.
+@AUTHOR: ASJRD018
+@NAME: AnsjerFormal
+@software: PyCharm
+@DATE: 2019/6/1 17:25
+@Version: python3.6
+@MODIFY DECORD:ansjer dev
+@file: ETkObject.py
+@Contact: chanjunkai@163.com
+"""
+
+import base64
+import urllib.parse
+from random import Random
+
+
+class ETkObject(object):
+    def __init__(self, etk):
+        self.uid = ''
+        self.parseUid(etk)
+
+    def parseUid(self, etk):
+        try:
+            c = base64.b64decode(etk)
+            c = c[2:-2]
+            c = urllib.parse.unquote(c.decode('utf-8'))
+            c = base64.b64decode(c)
+            uid = c.decode('utf-8')
+            if len(uid) == 20:
+                self.uid = uid
+                print(uid)
+        except Exception as e:
+            print(repr(e))
+
+    def encrypt(self,data):
+        s = data.encode()
+        s = base64.b64encode(s)
+        startStr = self.randomParam()
+        endStr = self.randomParam()
+        s = '{startStr}{s}{endStr}'.format(startStr=startStr,s=s.decode('utf-8'),endStr=endStr)
+        s = base64.b64encode(s.encode())
+        s=s.decode('utf-8')
+        return s
+
+    def randomParam(self):
+        characterSet = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsT' \
+                       'tUuVvWwXxYyZz0123456789'
+        length = len(characterSet) - 1
+
+        random = Random()
+        ss = ''
+        for index in range(2):
+            ss += characterSet[random.randint(0, length)]
+        return ss
+
+
+# etkObj = ETkObject(etk='')
+# PP = etkObj.encrypt('HLK7EJ2VYLNHHUMG111A')
+# print('encode_data:')
+# print(PP)
+# print('decode_data:')
+# eobj = ETkObject(etk='T1dha3hDUkZOVk9UVTBOMDVVVWxOTlJqRXhNVUU9U2w=')
+# uid = eobj.uid
+# print(uid)
+

+ 82 - 0
Object/RedisObject.py

@@ -0,0 +1,82 @@
+#!/usr/bin/env python3  
+# -*- coding: utf-8 -*-  
+"""
+@Copyright (C) ansjer cop Video Technology Co.,Ltd.All rights reserved.
+@AUTHOR: ASJRD018
+@NAME: AnsjerOA
+@software: PyCharm
+@DATE: 2018/8/8 17:00
+@Version: python3.6
+@MODIFY DECORD:ansjer dev
+@file: RedisObject.py
+@Contact: chanjunkai@163.com
+"""
+import redis
+
+from AnsjerPush.config import REDIS_ADDRESS
+
+# SERVER_HOST = '192.168.136.45'
+
+'''
+db=3  -> 统计在线人数用
+'''
+
+
+class RedisObject:
+
+    def __init__(self, db=0):
+        self.POOL = redis.ConnectionPool(host=REDIS_ADDRESS, port=6379, db=db)
+        self.CONN = redis.Redis(connection_pool=self.POOL)
+
+    def set_data(self, key, val, expire=0):
+        try:
+            self.CONN.set(key, val)
+            if expire > 0:
+                self.CONN.expire(key, expire)
+        except Exception as e:
+            return False
+        else:
+            return True
+
+    def get_data(self, key):
+        try:
+            val = self.CONN.get(key)
+        except Exception as e:
+            print(repr(e))
+            return False
+        else:
+            if val:
+                return val.decode('utf-8')
+            else:
+                return False
+
+    def del_data(self, key):
+        try:
+            val = self.CONN.delete(key)
+        except Exception as e:
+            print(repr(e))
+            return False
+        else:
+            return True
+
+    def get_size(self):
+        return self.CONN.dbsize()
+
+    # 向列表插入数据
+    def rpush(self, name, val):
+        self.CONN.rpush(name, val)
+
+    # 获取列表长度
+    def llen(self, name):
+        return self.CONN.llen(name=name)
+
+    # 获取列表所有数据
+    def lrange(self, name, start, end):
+        return self.CONN.lrange(name, start, end)
+
+    def get_ttl(self, key):
+        ttl = self.CONN.ttl(key)
+        if ttl:
+            return ttl
+        else:
+            return 0

+ 134 - 0
Object/ResponseObject.py

@@ -0,0 +1,134 @@
+from django.shortcuts import HttpResponse
+import simplejson as json
+
+
+class ResponseObject(object):
+    def __init__(self, lang='en'):
+        self.lang = lang
+
+    def data(self, code, res={}):
+        data_en = {
+            0: 'Success',
+            5: 'Please try again one minute later!',
+            10: res,
+            12: 'You are not the primary user of the device!',
+            14: 'Device is not belong to you',
+            15: 'Device has been bound',
+            44: 'System error! Can not send email',
+            48: 'System object error!',
+            89: 'Already send the code, please check it or get it again after 10m',
+            90: 'please check code or get it again after 1m',
+            99: 'Mail doesn\'t exist!',
+            100: 'Phone format error!',
+            101: 'Phone already existed!',
+            102: 'Phone doesn\'t exist!',
+            103: 'Mail already existed!',
+            104: 'Account doesn\'t exist!',
+            105: 'Email format error!',
+            107: 'The username not conform to the rules!',
+            109: 'The password not conform to the rules!',
+            110: 'user doesn\'t activated',
+            111: 'Error password',
+            119: 'The qr code has expired',
+            120: 'The code has expired',
+            121: 'The verification code is wrong!',
+            173: 'Data does not exists!',
+            174: 'Data already exists!',
+            176: 'Delete error',
+            177: 'Update error',
+            178: 'ADD error',
+            179: 'Nickname repeated',
+            306: 'The link has expired!',
+            309: 'Please ReLogin! errmsg token',
+            404: 'You don not have permission to access this!',
+            414: 'Please confirm the request url!',
+            424: 'Database Error !',
+            444: 'Wrong parameters!',
+            474: 'System Maintaining!',
+            475: 'App Version too low, please upgrade!',
+            500: 'Query Database Error:',
+            700: 'Upload file error',
+            701: 'The file does not exist!',
+            711: 'Do not downgrade',
+            712: 'Area needs to be consistent',
+            713: 'Storage rules cannot be changed during the validity period',
+            900: 'There is no information about this version!',
+            901: 'Getting URL failure!',
+            902: 'No update!',
+            903: 'Error filename',
+            906: 'Cause of file operation error',
+            907: 'The download file does not exist!',
+        }
+        data_cn = {
+            0: '成功',
+            5: '请一分钟后再尝试',
+            10: res,
+            12: '非设备主用户',
+            14: '设备不属于您',
+            15: '设备已被绑定',
+            44: '系统错误!无法发送电子邮件',
+            48: '系统对象错误',
+            89: '已发验证码,请检测或10分钟后重新获取。',
+            90: '请检测或1分钟后重新获取。',
+            99: '邮箱不存在!',
+            100: '手机格式错误!',
+            101: '手机已存在!',
+            102: '手机不存在!',
+            103: '邮箱已存在!',
+            104: '账户不存在!',
+            105: '邮箱格式错误!',
+            107: '用户名格式不符合!',
+            109: '密码格式不符合!',
+            110: '用户未激活!',
+            111: '密码不正确!',
+            119: '二维码过期',
+            120: '验证码过期',
+            121: '验证码错了!',
+            173: '数据不存在!',
+            174: '数据已存在!',
+            176: '删除错误',
+            177: '更新错误',
+            178: '增加错误',
+            179: '名称不能重复',
+            306: '链接已超过有效期!',
+            309: '请重新登录!',
+            404: '您没有访问的权限!',
+            414: '请确认请求url!',
+            424: '数据库错误!',
+            444: '参数错误!',
+            474: '系统维护中!',
+            475: '版本过低,请升级程序!',
+            500: '查询数据库错误!',
+            700: '上传文件错误',
+            701: '文件不存在',
+            711: '不可降级',
+            712: '区域不一致',
+            713: '有效期内不可更改存储规则',
+            900: '版本信息不存在',
+            901: '获取链接失败',
+            902: '无更新!',
+            903: '文件名不符合!',
+            906: '文件操作错误',
+            907: '文件不存在!',
+        }
+        if self.lang == 'cn':
+            msg = data_cn
+        elif self.lang == 'zh-Hans':
+            msg = data_cn
+        elif self.lang == 'zh-Hant':
+            msg = data_cn
+        else:
+            msg = data_en
+        try:
+            message = msg[code]
+        except Exception as e:
+            message = '系统错误,code不存在'
+        return {'result_code': code, 'reason': message, 'result': res, 'error_code': code}
+
+    def formal(self, code, res={}):
+        formal_data = self.data(code, res)
+        return json.dumps(formal_data, ensure_ascii=False)
+
+    def json(self, code, res={}):
+        result = self.formal(code, res)
+        return HttpResponse(result)

+ 48 - 0
Object/UidTokenObject.py

@@ -0,0 +1,48 @@
+#!/usr/bin/env python3  
+# -*- coding: utf-8 -*-  
+"""
+@Copyright (C) ansjer cop Video Technology Co.,Ltd.All rights reserved.
+@AUTHOR: ASJRD018
+@NAME: AnsjerFormal
+@software: PyCharm
+@DATE: 2018/12/5 11:52
+@Version: python3.6
+@MODIFY DECORD:ansjer dev
+@file: UidTokenObject.py
+@Contact: chanjunkai@163.com
+"""
+from AnsjerPush.config import UID_TOKEN_KEY
+import jwt
+# UID_TOKEN_KEY = 'c+565*j@%^'
+
+
+class UidTokenObject:
+
+    def __init__(self, token=None):
+        self.token = token
+        self.UID = ''
+        self.channel = ''
+        self.flag = self.valid()
+
+    def valid(self):
+        token = self.token
+        if self.token is None:
+            return False
+        res = jwt.decode(token, UID_TOKEN_KEY, algorithms='HS256')
+        print(res)
+        UID = res.get('uid', None)
+        channel = res.get('channel', None)
+        if UID is None:
+            return False
+        self.UID = UID
+        self.channel = channel
+
+    def generate(self, data={}):
+        token = jwt.encode(data, UID_TOKEN_KEY, algorithm='HS256').decode('utf-8')
+        self.token=token
+        return token
+#
+# uto = UidTokenObject()
+# res = uto.generate(data={'uid':'VVDHCVBYDKFMJRWA111A','channel':'1'})
+# print('---')
+# print(res)

+ 207 - 0
Service/CommonService.py

@@ -0,0 +1,207 @@
+# -*- coding: utf-8 -*-
+import datetime
+import time
+from pathlib import Path
+from random import Random
+import ipdb
+import simplejson as json
+from django.core import serializers
+from django.utils import timezone
+from pyipip import IPIPDatabase
+
+from AnsjerPush.config import BASE_DIR
+
+
+# 复用性且公用较高封装代码在这
+class CommonService:
+
+    # 添加模糊搜索
+    @staticmethod
+    def get_kwargs(data={}):
+        kwargs = {}
+        for (k, v) in data.items():
+            if v is not None and v != u'':
+                kwargs[k + '__icontains'] = v
+        return kwargs
+
+    # 定义静态方法
+    # 格式化query_set转dict
+    @staticmethod
+    def qs_to_dict(query_set):
+        sqlJSON = serializers.serialize('json', query_set)
+        sqlList = json.loads(sqlJSON)
+        sqlDict = dict(zip(["datas"], [sqlList]))
+        return sqlDict
+
+    # 获取文件大小
+    @staticmethod
+    def get_file_size(file_path='', suffix_type='', decimal_point=0):
+
+        # for x in ['bytes', 'KB', 'MB', 'GB', 'TB']:
+        # path = Path() / 'D:/TestServer/123444.mp4'
+        path = Path() / file_path
+        size = path.stat().st_size
+        mb_size = 0.0
+        if suffix_type == 'MB':
+            mb_size = size / 1024.0 / 1024.0
+        if decimal_point != 0:
+            mb_size = round(mb_size, decimal_point)
+        return mb_size
+
+    @staticmethod
+    def get_param_flag(data=[]):
+        # print(data)
+        flag = True
+        for v in data:
+            if v is None:
+                flag = False
+                break
+        return flag
+
+    @staticmethod
+    def get_ip_address(request):
+        """
+        获取ip地址
+        :param request:
+        :return:
+        """
+        try:
+            real_ip = request.META['HTTP_X_FORWARDED_FOR']
+            clientIP = real_ip.split(",")[0]
+        except:
+            try:
+                clientIP = request.META['REMOTE_ADDR']
+            except Exception as e:
+                clientIP = ''
+        return clientIP
+
+    # @获取一天每个小时的datetime.datetime
+    @staticmethod
+    def getTimeDict(times):
+        time_dict = {}
+        t = 0
+        for x in range(24):
+            if x < 10:
+                x = '0' + str(x)
+            else:
+                x = str(x)
+            a = times.strftime("%Y-%m-%d") + " " + x + ":00:00"
+            time_dict[t] = timezone.datetime.strptime(a, '%Y-%m-%d %H:%M:%S')
+            t += 1
+        return time_dict
+
+    # 根据ip获取地址
+    @staticmethod
+    def getAddr(ip):
+        base_dir = BASE_DIR
+        # ip数据库
+        db = IPIPDatabase(base_dir + '/DB/17monipdb.dat')
+        addr = db.lookup(ip)
+        ts = addr.split('\t')[0]
+        return ts
+
+    # 通过ip检索ipip指定信息 lang为CN或EN
+    @staticmethod
+    def getIpIpInfo(ip, lang, update=False):
+        ipbd_dir = BASE_DIR + "/DB/mydata4vipday2.ipdb"
+        db = ipdb.City(ipbd_dir)
+        if update:
+            from var_dump import var_dump
+            var_dump('is_update')
+            rr = db.reload(ipbd_dir)
+            var_dump(rr)
+        info = db.find_map(ip, lang)
+        return info
+
+    @staticmethod
+    def getUserID(userPhone='13800138000', getUser=True, setOTAID=False, μs=True):
+        if μs == True:
+            if getUser == True:
+                timeID = str(round(time.time() * 1000000))
+                userID = timeID + userPhone
+
+                return userID
+            else:
+                if setOTAID == False:
+                    timeID = str(round(time.time() * 1000000))
+                    ID = userPhone + timeID
+
+                    return ID
+                else:
+                    timeID = str(round(time.time() * 1000000))
+                    eID = '13800' + timeID + '138000'
+                    return eID
+        else:
+            if getUser == True:
+                timeID = str(round(time.time() * 1000))
+                userID = timeID + userPhone
+
+                return userID
+            else:
+                if setOTAID == False:
+                    timeID = str(round(time.time() * 1000))
+                    ID = userPhone + timeID
+
+                    return ID
+                else:
+                    timeID = str(round(time.time() * 1000))
+                    eID = '13800' + timeID + '138000'
+                    return eID
+
+    # 生成随机数
+    @staticmethod
+    def RandomStr(randomlength=8, number=True):
+        str = ''
+        if number == False:
+            characterSet = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsT' \
+                           'tUuVvWwXxYyZz0123456789'
+        else:
+            characterSet = '0123456789'
+
+        length = len(characterSet) - 1
+
+        random = Random()
+        for index in range(randomlength):
+            str += characterSet[random.randint(0, length)]
+        return str
+
+    # 生成订单好
+    @staticmethod
+    def createOrderID():
+        random_id = CommonService.RandomStr(6, True)
+        order_id = datetime.datetime.now().strftime('%Y%m%d%H%M%S') + str(random_id)
+        print('orderID:')
+        print(order_id)
+        return order_id
+
+    # qs转换list datetime处理
+    @staticmethod
+    def qs_to_list(qs):
+        res = []
+        # print(qs)
+        for ps in qs:
+            if 'add_time' in ps:
+                ps['add_time'] = ps['add_time'].strftime("%Y-%m-%d %H:%M:%S")
+            if 'update_time' in ps:
+                ps['update_time'] = ps['update_time'].strftime("%Y-%m-%d %H:%M:%S")
+            if 'end_time' in ps:
+                ps['end_time'] = ps['end_time'].strftime("%Y-%m-%d %H:%M:%S")
+            if 'data_joined' in ps:
+                if ps['data_joined']:
+                    ps['data_joined'] = ps['data_joined'].strftime("%Y-%m-%d %H:%M:%S")
+                else:
+                    ps['data_joined'] = ''
+            res.append(ps)
+        return res
+
+    # 获取当前时间
+    @staticmethod
+    def get_now_time_str(n_time, tz, lang):
+        print(n_time)
+        print(tz)
+        print(lang)
+        n_time = int(n_time) + 3600 * float(tz)
+        if lang == 'cn':
+            return time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(int(n_time)))
+        else:
+            return time.strftime('%m-%d-%Y %H:%M:%S', time.gmtime(int(n_time)))

+ 22 - 0
formal_manage.py

@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == '__main__':
+    arg_m = sys.argv[1]
+    if arg_m == 'makemigrations':
+        print('do not makemigrations')
+        exit()
+    if arg_m == 'migrate':
+        print('do not migrate')
+        exit()
+    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'AnsjerPush.formal_settings')
+    try:
+        from django.core.management import execute_from_command_line
+    except ImportError as exc:
+        raise ImportError(
+            "Couldn't import Django. Are you sure it's installed and "
+            "available on your PYTHONPATH environment variable? Did you "
+            "forget to activate a virtual environment?"
+        ) from exc
+    execute_from_command_line(sys.argv)

+ 22 - 0
local_manage.py

@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == '__main__':
+    arg_m = sys.argv[1]
+    if arg_m == 'makemigrations':
+        print('do not makemigrations')
+        exit()
+    if arg_m == 'migrate':
+        print('do not migrate')
+        exit()
+    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'AnsjerPush.local_settings')
+    try:
+        from django.core.management import execute_from_command_line
+    except ImportError as exc:
+        raise ImportError(
+            "Couldn't import Django. Are you sure it's installed and "
+            "available on your PYTHONPATH environment variable? Did you "
+            "forget to activate a virtual environment?"
+        ) from exc
+    execute_from_command_line(sys.argv)

+ 15 - 0
manage.py

@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == '__main__':
+    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'AnsjerPush.settings')
+    try:
+        from django.core.management import execute_from_command_line
+    except ImportError as exc:
+        raise ImportError(
+            "Couldn't import Django. Are you sure it's installed and "
+            "available on your PYTHONPATH environment variable? Did you "
+            "forget to activate a virtual environment?"
+        ) from exc
+    execute_from_command_line(sys.argv)

+ 224 - 0
requirements.txt

@@ -0,0 +1,224 @@
+alabaster==0.7.12
+anaconda-client==1.7.2
+anaconda-navigator==1.9.7
+anaconda-project==0.8.3
+asgiref==3.2.3
+asn1crypto==1.0.1
+astroid==2.3.1
+astropy==3.2.1
+atomicwrites==1.3.0
+attrs==19.2.0
+Babel==2.7.0
+backcall==0.1.0
+backports.functools-lru-cache==1.5
+backports.os==0.1.1
+backports.shutil-get-terminal-size==1.0.0
+backports.tempfile==1.0
+backports.weakref==1.0.post1
+beautifulsoup4==4.8.0
+bitarray==1.0.1
+bkcharts==0.2
+bleach==3.1.0
+bokeh==1.3.4
+boto==2.49.0
+Bottleneck==1.2.1
+certifi==2019.9.11
+cffi==1.12.3
+chardet==3.0.4
+Click==7.0
+cloudpickle==1.2.2
+clyent==1.2.2
+colorama==0.4.1
+comtypes==1.1.7
+conda==4.7.12
+conda-build==3.18.9
+conda-package-handling==1.6.0
+conda-verify==3.4.2
+contextlib2==0.6.0
+cryptography==2.7
+cycler==0.10.0
+Cython==0.29.13
+cytoolz==0.10.0
+dask==2.5.2
+decorator==4.4.0
+defusedxml==0.6.0
+distributed==2.5.2
+Django==3.0.3
+django-appconf==1.0.3
+django-cors-headers==3.2.1
+django-imagekit==4.0.2
+django-tinymce==2.8.0
+docutils==0.15.2
+entrypoints==0.3
+et-xmlfile==1.0.1
+fastcache==1.1.0
+filelock==3.0.12
+Flask==1.1.1
+fsspec==0.5.2
+future==0.17.1
+gevent==1.4.0
+glob2==0.7
+greenlet==0.4.15
+gunicorn==20.0.4
+h5py==2.9.0
+HeapDict==1.0.1
+html5lib==1.0.1
+idna==2.8
+imageio==2.6.0
+imagesize==1.1.0
+importlib-metadata==0.23
+ipykernel==5.1.2
+ipython==7.8.0
+ipython-genutils==0.2.0
+ipywidgets==7.5.1
+isort==4.3.21
+itsdangerous==1.1.0
+jdcal==1.4.1
+jedi==0.15.1
+Jinja2==2.10.3
+joblib==0.13.2
+json5==0.8.5
+jsonschema==3.0.2
+jupyter==1.0.0
+jupyter-client==5.3.3
+jupyter-console==6.0.0
+jupyter-core==4.5.0
+jupyterlab==1.1.4
+jupyterlab-server==1.0.6
+keyring==18.0.0
+kiwisolver==1.1.0
+lazy-object-proxy==1.4.2
+libarchive-c==2.8
+llvmlite==0.29.0
+locket==0.2.0
+lxml==4.4.1
+MarkupSafe==1.1.1
+matplotlib==3.1.1
+mccabe==0.6.1
+menuinst==1.4.16
+mistune==0.8.4
+mkl-fft==1.0.14
+mkl-random==1.1.0
+mkl-service==2.3.0
+mock==3.0.5
+more-itertools==7.2.0
+mpmath==1.1.0
+msgpack==0.6.1
+multipledispatch==0.6.0
+mysqlclient==1.4.6
+navigator-updater==0.2.1
+nbconvert==5.6.0
+nbformat==4.4.0
+networkx==2.3
+nltk==3.4.5
+nose==1.3.7
+notebook==6.0.1
+numba==0.45.1
+numexpr==2.7.0
+numpy==1.16.5
+numpydoc==0.9.1
+olefile==0.46
+openpyxl==3.0.0
+packaging==19.2
+pandas==0.25.1
+pandocfilters==1.4.2
+parso==0.5.1
+partd==1.0.0
+path.py==12.0.1
+pathlib2==2.3.5
+patsy==0.5.1
+pep8==1.7.1
+pickleshare==0.7.5
+pilkit==2.0
+Pillow==6.2.0
+pkginfo==1.5.0.1
+pluggy==0.13.0
+ply==3.11
+prometheus-client==0.7.1
+prompt-toolkit==2.0.10
+psutil==5.6.3
+py==1.8.0
+pycodestyle==2.5.0
+pycosat==0.6.3
+pycparser==2.19
+pycrypto==2.6.1
+pycurl==7.43.0.3
+pyflakes==2.1.1
+Pygments==2.4.2
+pylint==2.4.2
+PyMySQL==0.9.3
+pyodbc==4.0.27
+pyOpenSSL==19.0.0
+pyparsing==2.4.2
+pyreadline==2.1
+pyrsistent==0.15.4
+PySocks==1.7.1
+pytest==5.2.1
+pytest-arraydiff==0.3
+pytest-astropy==0.5.0
+pytest-doctestplus==0.4.0
+pytest-openfiles==0.4.0
+pytest-remotedata==0.3.2
+python-dateutil==2.8.0
+pytz==2019.3
+PyWavelets==1.0.3
+pywin32==223
+pywinpty==0.5.5
+PyYAML==5.1.2
+pyzmq==18.1.0
+QtAwesome==0.6.0
+qtconsole==4.5.5
+QtPy==1.9.0
+requests==2.22.0
+rope==0.14.0
+ruamel-yaml==0.15.46
+scikit-image==0.15.0
+scikit-learn==0.21.3
+scipy==1.3.1
+seaborn==0.9.0
+Send2Trash==1.5.0
+simplegeneric==0.8.1
+singledispatch==3.4.0.3
+six==1.12.0
+snowballstemmer==2.0.0
+sortedcollections==1.1.2
+sortedcontainers==2.1.0
+soupsieve==1.9.3
+Sphinx==2.2.0
+sphinxcontrib-applehelp==1.0.1
+sphinxcontrib-devhelp==1.0.1
+sphinxcontrib-htmlhelp==1.0.2
+sphinxcontrib-jsmath==1.0.1
+sphinxcontrib-qthelp==1.0.2
+sphinxcontrib-serializinghtml==1.1.3
+sphinxcontrib-websupport==1.1.2
+spyder==3.3.6
+spyder-kernels==0.5.2
+SQLAlchemy==1.3.9
+sqlparse==0.3.0
+statsmodels==0.10.1
+sympy==1.4
+tables==3.5.2
+tblib==1.4.0
+terminado==0.8.2
+testpath==0.4.2
+toolz==0.10.0
+tornado==6.0.3
+tqdm==4.36.1
+traitlets==4.3.3
+unicodecsv==0.14.1
+urllib3==1.24.2
+wcwidth==0.1.7
+webencodings==0.5.1
+Werkzeug==1.0.0
+widgetsnbextension==3.5.1
+win-inet-pton==1.1.0
+win-unicode-console==0.5
+wincertstore==0.2
+wrapt==1.11.2
+xlrd==1.2.0
+XlsxWriter==1.2.1
+xlwings==0.15.10
+xlwt==1.3.0
+zict==1.0.0
+zipp==0.6.0

+ 22 - 0
test_manage.py

@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == '__main__':
+    arg_m = sys.argv[1]
+    if arg_m == 'makemigrations':
+        print('do not makemigrations')
+        exit()
+    if arg_m == 'migrate':
+        print('do not migrate')
+        exit()
+    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'AnsjerPush.test_settings')
+    try:
+        from django.core.management import execute_from_command_line
+    except ImportError as exc:
+        raise ImportError(
+            "Couldn't import Django. Are you sure it's installed and "
+            "available on your PYTHONPATH environment variable? Did you "
+            "forget to activate a virtual environment?"
+        ) from exc
+    execute_from_command_line(sys.argv)