package com.juick.ws; import com.juick.User; import com.juick.server.MessagesQueries; import com.juick.server.UserQueries; import org.apache.http.NameValuePair; import org.apache.http.client.utils.URLEncodedUtils; import org.springframework.http.HttpHeaders; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; import javax.inject.Inject; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** * Created by vitalyster on 28.06.2016. */ @Component public class WebsocketComponent extends TextWebSocketHandler { @Inject JdbcTemplate jdbc; private static final Logger logger = Logger.getLogger(WebsocketComponent.class.getName()); final List clients = Collections.synchronizedList(new ArrayList()); @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 = new User(); List params = URLEncodedUtils.parse(hLocation, "UTF-8"); for (NameValuePair param : params) { if (param.getName().equals("hash")) { String hash = param.getValue(); if (hash.length() == 16) { visitor = UserQueries.getUserByHash(jdbc, hash); } else { try { logger.info(String.format("wrong hash for %d from %s", visitor.getUID(), hXRealIP)); session.close(new CloseStatus(403, "Forbidden")); } catch (IOException e) { logger.log(Level.WARNING, "ws error", e); } } break; } } logger.info(String.format("user %d connected to %s from %s", visitor.getUID(), hLocation.getPath(), hXRealIP)); int MID = 0; SocketSubscribed sockSubscr = null; if (hLocation.getPath().equals("/")) { logger.info(String.format("user %d connected", visitor.getUID())); sockSubscr = new SocketSubscribed(session, hXRealIP, visitor, false); } else if (hLocation.getPath().equals("/_all")) { logger.info(String.format("user %d connected to legacy _all (%s)", visitor.getUID(), hLocation.getPath())); sockSubscr = new SocketSubscribed(session, hXRealIP, visitor, true); sockSubscr.allMessages = true; } else if (hLocation.getPath().equals("/_replies")) { logger.info(String.format("user %d connected to legacy _replies (%s)", visitor.getUID(), hLocation.getPath())); sockSubscr = new SocketSubscribed(session, hXRealIP, visitor, true); sockSubscr.allReplies = true; } else if (hLocation.getPath().matches("/\\d+$")) { try { MID = Integer.parseInt(hLocation.getPath().substring(8)); } catch (Exception e) { } if (MID > 0) { if (MessagesQueries.canViewThread(jdbc, MID, visitor.getUID())) { logger.info(String.format("user %d connected to legacy thread (%d) from %s", visitor.getUID(), MID, hXRealIP)); sockSubscr = new SocketSubscribed(session, hXRealIP, visitor, true); sockSubscr.MID = MID; } else { try { session.close(new CloseStatus(403, "Forbidden")); } catch (IOException e) { logger.log(Level.WARNING, "ws error", e); } } } } if (sockSubscr != null) { clients.add(sockSubscr); } } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { synchronized (clients) { clients.removeIf(c -> { if (c.session.equals(session)) { logger.info(String.format("session from %s closed with status %d", c.clientName, status.getCode())); return true; } return false; }); } } 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; } } }