Selaa lähdekoodia

优化下发推流指令

locky 3 kuukautta sitten
vanhempi
commit
b93212a793
4 muutettua tiedostoa jossa 209 lisäystä ja 21 poistoa
  1. 21 5
      controller/index.py
  2. 22 0
      model/models.py
  3. 61 0
      requirements.txt
  4. 105 16
      service/CommonService.py

+ 21 - 5
controller/index.py

@@ -3,6 +3,7 @@ import logging
 import subprocess
 import subprocess
 import threading
 import threading
 import time
 import time
+from collections import OrderedDict
 from datetime import datetime
 from datetime import datetime
 
 
 import requests
 import requests
@@ -381,13 +382,25 @@ class oa2RtspStartView(TemplateView):
 
 
     def send_rtsp_command_thread(self, domain_name, UID, PWD, MSG, channel, logger, region):
     def send_rtsp_command_thread(self, domain_name, UID, PWD, MSG, channel, logger, region):
         """异步发送RTSP命令的线程函数"""
         """异步发送RTSP命令的线程函数"""
+
+        thing_name = CommonService.query_serial_with_uid(UID)
+        topic_name = 'ansjer/generic/{}'.format(thing_name)
+        msg = OrderedDict(
+            [
+                ('alexaRtspCommand', MSG),
+                ('enable', 1),
+            ]
+        )
+        publish_result = CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg)
+        logger.info('{}下发指令结果:{}'.format(UID, publish_result))
+
         command = "./pushtool {UID} {PWD} {MSG} 1 {channel}".format(
         command = "./pushtool {UID} {PWD} {MSG} 1 {channel}".format(
             UID=UID, PWD=PWD, MSG=MSG, channel=channel)
             UID=UID, PWD=PWD, MSG=MSG, channel=channel)
-        
+
         # 请求MQTT发布消息
         # 请求MQTT发布消息
         url = '{}/iot/requestPublishMessage'.format(domain_name)
         url = '{}/iot/requestPublishMessage'.format(domain_name)
         requests_data = {'UID': UID, 'rtsp': MSG, 'enable': '1'}
         requests_data = {'UID': UID, 'rtsp': MSG, 'enable': '1'}
-        
+
         try:
         try:
             r = requests.post(url, requests_data)
             r = requests.post(url, requests_data)
             if r.status_code == 200:
             if r.status_code == 200:
@@ -533,20 +546,23 @@ class oa2DiscoveryDevice(TemplateView):
         uid_rtsp_id_list = []
         uid_rtsp_id_list = []
         for uid_a in uid_arr:
         for uid_a in uid_arr:
             uid = uid_a['uid']
             uid = uid_a['uid']
+            serial_number = uid_a['serial_number']
             nick = uid_a['nick']
             nick = uid_a['nick']
             rtsp_url = rtko.encrypt(data=uid)
             rtsp_url = rtko.encrypt(data=uid)
 
 
             try:
             try:
                 uid_rtsp_qs = UidRtspModel.objects.get(uid=uid)
                 uid_rtsp_qs = UidRtspModel.objects.get(uid=uid)
             except UidRtspModel.DoesNotExist:
             except UidRtspModel.DoesNotExist:
-                uid_rtsp_qs = UidRtspModel.objects.create(user_id=userID, uid=uid, nick=nick, region=region_code,
-                                                          password=uid_a['password'],
-                                                          rtsp_url=rtsp_url, addTime=now_time, updTime=now_time)
+                uid_rtsp_qs = UidRtspModel.objects.create(
+                    user_id=userID, uid=uid, serial_number=serial_number, nick=nick, region=region_code,
+                    password=uid_a['password'], rtsp_url=rtsp_url, addTime=now_time, updTime=now_time)
             else:
             else:
                 uid_rtsp_qs.nick = nick
                 uid_rtsp_qs.nick = nick
                 uid_rtsp_qs.region = region_code
                 uid_rtsp_qs.region = region_code
                 uid_rtsp_qs.password = uid_a['password']
                 uid_rtsp_qs.password = uid_a['password']
                 uid_rtsp_qs.user_id = userID
                 uid_rtsp_qs.user_id = userID
