classroom düzeltmeler
This commit is contained in:
parent
b67080646c
commit
8acbd2e257
8 changed files with 62 additions and 75 deletions
|
|
@ -372,6 +372,7 @@ public class ClassroomHub : Hub
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// 1. Attendance kapat
|
||||||
var attendances = await _attendanceRepository.GetListAsync(
|
var attendances = await _attendanceRepository.GetListAsync(
|
||||||
x => x.SessionId == sessionId && x.StudentId == participantId && x.LeaveTime == null
|
x => x.SessionId == sessionId && x.StudentId == participantId && x.LeaveTime == null
|
||||||
);
|
);
|
||||||
|
|
@ -381,42 +382,60 @@ public class ClassroomHub : Hub
|
||||||
foreach (var attendance in attendances)
|
foreach (var attendance in attendances)
|
||||||
{
|
{
|
||||||
await CloseAttendanceAsync(attendance);
|
await CloseAttendanceAsync(attendance);
|
||||||
await Clients.Group(sessionId.ToString()).SendAsync("AttendanceUpdated", attendance);
|
await Clients.Group(sessionId.ToString())
|
||||||
|
.SendAsync("AttendanceUpdated", attendance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. Participant bul
|
||||||
var participant = await _participantRepository.FirstOrDefaultAsync(
|
var participant = await _participantRepository.FirstOrDefaultAsync(
|
||||||
x => x.SessionId == sessionId && x.UserId == participantId
|
x => x.SessionId == sessionId && x.UserId == participantId
|
||||||
);
|
);
|
||||||
|
|
||||||
if (participant != null && !string.IsNullOrEmpty(participant.ConnectionId))
|
if (participant == null)
|
||||||
{
|
{
|
||||||
await Clients.Client(participant.ConnectionId)
|
_logger.LogWarning("KickParticipant: Session {SessionId} için participant {ParticipantId} bulunamadı",
|
||||||
.SendAsync("ForceDisconnect", "You have been removed from the class.");
|
sessionId, participantId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await Groups.RemoveFromGroupAsync(participant.ConnectionId, sessionId.ToString());
|
// ConnectionId'yi kaydet (DB'ye null yazmadan önce)
|
||||||
|
var connectionId = participant.ConnectionId;
|
||||||
|
|
||||||
// ❌ pasif + ✅ kicked işaretle
|
// 3. DB'de kick flag setle
|
||||||
participant.IsActive = false;
|
participant.IsActive = false;
|
||||||
participant.IsKicked = true;
|
participant.IsKicked = true;
|
||||||
participant.ConnectionId = null;
|
participant.ConnectionId = null;
|
||||||
|
|
||||||
await _participantRepository.UpdateAsync(participant, autoSave: true);
|
await _participantRepository.UpdateAsync(participant, autoSave: true);
|
||||||
|
|
||||||
await Clients.Group(sessionId.ToString())
|
// 4. Hedef kullanıcıya bildir
|
||||||
.SendAsync("ParticipantLeft", new { UserId = participantId, SessionId = sessionId });
|
if (!string.IsNullOrEmpty(connectionId))
|
||||||
|
{
|
||||||
|
await Clients.Client(connectionId)
|
||||||
|
.SendAsync("ForceDisconnect", "You have been removed from the class.");
|
||||||
|
|
||||||
|
await Groups.RemoveFromGroupAsync(connectionId, sessionId.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 5. Diğer katılımcılara bildir
|
||||||
|
await Clients.Group(sessionId.ToString())
|
||||||
|
.SendAsync("ParticipantLeft", new { UserId = participantId, SessionId = sessionId });
|
||||||
|
|
||||||
// 3. Diğerlerine duyur
|
// 6. Log
|
||||||
_logger.LogInformation("👢 Participant {ParticipantId} kicked from session {SessionId}", participantId, sessionId);
|
_logger.LogInformation("👢 Participant {ParticipantId} kicked from session {SessionId}",
|
||||||
|
participantId, sessionId);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "❌ KickParticipant hata verdi");
|
_logger.LogError(ex, "❌ KickParticipant hata verdi (Session={SessionId}, Participant={ParticipantId})",
|
||||||
|
sessionId, participantId);
|
||||||
|
|
||||||
await Clients.Caller.SendAsync("Error", "Kick işlemi başarısız oldu.");
|
await Clients.Caller.SendAsync("Error", "Kick işlemi başarısız oldu.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[HubMethodName("ApproveHandRaise")]
|
[HubMethodName("ApproveHandRaise")]
|
||||||
public async Task ApproveHandRaiseAsync(Guid sessionId, Guid studentId)
|
public async Task ApproveHandRaiseAsync(Guid sessionId, Guid studentId)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -281,8 +281,7 @@ const RoomDetail: React.FC = () => {
|
||||||
signalRServiceRef.current.setParticipantJoinHandler(
|
signalRServiceRef.current.setParticipantJoinHandler(
|
||||||
async (userId: string, name: string, isTeacher: boolean, isActive: boolean) => {
|
async (userId: string, name: string, isTeacher: boolean, isActive: boolean) => {
|
||||||
if (userId === user.id) return
|
if (userId === user.id) return
|
||||||
if (!isActive) return // ❌ pasif kullanıcıyı ekleme
|
if (!isActive) return
|
||||||
if (isTeacher) setTeacherDisconnected(false)
|
|
||||||
|
|
||||||
console.log(`Participant joined: ${name}, isTeacher: ${isTeacher}`)
|
console.log(`Participant joined: ${name}, isTeacher: ${isTeacher}`)
|
||||||
|
|
||||||
|
|
@ -296,31 +295,19 @@ const RoomDetail: React.FC = () => {
|
||||||
isTeacher,
|
isTeacher,
|
||||||
isAudioMuted: classSettings.defaultMicrophoneState === 'muted',
|
isAudioMuted: classSettings.defaultMicrophoneState === 'muted',
|
||||||
isVideoMuted: classSettings.defaultCameraState === 'off',
|
isVideoMuted: classSettings.defaultCameraState === 'off',
|
||||||
isActive: isActive, // ✅ state’de tut
|
isActive: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
return updated
|
||||||
|
})
|
||||||
|
|
||||||
// ✅ güncel listedeki öğretmen kontrolü
|
// 🔑 Mesh: Herkes herkese offer gönderir
|
||||||
const teacherExists = updated.some((p) => p.isTeacher && p.isActive)
|
|
||||||
|
|
||||||
if (teacherExists) {
|
|
||||||
;(async () => {
|
|
||||||
if (!webRTCServiceRef.current?.getPeerConnection(userId)) {
|
if (!webRTCServiceRef.current?.getPeerConnection(userId)) {
|
||||||
await webRTCServiceRef.current?.createPeerConnection(userId)
|
await webRTCServiceRef.current?.createPeerConnection(userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ öğretmen ise her zaman offer başlatır
|
|
||||||
if (isActive) {
|
|
||||||
if (user.role === 'teacher') {
|
|
||||||
const offer = await webRTCServiceRef.current!.createOffer(userId)
|
const offer = await webRTCServiceRef.current!.createOffer(userId)
|
||||||
await signalRServiceRef.current?.sendOffer(classSession.id, userId, offer)
|
await signalRServiceRef.current?.sendOffer(classSession.id, userId, offer)
|
||||||
}
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
}
|
|
||||||
|
|
||||||
return updated
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -329,12 +316,12 @@ const RoomDetail: React.FC = () => {
|
||||||
async (
|
async (
|
||||||
existing: { userId: string; userName: string; isTeacher: boolean; isActive: boolean }[],
|
existing: { userId: string; userName: string; isTeacher: boolean; isActive: boolean }[],
|
||||||
) => {
|
) => {
|
||||||
setParticipants((prev) => {
|
|
||||||
let updated = [...prev]
|
|
||||||
|
|
||||||
for (const participant of existing) {
|
for (const participant of existing) {
|
||||||
if (!participant.isActive) continue // ❌ pasif kullanıcıyı alma
|
if (!participant.isActive) continue
|
||||||
if (participant.userId === user.id) continue
|
if (participant.userId === user.id) continue
|
||||||
|
|
||||||
|
setParticipants((prev) => {
|
||||||
|
const updated = [...prev]
|
||||||
if (!updated.find((p) => p.id === participant.userId)) {
|
if (!updated.find((p) => p.id === participant.userId)) {
|
||||||
updated.push({
|
updated.push({
|
||||||
id: participant.userId,
|
id: participant.userId,
|
||||||
|
|
@ -343,39 +330,20 @@ const RoomDetail: React.FC = () => {
|
||||||
isTeacher: participant.isTeacher,
|
isTeacher: participant.isTeacher,
|
||||||
isAudioMuted: classSettings.defaultMicrophoneState === 'muted',
|
isAudioMuted: classSettings.defaultMicrophoneState === 'muted',
|
||||||
isVideoMuted: classSettings.defaultCameraState === 'off',
|
isVideoMuted: classSettings.defaultCameraState === 'off',
|
||||||
isActive: participant.isActive, // ✅ state’de tut
|
isActive: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
return updated
|
||||||
|
})
|
||||||
// ✅ güncel listede öğretmen var mı?
|
|
||||||
const teacherExists = updated.some((p) => p.isTeacher && p.isActive)
|
|
||||||
|
|
||||||
if (teacherExists) {
|
|
||||||
;(async () => {
|
|
||||||
for (const participant of existing) {
|
|
||||||
if (!participant.isActive) continue
|
|
||||||
if (participant.userId === user.id) continue
|
|
||||||
|
|
||||||
if (!webRTCServiceRef.current?.getPeerConnection(participant.userId)) {
|
if (!webRTCServiceRef.current?.getPeerConnection(participant.userId)) {
|
||||||
await webRTCServiceRef.current?.createPeerConnection(participant.userId)
|
await webRTCServiceRef.current?.createPeerConnection(participant.userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ sadece öğretmen offer başlatır
|
// 🔑 Mesh: yeni gelen user da karşıya offer yollar
|
||||||
if (user.role === 'teacher') {
|
|
||||||
const offer = await webRTCServiceRef.current!.createOffer(participant.userId)
|
const offer = await webRTCServiceRef.current!.createOffer(participant.userId)
|
||||||
await signalRServiceRef.current?.sendOffer(
|
await signalRServiceRef.current?.sendOffer(classSession.id, participant.userId, offer)
|
||||||
classSession.id,
|
|
||||||
participant.userId,
|
|
||||||
offer,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})()
|
|
||||||
}
|
|
||||||
|
|
||||||
return updated
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue