Skip to content

Commit c4893ca

Browse files
authored
Merge pull request #69 from CS3219-AY2425S1/collab-post-ms6-risky
Unify expiry handling with main collab-post-ms6 branch
2 parents 092d26a + 52b21d6 commit c4893ca

File tree

11 files changed

+169
-85
lines changed

11 files changed

+169
-85
lines changed

collab/main.go

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"os"
1111
"strconv"
1212
"sync"
13+
"time"
1314

1415
"github.com/gin-gonic/gin"
1516
"github.com/gorilla/websocket"
@@ -22,7 +23,7 @@ const (
2223
AUTH_FAIL = "auth_fail"
2324
CLOSE_SESSION = "close_session"
2425
CONTENT_CHANGE = "content_change"
25-
PING = "ping"
26+
PING = "ping"
2627
)
2728

2829
var upgrader = websocket.Upgrader{
@@ -139,7 +140,9 @@ func (h *Hub) Run() {
139140
case message := <-h.broadcast:
140141
h.mutex.Lock()
141142
// Update the current workspace for this RoomID
142-
h.workspaces[message.RoomID] = message.Content
143+
if message.Content != "" {
144+
h.workspaces[message.RoomID] = message.Content
145+
}
143146
for client := range h.clients {
144147
if client.roomID == message.RoomID {
145148

@@ -162,8 +165,6 @@ func (h *Hub) Run() {
162165
h.mutex.Unlock()
163166
}
164167

165-
166-
167168
}
168169
}
169170

@@ -305,34 +306,48 @@ func handleMessages(
305306
// if msgData["type"] == "ping" {
306307
// //receives ping from client1, need to send a ping to client2
307308
// //eventually, if present, client2 will send the ping back, which will be broadcasted back to client1.
308-
309+
309310
// userID, _ := msgData["userId"].(string)
310311
// request := Message {
311312
// RoomID: client.roomID,
312313
// UserID: userID,
313314
// Content: []byte("ping request"),
314315
// }
315-
316+
316317
// hub.broadcast <- request
317318
// }
318319

319320
if msgData.Type == CLOSE_SESSION {
320321
closeMessage := Message{
322+
Type: CLOSE_SESSION,
321323
RoomID: client.roomID,
322324
Content: "The session has been closed by a user.",
323325
}
324326
targetId := msgData.UserID
325-
data, err := persistMappings.Conn.HGetAll(context.Background(), targetId).Result()
327+
ownData, err := persistMappings.Conn.HGetAll(context.Background(), targetId).Result()
326328
if err != nil {
327329
log.Printf("Error retrieving data for userID %s: %v", targetId, err)
328330
} else {
329-
_, err1 := persistMappings.Conn.Del(context.Background(), targetId).Result()
330-
if err1 != nil {
331-
log.Printf("Error deleting data for userID %s: %v", targetId, err1)
331+
// delete room under user id if it curr matches the room ID
332+
ownRoomId := ownData["roomId"]
333+
if ownRoomId == client.roomID {
334+
_, err := persistMappings.Conn.Del(context.Background(), targetId).Result()
335+
if err != nil {
336+
log.Printf("Error deleting data for userID %s: %v", targetId, err)
337+
}
332338
}
333-
_, err2 := persistMappings.Conn.Del(context.Background(), data["otherUser"]).Result()
334-
if err2 != nil {
335-
log.Printf("Error deleting data for other user %s: %v", data["otherUser"], err2)
339+
// delete room under other user if it curr matches the room ID
340+
otherUser := ownData["otherUser"]
341+
othRoomId, err := persistMappings.Conn.HGet(context.Background(), otherUser, "roomId").Result()
342+
if err != nil {
343+
log.Printf("Error retrieving data for otherUser %s: %v", otherUser, err)
344+
} else {
345+
if othRoomId == client.roomID {
346+
_, err := persistMappings.Conn.Del(context.Background(), otherUser).Result()
347+
if err != nil {
348+
log.Printf("Error deleting data for other user %s: %v", otherUser, err)
349+
}
350+
}
336351
}
337352
}
338353
hub.broadcast <- closeMessage
@@ -347,16 +362,30 @@ func handleMessages(
347362
} else if msgData.Type == PING {
348363
// Broadcast the message to other clients
349364
hub.broadcast <- Message{
350-
RoomID: client.roomID,
351-
Type: msgData.Type,
352-
UserID: msgData.UserID,
365+
RoomID: client.roomID,
366+
Type: msgData.Type,
367+
UserID: msgData.UserID,
353368
}
369+
370+
extendExpiryTime(msgData.UserID, persistMappings)
354371
} else {
355372
log.Printf("Unknown message type: %s", msgData.Type)
356373
}
357374
}
358375
}
359376

377+
func extendExpiryTime(userId string, persistMappings *verify.PersistMappings) {
378+
379+
ctx := context.Background()
380+
if err := persistMappings.Conn.Expire(ctx, userId, time.Minute*10).Err(); err != nil {
381+
log.Println("Error extending room time on ping: ", err.Error())
382+
} else {
383+
384+
log.Printf("expiration reset for 10 minutes for user %s: ", userId)
385+
}
386+
387+
}
388+
360389
type ClientWorkspace struct {
361390
Clients int `json:"clients"`
362391
Workspace string `json:"workspace"`

collab/verify/persistMappings.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,7 @@ func VerifyPersist(persistMappings *PersistMappings, roomID string, userID strin
3030
return false
3131
}
3232

33+
log.Printf("current roomID: %s, expected roomID: %s", data["roomId"], roomID)
34+
3335
return data["roomId"] == roomID
3436
}

collab/verify/roomMappings.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package verify
33
import (
44
"context"
55
"log"
6+
//"time"
67

78
redis "github.com/go-redis/redis/v8"
89
)
@@ -54,5 +55,13 @@ func VerifyRoomAndMoveToPersist(
5455
log.Printf("error sending room to persistent storage: %s", err.Error())
5556
}
5657

58+
/*
59+
if err := persistMappings.Conn.Expire(ctx, userId, 20 * time.Second).Err(); err != nil {
60+
log.Printf("error setting expiration for persisting room storage: %s", err.Error())
61+
} else {
62+
log.Printf("expiration set for 10 minutes for user %s: ", userId)
63+
64+
}
65+
*/
5766
return true
5867
}

comms/server.js

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,30 @@ const io = require("socket.io")(server, {
1515
io.on("connection", (socket) => {
1616
// emit endCall to the room it was in.
1717
socket.on("disconnecting", () => {
18-
socket.to(Array.from(socket.rooms))
19-
.except(socket.id)
20-
.emit("endCall");
18+
// for each room in the disconnecting socket...
19+
socket.rooms.forEach((target) => {
20+
// ignoring the room matching its own id...
21+
if (target === socket.id) {
22+
return;
23+
}
24+
// get the user ids within the room...
25+
io.sockets.adapter.rooms
26+
.get(target)
27+
.forEach(
28+
(id) => {
29+
// and for each user id in the room not matching
30+
// its own id...
31+
if (id === socket.id) {
32+
return;
33+
}
34+
// leave the target room...
35+
io.sockets.sockets.get(id).leave(target);
36+
console.log(id + " leaves " + target);
37+
// then tell the user id to endCall.
38+
io.to(id).emit("endCall");
39+
}
40+
);
41+
});
2142
});
2243

2344
// join a room and inform the peer that the other person has joined

peerprep/app/actions/server_actions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export async function hydrateUid(): Promise<null | UserData> {
9595
if (isError(json)) {
9696
console.log("Failed to fetch user ID.");
9797
console.log(`Error ${json.status}: ${json.error}`);
98-
redirect("/auth/logout");
98+
// redirect("/auth/logout");
9999
}
100100
// TODO: handle error handling
101101
const response = json as UserServiceResponse;

peerprep/app/questions/page.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,15 @@ import { hydrateUid } from "../actions/server_actions";
66
import { isError, Question, StatusBody, UserData } from "@/api/structs";
77
import { UserInfoProvider } from "@/contexts/UserInfoContext";
88
import { fetchAllQuestions } from "@/app/questions/helper";
9+
import { redirect } from "next/navigation";
910

1011
async function QuestionsPage() {
1112
const userData = (await hydrateUid()) as UserData;
1213

14+
if (!userData) {
15+
redirect("/auth/login");
16+
}
17+
1318
const questions: Question[] | StatusBody = await fetchAllQuestions();
1419

1520
if (isError(questions)) {

peerprep/components/navbar/ProfileDropdown.tsx

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
1-
"use client";
2-
31
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
42
import Image from "next/image";
53
import React from "react";
64
import Link from "next/link";
5+
import { UserData } from "@/api/structs";
6+
import { hydrateUid } from "@/app/actions/server_actions";
7+
8+
export const ProfileDropdown = async () => {
9+
let userData;
10+
try {
11+
userData = (await hydrateUid()) as UserData;
12+
} catch {
13+
userData = null;
14+
console.error("Error hydrating user data.");
15+
}
716

8-
export const ProfileDropdown = () => {
917
return (
1018
<div className="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0">
1119
{/* Profile dropdown */}
@@ -27,30 +35,34 @@ export const ProfileDropdown = () => {
2735
transition
2836
className="absolute right-0 z-10 mt-2 w-48 origin-top-right rounded-md bg-gray-1 py-1 shadow-lg ring-1 ring-black ring-opacity-5 transition focus:outline-none data-[closed]:scale-95 data-[closed]:transform data-[closed]:opacity-0 data-[enter]:duration-100 data-[leave]:duration-75 data-[enter]:ease-out data-[leave]:ease-in"
2937
>
30-
<MenuItem>
31-
<Link
32-
href="#"
33-
className="block px-4 py-2 text-sm data-[focus]:bg-gray-2"
34-
>
35-
Your Profile (Coming Soon)
36-
</Link>
37-
</MenuItem>
38-
<MenuItem>
39-
<Link
40-
href="#"
41-
className="block px-4 py-2 text-sm data-[focus]:bg-gray-2"
42-
>
43-
Settings (Coming Soon)
44-
</Link>
45-
</MenuItem>
46-
<MenuItem>
47-
<Link
48-
href="/auth/logout"
49-
className="block px-4 py-2 text-sm data-[focus]:bg-gray-2"
50-
>
51-
Sign out
52-
</Link>
53-
</MenuItem>
38+
{userData ? (
39+
<>
40+
<MenuItem>
41+
<div className="block px-4 py-2 text-sm text-white data-[focus]:bg-gray-2">
42+
Hello, {userData.username}!
43+
</div>
44+
</MenuItem>
45+
<MenuItem>
46+
<Link
47+
href="/auth/logout"
48+
className="block px-4 py-2 text-sm data-[focus]:bg-gray-2"
49+
>
50+
Sign out
51+
</Link>
52+
</MenuItem>
53+
</>
54+
) : (
55+
<>
56+
<MenuItem>
57+
<Link
58+
href="/auth/login"
59+
className="block px-4 py-2 text-sm data-[focus]:bg-gray-2"
60+
>
61+
Login
62+
</Link>
63+
</MenuItem>
64+
</>
65+
)}
5466
</MenuItems>
5567
</Menu>
5668
</div>

peerprep/components/questionpage/CollabEditor.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import CommsPanel from "./CommsPanel";
1919
// import { diff_match_patch } from "diff-match-patch";
2020
import { callFormatter } from "@/app/api/internal/formatter/helper";
2121
import { Ace } from "ace-builds";
22-
import { connect } from "http2";
2322

2423
const PING_INTERVAL_MILLISECONDS = 5000;
2524
const languages: Language[] = ["javascript", "python", "c_cpp"];
@@ -114,6 +113,7 @@ export default function CollabEditor({
114113
}
115114
} catch (e: unknown) {
116115
if (e instanceof Error) {
116+
alert(e.message);
117117
console.error(e.message);
118118
} else {
119119
console.error("An unknown error occurred");
@@ -265,7 +265,7 @@ export default function CollabEditor({
265265
const disconnectCheckInterval = setInterval(() => {
266266
if (
267267
lastPingReceived &&
268-
Date.now() - lastPingReceived > 2 * PING_INTERVAL_MILLISECONDS
268+
Date.now() - lastPingReceived > 3 * PING_INTERVAL_MILLISECONDS
269269
) {
270270
setOtherUserConnected(false);
271271
clearInterval(disconnectCheckInterval);
@@ -276,7 +276,7 @@ export default function CollabEditor({
276276
clearInterval(interval);
277277
clearInterval(disconnectCheckInterval);
278278
};
279-
}, [notifyRoomOfConnection, PING_INTERVAL_MILLISECONDS, connected, socket]);
279+
}, [notifyRoomOfConnection, connected, socket]);
280280

281281
const handleCloseConnection = () => {
282282
const confirmClose = confirm(

0 commit comments

Comments
 (0)