zhejiang_fire.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import base64
  4. import datetime
  5. import json
  6. import logging
  7. import urllib2
  8. import uuid
  9. import pika
  10. from Crypto import Random
  11. from Crypto.Cipher import PKCS1_v1_5
  12. from Crypto.PublicKey import RSA
  13. from mongoengine import DoesNotExist, StringField, IntField, DictField, DateTimeField
  14. from six.moves.urllib import parse
  15. from apilib.utils_datetime import to_datetime
  16. from apps.web.constant import Const
  17. from apps.web.core.db import Searchable
  18. from apps.web.dealer.models import Dealer
  19. from apps.web.device.models import Part, FaultRecord, Device
  20. from apps.web.exceptions import UserServerException
  21. logger = logging.getLogger(__name__)
  22. class ZhejiangRSA(object):
  23. # 本地产生的publicKey,北向会过来拿这个key,用于加密数据传递给我们,我们用私钥解密
  24. publicKeyHear = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAueN4TXcy27K/HoArURK5\n4NSNvWQhqpTk1s9bVlrSANwctascPBQlLWKf3HyL6+yxxgJ4oKZk00qagceSu85E\n1SG/opmvjPOQfIGwi/y0yuFWRM+x2DtfVxtH/4YMIMHq2DAmKY/MBj1RtPEz89oF\nsqJRHbZxe1aV5cDCRUJWgeSaJWbphrCRnko+PDGKIqc/5+9/zE1QRaTMEmifkjEg\nj/9+bOGZYYH+acgdeJe9jMUtPMytmCD/ovqIBH9ntAKWhFGzGqzjxkPnKQ/JOqX/\nMEV63R/CQAA/y2dypm1Ce2FXS6d6L7HlPs26YkXw6/Q1pzkbKSrnempbZUGc+5KT\noQIDAQAB\n-----END PUBLIC KEY-----"
  25. # 用于解密北向过来的数据
  26. privateKeyHear = '-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAueN4TXcy27K/HoArURK54NSNvWQhqpTk1s9bVlrSANwctasc\nPBQlLWKf3HyL6+yxxgJ4oKZk00qagceSu85E1SG/opmvjPOQfIGwi/y0yuFWRM+x\n2DtfVxtH/4YMIMHq2DAmKY/MBj1RtPEz89oFsqJRHbZxe1aV5cDCRUJWgeSaJWbp\nhrCRnko+PDGKIqc/5+9/zE1QRaTMEmifkjEgj/9+bOGZYYH+acgdeJe9jMUtPMyt\nmCD/ovqIBH9ntAKWhFGzGqzjxkPnKQ/JOqX/MEV63R/CQAA/y2dypm1Ce2FXS6d6\nL7HlPs26YkXw6/Q1pzkbKSrnempbZUGc+5KToQIDAQABAoIBAGLPtMJQ63r3gDph\nXSVCdAY8Vn/nOzIm5aH+JYo4ysrkNmqnY2HYP47pjxqwJdyqPDGKXL7g1FWwoYL9\nKFWmptY4k1qGoVemnRZiBgvTr/LsZ2Q6l0ne/aYa/WGpysaa7hAvQAn1wzlJ3SX2\n1Wv5Z+/18nJ96cLrWtD/bwVL5xoyFmgz36PgUbZAx0r9bAz630MFQkPWF33/ts1P\nzkImLTi8WAJQy8xDN6DisgUpj+GFjLn21IAXfMvg57wZaUVL8OPaqe5W1Q11ud27\nAkzBh6vVDrbx5g6vVno4MLopw61o7kiAH0i8E9g/IuTj6BHN4BV5MmL7CvZrxgIy\nYHksf5UCgYEAxbrULv03fm5aAIO4GYXJ2s6q9ZhN9EbPdAumzoeIyGZNLiSmRKcF\n9KDorWEwv9K+IPDdcV39xFtJQLDL27TVIgyeSKZV5KohQ7z58WeV0PWMQ7L2FSvd\nUOJQQAeZbk5H4GmJ3b/rMckWHH77hey6nrcY9PJKr69Nk2Z/krnWg88CgYEA8KtP\nu8QbZE+C6c9HZXCoIZL0iNfLCvwc57RJpGg5E/ChlxwN0D/Fi9DWEbcvGvr/+Dd6\nwgtE2C7GoP5RZb/8dgjJJZ72gfozlseH9TSdrEh1uQcMD8PMtkV+Qs58fFDtI/PB\np0bXopPy+/w9h2pwquEYh6d+9foMnmNbMVjHnY8CgYBc7DsxRgDhYtzbJwvKuswt\nDzjaqFPiO7DcuWkP4DQQ8brNt52H3/J1j3UpneY6D8EYW/nFgEV1FO1tAGkdfHM5\nSDLOs5TkHGv7mIDhyStoAy2C10S8mFuu2lyaarfZVeKDfTW0R7AxOm4wwCBWRPVD\nB4sr+f3NaJYNcnr7qmg8kwKBgQCw4rhvoOshBu+JOTeYbvyj8IaaLUCmijYUdoXJ\nuHB7H1kk3xGoBbcD1DICQ0jz45dOsDghdnbbDUYf/cuFpV3AwyRT6knzrhlMsMpU\nhp98iKU9oNhUnexP6zOplmoYVMJ2sima8I58h5EHc5Ulei3k6hxFV+4Qi//KSew0\nkLPmMQKBgF360CEMz7IAR3RokcXP554tRiUmoIcTn3io8+N4cLX9x6MTdA5Bh2Pq\nsNSfwk7mki38eQD3+kmEa+DmhK5URbGemc4xK8lau5t010A2KB9MUPC5O0NglJdZ\nzBR6Hzr3sriFmRCQKxGQ8ae+Ggkn/5rfc6GEbmRg0dyG98680VGI\n-----END RSA PRIVATE KEY-----'
  27. # 从北向接口那边得到的publicKey,用于加密数据后,发给北向
  28. publicKeyFromNorth = ''
  29. @staticmethod
  30. def make_rsa_key():
  31. rsaObj = RSA.generate(2048)
  32. privateKeyHear = rsaObj.exportKey()
  33. publicKeyHear = rsaObj.publickey().exportKey()
  34. ZhejiangRSA.privateKeyHear = privateKeyHear
  35. ZhejiangRSA.publicKeyHear = publicKeyHear
  36. @staticmethod
  37. def get_north_publicKey(ipPort):
  38. try:
  39. backInfo = send_url_request_to_north('http://%s/api/getPublicKey' % ipPort, 'GET')
  40. if backInfo['code'] != 0:
  41. return None
  42. ZhejiangRSA.publicKeyFromNorth = '-----BEGIN PUBLIC KEY-----\n' + backInfo['data'][
  43. 'publicKey'] + '\n-----END PUBLIC KEY-----'
  44. except Exception as e:
  45. logger.exception(e)
  46. return None
  47. return ZhejiangRSA.publicKeyFromNorth
  48. @staticmethod
  49. def decrypt(data):
  50. try:
  51. privateKey = RSA.importKey(ZhejiangRSA.privateKeyHear)
  52. cipher = PKCS1_v1_5.new(privateKey)
  53. random_generator = Random.new().read
  54. text = cipher.decrypt(base64.b64decode(data), random_generator)
  55. except Exception as e:
  56. logger.exception(e)
  57. return None
  58. return text
  59. class ZhejiangAddressType(Searchable):
  60. value = StringField(verbose_name = "地址类型编码", unique = True)
  61. label = StringField(verbose_name = "地址名称", default = "")
  62. typeId = StringField(verbose_name = "南向地址类型编码", default = "")
  63. typeName = StringField(verbose_name = "typeName", default = "")
  64. meta = {"collection": "ZhejiangAddressType", "db_alias": "default"}
  65. codeDict = {}
  66. @staticmethod
  67. def get_typeId(value):
  68. if not ZhejiangAddressType.codeDict:
  69. objs = ZhejiangAddressType.objects.all()
  70. for obj in objs:
  71. ZhejiangAddressType.codeDict[obj.value] = {'typeId': obj.typeId, 'typeName': obj.typeName}
  72. return str(ZhejiangAddressType.codeDict.get(value, {}).get('typeId', '999'))
  73. class ZhejiangZone(Searchable):
  74. code = StringField(verbose_name = "地址类型编码", unique = True)
  75. name = StringField(verbose_name = "northDistinctId", default = "")
  76. parent = StringField(verbose_name = "parent", default = "")
  77. level = IntField(verbose_name = "level", default = "")
  78. meta = {
  79. "collection": "ZhejiangZone",
  80. "db_alias": "default",
  81. "index": ["name"]
  82. }
  83. distinctDict = {}
  84. @staticmethod
  85. def get_distinct_id(area, address):
  86. defaultId = "330000"
  87. parent = ZhejiangZone.objects.filter(name = area).first()
  88. if not parent:
  89. return defaultId
  90. children = ZhejiangZone.objects.filter(name = address).first()
  91. if not children or children.parent != parent.code:
  92. return parent.code
  93. return children.code
  94. # if not ZhejiangZone.distinctDict:
  95. # objs = ZhejiangZone.objects.filter(level=3).all()
  96. # for obj in objs:
  97. # ZhejiangZone.distinctDict[obj.name] = obj.code
  98. #
  99. # parentCode = ZhejiangZone.distinctDict.get(area)
  100. # if not parentCode:
  101. # return "330000"
  102. # else:
  103. # z = ZhejiangZone.objects.filter(parent=parentCode, name=address)
  104. # if not z:
  105. # return parentCode
  106. # else:
  107. # return z.code
  108. class ZhejiangNorther(Searchable):
  109. """
  110. 一个代理商可以开一个接口
  111. """
  112. usernameFromHear = StringField(verbose_name = "用于登录我们平台", default = "")
  113. passwordFromHear = StringField(verbose_name = "password", default = "")
  114. tokenId = StringField(verbose_name = "tokenId 就是agentId", default = "")
  115. mqDomain = StringField(verbose_name = "mqDomain", default = "http://36.26.79.155:8120/")
  116. mqUser = StringField(verbose_name = "mqUser", default = "mqUser")
  117. mqPassword = StringField(verbose_name = "mqPassword", default = "mq258456")
  118. host = StringField(verbose_name = "host", default = "")
  119. port = IntField(verbose_name = "port", default = 5672)
  120. routingKey = StringField(verbose_name = "routingKey", default = '')
  121. exchange = DictField(verbose_name = "exchange", default = {})
  122. usernameFromNorth = StringField(verbose_name = "用于登录消防平台", default = "")
  123. passwordFromNorth = StringField(verbose_name = "password", default = "")
  124. serviceCodeFromNorth = StringField(verbose_name = "平台分配的服务编码", default = "")
  125. fetchedMQTime = DateTimeField(verbose_name = "获取MQ的时间,平台意见是每天要获取一次",
  126. default = to_datetime('2000-01-01 00:00:00'))
  127. northPort = StringField(verbose_name = "北向IP地址以及端口",
  128. default = "36.26.79.155:8120") # 测试和交付的端口可能不一样,每一家的也可能不一样,所以需要配置
  129. meta = {"collection": "ZhejiangNorther", "db_alias": "default"}
  130. def get_mq_info(self):
  131. # # obj.make_rsa_key()
  132. northPublicKey = ZhejiangRSA.get_north_publicKey(self.northPort)
  133. publicKey = RSA.importKey(northPublicKey)
  134. cipher = PKCS1_v1_5.new(publicKey)
  135. enPassword = base64.b64encode(cipher.encrypt(str(self.mqPassword)))
  136. result = send_url_request_to_north('http://%s/api/getMqInfo' % self.northPort, #
  137. method = 'POST',
  138. isNeedResponse = True,
  139. username = self.mqUser,
  140. password = enPassword)
  141. if result['code'] != 0:
  142. raise UnableToGetPublicKey('get publicKey from north error=%s' % (result['message'],))
  143. self.host = result['data']['mqInfo']['host']
  144. self.port = result['data']['mqInfo']['port']
  145. self.routingKey = result['data']['mqInfo']['routingKey']
  146. self.exchange = result['data']['mqInfo']['exchange']
  147. self.usernameFromNorth = result['data']['mqInfo']['username']
  148. self.passwordFromNorth = result['data']['mqInfo']['password']
  149. self.fetchedMQTime = datetime.datetime.now()
  150. self.save()
  151. return self
  152. def send_event_to_north(self, eventInfo):
  153. if not self.usernameFromNorth:
  154. self.get_mq_info()
  155. nowTime = datetime.datetime.now()
  156. if (nowTime - self.fetchedMQTime).days > 1:
  157. self.get_mq_info()
  158. credentials = pika.PlainCredentials(self.usernameFromNorth, self.passwordFromNorth)
  159. connection = pika.BlockingConnection(pika.ConnectionParameters(self.host, self.port, '/', credentials))
  160. channel = connection.channel()
  161. eventInfo.update({'producerCode': self.serviceCodeFromNorth})
  162. channel.basic_publish(exchange = self.exchange['chargingPile'],
  163. routing_key = '%s.5.pubinfo' % self.serviceCodeFromNorth,
  164. body = json.dumps(eventInfo))
  165. def send_url_request_to_north(url, method = "POST", isNeedResponse = True, **kwargs):
  166. paras = {}
  167. paras.update(kwargs)
  168. if method == 'POST':
  169. req = urllib2.Request(url = url, data = parse.urlencode(paras))
  170. else:
  171. if paras:
  172. getParas = parse.urlencode(paras)
  173. url = url + '?' + getParas
  174. req = urllib2.Request(url = url)
  175. response = urllib2.urlopen(req, timeout = 15)
  176. if isNeedResponse:
  177. return json.loads(response.read())
  178. return None
  179. def handler_event_to_zhejiang(alarm_id):
  180. """
  181. 报警时间处理结果反馈
  182. :param alarm_id:
  183. :return:
  184. """
  185. try:
  186. record = FaultRecord.objects.get(id = alarm_id)
  187. except DoesNotExist:
  188. return
  189. device = Device.get_dev(record.imei)
  190. dealer = Dealer.objects.filter(id = record.dealerId).first()
  191. if device is None:
  192. logger.info("can not find device, devNo is {}".format(record.imei))
  193. return
  194. if dealer is None:
  195. logger.info("can not find dealer dealer is {}".format(record.dealerId))
  196. try:
  197. norther = ZhejiangNorther.objects.get(tokenId = dealer.agentId)
  198. company = Company.objects.get(ownerId = str(dealer.id))
  199. except Exception as e:
  200. return
  201. devTypeCode = device.get("devType", dict()).get("code")
  202. if (not Const.ZHEJIANG_EVENT_TYPE_DICT.has_key(devTypeCode)) or \
  203. (not Const.ZHEJIANG_EVENT_TYPE_DICT[devTypeCode].has_key(record.faultCode)):
  204. return
  205. eventType = Const.ZHEJIANG_EVENT_TYPE_DICT[devTypeCode][record.faultCode]
  206. try:
  207. part = Part.objects.get(logicalCode = device.get('logicalCode'), partNo = str(record.portNo))
  208. except Exception as e:
  209. logger.exception(e)
  210. return
  211. event = {
  212. 'handlerEventId': str(uuid.uuid4()),
  213. 'alarmEventId': record.alarmEventId,
  214. 'deviceId': record.logicalCode,
  215. 'buildingId': device.get("groupId"),
  216. 'happenTime': str(record.createdTime)[:19],
  217. 'alarmContent': {u'详细描述': record.description},
  218. 'alarmType': eventType,
  219. 'partsId': str(part.id),
  220. 'producerCode': company.unifiedSocialCreditCode,
  221. "handleContent": record.dealedDetail,
  222. "handleType": "1",
  223. "handleName": dealer.nickname,
  224. "handlePhone": dealer.username,
  225. "handleTime": str(record.dealedTime)[:19]
  226. }
  227. norther.send_event_to_north(event)
  228. def send_event_to_zhejiang(dealer, device, eventInfo, partId = None):
  229. try:
  230. norther = ZhejiangNorther.objects.get(tokenId = dealer.agentId)
  231. company = Company.objects.get(ownerId = str(dealer.id))
  232. except Exception as e:
  233. return
  234. devTypeCode = device['devType']['code']
  235. if (not Const.ZHEJIANG_EVENT_TYPE_DICT.has_key(devTypeCode)) or \
  236. (not Const.ZHEJIANG_EVENT_TYPE_DICT[devTypeCode].has_key(eventInfo['reasonCode'])):
  237. return
  238. eventType = Const.ZHEJIANG_EVENT_TYPE_DICT[devTypeCode][eventInfo['reasonCode']]
  239. try:
  240. if not partId:
  241. part = Part.objects.get(logicalCode = device.logicalCode, partNo = str(eventInfo['port']))
  242. else:
  243. part = Part.objects.get(id = partId)
  244. except Exception as e:
  245. logger.exception(e)
  246. return
  247. nowDate = datetime.datetime.now()
  248. alarmEventId = str(uuid.uuid4())
  249. event = {
  250. 'alarmEventId': alarmEventId,
  251. 'deviceId': device.logicalCode,
  252. 'buildingId': device.groupId,
  253. 'happenTime': nowDate.strftime(Const.DATETIME_FMT),
  254. 'alarmContent': {u'详细描述': eventInfo['reason']},
  255. 'alarmType': eventType,
  256. 'partsId': str(part.id),
  257. 'producerCode': company.unifiedSocialCreditCode
  258. }
  259. # 存储记录 存储的时候存储端口号,然后取出发送处置结果的时候 通过端口号查找partId
  260. try:
  261. FaultRecord.record_xf(
  262. logicalCode = device.logicalCode,
  263. port = eventInfo["port"],
  264. description = eventInfo["reason"],
  265. faultCode = eventInfo["reasonCode"],
  266. groupId = device.groupId,
  267. createdTime = nowDate,
  268. alarmEventId = alarmEventId
  269. )
  270. except Exception as e:
  271. logger.error(e)
  272. return
  273. norther.send_event_to_north(event)
  274. class Company(Searchable):
  275. ownerId = StringField(verbose_name = "ownerId", unique = True)
  276. agentId = StringField(verbose_name = "agentId", default = "")
  277. name = StringField(verbose_name = "name", default = "")
  278. code = StringField(verbose_name = "code", default = "")
  279. unifiedSocialCreditCode = StringField(verbose_name = '统一社会信用编码', default = '')
  280. address = StringField(verbose_name = "address", default = "")
  281. contactName = StringField(verbose_name = "contactName", default = "")
  282. telephone = StringField(verbose_name = "telephone", default = "")
  283. manufacturer = StringField(verbose_name = "manufacturer", default = "充电桩厂家")
  284. dateTimeAdded = DateTimeField(default = datetime.datetime.now, verbose_name = '添加进来的时间')
  285. dateTimeUpdated = DateTimeField(default = datetime.datetime.now, verbose_name = '更新时间')
  286. meta = {"collection": "Company", "db_alias": "default"}
  287. class UnableToGetPublicKey(UserServerException):
  288. pass