aboutsummaryrefslogtreecommitdiff
path: root/juick-server/src/main/java/com/juick/server/WebsocketManager.java
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2018-02-08 22:06:08 +0300
committerGravatar Vitaly Takmazov2018-02-08 22:06:08 +0300
commit7414f1034d32c249294a081f1e176a9266fc92ac (patch)
treec780ea6f8a4a4d4db22147b1eea151317765abce /juick-server/src/main/java/com/juick/server/WebsocketManager.java
parentc97d1475dc0faa0e791257ca6c6a8561df2ffa90 (diff)
reorganize project structure
Diffstat (limited to 'juick-server/src/main/java/com/juick/server/WebsocketManager.java')
-rw-r--r--juick-server/src/main/java/com/juick/server/WebsocketManager.java163
1 files changed, 163 insertions, 0 deletions
diff --git a/juick-server/src/main/java/com/juick/server/WebsocketManager.java b/juick-server/src/main/java/com/juick/server/WebsocketManager.java
new file mode 100644
index 00000000..6e3fbea2
--- /dev/null
+++ b/juick-server/src/main/java/com/juick/server/WebsocketManager.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2008-2017, Juick
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.juick.server;
+
+import com.juick.User;
+import com.juick.server.helpers.AnonymousUser;
+import com.juick.server.util.HttpBadRequestException;
+import com.juick.server.util.HttpForbiddenException;
+import com.juick.server.util.HttpNotFoundException;
+import com.juick.service.MessagesService;
+import com.juick.service.SubscriptionService;
+import com.juick.service.UserService;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpHeaders;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.web.socket.CloseStatus;
+import org.springframework.web.socket.PingMessage;
+import org.springframework.web.socket.WebSocketSession;
+import org.springframework.web.socket.handler.TextWebSocketHandler;
+import org.springframework.web.util.UriComponents;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import javax.inject.Inject;
+import java.io.IOException;
+import java.net.URI;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Created by vitalyster on 28.06.2016.
+ */
+public class WebsocketManager extends TextWebSocketHandler {
+ private static final Logger logger = LoggerFactory.getLogger(WebsocketManager.class);
+
+ private final List<SocketSubscribed> clients = Collections.synchronizedList(new LinkedList<>());
+
+ @Inject
+ private UserService userService;
+ @Inject
+ private MessagesService messagesService;
+ @Inject
+ private SubscriptionService subscriptionService;
+
+
+ @Override
+ public void afterConnectionEstablished(WebSocketSession session) throws Exception {
+ URI hLocation;
+ String hXRealIP;
+
+ hLocation = session.getUri();
+ HttpHeaders headers = session.getHandshakeHeaders();
+ hXRealIP = headers.getOrDefault("X-Real-IP",
+ Collections.singletonList(session.getRemoteAddress().toString())).get(0);
+
+ // Auth
+ User visitor = AnonymousUser.INSTANCE;
+ UriComponents uriComponents = UriComponentsBuilder.fromUri(hLocation).build();
+ List<String> hash = uriComponents.getQueryParams().get("hash");
+ if (hash != null && hash.get(0).length() == 16) {
+ visitor = userService.getUserByHash(hash.get(0));
+ } else {
+ logger.debug("wrong hash for {} from {}", visitor.getUid(), hXRealIP);
+ }
+
+ int MID = 0;
+ SocketSubscribed sockSubscr = null;
+ if (hLocation.getPath().equals("/ws/")) {
+ logger.debug("user {} connected", visitor.getUid());
+ sockSubscr = new SocketSubscribed(session, hXRealIP, visitor, false);
+ } else if (hLocation.getPath().equals("/ws/_all")) {
+ logger.debug("user {} connected to legacy _all ({})", visitor.getUid(), hLocation.getPath());
+ sockSubscr = new SocketSubscribed(session, hXRealIP, visitor, true);
+ sockSubscr.allMessages = true;
+ } else if (hLocation.getPath().equals("/ws/_replies")) {
+ logger.debug("user {} connected to legacy _replies ({})", visitor.getUid(), hLocation.getPath());
+ sockSubscr = new SocketSubscribed(session, hXRealIP, visitor, true);
+ sockSubscr.allReplies = true;
+ } else if (hLocation.getPath().matches("^/ws/(\\d)+$")) {
+ MID = NumberUtils.toInt(hLocation.getPath().substring(4), 0);
+ if (MID > 0) {
+ if (messagesService.canViewThread(MID, visitor.getUid())) {
+ logger.debug("user {} connected to legacy thread ({}) from {}", visitor.getUid(), MID, hXRealIP);
+ sockSubscr = new SocketSubscribed(session, hXRealIP, visitor, true);
+ sockSubscr.MID = MID;
+ } else {
+ throw new HttpForbiddenException();
+ }
+ }
+ } else {
+ throw new HttpNotFoundException();
+ }
+ if (sockSubscr != null) {
+ synchronized (clients) {
+ clients.add(sockSubscr);
+ logger.debug("{} clients connected", clients.size());
+ }
+ } else {
+ throw new HttpBadRequestException();
+ }
+ }
+
+ @Override
+ public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
+ synchronized (clients) {
+ logger.debug("session closed with status {}: {}", status.getCode(), status.getReason());
+ clients.removeIf(c -> c.session.getId().equals(session.getId()));
+ logger.debug("{} clients connected", clients.size());
+ }
+
+ }
+
+ @Scheduled(fixedRate = 30000)
+ public void ping() {
+ clients.forEach(c -> {
+ try {
+ c.session.sendMessage(new PingMessage());
+ } catch (IOException e) {
+ logger.error("WebSocket PING exception", e);
+ }
+ });
+ }
+ public List<SocketSubscribed> getClients() {
+ return clients;
+ }
+
+ class SocketSubscribed {
+ WebSocketSession session;
+ String clientName;
+ User visitor;
+ int MID;
+ boolean allMessages;
+ boolean allReplies;
+ long tsConnected;
+ long tsLastData;
+ boolean legacy;
+
+ public SocketSubscribed(WebSocketSession session, String clientName, User visitor, boolean legacy) {
+ this.session = session;
+ this.clientName = clientName;
+ this.visitor = visitor;
+ tsConnected = tsLastData = System.currentTimeMillis();
+ this.legacy = legacy;
+ }
+ }
+}