+                uid_rtsp_qs.serial_number = serial_number
+
                 uid_rtsp_qs.save()
                 uid_rtsp_qs.save()
             uid_rtsp_id_list.append(uid_rtsp_qs.id)
             uid_rtsp_id_list.append(uid_rtsp_qs.id)
 
 

+ 22 - 0
model/models.py

@@ -45,6 +45,7 @@ class UidRtspModel(models.Model):
     user_id = models.CharField(default='', max_length=32, verbose_name='关联用户表的userID')
     user_id = models.CharField(default='', max_length=32, verbose_name='关联用户表的userID')
     nick = models.CharField(max_length=32, verbose_name=u'设备昵称', default='')
     nick = models.CharField(max_length=32, verbose_name=u'设备昵称', default='')
     uid = models.CharField(max_length=20, verbose_name=u'设备UID', default='', unique=True)
     uid = models.CharField(max_length=20, verbose_name=u'设备UID', default='', unique=True)
+    serial_number = models.CharField(default='', max_length=9, verbose_name='序列号')
     password = models.CharField(max_length=32, verbose_name=u'设备密码', default='')
     password = models.CharField(max_length=32, verbose_name=u'设备密码', default='')
     rtsp_url = models.CharField(max_length=128, verbose_name='rtsp流地址', default='')
     rtsp_url = models.CharField(max_length=128, verbose_name='rtsp流地址', default='')
     region = models.CharField(max_length=8, verbose_name='区域', default='CN')
     region = models.CharField(max_length=8, verbose_name='区域', default='CN')
@@ -97,3 +98,24 @@ class AlexaAuthModel(models.Model):
 
 
     def __str__(self):
     def __str__(self):
         return self.id
         return self.id
+
+
+class iotdeviceInfoModel(models.Model):
+    id = models.AutoField(primary_key=True)
+    serial_number = models.CharField(default='', max_length=9, db_index=True, verbose_name='序列号')
+    uid = models.CharField(default='', max_length=32, db_index=True, verbose_name='uid')
+    certificate_id = models.CharField(default='', max_length=128, verbose_name='证书id')
+    certificate_pem = models.TextField(default='', verbose_name='证书')
+    public_key = models.TextField(default='', verbose_name='公钥')
+    private_key = models.TextField(default='', verbose_name='私钥')
+    thing_name = models.CharField(default='', max_length=64, db_index=True, verbose_name='物品名')
+    thing_groups = models.CharField(default='', max_length=64, verbose_name='物品组')
+    endpoint = models.CharField(default='', max_length=100, db_index=True, verbose_name='终端节点')
+    token_iot_number = models.CharField(default='', db_index=True, max_length=50, verbose_name='签名令牌')
+    add_time = models.DateTimeField(auto_now_add=True, verbose_name='添加时间')
+    update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
+
+    class Meta:
+        db_table = 'iot_deviceInfo'
+        verbose_name = 'iot设备信息表'
+

+ 61 - 0
requirements.txt

@@ -0,0 +1,61 @@
+asgiref==3.4.1
+asn1crypto==0.24.0
+attrs==17.4.0
+Automat==0.6.0
+blinker==1.4
+boto3==1.23.10
+botocore==1.26.10
+certifi==2018.1.18
+chardet==3.0.4
+click==6.7
+colorama==0.3.7
+configobj==5.0.6
+configparser==5.2.0
+constantly==15.1.0
+decorator==4.1.2
+Django==3.2.20
+django-cors-headers==3.2.1
+django-filter==21.1
+djangorestframework==3.14.0
+gunicorn==20.0.4
+httplib2==0.9.2
+hyperlink==17.3.1
+idna==2.6
+incremental==16.10.1
+ipip-ipdb==1.3.2
+Jinja2==2.10
+jmespath==0.10.0
+jsonpatch==1.16
+jsonpointer==1.10
+keyring==10.6.0
+keyrings.alt==3.0
+mysqlclient==1.4.6
+netifaces==0.10.4
+oauthlib==2.0.6
+PAM
+pexpect==4.2.1
+pyasn1==0.4.2
+pyasn1-modules==0.2.1
+pyipip==0.1.1
+PyJWT==1.5.3
+PyMySQL==1.0.2
+pyOpenSSL==23.2.0
+pyserial==3.4
+python-dateutil==2.8.2
+python-debian==0.1.32
+pytz==2023.3
+pyxdg==0.25
+PyYAML==3.12
+redis==3.4.1
+requests
+requests-unixsocket==0.1.5
+s3transfer==0.5.2
+SecretStorage==2.3.1
+service-identity==16.0.0
+simplejson==3.17.0
+six==1.11.0
+sqlparse==0.4.4
+supervisor==4.1.0
+Twisted
+typing-extensions
+urllib3

