CustomizedPushService.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. # @Author : Rocky
  2. # @File : CustomizedPushService.py
  3. # @Time : 2023/10/19 15:49
  4. import logging
  5. import threading
  6. import time
  7. from concurrent.futures import ThreadPoolExecutor
  8. from AnsjerPush.config import CONFIG_INFO, CONFIG_TEST, CONFIG_CN, XM_PUSH_CHANNEL_ID
  9. from Model.models import DeviceTypeModel, Device_Info, GatewayPush, CountryModel, SysMsgModel
  10. from Service.CommonService import CommonService
  11. from Service.HuaweiPushService.HuaweiPushService import HuaweiPushObject
  12. from Service.PushService import PushObject
  13. CUSTOMIZED_PUSH_LOGGER = logging.getLogger('customized_push')
  14. class CustomizedPushObject:
  15. @staticmethod
  16. def query_push_user(device_name, country, register_period):
  17. """
  18. 查询需要推送的用户id列表
  19. @param device_name: 设备型号
  20. @param country: 国家
  21. @param register_period: 用户注册年限
  22. @return: uid_id_list
  23. """
  24. # 设备型号和国家
  25. device_name_list = device_name.split(',')
  26. device_type_list = DeviceTypeModel.objects.filter(name__in=device_name_list).values_list('type', flat=True)
  27. # 测试和国内服推给所有用户
  28. if CONFIG_INFO in [CONFIG_TEST, CONFIG_CN]:
  29. device_info_qs = Device_Info.objects.filter(Type__in=device_type_list)
  30. else:
  31. country_name_list = country.split(',')
  32. country_id_list = CountryModel.objects.filter(country_name__in=country_name_list).\
  33. values_list('id', flat=True)
  34. device_info_qs = Device_Info.objects.filter(Type__in=device_type_list,
  35. userID__region_country__in=country_id_list)
  36. # 获取时间范围
  37. now_time = int(time.time())
  38. index = register_period.find('-')
  39. n, m = register_period[:index], register_period[index + 1:]
  40. if m == '':
  41. # 0-,所有时间
  42. if n == '0':
  43. device_info_qs = device_info_qs.values_list('userID_id', flat=True)
  44. # n-,n年以上
  45. else:
  46. # n年前时间戳转时间字符串
  47. n_years_seconds = int(n) * 365 * 24 * 60 * 60
  48. n_year_ago_timestamp = now_time - n_years_seconds
  49. n_year_ago = CommonService.timestamp_to_str(n_year_ago_timestamp)
  50. # 注册时间越小越早
  51. device_info_qs = device_info_qs.filter(userID__data_joined__lte=n_year_ago). \
  52. values_list('userID_id', flat=True)
  53. else:
  54. # n-m年,(如2-3年)
  55. n_years_seconds, m_years_seconds = int(n) * 365 * 24 * 60 * 60, int(m) * 365 * 24 * 60 * 60
  56. n_year_ago_timestamp = now_time - n_years_seconds
  57. m_year_ago_timestamp = now_time - m_years_seconds
  58. # 时间戳转时间字符串
  59. n_year_ago = CommonService.timestamp_to_str(n_year_ago_timestamp) # 2021
  60. m_year_ago = CommonService.timestamp_to_str(m_year_ago_timestamp) # 2020
  61. # 2020 <= 注册时间 <= 2021
  62. device_info_qs = device_info_qs. \
  63. filter(userID__data_joined__gte=m_year_ago, userID__data_joined__lte=n_year_ago). \
  64. values_list('userID_id', flat=True)
  65. user_id_list = list(device_info_qs)
  66. return user_id_list
  67. @classmethod
  68. def push_and_save_sys_msg(cls, **kwargs):
  69. """
  70. 推送和保存系统消息
  71. @param kwargs: 参数
  72. @return:
  73. """
  74. customized_push_id = kwargs['id']
  75. user_id_list = kwargs['user_id_list']
  76. title = kwargs['title']
  77. msg = kwargs['msg']
  78. link = kwargs['link']
  79. icon_link = kwargs['icon_link'] if kwargs['icon_link'] != '' else None
  80. n_time = int(time.time())
  81. push_kwargs = {
  82. 'n_time': n_time,
  83. 'title': title,
  84. 'msg': msg,
  85. 'icon_link': icon_link
  86. }
  87. # 推送
  88. if kwargs['push_app'] == 'ZosiSmart':
  89. app_bundle_id_list = ['com.ansjer.zccloud_a', 'com.ansjer.zccloud']
  90. else:
  91. app_bundle_id_list = ['com.ansjer.zccloud_ab', 'com.ansjer.customizede']
  92. try:
  93. gateway_push_qs = GatewayPush.objects.filter(
  94. user_id__in=user_id_list, app_bundle_id__in=app_bundle_id_list).\
  95. values('user_id', 'app_bundle_id', 'push_type', 'token_val')
  96. if gateway_push_qs.exists():
  97. sys_msg_list = []
  98. saved_user_id_list = []
  99. gateway_push_list = []
  100. for gateway_push in gateway_push_qs:
  101. # user_id保存列表,避免重复写入数据
  102. user_id = gateway_push['user_id']
  103. if user_id not in saved_user_id_list:
  104. saved_user_id_list.append(user_id)
  105. sys_msg_list.append(SysMsgModel(
  106. userID_id=user_id, title=title, msg=msg, jumpLink=link, addTime=n_time, updTime=n_time))
  107. gateway_push_list.append(gateway_push)
  108. # 保存系统消息和异步推送消息
  109. SysMsgModel.objects.bulk_create(sys_msg_list)
  110. pre_push_kwargs = {
  111. 'push_kwargs': push_kwargs,
  112. 'gateway_push_list': gateway_push_list
  113. }
  114. pre_push_thread = threading.Thread(
  115. target=cls.thr_pool_push,
  116. kwargs=pre_push_kwargs)
  117. pre_push_thread.start()
  118. CUSTOMIZED_PUSH_LOGGER.info('customized_push_id:{}推送完成'.format(customized_push_id))
  119. except Exception as e:
  120. CUSTOMIZED_PUSH_LOGGER.info('定制化推送或保存数据异常,'
  121. 'error_line:{},error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  122. @classmethod
  123. def thr_pool_push(cls, **kwargs):
  124. CUSTOMIZED_PUSH_LOGGER.info('线程池推送开始')
  125. push_kwargs = kwargs['push_kwargs']
  126. gateway_push_list = kwargs['gateway_push_list']
  127. with ThreadPoolExecutor() as executor:
  128. executor.map(
  129. lambda gateway_push_kwargs: cls.start_push(push_kwargs, gateway_push_kwargs), gateway_push_list)
  130. @classmethod
  131. def start_push(cls, push_kwargs, gateway_push_kwargs):
  132. title = push_kwargs['title']
  133. n_time = push_kwargs['n_time']
  134. msg = push_kwargs['msg']
  135. icon_link = push_kwargs['icon_link']
  136. push_type = gateway_push_kwargs['push_type']
  137. user_id = gateway_push_kwargs['user_id']
  138. app_bundle_id = gateway_push_kwargs['app_bundle_id']
  139. token_val = gateway_push_kwargs['token_val']
  140. push_succeed = cls.push_msg(push_type, app_bundle_id, token_val, n_time, title, msg, icon_link)
  141. push_status = '成功' if push_succeed else '失败'
  142. CUSTOMIZED_PUSH_LOGGER.info('{}推送{},push_type:{}'.format(user_id, push_status, push_type))
  143. @staticmethod
  144. def push_msg(push_type, app_bundle_id, token_val, n_time, title, msg, icon_link):
  145. push_kwargs = {
  146. 'nickname': '',
  147. 'event_type': 0,
  148. 'app_bundle_id': app_bundle_id,
  149. 'token_val': token_val,
  150. 'msg_title': title,
  151. 'msg_text': msg,
  152. 'n_time': n_time,
  153. }
  154. try:
  155. # ios
  156. if push_type == 0:
  157. push_kwargs['launch_image'] = icon_link
  158. return PushObject.ios_apns_push(**push_kwargs)
  159. # gcm
  160. elif push_type == 1:
  161. if icon_link is None:
  162. icon_link = ''
  163. push_kwargs['image'] = icon_link
  164. return PushObject.android_fcm_push_v1(**push_kwargs)
  165. # 极光
  166. elif push_type == 2:
  167. return PushObject.android_jpush(**push_kwargs)
  168. # 华为
  169. elif push_type == 3:
  170. push_kwargs['image_url'] = icon_link
  171. huawei_push_object = HuaweiPushObject()
  172. return huawei_push_object.send_push_notify_message(**push_kwargs)
  173. # 小米
  174. elif push_type == 4:
  175. push_kwargs['channel_id'] = XM_PUSH_CHANNEL_ID['service_reminder']
  176. return PushObject.android_xmpush(**push_kwargs)
  177. # vivo
  178. elif push_type == 5:
  179. return PushObject.android_vivopush(**push_kwargs)
  180. # oppo
  181. elif push_type == 6:
  182. push_kwargs['channel_id'] = 'VALUE_ADDED'
  183. return PushObject.android_oppopush(**push_kwargs)
  184. # 魅族
  185. elif push_type == 7:
  186. return PushObject.android_meizupush(**push_kwargs)
  187. else:
  188. return False
  189. except Exception as e:
  190. CUSTOMIZED_PUSH_LOGGER.info('定制化推送异常,'
  191. 'error_line:{},error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  192. return False