Skip to content

Commit

Permalink
2024-1-7
Browse files Browse the repository at this point in the history
错误页面
权限化部分页面
减少画面延迟
添加画面水印
  • Loading branch information
hhhfsj committed Jan 7, 2024
1 parent 209f199 commit ed936e3
Show file tree
Hide file tree
Showing 26 changed files with 363 additions and 223 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ IPKVM Core是一个由Python+django编写的KVM程序,拥有更强大的审计
**请求参数:**

##### 获取用户信息
>**URL:** /admin/api/getUserInfo
>**URL:** /admin/api/getUserInfo
**方法:** POST
**需求权限:** manageUsers
**请求参数:**
Expand Down
2 changes: 2 additions & 0 deletions app/apis/Screen.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from django.http import StreamingHttpResponse, HttpResponse

import app.apps
from app.util.DataBaseTools import writeAudit


def getScreen(req):
frame = app.apps.cameraObj.getDisplayFrame()
# print(frame)
writeAudit(req.session.get("userId"), "Get Display Screen Image", "control", "")
return HttpResponse(content=frame, content_type="image/jpeg")
13 changes: 7 additions & 6 deletions app/apis/WebSocket/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import app.apps as app
import app.util.Config as Config
from app.util.logger import Log
from app.util.DataBaseTools import writeAccessLog
from app.util.DataBaseTools import writeAccessLog, writeAudit

links = {}

Expand All @@ -23,10 +23,11 @@ def connect(self):
self.accept()
links.update({user: self})
writeAccessLog(self.__userID, self.__clientIP, "Control Page Websocket Connect")
writeAudit(self.__userID, "Control Start", "control", "")
if Config.main_config.get("main").get("record"):
app.cameraObj.startRecord(op_user=user, machine_name="DEV")
writeAudit(self.__userID, "Recording starts", "control", "")
app.cameraObj.setOp(user)
Log.success(f"用户{user}已连接")
self.sendJson({
"method": "init",
"data": {
Expand All @@ -36,6 +37,7 @@ def connect(self):
}
}
})
self.send(bytes_data=app.cameraObj.getDisplayFrame())
else:
self.close(-1)

Expand All @@ -44,19 +46,19 @@ def disconnect(self, close_code):
user = self.scope["session"].get("user")
if Config.main_config.get("main").get("record"):
app.cameraObj.stopRecord()
writeAudit(self.__userID, "Recording ends", "control", "")
app.cameraObj.setOp(None)
links.pop(user)
Log.success(f"用户{user}已断开({close_code})")
writeAccessLog(self.__userID, self.__clientIP, f"Control Page Websocket Disconnect(Code:{close_code})")
writeAudit(self.__userID, "Control ends", "control", "")
raise StopConsumer

