Что я пытаюсь сделать
У меня есть лобби с игроками, и когда кто-то покидает лобби, я хочу обновить его для каждого клиента, чтобы отображался фактический список игроков.
Что я сделал
Чтобы избежать циклических запросов от внешнего интерфейса к внутреннему, я решил использовать web sockets
.Когда кто-то покидает лобби, запрос отправляется в REST api, а затем бэкэнд, после получения этого запроса, выполняет всю бизнес-логику, а затем «высовывает» это лобби, используя сокет, чтобы обновить всех клиентов в лобби.
Моя проблема
Все работает нормально, за исключением случая, когда пользователь закрывает браузер или вкладку, потому что я не могу отправить запрос в этом сценарии.(насколько я знаю, это невозможно сделать, используя javascript и beforeunload
событие, onDestroy()
методы и т. д.)
Мой вопрос
Это так?можно проверить на стороне сервера, отключен ли какой-либо сокет, и если да, то как я могу это сделать?Я также пытался использовать heartbeat
, который отправляется из внешнего интерфейса в бэкэнд, но я не знаю, как обработать это сообщение heartbeat
на стороне сервера.
Сторона сервера (весенняя загрузка)
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguartion implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/api/socket")
.setAllowedOrigins("*")
.withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
ThreadPoolTaskScheduler te = new ThreadPoolTaskScheduler();
te.setPoolSize(1);
te.setThreadNamePrefix("wss-heartbeat-thread-");
te.initialize();
config.enableSimpleBroker("/lobby")
.setHeartbeatValue(new long[]{0, 1000})
.setTaskScheduler(te);
}
}
@Controller
public class WebSocketController {
private final SimpMessagingTemplate template;
WebSocketController(SimpMessagingTemplate template) {
this.template = template;
}
public void pokeLobby(@DestinationVariable String lobbyName, SocketMessage message) {
this.template.convertAndSend("/lobby/"+lobbyName.toLowerCase(), message);
}
}
Клиентская сторона
connectToLobbyWebSocket(lobbyName: string): void {
const ws = new SockJS(this.addressStorage.apiAddress + '/socket');
this.stompClient = Stomp.over(ws);
// this.stompClient.debug = null;
const that = this;
this.stompClient.connect({}, function () {
that.stompClient.subscribe('/lobby/' + lobbyName, (message) => {
if (message.body) {
that.socketMessage.next(message.body); // do client logic
}
});
});
}