Skip to content

Commit e131c4f

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

File tree

6 files changed

+114
-14
lines changed

6 files changed

+114
-14
lines changed

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

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,40 @@
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

25+
private static final long SCAN_TIMEOUT = 120 * 1000;
26+
2427
private final Chats chats;
2528
private final MessageSendingOperations<String> operations;
29+
private final Sender sender;
30+
private final StatusMap statusMap = new StatusMap();
31+
private long lastScan;
2632

2733
ChatController(
2834
Chats chats,
29-
MessageSendingOperations<String> operations) {
35+
MessageSendingOperations<String> operations,
36+
Sender sender) {
3037
this.chats = chats;
3138
this.operations = operations;
39+
this.sender = sender;
3240
}
3341

3442
@ResponseBody
@@ -37,8 +45,8 @@ public Chat getChat(@PathVariable String id) {
3745
return chats.get(id);
3846
}
3947

40-
@MessageMapping("/chat/send/")
41-
public ResponseEntity<?> sendChat(ChatRequest chatRequest, Principal principal) {
48+
@MessageMapping("/chat/send")
49+
public void sendChat(ChatRequest chatRequest, Principal principal) {
4250
String user = Auth.getPrincipal(principal);
4351
Chat chat = chats.get(chatRequest.id());
4452
ChatMessage message = new ChatMessage(chat.counter().getAndIncrement(), chatRequest.message(), user);
@@ -47,6 +55,25 @@ public ResponseEntity<?> sendChat(ChatRequest chatRequest, Principal principal)
4755
operations.convertAndSend("/topic/users/" + chat.id(), new UsersMessage(chat.users()));
4856
}
4957
operations.convertAndSend("/topic/chat/" + chat.id(), message);
50-
return ResponseEntity.ok().build();
58+
}
59+
60+
@MessageMapping("/chat/status")
61+
public void updateStatus(Status status, Principal principal) {
62+
String user = Auth.getPrincipal(principal);
63+
UserStatus old = statusMap.put(user, UserStatus.create(status.room()));
64+
if (lastScan + SCAN_TIMEOUT < System.currentTimeMillis()) {
65+
Map<String, List<String>> allRooms = statusMap.allRooms();
66+
for (Map.Entry<String, List<String>> e : allRooms.entrySet()) {
67+
String room = e.getKey();
68+
List<String> users = e.getValue();
69+
sender.sendUsers(room, users);
70+
}
71+
lastScan = System.currentTimeMillis();
72+
} else if (old == null) {
73+
sender.sendUsers(status.room(), statusMap.usersInRoom(status.room()));
74+
} else if (!old.room().equals(status.room())) {
75+
sender.sendUsers(status.room(), statusMap.usersInRoom(status.room()));
76+
sender.sendUsers(status.room(), statusMap.usersInRoom(old.room()));
77+
}
5178
}
5279
}
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: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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+
10+
private static final long USER_TIMEOUT = 90 * 1000;
11+
12+
private final Map<String, UserStatus> map = new LinkedHashMap<>();
13+
14+
public UserStatus put(String user, UserStatus status) {
15+
return map.put(user, status);
16+
}
17+
18+
public List<String> usersInRoom(String room) {
19+
List<String> result = new ArrayList<>();
20+
for (Map.Entry<String, UserStatus> e : map.entrySet()) {
21+
if (e.getValue().room().equals(room)) {
22+
result.add(e.getKey());
23+
}
24+
}
25+
return result;
26+
}
27+
28+
public Map<String, List<String>> allRooms() {
29+
long current = System.currentTimeMillis();
30+
Map<String, List<String>> result = new LinkedHashMap<>();
31+
List<String> remove = new ArrayList<>();
32+
for (Map.Entry<String, UserStatus> e : map.entrySet()) {
33+
UserStatus status = e.getValue();
34+
String user = e.getKey();
35+
if (status.lastSeen() + USER_TIMEOUT < current) {
36+
remove.add(user);
37+
} else {
38+
result.computeIfAbsent(status.room(), key -> new ArrayList<>())
39+
.add(user);
40+
}
41+
}
42+
for (String user : remove) {
43+
map.remove(user);
44+
}
45+
return result;
46+
}
47+
}
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)