PushService.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. # -*- coding: utf-8 -*-
  2. """
  3. @Time : 2022/5/19 11:43
  4. @Auth : Locky
  5. @File :PushService.py
  6. @IDE :PyCharm
  7. """
  8. import hashlib
  9. import json
  10. import logging
  11. import os
  12. import time
  13. import apns2
  14. import jpush
  15. import requests
  16. from pyfcm import FCMNotification
  17. from AnsjerPush.config import APP_BUNDLE_DICT, APNS_MODE, BASE_DIR, APNS_CONFIG, FCM_CONFIG, JPUSH_CONFIG, XMPUSH_CONFIG \
  18. , VIVOPUSH_CONFIG, OPPOPUSH_CONFIG
  19. from Object.RedisObject import RedisObject
  20. from Service.CommonService import CommonService
  21. from Service.VivoPushService.push_admin.APIMessage import PushMessage
  22. from Service.VivoPushService.push_admin.APISender import APISender
  23. class PushObject:
  24. # 推送对象
  25. @staticmethod
  26. def get_msg_title(app_bundle_id, nickname):
  27. """
  28. 获取推送消息标题
  29. @param app_bundle_id: app包id
  30. @param nickname: 设备名
  31. @return: msg_title
  32. """
  33. if app_bundle_id in APP_BUNDLE_DICT.keys():
  34. msg_title = APP_BUNDLE_DICT[app_bundle_id] + '(' + nickname + ')'
  35. else:
  36. msg_title = nickname
  37. return msg_title
  38. @staticmethod
  39. def get_gateway_msg_text(n_time, tz, lang, alarm):
  40. """
  41. 获取网关推送消息内容
  42. @param n_time: 当前时间
  43. @param tz: 时区
  44. @param lang: 语言
  45. @param alarm: 警报
  46. @return: msg_text
  47. """
  48. n_date = CommonService.get_now_time_str(n_time=n_time, tz=tz, lang=lang)
  49. if lang == 'cn':
  50. msg_text = '{} 日期:{}'.format(alarm, n_date)
  51. else:
  52. msg_text = '{} date:{}'.format(alarm, n_date)
  53. return msg_text
  54. @staticmethod
  55. def get_ai_msg_text(channel, n_time, lang, tz, label):
  56. """
  57. 获取AI推送内容
  58. @param channel: 通道
  59. @param n_time: 当前时间
  60. @param lang: 语言
  61. @param tz: 时区
  62. @param label: 识别到的标签
  63. @return: ai_msg_text
  64. """
  65. n_date = CommonService.get_now_time_str(n_time=n_time, tz=tz, lang=lang)
  66. if lang == 'cn':
  67. msg = '摄像头AI识别到了{}'.format(label)
  68. ai_msg_text = '{msg} 通道:{channel} 日期:{date}'.format(msg=msg, channel=channel, date=n_date)
  69. else:
  70. msg = 'Camera AI recognizes {}'.format(label)
  71. ai_msg_text = '{msg} channel:{channel} date:{date}'.format(msg=msg, channel=channel, date=n_date)
  72. return ai_msg_text
  73. @staticmethod
  74. def get_low_power_msg_text(channel, n_time, lang, tz, electricity, is_sys=0):
  75. """
  76. 获取低电量推送内容
  77. @param channel: 通道
  78. @param n_time: 当前时间
  79. @param lang: 语言
  80. @param tz: 时区
  81. @param electricity: 电量
  82. @param is_sys: 是否为系统消息
  83. @return: low_power_msg_text
  84. """
  85. n_date = CommonService.get_now_time_str(n_time=n_time, tz=tz, lang=lang)
  86. if lang == 'cn':
  87. alarm = '剩余电量:' + electricity
  88. if is_sys:
  89. low_power_msg_text = '{} 通道:{}'.format(alarm, channel)
  90. else:
  91. low_power_msg_text = '{} 通道:{} 日期:{}'.format(alarm, channel, n_date)
  92. else:
  93. alarm = 'Battery remaining:' + electricity
  94. if is_sys:
  95. low_power_msg_text = '{} channel:{}'.format(alarm, channel)
  96. else:
  97. low_power_msg_text = '{} channel:{} date:{}'.format(alarm, channel, n_date)
  98. return low_power_msg_text
  99. @staticmethod
  100. def ios_apns_push(nickname, app_bundle_id, token_val, n_time, event_type, msg_title, msg_text,
  101. uid='', channel='1', launch_image=None):
  102. """
  103. ios apns 推送
  104. @param nickname: 设备昵称
  105. @param app_bundle_id: app包id
  106. @param token_val: 推送token
  107. @param n_time: 当前时间
  108. @param event_type: 事件类型
  109. @param msg_title: 推送标题
  110. @param msg_text: 推送内容
  111. @param uid: uid
  112. @param channel: 通道
  113. @param launch_image: 推送图片链接
  114. @return: None
  115. """
  116. logger = logging.getLogger('info')
  117. try:
  118. pem_path = os.path.join(BASE_DIR, APNS_CONFIG[app_bundle_id]['pem_path'])
  119. logger.info('apns推送app_bundle_id:{}, pem_path:{}'.format(app_bundle_id, pem_path))
  120. cli = apns2.APNSClient(mode=APNS_MODE, client_cert=pem_path)
  121. alert = apns2.PayloadAlert(title=msg_title, body=msg_text, launch_image=launch_image)
  122. push_data = {'alert': 'Motion', 'msg': '', 'sound': '', 'zpush': '1', 'uid': uid, 'channel': channel,
  123. 'received_at': n_time, 'event_time': n_time, 'event_type': event_type, 'nickname': nickname,
  124. 'image_url': launch_image
  125. }
  126. payload = apns2.Payload(alert=alert, custom=push_data, sound='default', category='myCategory',
  127. mutable_content=True)
  128. n = apns2.Notification(payload=payload, priority=apns2.PRIORITY_LOW)
  129. res = cli.push(n=n, device_token=token_val, topic=app_bundle_id)
  130. assert res.status_code == 200
  131. except Exception as e:
  132. logger.info('--->IOS推送异常{}'.format(repr(e)))
  133. return repr(e)
  134. @staticmethod
  135. def android_fcm_push(nickname, app_bundle_id, token_val, n_time, event_type, msg_title, msg_text,
  136. uid='', channel='1', image=''):
  137. """
  138. android fcm 推送
  139. @param nickname: 设备昵称
  140. @param app_bundle_id: app包id
  141. @param token_val: 推送token
  142. @param n_time: 当前时间
  143. @param event_type: 事件类型
  144. @param msg_title: 推送标题
  145. @param msg_text: 推送内容
  146. @param uid: uid
  147. @param channel: 通道
  148. @param image: 推送图片链接
  149. @return: None
  150. """
  151. logger = logging.getLogger('info')
  152. try:
  153. serverKey = FCM_CONFIG[app_bundle_id]
  154. push_service = FCMNotification(api_key=serverKey)
  155. push_data = {'alert': 'Motion', 'msg': '', 'sound': 'sound.aif', 'zpush': '1', 'image': image,
  156. 'received_at': n_time, 'event_time': n_time, 'event_type': event_type, 'nickname': nickname,
  157. 'uid': uid, 'channel': channel
  158. }
  159. result = push_service.notify_single_device(registration_id=token_val, message_title=msg_title,
  160. message_body=msg_text, data_message=push_data,
  161. extra_kwargs={'default_sound': True,
  162. 'default_vibrate_timings': True,
  163. 'default_light_settings': True,
  164. }
  165. )
  166. logger.info('fcm推送结果:{}'.format(result))
  167. except Exception as e:
  168. return repr(e)
  169. @staticmethod
  170. def android_jpush(nickname, app_bundle_id, token_val, n_time, event_type, msg_title, msg_text):
  171. """
  172. android 极光 推送
  173. @param nickname: 设备昵称
  174. @param app_bundle_id: app包id
  175. @param token_val: 推送token
  176. @param n_time: 当前时间
  177. @param event_type: 事件类型
  178. @param msg_title: 推送标题
  179. @param msg_text: 推送内容
  180. @return: None
  181. """
  182. try:
  183. app_key = JPUSH_CONFIG[app_bundle_id]['Key']
  184. master_secret = JPUSH_CONFIG[app_bundle_id]['Secret']
  185. # 换成各自的app_key和master_secret
  186. _jpush = jpush.JPush(app_key, master_secret)
  187. push = _jpush.create_push()
  188. push.audience = jpush.registration_id(token_val)
  189. push_data = {'alert': 'Motion', 'msg': '', 'sound': 'sound.aif', 'zpush': '1',
  190. 'received_at': n_time, 'event_time': n_time, 'event_type': event_type, 'nickname': nickname
  191. }
  192. android = jpush.android(title=msg_title, big_text=msg_text, alert=msg_text, extras=push_data,
  193. priority=1, style=1, alert_type=7
  194. )
  195. push.notification = jpush.notification(android=android)
  196. push.platform = jpush.all_
  197. res = push.send()
  198. assert res.status_code == 200
  199. except Exception as e:
  200. return repr(e)
  201. @staticmethod
  202. def android_xmpush(nickname, app_bundle_id, token_val, n_time, event_type, msg_title, msg_text,
  203. uid='', channel='1', image=''):
  204. """
  205. android 小米 推送
  206. @param nickname: 设备昵称
  207. @param app_bundle_id: app包id
  208. @param token_val: 推送token
  209. @param n_time: 当前时间
  210. @param event_type: 事件类型
  211. @param msg_title: 推送标题
  212. @param msg_text: 推送内容
  213. @param uid: uid
  214. @param channel: 通道
  215. @param image: 推送图片链接
  216. @return: None
  217. """
  218. logger = logging.getLogger('info')
  219. try:
  220. url = 'https://api.xmpush.xiaomi.com/v3/message/regid'
  221. app_secret = XMPUSH_CONFIG[app_bundle_id]
  222. payload = {'alert': 'Motion', 'msg': '', 'sound': 'sound.aif', 'zpush': '1',
  223. 'received_at': n_time, 'event_time': n_time, 'event_type': event_type, 'nickname': nickname,
  224. 'uid': uid, 'channel': channel
  225. }
  226. data = {
  227. 'title': msg_title,
  228. 'description': msg_text,
  229. 'payload': 'payload',
  230. 'restricted_package_name': app_bundle_id,
  231. 'registration_id': token_val,
  232. }
  233. # if image:
  234. # data['extra.notification_style_type'] = 2
  235. # data['extra.notification_bigPic_uri'] = image
  236. headers = {
  237. 'Authorization': 'key={}'.format(app_secret)
  238. }
  239. response = requests.post(url, data=data, headers=headers)
  240. logger.info("小米推送返回值:{}".format(response.json()))
  241. assert response.status_code == 200
  242. except Exception as e:
  243. return repr(e)
  244. @staticmethod
  245. def android_vivopush(app_bundle_id, token_val, n_time, event_type, msg_title, msg_text,
  246. uid='', channel='1', image='', skip_type='1', nickname=''):
  247. """
  248. vivo 推送
  249. @param app_bundle_id: app包id
  250. @param token_val: 推送token
  251. @param event_type: 消息类型 (0:运营类消息,1:系统类消息。默认为 0)
  252. @param msg_title: 推送标题
  253. @param msg_text: 推送内容
  254. @param push_mode: 推送模式 (0:正式推送;1:测试推送,默认为0)
  255. @param m_code: 用户请求唯一标识 最大 64 字符
  256. @param skip_type: 跳转类型(1:打开 APP 首页 2:打开链接 3:自定义 4:打开 app 内指定页面)
  257. @param n_time: 当前时间
  258. @param nickname: 设备昵称
  259. @param uid: uid
  260. @param image: 推送图片链接
  261. @param channel: 通道
  262. @return: None
  263. """
  264. logger = logging.getLogger('info')
  265. try:
  266. authToken = 'authToken_' + app_bundle_id
  267. redisObj = RedisObject()
  268. # 获取redis里面的authToken
  269. redis_authToken = redisObj.get_data(key=authToken)
  270. if msg_title == '':
  271. msg_title = '周视'
  272. if redis_authToken is not False:
  273. app_secret = VIVOPUSH_CONFIG[app_bundle_id]['Secret']
  274. sender_send = APISender(app_secret)
  275. sender_send.set_token(redis_authToken)
  276. else:
  277. skip_type = int(skip_type)
  278. app_id = VIVOPUSH_CONFIG[app_bundle_id]['ID']
  279. app_key = VIVOPUSH_CONFIG[app_bundle_id]['Key']
  280. app_secret = VIVOPUSH_CONFIG[app_bundle_id]['Secret']
  281. sender = APISender(app_secret)
  282. rec = sender.get_token(app_id, app_key)
  283. # 存放authToken,有效期3个小时
  284. redisObj = RedisObject()
  285. redisObj.set_data(key=authToken, val=rec['authToken'], expire=10800)
  286. sender_send = APISender(app_secret)
  287. sender_send.set_token(rec['authToken'])
  288. push_data = {'alert': 'Motion', 'msg': '', 'sound': 'sound.aif', 'zpush': '1', 'image': image,
  289. 'received_at': n_time, 'event_time': n_time, 'event_type': event_type, 'nickname': nickname,
  290. 'uid': uid, 'channel': channel
  291. }
  292. # 推送
  293. message = PushMessage() \
  294. .reg_id(token_val) \
  295. .title(msg_title) \
  296. .content(msg_text) \
  297. .push_mode(1) \
  298. .notify_type(1) \
  299. .skip_type(skip_type) \
  300. .request_id('123456') \
  301. .classification(1) \
  302. .client_custom_map(**push_data) \
  303. .message_dict()
  304. rec2 = sender_send.send(message)
  305. logger.info('vivo推送结果:{}'.format(rec2))
  306. except Exception as e:
  307. logger.info('vivo推送异常:{}'.format(e))
  308. @staticmethod
  309. def android_oppopush(nickname, app_bundle_id, token_val, n_time, event_type, msg_title, msg_text,
  310. uid='', channel='1', image=''):
  311. """
  312. android oppo 推送
  313. @param nickname: 设备昵称
  314. @param app_bundle_id: app包id
  315. @param token_val: 推送token
  316. @param n_time: 当前时间
  317. @param event_type: 事件类型
  318. @param msg_title: 推送标题
  319. @param msg_text: 推送内容
  320. @param uid: uid
  321. @param channel: 通道
  322. @param image: 推送图片链接
  323. @return: None
  324. """
  325. logger = logging.getLogger('info')
  326. try:
  327. """
  328. android 国内oppo APP消息提醒推送
  329. """
  330. app_key = OPPOPUSH_CONFIG[app_bundle_id]['Key']
  331. master_secret = OPPOPUSH_CONFIG[app_bundle_id]['Secret']
  332. url = 'https://api.push.oppomobile.com/'
  333. now_time = str(round(time.time() * 1000))
  334. # 1、实例化一个sha256对象
  335. sha256 = hashlib.sha256()
  336. # 2、调用update方法进行加密
  337. sha256.update((app_key + now_time + master_secret).encode('utf-8'))
  338. # 3、调用hexdigest方法,获取加密结果
  339. sign = sha256.hexdigest()
  340. # 获取auth_token
  341. get_token_url = url + 'server/v1/auth'
  342. post_data = {
  343. 'app_key': app_key,
  344. 'sign': sign,
  345. 'timestamp': now_time
  346. }
  347. headers = {'Content-Type': 'application/x-www-form-urlencoded'}
  348. response = requests.post(get_token_url, data=post_data, headers=headers)
  349. result = response.json()
  350. # 发送推送
  351. push_url = url + 'server/v1/message/notification/unicast'
  352. push_data = {'alert': 'Motion', 'msg': '', 'sound': 'sound.aif', 'zpush': '1',
  353. 'received_at': n_time, 'event_time': n_time, 'event_type': event_type, 'nickname': nickname,
  354. 'uid': uid, 'channel': channel
  355. }
  356. message = {
  357. "target_type": 2,
  358. "target_value": token_val,
  359. "notification": {
  360. "title": msg_title,
  361. "content": msg_text,
  362. }
  363. }
  364. push_data = {
  365. 'auth_token': result['data']['auth_token'],
  366. 'message': json.dumps(message)
  367. }
  368. response = requests.post(push_url, data=push_data, headers=headers)
  369. logger.info("oppo推送返回值:{}".format(response.json()))
  370. assert response.status_code == 200
  371. except Exception as e:
  372. return repr(e)