This commit is contained in:
@@ -5197,6 +5197,14 @@ input:checked + .slider:before {
|
|||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.grid-proctor-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.grid-proctor-layout {
|
.grid-proctor-layout {
|
||||||
/* Columns configured inline */
|
/* Columns configured inline */
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
|||||||
@@ -23,8 +23,16 @@ type SocketClient struct {
|
|||||||
StaffID uint
|
StaffID uint
|
||||||
Role string // "student" | "teacher"
|
Role string // "student" | "teacher"
|
||||||
Addr string
|
Addr string
|
||||||
|
writeMu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *SocketClient) WriteJSON(v any) error {
|
||||||
|
c.writeMu.Lock()
|
||||||
|
defer c.writeMu.Unlock()
|
||||||
|
return c.Conn.WriteJSON(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
type WsHub struct {
|
type WsHub struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
students map[int64]*SocketClient
|
students map[int64]*SocketClient
|
||||||
@@ -54,7 +62,7 @@ func (h *WsHub) PushExamToStudent(studentRkID int64, data map[string]any) {
|
|||||||
if !ok || client == nil {
|
if !ok || client == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = client.Conn.WriteJSON(SocketMsg{Event: "exam:paper-sent", Data: data})
|
_ = client.WriteJSON(SocketMsg{Event: "exam:paper-sent", Data: data})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *WsHub) PushChatToStudent(studentRkID int64, data map[string]any) {
|
func (h *WsHub) PushChatToStudent(studentRkID int64, data map[string]any) {
|
||||||
@@ -64,7 +72,7 @@ func (h *WsHub) PushChatToStudent(studentRkID int64, data map[string]any) {
|
|||||||
if !ok || client == nil {
|
if !ok || client == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = client.Conn.WriteJSON(SocketMsg{Event: "chat:message", Data: data})
|
_ = client.WriteJSON(SocketMsg{Event: "chat:message", Data: data})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *WsHub) PushChatToStaff(staffID uint, data map[string]any) {
|
func (h *WsHub) PushChatToStaff(staffID uint, data map[string]any) {
|
||||||
@@ -77,7 +85,7 @@ func (h *WsHub) PushChatToStaff(staffID uint, data map[string]any) {
|
|||||||
defer h.mu.RUnlock()
|
defer h.mu.RUnlock()
|
||||||
for _, t := range h.teachers {
|
for _, t := range h.teachers {
|
||||||
if t != nil && t.Role == "teacher" {
|
if t != nil && t.Role == "teacher" {
|
||||||
_ = t.Conn.WriteJSON(msg)
|
_ = t.WriteJSON(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,8 +115,8 @@ func (h *WsHub) Register(c *SocketClient) {
|
|||||||
h.students[c.StudentID] = c
|
h.students[c.StudentID] = c
|
||||||
log.Printf("[WS] Student %d registered (Address: %s, Class: %d)", c.StudentID, c.Addr, c.ClassID)
|
log.Printf("[WS] Student %d registered (Address: %s, Class: %d)", c.StudentID, c.Addr, c.ClassID)
|
||||||
if subs, exists := h.subscribers[c.StudentID]; exists && len(subs) > 0 {
|
if subs, exists := h.subscribers[c.StudentID]; exists && len(subs) > 0 {
|
||||||
_ = c.Conn.WriteJSON(SocketMsg{Event: "start_screenshot_stream"})
|
_ = c.WriteJSON(SocketMsg{Event: "start_screenshot_stream"})
|
||||||
_ = c.Conn.WriteJSON(SocketMsg{Event: "start_webcam_stream"})
|
_ = c.WriteJSON(SocketMsg{Event: "start_webcam_stream"})
|
||||||
log.Printf("[WS] Student %d has active subscribers. Sent start stream commands.", c.StudentID)
|
log.Printf("[WS] Student %d has active subscribers. Sent start stream commands.", c.StudentID)
|
||||||
}
|
}
|
||||||
} else if c.Role == "teacher" {
|
} else if c.Role == "teacher" {
|
||||||
@@ -132,7 +140,7 @@ func (h *WsHub) Unregister(c *SocketClient) {
|
|||||||
if teachers, exists := h.subscribers[c.StudentID]; exists {
|
if teachers, exists := h.subscribers[c.StudentID]; exists {
|
||||||
for _, tAddr := range teachers {
|
for _, tAddr := range teachers {
|
||||||
if t, found := h.teachers[tAddr]; found {
|
if t, found := h.teachers[tAddr]; found {
|
||||||
_ = t.Conn.WriteJSON(SocketMsg{
|
_ = t.WriteJSON(SocketMsg{
|
||||||
Event: "teacher:stream-stopped",
|
Event: "teacher:stream-stopped",
|
||||||
Data: map[string]any{"studentId": c.StudentID},
|
Data: map[string]any{"studentId": c.StudentID},
|
||||||
})
|
})
|
||||||
@@ -170,8 +178,8 @@ func (h *WsHub) Unregister(c *SocketClient) {
|
|||||||
delete(h.subscribers, sID)
|
delete(h.subscribers, sID)
|
||||||
// Nếu không còn ai xem học sinh này, gửi lệnh tắt camera/screen cho client học sinh
|
// Nếu không còn ai xem học sinh này, gửi lệnh tắt camera/screen cho client học sinh
|
||||||
if student, exists := h.students[sID]; exists {
|
if student, exists := h.students[sID]; exists {
|
||||||
_ = student.Conn.WriteJSON(SocketMsg{Event: "stop_screenshot_stream"})
|
_ = student.WriteJSON(SocketMsg{Event: "stop_screenshot_stream"})
|
||||||
_ = student.Conn.WriteJSON(SocketMsg{Event: "stop_webcam_stream"})
|
_ = student.WriteJSON(SocketMsg{Event: "stop_webcam_stream"})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
h.subscribers[sID] = newList
|
h.subscribers[sID] = newList
|
||||||
@@ -201,8 +209,8 @@ func (h *WsHub) Subscribe(teacherAddr string, studentID int64) {
|
|||||||
|
|
||||||
// Phát lệnh cho máy học sinh bật stream (nếu học sinh đang online)
|
// Phát lệnh cho máy học sinh bật stream (nếu học sinh đang online)
|
||||||
if student, exists := h.students[studentID]; exists {
|
if student, exists := h.students[studentID]; exists {
|
||||||
_ = student.Conn.WriteJSON(SocketMsg{Event: "start_screenshot_stream"})
|
_ = student.WriteJSON(SocketMsg{Event: "start_screenshot_stream"})
|
||||||
_ = student.Conn.WriteJSON(SocketMsg{Event: "start_webcam_stream"})
|
_ = student.WriteJSON(SocketMsg{Event: "start_webcam_stream"})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,8 +237,8 @@ func (h *WsHub) Unsubscribe(teacherAddr string, studentID int64) {
|
|||||||
|
|
||||||
// Báo học sinh tắt camera & screen stream để tiết kiệm mạng và CPU
|
// Báo học sinh tắt camera & screen stream để tiết kiệm mạng và CPU
|
||||||
if student, exists := h.students[studentID]; exists {
|
if student, exists := h.students[studentID]; exists {
|
||||||
_ = student.Conn.WriteJSON(SocketMsg{Event: "stop_screenshot_stream"})
|
_ = student.WriteJSON(SocketMsg{Event: "stop_screenshot_stream"})
|
||||||
_ = student.Conn.WriteJSON(SocketMsg{Event: "stop_webcam_stream"})
|
_ = student.WriteJSON(SocketMsg{Event: "stop_webcam_stream"})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
h.subscribers[studentID] = newList
|
h.subscribers[studentID] = newList
|
||||||
@@ -262,7 +270,7 @@ func (h *WsHub) RelayFrame(studentID int64, event string, data map[string]any) {
|
|||||||
|
|
||||||
for _, addr := range teachersList {
|
for _, addr := range teachersList {
|
||||||
if t, found := h.teachers[addr]; found {
|
if t, found := h.teachers[addr]; found {
|
||||||
_ = t.Conn.WriteJSON(msg)
|
_ = t.WriteJSON(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user