Browse Source

12344

master
lichong 9 months ago
parent
commit
f47a3bdbf7
  1. 114
      api/main.py
  2. 2
      front/package.json
  3. 127
      front/src/views/student.vue
  4. 82
      front/src/views/teacher.vue
  5. 22
      test.py

114
api/main.py

@ -4,7 +4,7 @@ from bson import ObjectId
import hashlib
import json
from flask import Flask, render_template, request
from flask_socketio import SocketIO, Namespace, emit
from flask_socketio import SocketIO, emit, join_room, leave_room
import time
app = Flask(__name__)
@ -12,95 +12,46 @@ client = MongoClient("mongodb://localhost:27019/")
db = client["back"]
collection = db["users"]
# sockitIo解决跨域问题
socketMsg = SocketIO(app, cors_allowed_origins="*")
socketVedio = SocketIO(app, cors_allowed_origins="*")
# 用来存放客户端的 sid,即 session id
# 可以不单独定义字典存放 sid与namespace,flask-socketio 默认将 sid 存放在 room 中
socket_pool = {}
app.config["SECRET_KEY"] = "secret!"
socketio = SocketIO(app, cors_allowed_origins="*")
# 存储连接的客户端的房间号
clients = {}
# Websocket 通过namespace 和 sid 标识具体客户端
# 第一个 Websocket 类用于聊天
class MyCustomNamespace(Namespace):
name_space = "/msg"
@socketio.on("connect", namespace="/ws/video")
def on_connect():
print("Client connected")
# 连接成功调用的方法
def on_connect(self):
global socket_pool
socket_pool[request.sid] = self.name_space
print(1, socket_pool)
print(2, "Client connected")
print(3, "-----------------")
# 断开连接调用的方法
def on_disconnect(self):
global socket_pool
print(4, "disconnect...")
del socket_pool[request.sid]
print(5, socket_pool)
@socketio.on("disconnect", namespace="/ws/video")
def on_disconnect():
print("Client disconnected")
# 移除客户端的房间关联
room = clients.pop(request.sid, None)
if room:
leave_room(room)
# 往 接收客户端标消息识为 'message' 的方法
def on_message(self, data):
print(6, data)
# 把消息发送到客户端的 'response' 标识的方法中, 一般是 on_response()
emit("response", "123", to=request.sid)
print(7, "--------------")
print(8, request.sid)
print(9, "--------------")
print(10, socketio.server.manager.rooms)
# 往 接收客户端标消息识为 'hello' 的方法
def on_hello(self, data):
print(11, "hello world")
@socketio.on("join", namespace="/ws/video")
def on_join(data):
room = data["room"]
join_room(room)
clients[request.sid] = room
# 发送消息
def send(self, data):
# 向 namespace中的所有 Websocket 连接广播消息, namespace参数不能少, to缺省是广播模式
emit("response", data, namespace=self.name_space)
# 向 sid 所标识的客户端 单播
emit("response", data, namespace=self.name_space, to=request.sid)
@socketio.on("leave", namespace="/ws/video")
def on_leave(data):
room = data["room"]
leave_room(room)
clients.pop(request.sid, None)
# 为了详细展示不同类,这里就不做继承
# 第二个 Websocket 类用于视频
class MyCustomNamespace1(Namespace):
name_space = "/vedio"
def on_connect(self):
global socket_pool
print(12, "connect..")
print(13, request.namespace)
socket_pool[request.sid] = self.name_space
print(14, socket_pool)
def on_disconnect(self):
global socket_pool
print(15, "disconnect...")
del socket_pool[request.sid]
print(16, socket_pool)
def on_message(self, data):
print(17, data)
emit("response", "123")
self.send("asd")
# 发送消息
def send(self, data):
emit("response", data, namespace=self.name_space)
socketMsg.on_namespace(MyCustomNamespace("/msg"))
socketVedio.on_namespace(MyCustomNamespace("/vedio"))
@app.route("/sendMsg")
def sendMsg():
for sid, namespace_value in socket_pool.items():
print(18, sid)
emit("response", "123456", namespace=namespace_value, to=sid)
print(19, "ok")
return "ok"
@socketio.on("message", namespace="/ws/video")
def handle_video_frame(message):
# 广播视频帧给房间内的所有客户端,除了发送该帧的客户端
room = clients.get(request.sid)
if room:
emit("message", message, room=room, include_self=False)
# md5加密
@ -332,5 +283,4 @@ def updatePassword():
if __name__ == "__main__":
initData()
# app.run(debug=True)
socketMsg.run(app, debug=True)
# socketVedio.run(app, debug=True)
socketio.run(app, debug=True)

