|
10 | 10 | */ |
11 | 11 | package org.eclipse.che.api.core.websocket.impl; |
12 | 12 |
|
13 | | -import java.util.ArrayList; |
14 | | -import java.util.HashMap; |
15 | | -import java.util.LinkedList; |
16 | | -import java.util.List; |
| 13 | +import com.google.common.collect.EvictingQueue; |
17 | 14 | import java.util.Map; |
18 | 15 | import java.util.Optional; |
| 16 | +import java.util.Queue; |
| 17 | +import java.util.concurrent.ConcurrentHashMap; |
19 | 18 | import javax.inject.Inject; |
20 | 19 | import javax.inject.Singleton; |
21 | 20 | import javax.websocket.Session; |
| 21 | +import org.eclipse.che.commons.schedule.ScheduleDelay; |
22 | 22 |
|
23 | 23 | /** |
24 | 24 | * Instance is responsible for re-sending messages that were not sent during the period when WEB |
|
29 | 29 | */ |
30 | 30 | @Singleton |
31 | 31 | public class MessagesReSender { |
| 32 | + |
32 | 33 | private static final int MAX_MESSAGES = 100; |
33 | 34 |
|
34 | 35 | private final WebSocketSessionRegistry registry; |
35 | 36 |
|
36 | | - private final Map<String, List<String>> messagesMap = new HashMap<>(); |
| 37 | + private final Map<String, Queue<DelayedMessage>> delayedMessageRegistry = |
| 38 | + new ConcurrentHashMap<>(); |
37 | 39 |
|
38 | 40 | @Inject |
39 | 41 | public MessagesReSender(WebSocketSessionRegistry registry) { |
40 | 42 | this.registry = registry; |
41 | 43 | } |
42 | 44 |
|
43 | | - public void add(String endpointId, String message) { |
44 | | - List<String> messages = messagesMap.get(endpointId); |
| 45 | + @ScheduleDelay(initialDelay = 60, delay = 60) |
| 46 | + void cleanStaleMessages() { |
| 47 | + long currentTimeMillis = System.currentTimeMillis(); |
45 | 48 |
|
46 | | - if (messages == null) { |
47 | | - messages = new LinkedList<>(); |
48 | | - messagesMap.put(endpointId, messages); |
49 | | - } |
| 49 | + delayedMessageRegistry |
| 50 | + .values() |
| 51 | + .forEach(it -> it.removeIf(m -> currentTimeMillis - m.timeMillis > 60_000)); |
50 | 52 |
|
51 | | - if (messages.size() <= MAX_MESSAGES) { |
52 | | - messages.add(message); |
53 | | - } |
| 53 | + delayedMessageRegistry.values().removeIf(Queue::isEmpty); |
| 54 | + } |
| 55 | + |
| 56 | + public void add(String endpointId, String message) { |
| 57 | + |
| 58 | + delayedMessageRegistry |
| 59 | + .computeIfAbsent(endpointId, k -> EvictingQueue.create(MAX_MESSAGES)) |
| 60 | + .offer(new DelayedMessage(message)); |
54 | 61 | } |
55 | 62 |
|
56 | 63 | public void resend(String endpointId) { |
57 | | - final List<String> messages = messagesMap.remove(endpointId); |
| 64 | + Queue<DelayedMessage> delayedMessages = delayedMessageRegistry.remove(endpointId); |
58 | 65 |
|
59 | | - if (messages == null || messages.isEmpty()) { |
| 66 | + if (delayedMessages == null || delayedMessages.isEmpty()) { |
60 | 67 | return; |
61 | 68 | } |
62 | 69 |
|
63 | | - final Optional<Session> sessionOptional = registry.get(endpointId); |
| 70 | + Optional<Session> sessionOptional = registry.get(endpointId); |
64 | 71 |
|
65 | 72 | if (!sessionOptional.isPresent()) { |
66 | 73 | return; |
67 | 74 | } |
68 | 75 |
|
69 | | - final Session session = sessionOptional.get(); |
70 | | - |
71 | | - final List<String> backing = new ArrayList<>(messages); |
72 | | - messages.clear(); |
73 | | - |
74 | | - for (String message : backing) { |
| 76 | + Queue<DelayedMessage> backingQueue = EvictingQueue.create(delayedMessages.size()); |
| 77 | + while (!delayedMessages.isEmpty()) { |
| 78 | + backingQueue.offer(delayedMessages.poll()); |
| 79 | + } |
75 | 80 |
|
| 81 | + Session session = sessionOptional.get(); |
| 82 | + for (DelayedMessage delayedMessage : backingQueue) { |
76 | 83 | if (session.isOpen()) { |
77 | | - session.getAsyncRemote().sendText(message); |
| 84 | + session.getAsyncRemote().sendText(delayedMessage.message); |
78 | 85 | } else { |
79 | | - messages.add(message); |
| 86 | + delayedMessages.add(delayedMessage); |
80 | 87 | } |
81 | 88 | } |
82 | 89 |
|
83 | | - messagesMap.put(endpointId, messages); |
| 90 | + if (!delayedMessages.isEmpty()) { |
| 91 | + delayedMessageRegistry.put(endpointId, delayedMessages); |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + private static class DelayedMessage { |
| 96 | + |
| 97 | + private final long timeMillis; |
| 98 | + private final String message; |
| 99 | + |
| 100 | + private DelayedMessage(String message) { |
| 101 | + this.message = message; |
| 102 | + this.timeMillis = System.currentTimeMillis(); |
| 103 | + } |
84 | 104 | } |
85 | 105 | } |
0 commit comments