def receive(self, text_data):
# 处理接收到的消息
Log.debug(text_data)
try:
jsonData = json.loads(text_data)
except Exception as e:
print(f"解析Websocket消息时发生错误:\n{e}")
Log.error(f"解析Websocket消息时发生错误:\n{e}")
else:
if jsonData.get("method"):
match jsonData.get("method"):
Expand Down Expand Up @@ -126,7 +128,6 @@ def receive(self, text_data):
app.HID.keyBoardInput(key)
# 键盘 - 抬起
case "keyup":
# TODO 待重构
Log.debug("收到键盘抬起请求")
app.HID.keyBoardInput(mode="Clear")
# 粘贴
Expand Down
4 changes: 0 additions & 4 deletions app/apis/admin/auditAndLogger.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ def getAudit(req):
pageSize = req_json.get("pageSize", 20)
result = Audit.objects.filter()
pageQuery = getPageContent(result, page if page > 0 else 1, pageSize)
Log.debug(result.count())
if pageQuery:
for item in pageQuery:
PageContent.append({
Expand Down Expand Up @@ -52,7 +51,6 @@ def getAccessLog(req):
pageSize = req_json.get("pageSize", 20)
result = Access_Log.objects.filter()
pageQuery = getPageContent(result, page if page > 0 else 1, pageSize)
Log.debug(result.count())
if pageQuery:
for item in pageQuery:
PageContent.append({
Expand Down Expand Up @@ -86,7 +84,6 @@ def getFileChangeLog(req):
pageSize = req_json.get("pageSize", 20)
result = FileChange_Log.objects.filter()
pageQuery = getPageContent(result, page if page > 0 else 1, pageSize)
Log.debug(result.count())
if pageQuery:
for item in pageQuery:
PageContent.append({
Expand Down Expand Up @@ -120,7 +117,6 @@ def getSystemLog(req):
pageSize = req_json.get("pageSize", 20)
result = System_Log.objects.filter()
pageQuery = getPageContent(result, page if page > 0 else 1, pageSize)
Log.debug(result.count())
if pageQuery:
for item in pageQuery:
PageContent.append({
Expand Down
1 change: 0 additions & 1 deletion app/apis/admin/permission.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ def getPermissionGroupsList(req):
search = req_json.get("search", "")
result = Permission_groups.objects.filter(name__icontains=search if search else "")
pageQuery = getPageContent(result, page if page > 0 else 1, pageSize)
Log.debug(result.count())
if pageQuery:
for item in pageQuery:
PageContent.append({
Expand Down
2 changes: 0 additions & 2 deletions app/apis/admin/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ def getUserList(req):
search = req_json.get("search", "")
result = Users.objects.filter(userName__icontains=search if search else "")
pageQuery = getPageContent(result, page if page > 0 else 1, pageSize)
Log.debug(result.count())
maxPage = getMaxPage(result.count(), pageSize)
Log.debug(result)
if pageQuery:
for item in pageQuery:
PageContent.append({
Expand Down
26 changes: 11 additions & 15 deletions app/apis/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,18 @@ def AuthLogin(req):
if req.method == 'POST':
req_json = RequestLoadJson(req)
user = req_json.get("username")
password = req_json.get("password")
password = PasswordToMd5(password)
if Users.objects.filter(userName=user, password=password):
User = Users.objects.filter(userName=user, password=password).first()
if not User.disable:
req.session["user"] = user
req.session["userID"] = User.id
password = PasswordToMd5(req_json.get("password"))
user = Users.objects.filter(userName=user, password=password).first()
if user:
if not user.disable:
req.session["user"] = user.userName
req.session["userID"] = user.id
req.session.set_expiry(int(Config.main_config.get("main").get("sessionExpiry")) * 60)
Log.success(f"用户[{user}]已登陆")
User.lastLoginIP = getClientIp(req)
User.lastLoginTime = datetime.datetime.now()
User.save()
writeAudit(User.id, "Login", "Auth", User.lastLoginIP)
user.lastLoginIP = getClientIp(req)
user.lastLoginTime = datetime.datetime.now()
user.save()
writeAudit(user.id, "Login", "Auth", user.lastLoginIP)
return ResponseJson({"status": 1, "msg": "登录成功"})
else:
return ResponseJson({"status": 0, "msg": "账户被禁用,请联系管理员"})
Expand All @@ -42,11 +41,8 @@ def AuthLogin(req):
# 登出
def AuthOutLog(req):
if req.session.get("user"):
user = req.session.get("user")
userId = req.session.get("UserID")
writeAudit(req.session.get("userID"), "Outlog", "Auth", getClientIp(req))
req.session.clear()
Log.success(f"用户[{user}]已登出")
writeAudit(userId, "Outlog", "Auth", getClientIp(req))
return ResponseJson({"status": 1, "msg": "登出成功"})
else:
return ResponseJson({"status": 0, "msg": "您未登录"})
18 changes: 9 additions & 9 deletions app/apps.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
from django.apps import AppConfig
from app.util.Config import main_config
from app.devices.camera import camera
# from devices.ch9329 import ch3929
from app.devices.ch9329 import ch3929

# if len(main_config.get("main").get("serial")) != 0:
# HID = ch3929(main_config.get("main").get("serial"))
# else:
# raise RuntimeError("HID串口未填写")
if len(main_config.get("main").get("serial")) != 0:
HID = ch3929(main_config.get("main").get("serial"))
else:
raise RuntimeError("HID串口未填写")

# if main_config.get("main").get("camera") is not None:
# cameraObj = camera(main_config.get("main").get("camera"))
# else:
# raise RuntimeError("摄像头id未填写")
if main_config.get("main").get("camera") is not None:
cameraObj = camera(main_config.get("main").get("camera"))
else:
raise RuntimeError("摄像头id未填写")

class AppConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
Expand Down
87 changes: 82 additions & 5 deletions app/devices/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
import os
from copy import copy
from threading import Thread

import msgpack
from PIL import Image, ImageDraw, ImageFont

import app.apis.WebSocket.control
import app.util.Config as Config

Expand All @@ -23,6 +27,7 @@ class camera:
__after = None
__flag = 0
__op = None
__watermark = None
# 录制参数
__recordArgs = {
"User": None,
Expand Down Expand Up @@ -83,7 +88,7 @@ def __del__(self):
def isOpened(self):
"""查询摄像头是否开启"""
return self.__camera.isOpened()

@Log.catch
def __movingDetect(self, frame1, frame2):
"""检测图片是否变动"""
Expand Down Expand Up @@ -130,10 +135,21 @@ def __GetFrame(self):
else:
sleep(0.5)
return
def setOp(self,value):

def setOp(self, value):
self.__op = value
Log.debug(f"已设置操作员:{value}")
if value:
print(int(self.__camera.get(cv2.CAP_PROP_FRAME_WIDTH)))
print(int(self.__camera.get(cv2.CAP_PROP_FRAME_HEIGHT)))
self.__watermark = self.__createWatermarkImage(
int(self.__camera.get(cv2.CAP_PROP_FRAME_WIDTH)),
int(self.__camera.get(cv2.CAP_PROP_FRAME_HEIGHT)),
f"Operator: {value}"
)
Log.debug(f"已设置操作员:{value}")
else:
self.__watermark = None
Log.debug(f"已清除操作员")

def stopGetFrame(self):
self.__status["GetFrameThread"] = False
Expand Down Expand Up @@ -220,6 +236,60 @@ def __recordVideo(self):
Log.success("采集卡录制已停止")
return

@Log.catch
def __createWatermarkImage(self, width: int, height: int, text: str, font_path=os.path.join(os.getcwd(),"font/Noto_Sans_SC/NotoSansSC-Medium.otf",), font_size=16, density=0.2)->np.array:
"""
创建水印图片
:param width: 水印图片宽度
:param height: 水印图片高度
:param text: 水印文字
:param font_path: 字体路径
:param font_size: 字体大小
:param density: 密度
:return: np.array
"""

# 创建一个透明的水印图片
watermark = np.zeros((height, width, 4), dtype=np.uint8)

# 使用默认字体或加载自定义字体
if font_path is not None and os.path.exists(font_path):
custom_font = ImageFont.truetype(font_path, size=font_size)
else:
custom_font = ImageFont.load_default()

# 使用PIL库添加文字水印
pil_watermark = Image.fromarray(watermark)
draw = ImageDraw.Draw(pil_watermark, 'RGBA')

# 计算水印的密度
num_watermarks = int(width * density)

# 计算水印的间隔,确保水印图像不超过原始图像的范围
interval = int(width / num_watermarks)

# 在整张画面添加水印
for y in range(0, height, font_size + 35 + interval):
for x in range(0, width, font_size + 150 + interval):
draw.text((x, y), text, font=custom_font, fill=(255, 255, 255, 255))

# 转换为NumPy数组
return np.array(pil_watermark)

@Log.catch
def __loadWatermarkToImage(self, frame, watermark: np.array, alpha=0.05):
"""
加载水印到图像中
:param frame: 图像帧
:param watermark: 水印数组
:param alpha: 透明度
:return: frame
"""
# # 将水印叠加到原始图片上
if watermark is not None:
return cv2.addWeighted(cv2.cvtColor(frame, cv2.COLOR_BGR2BGRA), 1 - alpha, watermark, alpha, 0)
return frame

def startRecord(self, op_user=None, machine_name=None, fps=24, dev=False):
"""启动后台录制
Expand Down Expand Up @@ -260,4 +330,11 @@ def getRecordStatus(self):

def getDisplayFrame(self):
"""获取用于web显示的采集卡帧"""
return cv2.imencode(".jpg", self.__cameraFrame)[1].tobytes()

# 将帧数据转换为字节流
_, encoded_frame = cv2.imencode(".jpg", self.__loadWatermarkToImage(self.__cameraFrame, self.__watermark))

# 使用MessagePack序列化帧数据
packed_frame = msgpack.packb(encoded_frame.tobytes(), use_bin_type=True)

return packed_frame
2 changes: 1 addition & 1 deletion app/middleware/AuthMiddleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class AuthMiddleware(MiddlewareMixin):
def process_request(self, request):
if request.path_info in ["/login", "/auth/login"]:
return
if request.session.get("user"):
if request.session.get("user") and request.session.get("userID"):
return
else:
return redirect("/login")
Loading

0 comments on commit ed936e3

Please sign in to comment.