2
front/package.json

@ -28,4 +28,4 @@
"@vitejs/plugin-vue": "^4.6.2",
"vite": "^5.0.8"
}
}
}

127
front/src/views/student.vue

@ -34,21 +34,25 @@
<span>实时作弊信息</span>
</div>
</template>
<p>实时作弊信息</p>
<p>
<span>
实时作弊信息
</span>
<el-button type="primary" @click="startExam">开始考试</el-button>
</p>
</el-card>
</el-col>
<el-col :span="12">
视频
<video ref="videoEL" class="canvasClass" playsinline></video>
</el-col>
</el-row>
</template>
<script>
import _ from "lodash";
import { io } from "socket.io-client";
import {
getUser, //user
} from "@/api/student";
import { ElMessage, ElMessageBox } from 'element-plus'
export default {
name: "student",
components: {},
@ -115,8 +119,8 @@ export default {
},
],
userData: {},
socketMsg: io("http://localhost:3000/msg"),
socketVedio: io("http://localhost:3000/vedio")
ws: null,
videoStream: null,
};
},
watch: {},
@ -124,7 +128,7 @@ export default {
async mounted() {
this.userId = _.get(this.$route, ["params", "id"], "")
await this.getUser()
this.initMsg()
await this.initWebSocket();
},
methods: {
async getUser() {
@ -133,39 +137,86 @@ export default {
})
this.userData = res.list[0]
},
initMsg() {
this.socketMsg.on("connect", (data) => {
console.log(data);
});
this.socketMsg.on("data", (data) => {
console.log(data);
});
this.socketMsg.on("disconnect", (data) => {
console.log(data);
});
this.socketMsg.on('response', (data) => {
this.messages.push({ id: Date.now(), text: data.data });
});
async initWebSocket() {
this.ws = new WebSocket('ws://127.0.0.1:5000/ws/video');
this.ws.binaryType = 'arraybuffer';
this.ws.onopen = () => {
console.log(1, 'WebSocket connected');
};
this.ws.onerror = (err) => {
console.error(2, 'WebSocket error:', err);
};
this.ws.onclose = () => {
console.log(3, 'WebSocket disconnected');
};
},
async connectTeacher() {
console.log(78744, this.socketMsg)
this.socketMsg.emit('sendMsg', { sid: this.socketMsg.id, id: this.userId, msg: "我有问题" });
},
async startExam() {
try {
let device = {}
let devices = await navigator.mediaDevices.enumerateDevices()
for (let key in devices) {
if (devices[key].kind === 'videoinput') {
device = devices[key]
break
}
}
let stream = await navigator.mediaDevices.getUserMedia({
audio: false,
video: {
sourceId: device.deviceId, // ID
width: 600,
height: 600,
}
})
//
this.$refs['videoEL'].srcObject = stream
this.$refs['videoEL'].play()
this.sendVideoFrames();
} catch (error) {
ElMessage.error(`摄像头开启失败,请检查摄像头是否可用!${error}`)
}
},
initVedio() {
this.socketVedio.on("connect", (data) => {
console.log(data);
});
this.socketVedio.on("data", (data) => {
console.log(data);
});
this.socketVedio.on("disconnect", (data) => {
console.log(data);
});
this.socketVedio.on('response', (data) => {
this.messages.push({ id: Date.now(), text: data.data });
});
sendVideoFrames() {
let that = this
let video = this.$refs['videoEL'];
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
let sendFrame = () => {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
canvas.toBlob((blob) => {
let arrayBufferView = new Uint8Array(blob);
that.ws.send(arrayBufferView.buffer);
}, 'image/jpeg');
};
setInterval(sendFrame, 1000 / 30); // 30 FPS
},
connectTeacher() {
this.socketMsg.emit('message', "this.message");
}
stopVideoStream() {
if (this.videoStream) {
this.videoStream.getTracks().forEach(track => track.stop());
}
},
closeWebSocket() {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.close();
}
},
},
beforeUnmount() {
this.stopVideoStream();
this.closeWebSocket();
},
beforeUnmount() { },
};
</script>
<style scoped></style>
<style scoped>
.canvasClass {
position: relative;
width: 600px;
height: 600px;
}
</style>