+ 105 - 16
service/CommonService.py

@@ -1,28 +1,20 @@
-#!/usr/bin/env python3  
-# -*- coding: utf-8 -*-  
-"""
-@Copyright (C) ansjer cop Video Technology Co.,Ltd.All rights reserved.
-@AUTHOR: ASJRD018
-@NAME: azoauth
-@software: PyCharm
-@DATE: 2020/1/14 16:45
-@Version: python3.6
-@MODIFY DECORD:ansjer dev
-@file: CommonService.py
-@Contact: chanjunkai@163.com
-"""
-# -*- coding: utf-8 -*-
+
 import datetime
 import datetime
 import time
 import time
 from pathlib import Path
 from pathlib import Path
 from random import Random
 from random import Random
 import base64
 import base64
 import ipdb
 import ipdb
+import requests
+import OpenSSL.crypto as ct
+from base64 import encodebytes
 import simplejson as json
 import simplejson as json
 from django.core import serializers
 from django.core import serializers
 from django.utils import timezone
 from django.utils import timezone
 from pyipip import IPIPDatabase
 from pyipip import IPIPDatabase
 
 
+from model.models import iotdeviceInfoModel, UidRtspModel
+
 
 
 # 复用性且公用较高封装代码在这
 # 复用性且公用较高封装代码在这
 class CommonService:
 class CommonService:
@@ -100,5 +92,102 @@ class CommonService:
 
 
         return str
         return str
 
 
