# -*- coding: utf-8 -*- # !/usr/bin/env python import base64 import datetime import json import logging import urllib2 import uuid import pika from Crypto import Random from Crypto.Cipher import PKCS1_v1_5 from Crypto.PublicKey import RSA from mongoengine import DoesNotExist, StringField, IntField, DictField, DateTimeField from six.moves.urllib import parse from apilib.utils_datetime import to_datetime from apps.web.constant import Const from apps.web.core.db import Searchable from apps.web.dealer.models import Dealer from apps.web.device.models import Part, FaultRecord, Device from apps.web.exceptions import UserServerException logger = logging.getLogger(__name__) class ZhejiangRSA(object): # 本地产生的publicKey,北向会过来拿这个key,用于加密数据传递给我们,我们用私钥解密 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-----" # 用于解密北向过来的数据 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-----' # 从北向接口那边得到的publicKey,用于加密数据后,发给北向 publicKeyFromNorth = '' @staticmethod def make_rsa_key(): rsaObj = RSA.generate(2048) privateKeyHear = rsaObj.exportKey() publicKeyHear = rsaObj.publickey().exportKey() ZhejiangRSA.privateKeyHear = privateKeyHear ZhejiangRSA.publicKeyHear = publicKeyHear @staticmethod def get_north_publicKey(ipPort): try: backInfo = send_url_request_to_north('http://%s/api/getPublicKey' % ipPort, 'GET') if backInfo['code'] != 0: return None ZhejiangRSA.publicKeyFromNorth = '-----BEGIN PUBLIC KEY-----\n' + backInfo['data'][ 'publicKey'] + '\n-----END PUBLIC KEY-----' except Exception as e: logger.exception(e) return None return ZhejiangRSA.publicKeyFromNorth @staticmethod def decrypt(data): try: privateKey = RSA.importKey(ZhejiangRSA.privateKeyHear) cipher = PKCS1_v1_5.new(privateKey) random_generator = Random.new().read text = cipher.decrypt(base64.b64decode(data), random_generator) except Exception as e: logger.exception(e) return None return text class ZhejiangAddressType(Searchable): value = StringField(verbose_name = "地址类型编码", unique = True) label = StringField(verbose_name = "地址名称", default = "") typeId = StringField(verbose_name = "南向地址类型编码", default = "") typeName = StringField(verbose_name = "typeName", default = "") meta = {"collection": "ZhejiangAddressType", "db_alias": "default"} codeDict = {} @staticmethod def get_typeId(value): if not ZhejiangAddressType.codeDict: objs = ZhejiangAddressType.objects.all() for obj in objs: ZhejiangAddressType.codeDict[obj.value] = {'typeId': obj.typeId, 'typeName': obj.typeName} return str(ZhejiangAddressType.codeDict.get(value, {}).get('typeId', '999')) class ZhejiangZone(Searchable): code = StringField(verbose_name = "地址类型编码", unique = True) name = StringField(verbose_name = "northDistinctId", default = "") parent = StringField(verbose_name = "parent", default = "") level = IntField(verbose_name = "level", default = "") meta = { "collection": "ZhejiangZone", "db_alias": "default", "index": ["name"] } distinctDict = {} @staticmethod def get_distinct_id(area, address): defaultId = "330000" parent = ZhejiangZone.objects.filter(name = area).first() if not parent: return defaultId children = ZhejiangZone.objects.filter(name = address).first() if not children or children.parent != parent.code: return parent.code return children.code # if not ZhejiangZone.distinctDict: # objs = ZhejiangZone.objects.filter(level=3).all() # for obj in objs: # ZhejiangZone.distinctDict[obj.name] = obj.code # # parentCode = ZhejiangZone.distinctDict.get(area) # if not parentCode: # return "330000" # else: # z = ZhejiangZone.objects.filter(parent=parentCode, name=address) # if not z: # return parentCode # else: # return z.code class ZhejiangNorther(Searchable): """ 一个代理商可以开一个接口 """ usernameFromHear = StringField(verbose_name = "用于登录我们平台", default = "") passwordFromHear = StringField(verbose_name = "password", default = "") tokenId = StringField(verbose_name = "tokenId 就是agentId", default = "") mqDomain = StringField(verbose_name = "mqDomain", default = "http://36.26.79.155:8120/") mqUser = StringField(verbose_name = "mqUser", default = "mqUser") mqPassword = StringField(verbose_name = "mqPassword", default = "mq258456") host = StringField(verbose_name = "host", default = "") port = IntField(verbose_name = "port", default = 5672) routingKey = StringField(verbose_name = "routingKey", default = '') exchange = DictField(verbose_name = "exchange", default = {}) usernameFromNorth = StringField(verbose_name = "用于登录消防平台", default = "") passwordFromNorth = StringField(verbose_name = "password", default = "") serviceCodeFromNorth = StringField(verbose_name = "平台分配的服务编码", default = "") fetchedMQTime = DateTimeField(verbose_name = "获取MQ的时间,平台意见是每天要获取一次", default = to_datetime('2000-01-01 00:00:00')) northPort = StringField(verbose_name = "北向IP地址以及端口", default = "36.26.79.155:8120") # 测试和交付的端口可能不一样,每一家的也可能不一样,所以需要配置 meta = {"collection": "ZhejiangNorther", "db_alias": "default"} def get_mq_info(self): # # obj.make_rsa_key() northPublicKey = ZhejiangRSA.get_north_publicKey(self.northPort) publicKey = RSA.importKey(northPublicKey) cipher = PKCS1_v1_5.new(publicKey) enPassword = base64.b64encode(cipher.encrypt(str(self.mqPassword))) result = send_url_request_to_north('http://%s/api/getMqInfo' % self.northPort, # method = 'POST', isNeedResponse = True, username = self.mqUser, password = enPassword) if result['code'] != 0: raise UnableToGetPublicKey('get publicKey from north error=%s' % (result['message'],)) self.host = result['data']['mqInfo']['host'] self.port = result['data']['mqInfo']['port'] self.routingKey = result['data']['mqInfo']['routingKey'] self.exchange = result['data']['mqInfo']['exchange'] self.usernameFromNorth = result['data']['mqInfo']['username'] self.passwordFromNorth = result['data']['mqInfo']['password'] self.fetchedMQTime = datetime.datetime.now() self.save() return self def send_event_to_north(self, eventInfo): if not self.usernameFromNorth: self.get_mq_info() nowTime = datetime.datetime.now() if (nowTime - self.fetchedMQTime).days > 1: self.get_mq_info() credentials = pika.PlainCredentials(self.usernameFromNorth, self.passwordFromNorth) connection = pika.BlockingConnection(pika.ConnectionParameters(self.host, self.port, '/', credentials)) channel = connection.channel() eventInfo.update({'producerCode': self.serviceCodeFromNorth}) channel.basic_publish(exchange = self.exchange['chargingPile'], routing_key = '%s.5.pubinfo' % self.serviceCodeFromNorth, body = json.dumps(eventInfo)) def send_url_request_to_north(url, method = "POST", isNeedResponse = True, **kwargs): paras = {} paras.update(kwargs) if method == 'POST': req = urllib2.Request(url = url, data = parse.urlencode(paras)) else: if paras: getParas = parse.urlencode(paras) url = url + '?' + getParas req = urllib2.Request(url = url) response = urllib2.urlopen(req, timeout = 15) if isNeedResponse: return json.loads(response.read()) return None def handler_event_to_zhejiang(alarm_id): """ 报警时间处理结果反馈 :param alarm_id: :return: """ try: record = FaultRecord.objects.get(id = alarm_id) except DoesNotExist: return device = Device.get_dev(record.imei) dealer = Dealer.objects.filter(id = record.dealerId).first() if device is None: logger.info("can not find device, devNo is {}".format(record.imei)) return if dealer is None: logger.info("can not find dealer dealer is {}".format(record.dealerId)) try: norther = ZhejiangNorther.objects.get(tokenId = dealer.agentId) company = Company.objects.get(ownerId = str(dealer.id)) except Exception as e: return devTypeCode = device.get("devType", dict()).get("code") if (not Const.ZHEJIANG_EVENT_TYPE_DICT.has_key(devTypeCode)) or \ (not Const.ZHEJIANG_EVENT_TYPE_DICT[devTypeCode].has_key(record.faultCode)): return eventType = Const.ZHEJIANG_EVENT_TYPE_DICT[devTypeCode][record.faultCode] try: part = Part.objects.get(logicalCode = device.get('logicalCode'), partNo = str(record.portNo)) except Exception as e: logger.exception(e) return event = { 'handlerEventId': str(uuid.uuid4()), 'alarmEventId': record.alarmEventId, 'deviceId': record.logicalCode, 'buildingId': device.get("groupId"), 'happenTime': str(record.createdTime)[:19], 'alarmContent': {u'详细描述': record.description}, 'alarmType': eventType, 'partsId': str(part.id), 'producerCode': company.unifiedSocialCreditCode, "handleContent": record.dealedDetail, "handleType": "1", "handleName": dealer.nickname, "handlePhone": dealer.username, "handleTime": str(record.dealedTime)[:19] } norther.send_event_to_north(event) def send_event_to_zhejiang(dealer, device, eventInfo, partId = None): try: norther = ZhejiangNorther.objects.get(tokenId = dealer.agentId) company = Company.objects.get(ownerId = str(dealer.id)) except Exception as e: return devTypeCode = device['devType']['code'] if (not Const.ZHEJIANG_EVENT_TYPE_DICT.has_key(devTypeCode)) or \ (not Const.ZHEJIANG_EVENT_TYPE_DICT[devTypeCode].has_key(eventInfo['reasonCode'])): return eventType = Const.ZHEJIANG_EVENT_TYPE_DICT[devTypeCode][eventInfo['reasonCode']] try: if not partId: part = Part.objects.get(logicalCode = device.logicalCode, partNo = str(eventInfo['port'])) else: part = Part.objects.get(id = partId) except Exception as e: logger.exception(e) return nowDate = datetime.datetime.now() alarmEventId = str(uuid.uuid4()) event = { 'alarmEventId': alarmEventId, 'deviceId': device.logicalCode, 'buildingId': device.groupId, 'happenTime': nowDate.strftime(Const.DATETIME_FMT), 'alarmContent': {u'详细描述': eventInfo['reason']}, 'alarmType': eventType, 'partsId': str(part.id), 'producerCode': company.unifiedSocialCreditCode } # 存储记录 存储的时候存储端口号,然后取出发送处置结果的时候 通过端口号查找partId try: FaultRecord.record_xf( logicalCode = device.logicalCode, port = eventInfo["port"], description = eventInfo["reason"], faultCode = eventInfo["reasonCode"], groupId = device.groupId, createdTime = nowDate, alarmEventId = alarmEventId ) except Exception as e: logger.error(e) return norther.send_event_to_north(event) class Company(Searchable): ownerId = StringField(verbose_name = "ownerId", unique = True) agentId = StringField(verbose_name = "agentId", default = "") name = StringField(verbose_name = "name", default = "") code = StringField(verbose_name = "code", default = "") unifiedSocialCreditCode = StringField(verbose_name = '统一社会信用编码', default = '') address = StringField(verbose_name = "address", default = "") contactName = StringField(verbose_name = "contactName", default = "") telephone = StringField(verbose_name = "telephone", default = "") manufacturer = StringField(verbose_name = "manufacturer", default = "充电桩厂家") dateTimeAdded = DateTimeField(default = datetime.datetime.now, verbose_name = '添加进来的时间') dateTimeUpdated = DateTimeField(default = datetime.datetime.now, verbose_name = '更新时间') meta = {"collection": "Company", "db_alias": "default"} class UnableToGetPublicKey(UserServerException): pass