Skip to content

Commit fd2b69d

Browse files
committed
add userstatus endpoint
1 parent 3c9ac4e commit fd2b69d

File tree

6 files changed

+111
-14
lines changed

6 files changed

+111
-14
lines changed

src/main/java/com/bernd/ChatController.java

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,39 @@
33
import com.bernd.model.Chat;
44
import com.bernd.model.ChatMessage;
55
import com.bernd.model.ChatRequest;
6+
import com.bernd.model.Status;
7+
import com.bernd.model.StatusMap;
8+
import com.bernd.model.UserStatus;
69
import com.bernd.model.UsersMessage;
710
import com.bernd.util.Auth;
8-
import org.springframework.http.ResponseEntity;
11+
import com.bernd.util.Sender;
12+
import java.security.Principal;
13+
import java.util.List;
14+
import java.util.Map;
915
import org.springframework.messaging.core.MessageSendingOperations;
1016
import org.springframework.messaging.handler.annotation.MessageMapping;
1117
import org.springframework.stereotype.Controller;
1218
import org.springframework.web.bind.annotation.GetMapping;
1319
import org.springframework.web.bind.annotation.PathVariable;
1420
import org.springframework.web.bind.annotation.ResponseBody;
1521

16-
import java.security.Principal;
17-
import java.util.ArrayList;
18-
import java.util.TreeSet;
19-
import java.util.concurrent.atomic.AtomicInteger;
20-
2122
@Controller
2223
public class ChatController {
2324

2425
private final Chats chats;
2526
private final MessageSendingOperations<String> operations;
27+
private final Sender sender;
28+
private final StatusMap statusMap = new StatusMap();
29+
private long lastScan;
30+
private static final long SCAN_TIMEOUT = 120 * 1000;
2631

2732
ChatController(
2833
Chats chats,
29-
MessageSendingOperations<String> operations) {
34+
MessageSendingOperations<String> operations,
35+
Sender sender) {
3036
this.chats = chats;
3137
this.operations = operations;
38+
this.sender = sender;
3239
}
3340

3441
@ResponseBody
@@ -37,8 +44,8 @@ public Chat getChat(@PathVariable String id) {
3744
return chats.get(id);
3845
}
3946

40-
@MessageMapping("/chat/send/")
41-
public ResponseEntity<?> sendChat(ChatRequest chatRequest, Principal principal) {
47+
@MessageMapping("/chat/send")
48+
public void sendChat(ChatRequest chatRequest, Principal principal) {
4249
String user = Auth.getPrincipal(principal);
4350
Chat chat = chats.get(chatRequest.id());
4451
ChatMessage message = new ChatMessage(chat.counter().getAndIncrement(), chatRequest.message(), user);
@@ -47,6 +54,25 @@ public ResponseEntity<?> sendChat(ChatRequest chatRequest, Principal principal)
4754
operations.convertAndSend("/topic/users/" + chat.id(), new UsersMessage(chat.users()));
4855
}
4956
operations.convertAndSend("/topic/chat/" + chat.id(), message);
50-
return ResponseEntity.ok().build();
57+
}
58+
59+
@MessageMapping("/chat/status")
60+
public void updateStatus(Status status, Principal principal) {
61+
String user = Auth.getPrincipal(principal);
62+
UserStatus old = statusMap.put(user, UserStatus.create(status.room()));
63+
if (lastScan + SCAN_TIMEOUT < System.currentTimeMillis()) {
64+
Map<String, List<String>> allRooms = statusMap.allRooms();
65+
for (Map.Entry<String, List<String>> e : allRooms.entrySet()) {
66+
String room = e.getKey();
67+
List<String> users = e.getValue();
68+
sender.sendUsers(room, users);
69+
}
70+
lastScan = System.currentTimeMillis();
71+
} else if (old == null) {
72+
sender.sendUsers(status.room(), statusMap.usersInRoom(status.room()));
73+
} else if (!old.room().equals(status.room())) {
74+
sender.sendUsers(status.room(), statusMap.usersInRoom(status.room()));
75+
sender.sendUsers(status.room(), statusMap.usersInRoom(old.room()));
76+
}
5177
}
5278
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
package com.bernd.model;
22

3-
public record Status(String name, String status) {
4-
}
3+
public record Status(String room) {
4+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.bernd.model;
2+
3+
import java.util.ArrayList;
4+
import java.util.LinkedHashMap;
5+
import java.util.List;
6+
import java.util.Map;
7+
8+
public final class StatusMap {
9+
private static final long USER_TIMEOUT = 90 * 1000;
10+
private final Map<String, UserStatus> map = new LinkedHashMap<>();
11+
12+
public UserStatus put(String user, UserStatus status) {
13+
return map.put(user, status);
14+
}
15+
16+
public List<String> usersInRoom(String room) {
17+
List<String> result = new ArrayList<>();
18+
for (Map.Entry<String, UserStatus> e : map.entrySet()) {
19+
if (e.getValue().room().equals(room)) {
20+
result.add(e.getKey());
21+
}
22+
}
23+
return result;
24+
}
25+
26+
public Map<String, List<String>> allRooms() {
27+
long current = System.currentTimeMillis();
28+
Map<String, List<String>> result = new LinkedHashMap<>();
29+
List<String> remove = new ArrayList<>();
30+
for (Map.Entry<String, UserStatus> e : map.entrySet()) {
31+
UserStatus status = e.getValue();
32+
String user = e.getKey();
33+
if (status.lastSeen() + USER_TIMEOUT < current) {
34+
remove.add(user);
35+
} else {
36+
result.computeIfAbsent(status.room(), key -> new ArrayList<>())
37+
.add(user);
38+
}
39+
}
40+
for (String user : remove) {
41+
map.remove(user);
42+
}
43+
return result;
44+
}
45+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.bernd.model;
2+
3+
public record UserStatus(String room, long lastSeen) {
4+
public static UserStatus create(String room) {
5+
return new UserStatus(room, System.currentTimeMillis());
6+
}
7+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.bernd.model;
22

3-
import java.util.Set;
3+
import java.util.Collection;
44

55
public record UsersMessage(
6-
Set<String> users) {
6+
Collection<String> users) {
77
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.bernd.util;
2+
3+
import com.bernd.model.UsersMessage;
4+
import java.util.Collection;
5+
import org.springframework.messaging.core.MessageSendingOperations;
6+
import org.springframework.stereotype.Component;
7+
8+
@Component
9+
public final class Sender {
10+
private final MessageSendingOperations<String> operations;
11+
12+
Sender(MessageSendingOperations<String> operations) {
13+
this.operations = operations;
14+
}
15+
16+
public void sendUsers(String room, Collection<String> users) {
17+
operations.convertAndSend("/topic/users/" + room, new UsersMessage(users));
18+
}
19+
}

0 commit comments

Comments
 (0)