Initial commit of secondary development sample code
This commit is contained in:
171
快速接收设备告警/custom-api-demo/README.md
Normal file
171
快速接收设备告警/custom-api-demo/README.md
Normal file
@ -0,0 +1,171 @@
|
||||
## 一、功能概述
|
||||
|
||||
`Api` 类是一个用于处理检测结果、告警信息和告警视频的工具类。
|
||||
|
||||
[api_demo.py](api_demo.py) 为原始默认实现。
|
||||
|
||||
[api_demo_tcp.py](api_demo_tcp.py)实现最简单的tcp通讯,如果需要自动重连,队列等业务代码请自行实现。
|
||||
|
||||
|
||||
此类名、方法名等框架是固定的,不可修改。你可以通过实现回调方法的具体逻辑(如 `send_result_callback`、`send_alert_callback` 和 `send_alert_video_callback`)以及配置类的属性(如 `ignore_result`、`ignore_alert` 等)来实现具体功能。
|
||||
|
||||
## 二、类的属性
|
||||
|
||||
`Api` 类**必须**包含以下主要属性,用于控制其行为:
|
||||
|
||||
| 属性名称 | 默认值 | 描述 |
|
||||
| :------------------- | :----- | :----------------------------------------------------------- |
|
||||
| `ignore_result` | `True` | 是否发送检测结果。`True` 表示不发送,`False` 表示发送。 |
|
||||
| `ignore_alert` | `True` | 是否发送告警信息。`True` 表示不发送,`False` 表示发送。 |
|
||||
| `draw_image` | `True` | 是否在告警图片上绘制告警信息。`True` 表示绘制,`False` 表示不绘制。 |
|
||||
| `ignore_alert_video` | `True` | 是否发送告警视频。`True` 表示不发送,`False` 表示发送。 |
|
||||
|
||||
## 三、类的方法
|
||||
|
||||
`Api` 类**必须**包含以下三个方法,用于发送检测结果、告警信息和告警视频。可根据需求实现具体的回调方法。
|
||||
|
||||
### 1. 检测结果
|
||||
|
||||
- **方法**:send_result_callback(self, result):
|
||||
|
||||
- **功能**:发送检测结果。
|
||||
|
||||
- **参数**:
|
||||
|
||||
- `result`:检测结果的内容。具体格式和内容如下:
|
||||
|
||||
- **示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"hit": false, //是否命中
|
||||
"time": 1742458167.288579, //告警时间戳
|
||||
"device": {
|
||||
"id": "设备id",
|
||||
"name": "设备名称",
|
||||
"desc": "设备描述"
|
||||
},
|
||||
"source": {
|
||||
"id": "数据源id",
|
||||
"ipv4": "ip地址",
|
||||
"desc": "数据源描述"
|
||||
},
|
||||
"alg": {
|
||||
"name": "算法名称英文",
|
||||
"ch_name": "算法名称中文",
|
||||
"type": "general"
|
||||
},
|
||||
"reserved_data": {
|
||||
"bbox": {
|
||||
"rectangles": [
|
||||
{
|
||||
"xyxy": [668,562,790,656], //左上角、右下角坐标
|
||||
"color": [0,0,255], //BGR颜色
|
||||
"label": "未佩戴安全帽", //标签
|
||||
"conf": 0.91, //置信度
|
||||
"ext": {} //扩展字段
|
||||
}
|
||||
],
|
||||
"polygons": {}, //多边形对象
|
||||
"lines": {} //线段对象
|
||||
},
|
||||
"custom": {}
|
||||
},
|
||||
"hazard_level": "", //危险等级
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 告警信息
|
||||
|
||||
- **方法**:send_alert_callback(self, alert)
|
||||
|
||||
- **功能**:发送告警信息。
|
||||
|
||||
- **参数**:
|
||||
|
||||
- `alert`:告警信息的内容。具体格式和内容如下:
|
||||
|
||||
- **示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "67dbcd3c5dc58a7aaa019e41", //告警id
|
||||
"alert_time": 1742458171.808598, //告警时间戳
|
||||
"device": {
|
||||
"id": "设备id",
|
||||
"name": "设备名称",
|
||||
"desc": "设备描述"
|
||||
},
|
||||
"source": {
|
||||
"id": "数据源id",
|
||||
"ipv4": "ip地址",
|
||||
"desc": "数据源描述"
|
||||
},
|
||||
"alg": {
|
||||
"name": "算法名称英文",
|
||||
"ch_name": "算法名称中文",
|
||||
"type": "general"
|
||||
},
|
||||
"hazard_level": "", //危险等级
|
||||
"image": "img_base64", //base64编码的图片数据
|
||||
"reserved_data": {
|
||||
"bbox": {
|
||||
"rectangles": [
|
||||
{
|
||||
"xyxy": [668,560,790,656], //左上角、右下角坐标
|
||||
"color": [0,0,255], //BGR颜色
|
||||
"label": "未佩戴安全帽", //标签
|
||||
"conf": 0.91, //置信度
|
||||
"ext": {} //扩展字段
|
||||
}
|
||||
],
|
||||
"polygons": {},//多边形对象
|
||||
"lines": {} //线段对象
|
||||
},
|
||||
"custom": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 告警视频
|
||||
|
||||
- **方法**:send_alert_video_callback(self, alert_video):
|
||||
|
||||
- **功能**:发送告警视频。
|
||||
|
||||
- **参数**:
|
||||
|
||||
- `alert_video`:告警视频的内容。具体格式和内容如下:
|
||||
|
||||
- **示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "67dbcd3c5dc58a7aaa019e41", //告警id
|
||||
"alert_time": 1742458171.808598, //告警时间戳
|
||||
"device": {
|
||||
"id": "设备id",
|
||||
"name": "设备名称",
|
||||
"desc": "设备描述"
|
||||
},
|
||||
"source": {
|
||||
"id": "数据源id",
|
||||
"ipv4": "ip地址",
|
||||
"desc": "数据源描述"
|
||||
},
|
||||
"alg": {
|
||||
"name": "算法名称英文",
|
||||
"ch_name": "算法名称中文",
|
||||
"type": "general"
|
||||
},
|
||||
"hazard_level": "", //危险等级
|
||||
"video": "video_base64" //base64编码的视频数据
|
||||
}
|
||||
```
|
||||
|
||||
## 四、注意事项
|
||||
|
||||
1. **属性配置**:在调用发送方法之前,确保已经正确配置了类的属性,以启用或禁用所需的功能。
|
||||
2. **方法实现**:默认情况下,`send_result_callback`、`send_alert_callback` 和 `send_alert_video_callback` 方法是空方法。在实际使用中,需要根据具体需求实现这些方法的逻辑,例如将数据发送到服务器。
|
||||
|
||||
|
||||
40
快速接收设备告警/custom-api-demo/api_demo.py
Normal file
40
快速接收设备告警/custom-api-demo/api_demo.py
Normal file
@ -0,0 +1,40 @@
|
||||
class Api:
|
||||
def __init__(self):
|
||||
"""
|
||||
Attributes:
|
||||
self.ignore_result: 为True时,不发送检测结果,为False则发送检测结果
|
||||
self.ignore_alert: 为True时,不发送告警信息,为False则发送告警信息
|
||||
self.draw_image: 为True时,告警图片会画上告警信息,为False则不画
|
||||
self.ignore_alert_video: 为True时,不发送告警视频,为False则发送
|
||||
"""
|
||||
self.ignore_result = True
|
||||
self.ignore_alert = True
|
||||
self.draw_image = True
|
||||
self.ignore_alert_video = True
|
||||
|
||||
def send_result_callback(self, result):
|
||||
"""
|
||||
发送检测结果回调函数
|
||||
Args:
|
||||
result: 检测结果数据
|
||||
Returns:
|
||||
"""
|
||||
pass
|
||||
|
||||
def send_alert_callback(self, alert):
|
||||
"""
|
||||
发送告警信息回调函数
|
||||
Args:
|
||||
alert: 告警数据
|
||||
Returns:
|
||||
"""
|
||||
pass
|
||||
|
||||
def send_alert_video_callback(self, alert_video):
|
||||
"""
|
||||
发送告警视频回调函数
|
||||
Args:
|
||||
alert_video: 告警视频数据
|
||||
Returns:
|
||||
"""
|
||||
pass
|
||||
68
快速接收设备告警/custom-api-demo/api_demo_tcp.py
Normal file
68
快速接收设备告警/custom-api-demo/api_demo_tcp.py
Normal file
@ -0,0 +1,68 @@
|
||||
import json
|
||||
import socket
|
||||
# 导入日志
|
||||
from logger import LOGGER
|
||||
|
||||
|
||||
class Api:
|
||||
"""
|
||||
API类,实现最简单的tcp通讯,如果需要自动重连,队列等业务代码请自行实现
|
||||
"""
|
||||
def __init__(self):
|
||||
"""
|
||||
Attributes:
|
||||
self.ignore_result: 为True时,不发送检测结果,为False则发送检测结果
|
||||
self.ignore_alert: 为True时,不发送告警信息,为False则发送告警信息
|
||||
self.draw_image: 为True时,告警图片会画上告警信息,为False则不画
|
||||
self.ignore_alert_video: 为True时,不发送告警视频,为False则发送
|
||||
"""
|
||||
self.ignore_result = True
|
||||
self.ignore_alert = False
|
||||
self.draw_image = True
|
||||
self.ignore_alert_video = True
|
||||
|
||||
def send_result_callback(self, result):
|
||||
"""
|
||||
发送检测结果回调函数
|
||||
Args:
|
||||
result: 检测结果数据
|
||||
Returns:
|
||||
"""
|
||||
pass
|
||||
|
||||
def send_alert_callback(self, alert):
|
||||
"""
|
||||
发送告警信息回调函数
|
||||
Args:
|
||||
alert: 告警数据
|
||||
Returns:
|
||||
"""
|
||||
|
||||
try:
|
||||
LOGGER.info('发送TCP告警')
|
||||
# 创建TCP socket
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
# 连接到目标服务器(这里用示例地址和端口)
|
||||
s.connect(('192.168.0.4', 10001))
|
||||
|
||||
# 为了方便查看日志,去掉base64编码图片
|
||||
alert.pop('image')
|
||||
|
||||
json_data = json.dumps(alert, ensure_ascii=False)
|
||||
data = json_data.encode('utf-8')
|
||||
|
||||
# 发送完整数据
|
||||
s.sendall(data)
|
||||
|
||||
LOGGER.info(f'告警已发送至TCP服务器: {data}')
|
||||
except Exception as e:
|
||||
LOGGER.error(f'发送TCP告警失败: {str(e)}')
|
||||
|
||||
def send_alert_video_callback(self, alert_video):
|
||||
"""
|
||||
发送告警视频回调函数
|
||||
Args:
|
||||
alert_video: 告警视频数据
|
||||
Returns:
|
||||
"""
|
||||
pass
|
||||
83
快速接收设备告警/http-server-demo/README.md
Normal file
83
快速接收设备告警/http-server-demo/README.md
Normal file
@ -0,0 +1,83 @@
|
||||
# HTTP告警推送
|
||||
|
||||
> **http-server-demo** 分为三个文件夹。
|
||||
>
|
||||
> 1. **headers** :http请求头的demo代码
|
||||
> 2. **http-server** :http服务端,接收告警推送(无token版本)
|
||||
> 3. **http-server-token** :http服务端,接收告警推送(有token版本)
|
||||
|
||||
## headers
|
||||
|
||||
如果需要将盒子产生的告警推送到您自建平台,并且你的平台需要验证**token**,则需要用到该文件夹下的`headers_demo.py`文件。
|
||||
你可自行修改`headers_demo.py`文件,并将此文件上传到盒子平台的【数据推送】-【告警】-【HTTP】-【配置token】。
|
||||
`headers_demo.py`文件说明:
|
||||
|
||||
- 类名必须为`Headers`,继承`BaseHeaders`类。`BaseHeaders`类通过`api.http`导入
|
||||
|
||||
```python
|
||||
from api.http import Headers as BaseHeaders
|
||||
```
|
||||
|
||||
- 定义三个实例变量:`get_headers_url`、`timeout`、`interval`。
|
||||
|
||||
`get_headers_url`:指定获取`token`的**URL**地址。
|
||||
|
||||
`timeout`:指定获取`token`的超时时间(单位:秒)。
|
||||
|
||||
`interval`:定时刷新`headers`的时间间隔(单位:秒)。
|
||||
|
||||
```python
|
||||
class Headers(BaseHeaders):
|
||||
def __init__(self):
|
||||
self.get_headers_url = None
|
||||
self.timeout = 5
|
||||
interval = 60 * 10
|
||||
super().__init__(interval)
|
||||
```
|
||||
|
||||
- 必须实现`_generate_headers`方法。返回请求头字典`headers`。返回示例:
|
||||
|
||||
|
||||
```python
|
||||
{'authorization': 'Bearer abcdefghijklmnopqrstuvwxyz'}
|
||||
```
|
||||
|
||||
|
||||
- 完整实例如下:
|
||||
|
||||
```python
|
||||
import requests
|
||||
from api.http import Headers as BaseHeaders
|
||||
from logger import LOGGER
|
||||
|
||||
class Headers(BaseHeaders):
|
||||
def __init__(self):
|
||||
self.get_headers_url = None
|
||||
self.timeout = 5
|
||||
interval = 60 * 10
|
||||
super().__init__(interval)
|
||||
|
||||
def _generate_headers(self):
|
||||
try:
|
||||
headers = {
|
||||
'authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkXXX'
|
||||
}
|
||||
return headers
|
||||
except:
|
||||
LOGGER.exception('_generate_headers')
|
||||
return None
|
||||
```
|
||||
|
||||
## http-server
|
||||
|
||||
该文件夹为**http**服务端代码,提供**python**和**java**代码。它主要用于接收盒子的**http**告警推送。如果您需要验证盒子的**http**推送功能是否正常,可使用此文件夹进行测试。
|
||||
运行该文件夹下的代码,即可开启一个**http**服务端。在盒子平台的【数据推送】-【告警】-【HTTP】中启用推送管理,并填写**http**服务端地址,即可开启推送功能。
|
||||
|
||||
|
||||
## http-server-token
|
||||
|
||||
此文件夹同**http-server**文件夹,只是增加了**token**验证功能。
|
||||
|
||||
你首先需把其下的`headers_demo1.py`或`headers_demo2.py`文件上传到盒子平台的【数据推送】-【告警】-【HTTP】-【配置TOKEN】。
|
||||
`headers_demo1.py`:通过调用url接口获取token。(盒子必须可以ping通该url,文件中的`get_headers_url`变量为**http**服务端URL)
|
||||
`headers_demo2.py`:固定token。
|
||||
46
快速接收设备告警/http-server-demo/headers/headers_demo.py
Normal file
46
快速接收设备告警/http-server-demo/headers/headers_demo.py
Normal file
@ -0,0 +1,46 @@
|
||||
import requests
|
||||
|
||||
from api.http import Headers as BaseHeaders
|
||||
from logger import LOGGER
|
||||
|
||||
|
||||
class Headers(BaseHeaders):
|
||||
def __init__(self):
|
||||
"""
|
||||
初始化Headers类
|
||||
- `self.get_headers_url`: 获取token的URL地址,根据实际环境修改。
|
||||
- `self.timeout`: 请求超时时间,设置为5秒。
|
||||
- `interval`: 定时刷新headers的时间间隔,设置为10分钟(60秒 * 10)。
|
||||
"""
|
||||
self.get_headers_url = None
|
||||
self.timeout = 5
|
||||
interval = 60 * 10
|
||||
super().__init__(interval)
|
||||
|
||||
def _generate_headers(self):
|
||||
"""
|
||||
生成请求头的方法,_generate_headers方法名不允许修改
|
||||
通过向指定的URL发送GET请求获取token,并将token添加到请求头中
|
||||
:return: 请求头字典
|
||||
"""
|
||||
try:
|
||||
# 定义请求参数
|
||||
params = {
|
||||
'arg1': 'xxx',
|
||||
'arg2': 'xxx'
|
||||
}
|
||||
if self.get_headers_url is not None:
|
||||
# 发送GET请求获取token
|
||||
resp = requests.get(self.get_headers_url, params=params, timeout=self.timeout)
|
||||
if resp.status_code == 200:
|
||||
token = resp.text
|
||||
headers = {
|
||||
'authorization': 'Bearer {}'.format(token)
|
||||
}
|
||||
return headers
|
||||
else:
|
||||
LOGGER.error('Get headers failed')
|
||||
return None
|
||||
except:
|
||||
LOGGER.exception('_generate_headers')
|
||||
return None
|
||||
47
快速接收设备告警/http-server-demo/http-server-token/headers_demo1.py
Normal file
47
快速接收设备告警/http-server-demo/http-server-token/headers_demo1.py
Normal file
@ -0,0 +1,47 @@
|
||||
import requests
|
||||
|
||||
from api.http import Headers as BaseHeaders
|
||||
from logger import LOGGER
|
||||
|
||||
|
||||
class Headers(BaseHeaders):
|
||||
def __init__(self):
|
||||
"""
|
||||
初始化Headers类
|
||||
- `self.get_headers_url`: 获取token的URL地址,根据实际环境修改。
|
||||
- `self.timeout`: 请求超时时间,设置为5秒。
|
||||
- `interval`: 定时刷新headers的时间间隔,设置为10分钟(60秒 * 10)。
|
||||
"""
|
||||
self.get_headers_url = 'http://192.168.1.75:10000/token'
|
||||
self.timeout = 5
|
||||
interval = 60 * 10
|
||||
super().__init__(interval)
|
||||
|
||||
def _generate_headers(self):
|
||||
"""
|
||||
生成请求头的方法,_generate_headers方法名不允许修改
|
||||
通过向指定的URL发送GET请求获取token,并将token添加到请求头中
|
||||
:return: 请求头字典
|
||||
"""
|
||||
try:
|
||||
# 定义请求参数
|
||||
params = {
|
||||
'arg1': 'xxx',
|
||||
'arg2': 'xxx'
|
||||
}
|
||||
if self.get_headers_url is not None:
|
||||
# 发送GET请求获取token
|
||||
resp = requests.get(self.get_headers_url, params=params, timeout=self.timeout)
|
||||
LOGGER.info('Get headers resp {}'.format(resp))
|
||||
if resp.status_code == 200:
|
||||
token = resp.text
|
||||
headers = {
|
||||
'authorization': 'Bearer {}'.format(token)
|
||||
}
|
||||
return headers
|
||||
else:
|
||||
LOGGER.error('Get headers failed')
|
||||
return None
|
||||
except:
|
||||
LOGGER.exception('_generate_headers')
|
||||
return None
|
||||
35
快速接收设备告警/http-server-demo/http-server-token/headers_demo2.py
Normal file
35
快速接收设备告警/http-server-demo/http-server-token/headers_demo2.py
Normal file
@ -0,0 +1,35 @@
|
||||
import requests
|
||||
|
||||
from api.http import Headers as BaseHeaders
|
||||
from logger import LOGGER
|
||||
|
||||
|
||||
class Headers(BaseHeaders):
|
||||
def __init__(self):
|
||||
"""
|
||||
初始化Headers类
|
||||
- `self.get_headers_url`: 获取token的URL地址,根据实际环境修改。
|
||||
- `self.timeout`: 请求超时时间,设置为5秒。
|
||||
- `interval`: 定时刷新headers的时间间隔,设置为10分钟(60秒 * 10)。
|
||||
"""
|
||||
self.get_headers_url = None
|
||||
self.timeout = 5
|
||||
interval = 60 * 10
|
||||
super().__init__(interval)
|
||||
|
||||
def _generate_headers(self):
|
||||
"""
|
||||
生成请求头的方法,_generate_headers方法名不允许修改
|
||||
固定http请求头,authorization以及值可自定义
|
||||
:return: 请求头字典
|
||||
"""
|
||||
try:
|
||||
|
||||
headers = {
|
||||
'authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkXXX'
|
||||
}
|
||||
return headers
|
||||
|
||||
except:
|
||||
LOGGER.exception('_generate_headers')
|
||||
return None
|
||||
@ -0,0 +1,45 @@
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping(path = "")
|
||||
public class AlertController {
|
||||
|
||||
|
||||
/**
|
||||
* 目标平台接收告警及告警图片
|
||||
* @param alertMsg
|
||||
* @param authorization
|
||||
*/
|
||||
|
||||
@PostMapping(path = "/alert")
|
||||
public void getAlertMsg(@RequestBody AlertMsg alertMsg, @RequestHeader("Authorization") String authorization) {
|
||||
log.info("authorization:{}", authorization);
|
||||
log.info("示例接收告警及告警图片:{}", alertMsg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 目标平台接收告警及告警视频
|
||||
*
|
||||
* @param alertVideo
|
||||
*/
|
||||
|
||||
@PostMapping(path = "/video")
|
||||
public void getAlertVideo(@RequestBody AlertVideo alertVideo,@RequestHeader("Authorization") String authorization) {
|
||||
log.info("authorization:{}", authorization);
|
||||
log.info("示例接收告警及告警视频:{}", alertVideo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@GetMapping(path = "/token")
|
||||
public String token() {
|
||||
return RandomUtil.randomString(16);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
public class AlertMsg {
|
||||
private String id;
|
||||
@JsonProperty("alert_time")
|
||||
private Double alertTime;
|
||||
private Object device;
|
||||
private Object source;
|
||||
private Object alg;
|
||||
private String image;
|
||||
@JsonProperty("reserved_data")
|
||||
private Object reservedData;
|
||||
@JsonProperty("hazard_leve")
|
||||
private String hazardLeve;
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
public class AlertVideo {
|
||||
private String id;
|
||||
@JsonProperty("alert_time")
|
||||
private Double alertTime;
|
||||
private Object device;
|
||||
private Object source;
|
||||
private Object alg;
|
||||
private String video;
|
||||
@JsonProperty("hazard_leve")
|
||||
private String hazardLeve;
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
from flask import Flask
|
||||
|
||||
CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(CURRENT_PATH)
|
||||
|
||||
url_prefix = '/'
|
||||
|
||||
from app import alert
|
||||
|
||||
|
||||
def create_app():
|
||||
# 初始化Flask对象
|
||||
app_ = Flask(__name__)
|
||||
|
||||
# 注册蓝图
|
||||
app_.register_blueprint(alert.bp)
|
||||
return app_
|
||||
|
||||
|
||||
app = create_app()
|
||||
@ -0,0 +1,31 @@
|
||||
import base64
|
||||
import hashlib
|
||||
import json
|
||||
import secrets
|
||||
import time
|
||||
|
||||
from flask import Blueprint, request
|
||||
|
||||
from app import url_prefix
|
||||
|
||||
bp = Blueprint('alert', __name__, url_prefix=url_prefix)
|
||||
|
||||
|
||||
@bp.route('alert', methods=['POST'])
|
||||
def post_alert():
|
||||
# 获取token
|
||||
auth_header = request.headers.get('authorization')
|
||||
print(f"Authorization Header: {auth_header}")
|
||||
data = json.loads(request.get_data().decode('utf-8'))
|
||||
image = data.pop('image')
|
||||
print(data)
|
||||
with open('image.jpg', 'wb') as f:
|
||||
f.write(base64.b64decode(image.encode('utf-8')))
|
||||
return data
|
||||
|
||||
|
||||
@bp.route('/token', methods=['GET'])
|
||||
def gen_token():
|
||||
print(request.args)
|
||||
token = secrets.token_hex(32)
|
||||
return token
|
||||
BIN
快速接收设备告警/http-server-demo/http-server-token/python/image.jpg
Normal file
BIN
快速接收设备告警/http-server-demo/http-server-token/python/image.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
@ -0,0 +1,4 @@
|
||||
from app import app
|
||||
|
||||
if '__main__' == __name__:
|
||||
app.run(host='0.0.0.0', port=10000, debug=False)
|
||||
@ -0,0 +1,37 @@
|
||||
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping(path = "")
|
||||
public class AlertController {
|
||||
|
||||
|
||||
/**
|
||||
* 目标平台接收告警及告警图片
|
||||
*
|
||||
* @param alertMsg
|
||||
*/
|
||||
|
||||
@PostMapping(path = "/alert")
|
||||
public void getAlertMsg(@RequestBody AlertMsg alertMsg) {
|
||||
log.info("示例接收告警及告警图片:{}", alertMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 目标平台接收告警及告警视频
|
||||
*
|
||||
* @param alertVideo
|
||||
*/
|
||||
|
||||
@PostMapping(path = "/video")
|
||||
public void getAlertVideo(@RequestBody AlertVideo alertVideo) {
|
||||
log.info("示例接收告警及告警视频:{}", alertVideo);
|
||||
}
|
||||
|
||||
}
|
||||
21
快速接收设备告警/http-server-demo/http-server/java/AlertMsg.java
Normal file
21
快速接收设备告警/http-server-demo/http-server/java/AlertMsg.java
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
public class AlertMsg {
|
||||
private String id;
|
||||
@JsonProperty("alert_time")
|
||||
private Double alertTime;
|
||||
private Object device;
|
||||
private Object source;
|
||||
private Object alg;
|
||||
private String image;
|
||||
@JsonProperty("reserved_data")
|
||||
private Object reservedData;
|
||||
@JsonProperty("hazard_leve")
|
||||
private String hazardLeve;
|
||||
}
|
||||
19
快速接收设备告警/http-server-demo/http-server/java/AlertVideo.java
Normal file
19
快速接收设备告警/http-server-demo/http-server/java/AlertVideo.java
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
public class AlertVideo {
|
||||
private String id;
|
||||
@JsonProperty("alert_time")
|
||||
private Double alertTime;
|
||||
private Object device;
|
||||
private Object source;
|
||||
private Object alg;
|
||||
private String video;
|
||||
@JsonProperty("hazard_leve")
|
||||
private String hazardLeve;
|
||||
}
|
||||
23
快速接收设备告警/http-server-demo/http-server/python/app/__init__.py
Normal file
23
快速接收设备告警/http-server-demo/http-server/python/app/__init__.py
Normal file
@ -0,0 +1,23 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
from flask import Flask
|
||||
|
||||
CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(CURRENT_PATH)
|
||||
|
||||
url_prefix = '/'
|
||||
|
||||
from app import alert
|
||||
|
||||
|
||||
def create_app():
|
||||
# 初始化Flask对象
|
||||
app_ = Flask(__name__)
|
||||
|
||||
# 注册蓝图
|
||||
app_.register_blueprint(alert.bp)
|
||||
return app_
|
||||
|
||||
|
||||
app = create_app()
|
||||
28
快速接收设备告警/http-server-demo/http-server/python/app/alert.py
Normal file
28
快速接收设备告警/http-server-demo/http-server/python/app/alert.py
Normal file
@ -0,0 +1,28 @@
|
||||
import base64
|
||||
import json
|
||||
|
||||
from flask import Blueprint, request
|
||||
|
||||
from app import url_prefix
|
||||
|
||||
bp = Blueprint('alert', __name__, url_prefix=url_prefix)
|
||||
|
||||
|
||||
@bp.route('alert', methods=['POST'])
|
||||
def post_alert():
|
||||
data = json.loads(request.get_data().decode('utf-8'))
|
||||
image = data.pop('image')
|
||||
print(data)
|
||||
with open('image.jpg', 'wb') as f:
|
||||
f.write(base64.b64decode(image.encode('utf-8')))
|
||||
return data
|
||||
|
||||
|
||||
@bp.route('alert/video', methods=['POST'])
|
||||
def post_alert_video():
|
||||
data = json.loads(request.get_data().decode('utf-8'))
|
||||
video = data.pop('video')
|
||||
print(data)
|
||||
with open('video.mp4', 'wb') as f:
|
||||
f.write(base64.b64decode(video.encode('utf-8')))
|
||||
return data
|
||||
BIN
快速接收设备告警/http-server-demo/http-server/python/image.jpg
Normal file
BIN
快速接收设备告警/http-server-demo/http-server/python/image.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 162 KiB |
4
快速接收设备告警/http-server-demo/http-server/python/main.py
Normal file
4
快速接收设备告警/http-server-demo/http-server/python/main.py
Normal file
@ -0,0 +1,4 @@
|
||||
from app import app
|
||||
|
||||
if '__main__' == __name__:
|
||||
app.run(host='0.0.0.0', port=10000, debug=False)
|
||||
107
快速接收设备告警/tcp-server-demo/server.py
Normal file
107
快速接收设备告警/tcp-server-demo/server.py
Normal file
@ -0,0 +1,107 @@
|
||||
import json
|
||||
import socket
|
||||
import struct
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
|
||||
|
||||
class SocketServer:
|
||||
def __init__(self):
|
||||
self.server_host = '0.0.0.0'
|
||||
self.server_port = 10001
|
||||
self.socket_server = self.__listen()
|
||||
self.conns = {}
|
||||
self.__accept()
|
||||
|
||||
@staticmethod
|
||||
def __set_reuse_addr(socket_obj):
|
||||
"""
|
||||
断开连接之后立马释放本地端口
|
||||
Args:
|
||||
socket_obj: socket对象
|
||||
Returns: True or False
|
||||
"""
|
||||
socket_obj.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
return True
|
||||
|
||||
def __listen(self):
|
||||
socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
self.__set_reuse_addr(socket_server)
|
||||
# 绑定IP/端口
|
||||
socket_server.bind((self.server_host, self.server_port))
|
||||
# 最多同时处理5个连接请求
|
||||
socket_server.listen(5)
|
||||
except:
|
||||
print(traceback.format_exc())
|
||||
finally:
|
||||
return socket_server
|
||||
|
||||
def __disconnect(self, addr):
|
||||
print('Disconnected, client={}'.format(addr))
|
||||
self.__close(self.conns[addr])
|
||||
self.conns.pop(addr)
|
||||
return True
|
||||
|
||||
def __accept(self):
|
||||
def accept():
|
||||
while True:
|
||||
try:
|
||||
conn, addr = self.socket_server.accept()
|
||||
print('Connection established, client={}'.format(addr))
|
||||
self.__set_reuse_addr(conn)
|
||||
self.conns[addr] = conn
|
||||
threading.Thread(target=self.__recv, args=(addr, conn), daemon=True).start()
|
||||
except:
|
||||
print(traceback.format_exc())
|
||||
|
||||
threading.Thread(target=accept, daemon=True).start()
|
||||
return True
|
||||
|
||||
def __recv(self, addr, client_socket, buff_size=1024):
|
||||
while True:
|
||||
try:
|
||||
data_length = client_socket.recv(4)
|
||||
# 读取data_length
|
||||
if data_length:
|
||||
data_length = struct.unpack('i', data_length)[0]
|
||||
print('Recv from: {}, data_length: {}'.format(addr, data_length))
|
||||
# 读取data
|
||||
if data_length <= buff_size:
|
||||
data = client_socket.recv(data_length)
|
||||
else:
|
||||
buff_size_ = buff_size
|
||||
# 已接收到的size
|
||||
total_recv_size = 0
|
||||
data = b''
|
||||
while total_recv_size < data_length:
|
||||
recv_data = client_socket.recv(buff_size_)
|
||||
data += recv_data
|
||||
total_recv_size += len(recv_data)
|
||||
left_size = data_length - total_recv_size
|
||||
if left_size < buff_size:
|
||||
buff_size_ = left_size
|
||||
data = json.loads(data.decode('utf-8'))
|
||||
print('Recv from: {}, data: {}'.format(addr, data))
|
||||
else:
|
||||
break
|
||||
except:
|
||||
print(traceback.format_exc())
|
||||
break
|
||||
self.__disconnect(addr)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def __close(socket_obj):
|
||||
try:
|
||||
socket_obj.close()
|
||||
except:
|
||||
print(traceback.format_exc())
|
||||
return True
|
||||
|
||||
|
||||
if '__main__' == __name__:
|
||||
tcp_server = SocketServer()
|
||||
while True:
|
||||
time.sleep(3)
|
||||
Reference in New Issue
Block a user