-# data = CommonService.encrypt_data(20)
-# print(data)
+    @staticmethod
+    def query_serial_with_uid(uid):
+        # 根据uid查询序列号,存在则返回序列号,否则返uid
+        uid_qs = UidRtspModel.objects.filter(uid=uid).values('serial_number')
+        if uid_qs.exists():
+            serial_number = uid_qs[0]['serial_number']
+            if serial_number:
+                return serial_number
+        return uid
+
+    @staticmethod
+    def req_publish_mqtt_msg(identification_code, topic_name, msg, qos=1):
+        """
+        通用发布MQTT消息函数
+        @param identification_code: 标识码
+        @param topic_name: 主题名
+        @param msg: 消息内容
+        @param qos: mqtt qos等级
+        @return: boolean
+        """
+        if not all([identification_code, topic_name]):
+            return False
+
+        if identification_code.endswith('11L'):
+            thing_name = 'LC_' + identification_code
+        else:
+            thing_name = 'Ansjer_Device_' + identification_code
+
+        try:
+            # 获取数据组织将要请求的url
+            iot = iotdeviceInfoModel.objects.filter(
+                thing_name=thing_name).values(
+                'endpoint', 'token_iot_number')
+            if not iot.exists():
+                return False
+            endpoint = iot[0]['endpoint']
+            Token = iot[0]['token_iot_number']
+
+            # api doc: https://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/http.html
+            # url: https://IoT_data_endpoint/topics/url_encoded_topic_name?qos=1
+            # post请求url发布MQTT消息
+            url = 'https://{}/topics/{}?qos={}'.format(endpoint, topic_name, qos)
+            authorizer_name = 'Ansjer_Iot_Auth'
+            signature = CommonService.rsa_sign(Token)  # Token签名
+            headers = {
+                'x-amz-customauthorizer-name': authorizer_name,
+                'Token': Token,
+                'x-amz-customauthorizer-signature': signature}
+            r = requests.post(url=url, headers=headers, json=msg, timeout=2)
+            if r.status_code == 200:
+                res = r.json()
+                if res['message'] == 'OK':
+                    return True
+                return False
+            else:
+                return False
+        except Exception as e:
+            return False
+
+    @staticmethod
+    def rsa_sign(Token):
+        # 私钥签名Token
+        if not Token:
+            return ''
+        private_key_file = '''-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEA5iJzEDPqtGmFMggekVro6C0lrjuC2BjunGkrFNJWpDYzxCzE
+X5jf4/Fq7hcIaQd5sqHugDxPVollSLPe9zNilbrd0sZfU+Ed8gRVuKW9KwfE9XFr
+L0pt6bKRQ0IIRfiZ9TuR0tsQysvcO1GZSXcYfPue3tGM1zOnWFThWDqZ06+sOxzt
+RMRl4yNfbpCG4MfxG3itNXOfrjZv2OMLSXrxmzubSvRpUYSvQPs4fm9302SAnySY
+0MKzx6H6528ZQm/IDDSZy6EmNBIyTRDfxC56vnYcXvqedAQh7jJnjdvt6Q4MhASH
+eIYi1FBSdu2NT6wgpnrqXzx5pq9kR/lnsLID0wIDAQABAoIBAQCiF4GT1/1oNSpr
+ouxk1PNXFPWFUsVGD8mAwVJmx//eiY7MjfuCmdqYYmI+cFqsH2fIOeYSzGfVO9Dq
+9EYHN1oovAWhf7eFDPpajFMUSyiCNmazub8VAAeKowtNpCTPo9pMsDh1m3aoYA4u
+ebrN0+Sbo16y8kWRDgDAZoiR7DSMs8lczk16hwfv5mw8XpNDbaL3Coi4Koe2S1Yh
+2SX3vWFlpd7qF1ZYXuZIp+b8JPrV7n9eUKoFgzj0gqgwQK80CoexIjiOrNMPvkQa
+q+8kCvFjAzKxOK7e8gjM8lMRiGodb61kmYZkkJzFwWO4EaGbl34lfVECd1Ixp3tF
+be0OWAGBAoGBAPSteXDzzToD8ovM7LL11x0jWwI6HOiHu89kZtW566rIezjWBuA2
+TxrcYKM3h9jQRXS3CsMdoIv6XGk5lqM8ADtjn23FBWe/THYLh8bm8JOgh5RRWQDg
+SvkLfi9Ih2mM4NJfmuuDOh3Nze2efLM7+kOZWUQwF2Zx9mL5jvRBk351AoGBAPDI
+sYmT2Li+i5+0vykA2m5uPF8ZOW8BGtAfCZv0suW7BNzSgin78g9WapRd/4p0NNiL
+/nVMqPPCpd1akCUpV+GDWQt0hV+HZjxANE0KWhciQRyo2qvo51j8SWILJSgh0tXC
+aTF8qt6oGw3VN3m57vKhbrlDaz0J/NDJFci6msAnAoGBAOuG6bXPGijUj+//DYKf
+n7jOxdZ49kboEePrtAncdHzri6IEdI3z+WXT6bpzw/LzWUimwldb96WHFNm9s8Hi
+Ch8hIODbnP5naUTgiIzw1XhmONyPCewL/F+LrqX5XVA/alNX8JrwsUrrR2WLAGLQ
+Q3I69XDsEjptTU2tCO0bCs3ZAoGBAJ2lCHfm0JHET230zONvp5N9oREyVqQSuRdh
++syc3TQDyh85w/bw+X6JOaaCFHj1tFPC9Iqf8k4GNspCLPXnp54CfR4+38O3xnvU
+HWoDSRC0YKT++IxtJGriYrlKSr2Hx54kdvLriIPW1D+uRW/xCDza7L9nIKMKEvgv
+b4/IfOEpAoGAeKM9Te7T1VzlAkS0CJOwanzwYV/zrex84WuXxlsGgPQ871lTs5AP
+H1QLfLfFXH+UVrCEC2yv4eml/cqFkpB3gE5i4MQ8GPVIOSs5tsIyl8YUA03vdNdB
+GCqvlyw5dfxNA+EtxNE2wCW/LW7ENJlACgcfgPlBZtpLheWoZB/maw4=
+-----END RSA PRIVATE KEY-----'''
+        # 使用密钥文件方式
+        # private_key_file_path = os.path.join(BASE_DIR, 'static/iotCore/private.pem')#.replace('\\', '/')
+        # private_key_file = open(private_key_file_path, 'r')
+        private_key = ct.load_privatekey(ct.FILETYPE_PEM, private_key_file)
+        signature = ct.sign(private_key, Token.encode('utf8'), 'sha256')
+        signature = encodebytes(signature).decode('utf8').replace('\n', '')
+        # print('signature:', signature)
+        return signature