Browse Source

优化下发推流指令

locky 3 months ago
parent
commit
b93212a793
4 changed files with 209 additions and 21 deletions
  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 threading
 import time
+from collections import OrderedDict
 from datetime import datetime
 
 import requests
@@ -381,13 +382,25 @@ class oa2RtspStartView(TemplateView):
 
     def send_rtsp_command_thread(self, domain_name, UID, PWD, MSG, channel, logger, region):
         """异步发送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(
             UID=UID, PWD=PWD, MSG=MSG, channel=channel)
-        
+
         # 请求MQTT发布消息
         url = '{}/iot/requestPublishMessage'.format(domain_name)
         requests_data = {'UID': UID, 'rtsp': MSG, 'enable': '1'}
-        
+
         try:
             r = requests.post(url, requests_data)
             if r.status_code == 200:
@@ -533,20 +546,23 @@ class oa2DiscoveryDevice(TemplateView):
         uid_rtsp_id_list = []
         for uid_a in uid_arr:
             uid = uid_a['uid']
+            serial_number = uid_a['serial_number']
             nick = uid_a['nick']
             rtsp_url = rtko.encrypt(data=uid)
 
             try:
                 uid_rtsp_qs = UidRtspModel.objects.get(uid=uid)
             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:
                 uid_rtsp_qs.nick = nick
                 uid_rtsp_qs.region = region_code
                 uid_rtsp_qs.password = uid_a['password']
                 uid_rtsp_qs.user_id = userID
+                uid_rtsp_qs.serial_number = serial_number
+
                 uid_rtsp_qs.save()
             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')
     nick = models.CharField(max_length=32, verbose_name=u'设备昵称', default='')
     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='')
     rtsp_url = models.CharField(max_length=128, verbose_name='rtsp流地址', default='')
     region = models.CharField(max_length=8, verbose_name='区域', default='CN')
@@ -97,3 +98,24 @@ class AlexaAuthModel(models.Model):
 
     def __str__(self):
         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 time
 from pathlib import Path
 from random import Random
 import base64
 import ipdb
+import requests
+import OpenSSL.crypto as ct
+from base64 import encodebytes
 import simplejson as json
 from django.core import serializers
 from django.utils import timezone
 from pyipip import IPIPDatabase
 
+from model.models import iotdeviceInfoModel, UidRtspModel
+
 
 # 复用性且公用较高封装代码在这
 class CommonService:
@@ -100,5 +92,102 @@ class CommonService:
 
         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