82
front/src/views/teacher.vue

@ -1,6 +1,6 @@
<template>
<el-row>
<el-col :span="16">
<el-col :span="14">
<div style="margin-bottom: 4px;">
<el-button icon="Plus" type="primary" @click="addUserData">
add User
@ -18,8 +18,21 @@
</vueTable>
</div>
</el-col>
<el-col :span="8">
监控画面
<el-col :span="10">
<el-row>
<el-col :span="12">
<video ref="videoEL1" class="canvasClass"></video>
</el-col>
<el-col :span="12">
<video ref="videoEL2" class="canvasClass"></video>
</el-col>
<el-col :span="12">
<video ref="videoEL3" class="canvasClass"></video>
</el-col>
<el-col :span="12">
<video ref="videoEL4" class="canvasClass"></video>
</el-col>
</el-row>
</el-col>
</el-row>
<el-dialog v-model="addDialog.show" :title="addDialog.title" width="80%" draggable
@ -37,7 +50,6 @@
</el-dialog>
</template>
<script>
import md5 from "md5";
import vueTable from "../component/table.vue";
import changeItem from "../component/changeItem.vue";
import _ from "lodash";
@ -48,6 +60,8 @@ import {
getUser, //user
updatePassword,//
} from "@/api/teacher";
import io from "socket.io-client";
import { ElMessage, ElMessageBox } from 'element-plus'
export default {
name: "teacher",
components: { vueTable, changeItem },
@ -188,6 +202,9 @@ export default {
formHeader: [],
formHeaderLocal: [],
formDisabled: false,
ws: null,
videoStream: null,
room: 'defaultRoom', //
};
},
watch: {},
@ -196,8 +213,9 @@ export default {
this.dealTableHeader()
this.dealFormHeader()
await this.init();
await this.initWebSocket()
},
beforeUnmount() { },
methods: {
dealTableHeader() {
this.tableHeader = _.filter(this.localComponent, o => {
@ -332,7 +350,59 @@ export default {
});
})
},
//
async initWebSocket() {
this.ws = new WebSocket(`ws://127.0.0.1:5000/ws/video`);
console.log(787844, this.ws)
this.ws.binaryType = 'arraybuffer';
this.ws.onopen = () => {
console.log(4, 'WebSocket connected');
this.ws.send(JSON.stringify({ type: 'join', room: this.room }));
};
this.ws.onerror = (err) => {
console.error(5, 'WebSocket error:', err);
};
this.ws.onclose = () => {
console.log(6, 'WebSocket disconnected');
};
this.ws.onmessage = (event) => {
//
const arrayBuffer = event.data;
const blob = new Blob([arrayBuffer], { type: 'image/jpeg' });
const urlCreator = window.URL || window.webkitURL;
const imageUrl = urlCreator.createObjectURL(blob);
const img = new Image();
img.onload = function () {
urlCreator.revokeObjectURL(this.src);
};
img.src = imageUrl;
this.$refs.videoEL1.srcObject = null; //
this.$refs.videoEL1.src = imageUrl; //
this.$refs.videoEL1.play();
};
},
stopVideoStream() {
if (this.videoStream) {
this.videoStream.getTracks().forEach(track => track.stop());
}
},
closeWebSocket() {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.close();
}
},
},
beforeUnmount() {
this.stopVideoStream();
this.closeWebSocket();
},
};
</script>
<style scoped></style>
<style scoped>
.canvasClass {
position: relative;
width: 390px;
height: 390px;
background-color: blueviolet
}
</style>

22
test.py

@ -1,22 +0,0 @@
from flask import Flask, render_template
from flask_socketio import SocketIO, emit, Namespace
from threading import Thread, Event
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, cors_allowed_origins="*")
class MyCustomNamespace(Namespace):
def on_connect(self):
print('Client connected')
def on_disconnect(self):
print('Client disconnected')
def on_message(self, message):
emit('response', {'data': 'Got it!'}, broadcast=True)
socketio.on_namespace(MyCustomNamespace('/test'))
if __name__ == '__main__':
socketio.run(app, debug=True)
Loading…
Cancel
Save