From 74b06a344104f2c9aa30f4c602d615393a07bdc1 Mon Sep 17 00:00:00 2001 From: stzups Date: Sat, 3 Apr 2021 00:44:03 -0400 Subject: [PATCH 01/35] Improve debug --- .../src/main/java/net/stzups/board/server/websocket/Room.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/Room.java b/board-room/src/main/java/net/stzups/board/server/websocket/Room.java index 7ce71e85..b90e7953 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/Room.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/Room.java @@ -50,6 +50,7 @@ private Room(Document document) { static Room startRoom(Document document) { Room room = new Room(document); rooms.add(room); + BoardRoom.getLogger().info("Started room " + room); return room; } @@ -57,7 +58,7 @@ void end() { rooms.remove(this); BoardRoom.getDatabase().saveCanvas(canvas);//todo save interval and dirty flags //todo - BoardRoom.getLogger().info("Destroyed room for canvas " + canvas); + BoardRoom.getLogger().info("Ended room " + this); } Document getDocument() { From 06d09904ad043c5c1cf25e7678178b9e061e323f Mon Sep 17 00:00:00 2001 From: stzups Date: Sat, 3 Apr 2021 01:04:07 -0400 Subject: [PATCH 02/35] maybe make client save changes to document before switching documents --- frontend/html/scripts/Document.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/html/scripts/Document.js b/frontend/html/scripts/Document.js index ac90cb48..8254d693 100644 --- a/frontend/html/scripts/Document.js +++ b/frontend/html/scripts/Document.js @@ -49,7 +49,7 @@ class Document { } close() { - //localClient.update(); + localUpdate(); ctx.clearRect(0, 0, canvas.width, canvas.height);//todo a loading screen? this.clients.forEach((client) => { this.removeClient(client.id); @@ -159,13 +159,14 @@ const MAX_TIME = 2000; const UPDATE_INTERVAL = 1000; let lastUpdate = 0; let updateCanvas = new Canvas(); -setInterval(() => { +setInterval(localUpdate, UPDATE_INTERVAL); +function localUpdate() { lastUpdate = window.performance.now(); if (updateCanvas.updateCanvasObjects.size > 0) { socket.send(new ClientMessageUpdateCanvas(updateCanvas.updateCanvasObjects));//todo breaks the server when the size is 0 updateCanvas.updateCanvasObjects.clear(); } -}, UPDATE_INTERVAL); +} function getDt() { return (window.performance.now() - lastUpdate) / MAX_TIME * 255; From c70fe074a011383c7bffe95821d9bc0e62fdfa8c Mon Sep 17 00:00:00 2001 From: stzups Date: Sat, 3 Apr 2021 01:04:14 -0400 Subject: [PATCH 03/35] start to fix canvas not being saved --- CHANGELOG.md | 4 +++ .../database/postgres/PostgresDatabase.java | 13 +++++---- .../server/websocket/MessageHandler.java | 20 ++------------ .../stzups/board/server/websocket/Room.java | 27 +++++++++---------- 4 files changed, 24 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 444b216f..d285f123 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -89,3 +89,7 @@ Rework db, implement document persistence - Canvas is saved in db - Rework user authentication + +### v0.3.4 + +- Fix changes not being saved on canvas close diff --git a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java index 00611b82..d1687dce 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java +++ b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java @@ -10,6 +10,8 @@ import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.sql.Blob; import java.sql.Connection; import java.sql.DriverManager; @@ -119,12 +121,11 @@ public Canvas getCanvas(Document document) { preparedStatement.setLong(1, document.getId()); ResultSet resultSet = preparedStatement.executeQuery(); if (resultSet.next()) { - Blob blob = resultSet.getBlob("data"); - return new Canvas(document, Unpooled.wrappedBuffer(blob.getBytes(1, (int) blob.length()))); + return new Canvas(document, Unpooled.wrappedBuffer(resultSet.getBinaryStream("data").readAllBytes())); } else { return new Canvas(document); } - } catch (SQLException e) { + } catch (SQLException | IOException e) { e.printStackTrace(); } return null;//todo error handling?? @@ -133,13 +134,11 @@ public Canvas getCanvas(Document document) { @Override public void saveCanvas(Canvas canvas) { try { - PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO canvases(document, data) VALUES(?, ?) ON CONFLICT (document) DO UPDATE SET data=?"); + PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO canvases(document, data) VALUES(?, ?) ON CONFLICT (document) DO UPDATE SET data=excluded.data"); preparedStatement.setLong(1, canvas.getDocument().getId()); ByteBuf byteBuf = Unpooled.buffer(); canvas.serialize(byteBuf); - ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteBuf.array()); - preparedStatement.setBinaryStream(2, byteArrayInputStream); - preparedStatement.setBinaryStream(3, byteArrayInputStream);//todo is this duplicate bad? + preparedStatement.setBinaryStream(2, new ByteArrayInputStream(byteBuf.array())); preparedStatement.execute(); } catch (SQLException e) { e.printStackTrace(); diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java index 54b618d9..defa0cbe 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java @@ -19,7 +19,6 @@ import java.util.Map; public class MessageHandler extends SimpleChannelInboundHandler { - private static Map documents = new HashMap<>(); private Room room; private Client client; @@ -50,7 +49,7 @@ protected void channelRead0(ChannelHandlerContext ctx, ClientMessage message) { if (room != null) { room.removeClient(client); } - room = getRoom(document); + room = Room.getRoom(document); room.addClient(client); } else { System.out.println(client + " tried to open document not that does not exist"); @@ -63,7 +62,7 @@ protected void channelRead0(ChannelHandlerContext ctx, ClientMessage message) { room.removeClient(client); } try { - room = getRoom(BoardRoom.getDatabase().createDocument(client.getUser())); + room = Room.getRoom(BoardRoom.getDatabase().createDocument(client.getUser())); } catch (Exception e) { e.printStackTrace(); } @@ -126,19 +125,4 @@ private static Client createUserSession(ChannelHandlerContext ctx, User user) { BoardRoom.getDatabase().addUserSession(persistentUserSession); return client; } - - /** - * Gets or creates a room for an existing document - * - * @param document the existing document - * @return the live room - */ - private static Room getRoom(Document document) { - Room r = documents.get(document); - if (r == null) { - r = Room.startRoom(document); - documents.put(r.getDocument(), r); - } - return r; - } } diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/Room.java b/board-room/src/main/java/net/stzups/board/server/websocket/Room.java index b90e7953..b55602e0 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/Room.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/Room.java @@ -11,9 +11,8 @@ import net.stzups.board.server.websocket.protocol.server.messages.ServerMessageRemoveClient; import net.stzups.board.server.websocket.protocol.server.messages.ServerMessageUpdateCanvas; -import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.Timer; @@ -22,12 +21,12 @@ class Room { private static final int SEND_PERIOD = 1000; - private static List rooms = new ArrayList<>(); + private static Map rooms = new HashMap<>(); static { new Timer().scheduleAtFixedRate(new TimerTask() { @Override public void run() { - for (Room room : rooms) { + for (Room room : rooms.values()) { room.update(); } } @@ -38,24 +37,22 @@ public void run() { private Canvas canvas; - private Room(Document document) { + Room(Document document) { this.canvas = BoardRoom.getDatabase().getCanvas(document); + rooms.put(document, this); + BoardRoom.getLogger().info("Started room " + this); } - /** - * Creates a new room with a random id - * - * @return the created room - */ - static Room startRoom(Document document) { - Room room = new Room(document); - rooms.add(room); - BoardRoom.getLogger().info("Started room " + room); + static Room getRoom(Document document) { + Room room = rooms.get(document); + if (room == null) { + room = new Room(document); + } return room; } void end() { - rooms.remove(this); + rooms.remove(canvas.getDocument()); BoardRoom.getDatabase().saveCanvas(canvas);//todo save interval and dirty flags //todo BoardRoom.getLogger().info("Ended room " + this); From 1f8c1cfaf047b06f5bd6085766e46998df3ddf02 Mon Sep 17 00:00:00 2001 From: stzups Date: Sat, 3 Apr 2021 01:10:24 -0400 Subject: [PATCH 04/35] fix silly serialization issue --- .../java/net/stzups/board/data/objects/canvas/Canvas.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/board-room/src/main/java/net/stzups/board/data/objects/canvas/Canvas.java b/board-room/src/main/java/net/stzups/board/data/objects/canvas/Canvas.java index 4762034a..d0206225 100644 --- a/board-room/src/main/java/net/stzups/board/data/objects/canvas/Canvas.java +++ b/board-room/src/main/java/net/stzups/board/data/objects/canvas/Canvas.java @@ -23,11 +23,13 @@ public Canvas(Document document) { */ public Canvas(Document document, ByteBuf byteBuf) { this.document = document; - for (int i = 0; i < byteBuf.readUnsignedByte(); i++) { + int length = byteBuf.readUnsignedByte(); + for (int i = 0; i < length; i++) { CanvasObjectType canvasObjectType = CanvasObjectType.valueOf(byteBuf.readUnsignedByte()); Map map = new HashMap<>(); canvasObjects.put(canvasObjectType, map); - for (int j = 0; j < byteBuf.readUnsignedShort(); j++) { + int l = byteBuf.readUnsignedShort(); + for (int j = 0; j < l; j++) { map.put(byteBuf.readShort(), CanvasObject.getCanvasObject(canvasObjectType, byteBuf)); } } From d45c1364036cd13f61c34253eb1cad1f13835dfd Mon Sep 17 00:00:00 2001 From: stzups Date: Sat, 3 Apr 2021 10:10:15 -0400 Subject: [PATCH 05/35] cleanup --- CHANGELOG.md | 2 ++ .../net/stzups/board/server/websocket/MessageHandler.java | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d285f123..1bf0be64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -93,3 +93,5 @@ Rework db, implement document persistence ### v0.3.4 - Fix changes not being saved on canvas close +- Fix canvas serialization +- Fix connected clients list \ No newline at end of file diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java index defa0cbe..b9ca496b 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java @@ -74,7 +74,7 @@ protected void channelRead0(ChannelHandlerContext ctx, ClientMessage message) { ClientMessageHandshake clientPacketHandshake = (ClientMessageHandshake) message; if (client == null) { if (clientPacketHandshake.getToken() == 0) { - System.out.println("user authed with empty session"); + BoardRoom.getLogger().info(ctx.channel().remoteAddress() + " authenticated with blank session"); client = createUserSession(ctx, null); } else { PersistentUserSession persistentUserSession = BoardRoom.getDatabase().removeUserSession(clientPacketHandshake.getId()); @@ -97,10 +97,10 @@ protected void channelRead0(ChannelHandlerContext ctx, ClientMessage message) { } client.queueMessage(new ServerMessageAddUser(client.getUser())); if (client.getUser().getOwnedDocuments().size() == 0) { - client.queueMessage(new ServerMessageAddDocument(BoardRoom.getDatabase().createDocument(client.getUser()))); + client.queueMessage(new ServerMessageAddDocument(BoardRoom.getDatabase().createDocument(client.getUser())));//todo } else { for (long id : client.getUser().getOwnedDocuments()) { - client.queueMessage(new ServerMessageAddDocument(BoardRoom.getDatabase().getDocument(id))); + client.queueMessage(new ServerMessageAddDocument(BoardRoom.getDatabase().getDocument(id)));//todo aggregate } } client.flushMessages(); From 56464d25e9a52a33d621e040ddc6ad9f97afc3f6 Mon Sep 17 00:00:00 2001 From: stzups Date: Sat, 3 Apr 2021 10:13:11 -0400 Subject: [PATCH 06/35] add good auth debug --- .../java/net/stzups/board/server/websocket/MessageHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java index b9ca496b..896f9c9a 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java @@ -90,6 +90,7 @@ protected void channelRead0(ChannelHandlerContext ctx, ClientMessage message) { BoardRoom.getLogger().severe(ctx.channel().remoteAddress() + " somehow managed to authenticate with non existent user"); client = createUserSession(ctx, null); } else { + BoardRoom.getLogger().info(user + " authenticated with good persistent session"); client = createUserSession(ctx, user); } } From 0847866da85700491c1e6832ab161152ed92cea0 Mon Sep 17 00:00:00 2001 From: stzups Date: Sat, 3 Apr 2021 10:31:35 -0400 Subject: [PATCH 07/35] improve logging --- .../stzups/board/server/ServerInitializer.java | 12 ++++++++++-- .../board/server/WebSocketInitializer.java | 4 +--- .../board/server/websocket/MessageHandler.java | 16 ++++++++-------- .../websocket/protocol/MessageDecoder.java | 7 +++++-- .../websocket/protocol/MessageEncoder.java | 7 +++++-- 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/board-room/src/main/java/net/stzups/board/server/ServerInitializer.java b/board-room/src/main/java/net/stzups/board/server/ServerInitializer.java index ae2dad9f..13770e39 100644 --- a/board-room/src/main/java/net/stzups/board/server/ServerInitializer.java +++ b/board-room/src/main/java/net/stzups/board/server/ServerInitializer.java @@ -13,11 +13,14 @@ import io.netty.handler.stream.ChunkedWriteHandler; import io.netty.handler.traffic.GlobalTrafficShapingHandler; import io.netty.handler.traffic.TrafficCounter; +import io.netty.util.AttributeKey; import net.stzups.board.BoardRoom; +import net.stzups.board.LogFactory; import net.stzups.board.server.websocket.protocol.MessageEncoder; import net.stzups.board.server.websocket.protocol.MessageDecoder; import java.util.concurrent.Executors; +import java.util.logging.Logger; /** * Creates pipeline to handle Websocket connections @@ -25,6 +28,8 @@ * Connections not made to the WebSocket path go to ServerHandler */ public class ServerInitializer extends ChannelInitializer { + public static final AttributeKey LOGGER = AttributeKey.valueOf(ServerInitializer.class, "LOGGER"); + private static final String WEB_SOCKET_PATH = "/websocket"; private static final boolean DEBUG_LOG_TRAFFIC = BoardRoom.getConfig().getBoolean("debug.log.traffic", false); @@ -35,6 +40,7 @@ protected void doAccounting(TrafficCounter counter) { } }; + private Logger logger; private MessageEncoder messageEncoder = new MessageEncoder(); private MessageDecoder messageDecoder = new MessageDecoder(); private WebSocketInitializer webSocketInitializer = new WebSocketInitializer(); @@ -46,13 +52,15 @@ protected void doAccounting(TrafficCounter counter) { @Override protected void initChannel(SocketChannel socketChannel) { - BoardRoom.getLogger().info("New connection from " + socketChannel.remoteAddress()); + logger = LogFactory.getLogger(socketChannel.remoteAddress().toString()); + socketChannel.attr(LOGGER).set(logger); + logger.info("Initial connection"); ChannelPipeline pipeline = socketChannel.pipeline(); pipeline .addLast(new ChannelDuplexHandler() { @Override public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable throwable) { - BoardRoom.getLogger().warning("Uncaught exception"); + logger.warning("Uncaught exception"); throwable.printStackTrace(); } }) diff --git a/board-room/src/main/java/net/stzups/board/server/WebSocketInitializer.java b/board-room/src/main/java/net/stzups/board/server/WebSocketInitializer.java index 933c5d70..a51e0ca0 100644 --- a/board-room/src/main/java/net/stzups/board/server/WebSocketInitializer.java +++ b/board-room/src/main/java/net/stzups/board/server/WebSocketInitializer.java @@ -8,13 +8,11 @@ @ChannelHandler.Sharable public class WebSocketInitializer extends ChannelInboundHandlerAdapter { - //public static final AttributeKey HTTP_SESSION_KEY = AttributeKey.valueOf(WebSocketInitializer.class, "HTTP_SESSION"); @Override public void userEventTriggered(ChannelHandlerContext ctx, Object event) { if (event instanceof WebSocketServerProtocolHandler.HandshakeComplete) { - WebSocketServerProtocolHandler.HandshakeComplete handshakeComplete = (WebSocketServerProtocolHandler.HandshakeComplete) event; - //ctx.channel().attr(HTTP_SESSION_KEY).set(HttpSession.getSession(handshakeComplete.requestHeaders(), ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress())); + ctx.channel().attr(ServerInitializer.LOGGER).get().info("WebSocket connection initialized"); ctx.pipeline().addLast(new MessageHandler());//todo give this a different executor https://stackoverflow.com/questions/49133447/how-can-you-safely-perform-blocking-operations-in-a-netty-channel-handler } } diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java index 896f9c9a..300da07b 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java @@ -6,6 +6,7 @@ import net.stzups.board.data.objects.Document; import net.stzups.board.data.objects.User; import net.stzups.board.data.objects.PersistentUserSession; +import net.stzups.board.server.ServerInitializer; import net.stzups.board.server.websocket.protocol.client.ClientMessage; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageCreateDocument; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageHandshake; @@ -31,8 +32,7 @@ public void channelInactive(ChannelHandlerContext ctx) { @Override public void handlerAdded(ChannelHandlerContext ctx) { - //System.out.println(ctx.channel().hasAttr(WebSocketInitializer.HTTP_SESSION_KEY)); - //System.out.println(ctx.channel().attr(WebSocketInitializer.HTTP_SESSION_KEY).get()); + } @Override @@ -52,7 +52,7 @@ protected void channelRead0(ChannelHandlerContext ctx, ClientMessage message) { room = Room.getRoom(document); room.addClient(client); } else { - System.out.println(client + " tried to open document not that does not exist"); + ctx.channel().attr(ServerInitializer.LOGGER).get().warning(client + " tried to open document not that does not exist"); } break; } @@ -74,23 +74,23 @@ protected void channelRead0(ChannelHandlerContext ctx, ClientMessage message) { ClientMessageHandshake clientPacketHandshake = (ClientMessageHandshake) message; if (client == null) { if (clientPacketHandshake.getToken() == 0) { - BoardRoom.getLogger().info(ctx.channel().remoteAddress() + " authenticated with blank session"); + ctx.channel().attr(ServerInitializer.LOGGER).get().info("authenticated with blank session"); client = createUserSession(ctx, null); } else { PersistentUserSession persistentUserSession = BoardRoom.getDatabase().removeUserSession(clientPacketHandshake.getId()); if (persistentUserSession == null) { - BoardRoom.getLogger().warning(ctx.channel().remoteAddress() + " attempted to authenticate with non existent persistent user session"); + ctx.channel().attr(ServerInitializer.LOGGER).get().warning("attempted to authenticate with non existent persistent user session"); client = createUserSession(ctx, null); } else if (!persistentUserSession.validate(clientPacketHandshake.getToken())) { - BoardRoom.getLogger().warning(ctx.channel().remoteAddress() + " attempted to authenticate with invalid persistent user session " + persistentUserSession); + ctx.channel().attr(ServerInitializer.LOGGER).get().warning("attempted to authenticate with invalid persistent user session " + persistentUserSession); client = createUserSession(ctx, null); } else { User user = BoardRoom.getDatabase().getUser(persistentUserSession.getUser()); if (user == null) { - BoardRoom.getLogger().severe(ctx.channel().remoteAddress() + " somehow managed to authenticate with non existent user"); + ctx.channel().attr(ServerInitializer.LOGGER).get().severe("somehow managed to authenticate with non existent user"); client = createUserSession(ctx, null); } else { - BoardRoom.getLogger().info(user + " authenticated with good persistent session"); + ctx.channel().attr(ServerInitializer.LOGGER).get().info(user + " authenticated with good persistent session"); client = createUserSession(ctx, user); } } diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageDecoder.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageDecoder.java index 2f67a49c..02cc9543 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageDecoder.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageDecoder.java @@ -7,6 +7,8 @@ import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.handler.codec.http.websocketx.WebSocketFrame; +import net.stzups.board.BoardRoom; +import net.stzups.board.server.ServerInitializer; import net.stzups.board.server.websocket.protocol.client.ClientMessage; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageCreateDocument; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageUpdateCanvas; @@ -26,11 +28,11 @@ public class MessageDecoder extends MessageToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, WebSocketFrame webSocketFrame, List list) throws Exception { if (webSocketFrame instanceof TextWebSocketFrame) { - System.out.println(((TextWebSocketFrame) webSocketFrame).text()); + ctx.channel().attr(ServerInitializer.LOGGER).get().warning("Got TextWebSocketFrame, content:"); + ctx.channel().attr(ServerInitializer.LOGGER).get().warning(((TextWebSocketFrame) webSocketFrame).text()); } else if (webSocketFrame instanceof BinaryWebSocketFrame) { ByteBuf byteBuf = webSocketFrame.content(); ClientMessageType packetType = ClientMessageType.valueOf(byteBuf.readUnsignedByte()); - System.out.println("recv " + packetType); ClientMessage message; switch (packetType) { case OPEN_DOCUMENT: @@ -48,6 +50,7 @@ protected void decode(ChannelHandlerContext ctx, WebSocketFrame webSocketFrame, default: throw new OperationNotSupportedException("Unsupported message type " + packetType + " while decoding"); } + ctx.channel().attr(ServerInitializer.LOGGER).get().info("recv " + message.getClass().getSimpleName()); list.add(message); } } diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageEncoder.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageEncoder.java index 9465038d..6a6bf8ac 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageEncoder.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageEncoder.java @@ -5,6 +5,8 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; +import net.stzups.board.BoardRoom; +import net.stzups.board.server.ServerInitializer; import net.stzups.board.server.websocket.protocol.server.ServerMessage; import java.util.List; @@ -16,13 +18,14 @@ public class MessageEncoder extends MessageToByteEncoder> { @Override protected void encode(ChannelHandlerContext ctx, List serverMessages, ByteBuf b) { - System.out.println("encoding " + serverMessages.size()); + StringBuilder stringBuilder = new StringBuilder(); BinaryWebSocketFrame binaryWebSocketFrame = new BinaryWebSocketFrame(); ByteBuf byteBuf = binaryWebSocketFrame.content(); for (ServerMessage serverMessage : serverMessages) { - System.out.println("send " + serverMessage.getClass().getSimpleName()); + stringBuilder.append(serverMessage.getClass().getSimpleName()).append(", "); serverMessage.serialize(byteBuf); } + ctx.channel().attr(ServerInitializer.LOGGER).get().info("send " + stringBuilder.toString()); ctx.writeAndFlush(binaryWebSocketFrame); } } From 559dcaaf55c708e2ef0ab922ce2dc46fc0ac841c Mon Sep 17 00:00:00 2001 From: stzups Date: Sat, 3 Apr 2021 10:36:41 -0400 Subject: [PATCH 08/35] cleanup unused imports, remove extra debug --- board-room/src/main/java/net/stzups/board/BoardRoom.java | 3 +-- .../board/data/database/postgres/PostgresDatabase.java | 5 +---- .../java/net/stzups/board/data/objects/canvas/Canvas.java | 4 ++-- .../main/java/net/stzups/board/server/ServerInitializer.java | 3 +-- .../net/stzups/board/server/websocket/MessageHandler.java | 5 +---- .../board/server/websocket/protocol/MessageDecoder.java | 5 ++--- .../board/server/websocket/protocol/MessageEncoder.java | 1 - .../server/websocket/protocol/server/ServerMessage.java | 2 -- .../protocol/server/messages/ServerMessageOpenDocument.java | 1 - .../protocol/server/messages/ServerMessageUpdateCanvas.java | 2 -- 10 files changed, 8 insertions(+), 23 deletions(-) diff --git a/board-room/src/main/java/net/stzups/board/BoardRoom.java b/board-room/src/main/java/net/stzups/board/BoardRoom.java index d4f6140f..79572a01 100644 --- a/board-room/src/main/java/net/stzups/board/BoardRoom.java +++ b/board-room/src/main/java/net/stzups/board/BoardRoom.java @@ -7,12 +7,11 @@ import net.stzups.board.config.configs.EnvironmentVariableConfig; import net.stzups.board.config.configs.PropertiesConfig; import net.stzups.board.data.database.Database; -import net.stzups.board.data.database.postgres.PostgresDatabase; import net.stzups.board.data.database.memory.MemoryDatabase; +import net.stzups.board.data.database.postgres.PostgresDatabase; import net.stzups.board.server.Server; import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Random; import java.util.logging.Logger; diff --git a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java index d1687dce..4ef6b060 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java +++ b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java @@ -4,15 +4,12 @@ import io.netty.buffer.Unpooled; import net.stzups.board.data.database.Database; import net.stzups.board.data.objects.Document; -import net.stzups.board.data.objects.User; import net.stzups.board.data.objects.PersistentUserSession; +import net.stzups.board.data.objects.User; import net.stzups.board.data.objects.canvas.Canvas; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.sql.Blob; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; diff --git a/board-room/src/main/java/net/stzups/board/data/objects/canvas/Canvas.java b/board-room/src/main/java/net/stzups/board/data/objects/canvas/Canvas.java index d0206225..6f394488 100644 --- a/board-room/src/main/java/net/stzups/board/data/objects/canvas/Canvas.java +++ b/board-room/src/main/java/net/stzups/board/data/objects/canvas/Canvas.java @@ -1,6 +1,7 @@ package net.stzups.board.data.objects.canvas; import io.netty.buffer.ByteBuf; +import net.stzups.board.BoardRoom; import net.stzups.board.data.objects.Document; import net.stzups.board.data.objects.canvas.object.CanvasObject; import net.stzups.board.data.objects.canvas.object.CanvasObjectType; @@ -40,7 +41,6 @@ public Document getDocument() { } public void update(Map> updateCanvasObjects) { - System.out.println(canvasObjects.size()); for (Map.Entry> entry : updateCanvasObjects.entrySet()) { Map map = canvasObjects.computeIfAbsent(entry.getKey(), k -> new HashMap<>()); for (Map.Entry entry1 : entry.getValue().entrySet()) { @@ -57,7 +57,7 @@ public void delete(Map> deleteCanvasO for (Map.Entry> entry : deleteCanvasObjects.entrySet()) { Map map = canvasObjects.get(entry.getKey()); if (map == null) { - System.out.println("cant delete " + entry.getKey() + ", its already gone"); + BoardRoom.getLogger().warning("Tried to delete canvas object that does not exist"); } else { for (Map.Entry entry1 : entry.getValue().entrySet()) { map.remove(entry1.getKey()); diff --git a/board-room/src/main/java/net/stzups/board/server/ServerInitializer.java b/board-room/src/main/java/net/stzups/board/server/ServerInitializer.java index 13770e39..57152241 100644 --- a/board-room/src/main/java/net/stzups/board/server/ServerInitializer.java +++ b/board-room/src/main/java/net/stzups/board/server/ServerInitializer.java @@ -10,14 +10,13 @@ import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler; import io.netty.handler.ssl.SslContext; -import io.netty.handler.stream.ChunkedWriteHandler; import io.netty.handler.traffic.GlobalTrafficShapingHandler; import io.netty.handler.traffic.TrafficCounter; import io.netty.util.AttributeKey; import net.stzups.board.BoardRoom; import net.stzups.board.LogFactory; -import net.stzups.board.server.websocket.protocol.MessageEncoder; import net.stzups.board.server.websocket.protocol.MessageDecoder; +import net.stzups.board.server.websocket.protocol.MessageEncoder; import java.util.concurrent.Executors; import java.util.logging.Logger; diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java index 300da07b..e6e13e64 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java @@ -4,8 +4,8 @@ import io.netty.channel.SimpleChannelInboundHandler; import net.stzups.board.BoardRoom; import net.stzups.board.data.objects.Document; -import net.stzups.board.data.objects.User; import net.stzups.board.data.objects.PersistentUserSession; +import net.stzups.board.data.objects.User; import net.stzups.board.server.ServerInitializer; import net.stzups.board.server.websocket.protocol.client.ClientMessage; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageCreateDocument; @@ -16,9 +16,6 @@ import net.stzups.board.server.websocket.protocol.server.messages.ServerMessageAddUser; import net.stzups.board.server.websocket.protocol.server.messages.ServerMessageHandshake; -import java.util.HashMap; -import java.util.Map; - public class MessageHandler extends SimpleChannelInboundHandler { private Room room; private Client client; diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageDecoder.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageDecoder.java index 02cc9543..d498280f 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageDecoder.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageDecoder.java @@ -7,14 +7,13 @@ import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.handler.codec.http.websocketx.WebSocketFrame; -import net.stzups.board.BoardRoom; import net.stzups.board.server.ServerInitializer; import net.stzups.board.server.websocket.protocol.client.ClientMessage; +import net.stzups.board.server.websocket.protocol.client.ClientMessageType; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageCreateDocument; -import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageUpdateCanvas; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageHandshake; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageOpenDocument; -import net.stzups.board.server.websocket.protocol.client.ClientMessageType; +import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageUpdateCanvas; import javax.naming.OperationNotSupportedException; import java.nio.charset.StandardCharsets; diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageEncoder.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageEncoder.java index 6a6bf8ac..b1719c4c 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageEncoder.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageEncoder.java @@ -5,7 +5,6 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; -import net.stzups.board.BoardRoom; import net.stzups.board.server.ServerInitializer; import net.stzups.board.server.websocket.protocol.server.ServerMessage; diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/ServerMessage.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/ServerMessage.java index d87159a0..9fec2d32 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/ServerMessage.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/ServerMessage.java @@ -2,9 +2,7 @@ import io.netty.buffer.ByteBuf; -import java.io.BufferedReader; import java.nio.charset.StandardCharsets; -import java.util.Scanner; /** * Represents a packet sent by the server diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageOpenDocument.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageOpenDocument.java index 23555f4b..f8a56907 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageOpenDocument.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageOpenDocument.java @@ -1,7 +1,6 @@ package net.stzups.board.server.websocket.protocol.server.messages; import io.netty.buffer.ByteBuf; -import net.stzups.board.data.objects.Document; import net.stzups.board.data.objects.canvas.Canvas; import net.stzups.board.server.websocket.protocol.server.ServerMessage; import net.stzups.board.server.websocket.protocol.server.ServerMessageType; diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageUpdateCanvas.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageUpdateCanvas.java index 66609f72..ec1e5ab6 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageUpdateCanvas.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageUpdateCanvas.java @@ -1,10 +1,8 @@ package net.stzups.board.server.websocket.protocol.server.messages; import io.netty.buffer.ByteBuf; -import net.stzups.board.data.objects.canvas.Canvas; import net.stzups.board.data.objects.canvas.object.CanvasObjectType; import net.stzups.board.data.objects.canvas.object.CanvasObjectWrapper; -import net.stzups.board.server.websocket.Client; import net.stzups.board.server.websocket.protocol.server.ServerMessage; import net.stzups.board.server.websocket.protocol.server.ServerMessageType; From 7580bd6f00a3f936b26d1ef1c8a16c1b53d4d5f1 Mon Sep 17 00:00:00 2001 From: stzups Date: Sat, 3 Apr 2021 10:50:36 -0400 Subject: [PATCH 09/35] fix parse boolean bug --- board-room/src/main/java/net/stzups/board/config/Config.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board-room/src/main/java/net/stzups/board/config/Config.java b/board-room/src/main/java/net/stzups/board/config/Config.java index efde15ad..9a359e90 100644 --- a/board-room/src/main/java/net/stzups/board/config/Config.java +++ b/board-room/src/main/java/net/stzups/board/config/Config.java @@ -63,7 +63,7 @@ public boolean getBoolean(String key, boolean defaultValue) { if (value == null) { return defaultValue; } else { - return Boolean.parseBoolean(key); + return Boolean.parseBoolean(value); } } From c99c26b80b46f42b8dd1d368e5afa2ea6fa3fdc0 Mon Sep 17 00:00:00 2001 From: stzups Date: Sat, 3 Apr 2021 11:11:42 -0400 Subject: [PATCH 10/35] fix clients not showing up --- .../src/main/java/net/stzups/board/server/websocket/Room.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/Room.java b/board-room/src/main/java/net/stzups/board/server/websocket/Room.java index b55602e0..33739076 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/Room.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/Room.java @@ -79,6 +79,9 @@ void addClient(Client client) { //for the existing clients client.sendMessage(new ServerMessageOpenDocument(canvas)); sendMessage(new ServerMessageAddClient(client)); + for (Client c : clients) { + client.sendMessage(new ServerMessageAddClient(c)); + } clients.add(client); BoardRoom.getLogger().info("Added " + client + " to " + this); } From ad03ae003a98d7347d8f7e941bd3edca2f572384 Mon Sep 17 00:00:00 2001 From: stzups Date: Sat, 3 Apr 2021 11:36:41 -0400 Subject: [PATCH 11/35] improve message aggregation --- .../main/java/net/stzups/board/server/websocket/Room.java | 7 ++++--- frontend/html/scripts/protocol/WebSocketHandler.js | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/Room.java b/board-room/src/main/java/net/stzups/board/server/websocket/Room.java index 33739076..01865e87 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/Room.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/Room.java @@ -77,12 +77,13 @@ void addClient(Client client) { //for the new client //client.sendMessage(new ServerMessageOpenDocument(document));todo remove //for the existing clients - client.sendMessage(new ServerMessageOpenDocument(canvas)); - sendMessage(new ServerMessageAddClient(client)); + client.queueMessage(new ServerMessageOpenDocument(canvas)); + queueMessage(new ServerMessageAddClient(client)); for (Client c : clients) { - client.sendMessage(new ServerMessageAddClient(c)); + client.queueMessage(new ServerMessageAddClient(c));//todo } clients.add(client); + flushMessages(); BoardRoom.getLogger().info("Added " + client + " to " + this); } diff --git a/frontend/html/scripts/protocol/WebSocketHandler.js b/frontend/html/scripts/protocol/WebSocketHandler.js index 8369909b..309f5ac2 100644 --- a/frontend/html/scripts/protocol/WebSocketHandler.js +++ b/frontend/html/scripts/protocol/WebSocketHandler.js @@ -47,6 +47,7 @@ class WebSocketHandler { }); this.socket.addEventListener('message', (event) => { + console.warn('recv'); if (typeof event.data === 'string') { console.log(event.data); } else { From 27324017020fe18c85c066e973df885a5afdedbe Mon Sep 17 00:00:00 2001 From: stzups Date: Sat, 3 Apr 2021 11:45:57 -0400 Subject: [PATCH 12/35] make addUser work with lists --- .../net/stzups/board/server/websocket/Client.java | 6 ++++++ .../server/messages/ServerMessageAddClient.java | 13 +++++++++---- frontend/html/scripts/Document.js | 8 +++++--- .../server/messages/ServerMessageAddClient.js | 7 +++++-- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/Client.java b/board-room/src/main/java/net/stzups/board/server/websocket/Client.java index 0008815a..7270cbf8 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/Client.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/Client.java @@ -1,5 +1,6 @@ package net.stzups.board.server.websocket; +import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import net.stzups.board.BoardRoom; import net.stzups.board.data.objects.User; @@ -62,6 +63,11 @@ void disconnect() { } } + public void serialize(ByteBuf byteBuf) { + byteBuf.writeShort(id); + byteBuf.writeLong(user.getId()); + } + @Override public String toString() { return "Client{user=" + user + ",address=" + channel.remoteAddress() + "}"; diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageAddClient.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageAddClient.java index 5e7c1bac..2b187f1e 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageAddClient.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageAddClient.java @@ -5,18 +5,23 @@ import net.stzups.board.server.websocket.protocol.server.ServerMessage; import net.stzups.board.server.websocket.protocol.server.ServerMessageType; +import java.util.Collections; +import java.util.Set; + public class ServerMessageAddClient extends ServerMessage { - private Client client; + private Set clients; public ServerMessageAddClient(Client client) { super(ServerMessageType.ADD_CLIENT); - this.client = client; + this.clients = Collections.singleton(client); } @Override public void serialize(ByteBuf byteBuf) { super.serialize(byteBuf); - byteBuf.writeShort(client.getId()); - byteBuf.writeLong(client.getUser().getId()); + byteBuf.writeShort((short) clients.size()); + for (Client client : clients) { + client.serialize(byteBuf); + } } } diff --git a/frontend/html/scripts/Document.js b/frontend/html/scripts/Document.js index 8254d693..1b8367ad 100644 --- a/frontend/html/scripts/Document.js +++ b/frontend/html/scripts/Document.js @@ -100,9 +100,11 @@ function draw(now) { window.requestAnimationFrame(draw); socket.addMessageListener(ServerMessageType.ADD_CLIENT, (event) => { - let client = new Client(event.id, User.getUser(event.userId)); - activeDocument.addClient(client); - console.log('Add client ', client); + event.clients.forEach((value) => { + let client = new Client(value.id, User.getUser(value.userId)); + activeDocument.addClient(client); + console.log('Add client ', client); + }) }); socket.addMessageListener(ServerMessageType.REMOVE_CLIENT, (event) => { console.log('Remove client ', activeDocument.removeClient(event.id)); diff --git a/frontend/html/scripts/protocol/server/messages/ServerMessageAddClient.js b/frontend/html/scripts/protocol/server/messages/ServerMessageAddClient.js index e1d62b5f..c65c748e 100644 --- a/frontend/html/scripts/protocol/server/messages/ServerMessageAddClient.js +++ b/frontend/html/scripts/protocol/server/messages/ServerMessageAddClient.js @@ -4,7 +4,10 @@ import ServerMessageType from "../ServerMessageType.js"; export default class ServerMessageAddClient extends ServerMessage { constructor(reader) { super(ServerMessageType.ADD_CLIENT); - this.id = reader.readInt16(); - this.userId = reader.readBigInt64(); + this.clients = []; + let length = reader.readUint16(); + for (let i = 0; i < length; i++) { + this.clients[i] = {id:reader.readInt16(), userId:reader.readBigInt64()}; + } } } \ No newline at end of file From e5226c6c3f0e6873c11520a99970e81c340ab590 Mon Sep 17 00:00:00 2001 From: stzups Date: Sat, 3 Apr 2021 11:47:33 -0400 Subject: [PATCH 13/35] actually use user list --- .../main/java/net/stzups/board/server/websocket/Room.java | 4 +--- .../protocol/server/messages/ServerMessageAddClient.java | 6 +++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/Room.java b/board-room/src/main/java/net/stzups/board/server/websocket/Room.java index 01865e87..a3b9f19f 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/Room.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/Room.java @@ -79,9 +79,7 @@ void addClient(Client client) { //for the existing clients client.queueMessage(new ServerMessageOpenDocument(canvas)); queueMessage(new ServerMessageAddClient(client)); - for (Client c : clients) { - client.queueMessage(new ServerMessageAddClient(c));//todo - } + client.queueMessage(new ServerMessageAddClient(clients));//todo clients.add(client); flushMessages(); BoardRoom.getLogger().info("Added " + client + " to " + this); diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageAddClient.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageAddClient.java index 2b187f1e..45027a2f 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageAddClient.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageAddClient.java @@ -12,8 +12,12 @@ public class ServerMessageAddClient extends ServerMessage { private Set clients; public ServerMessageAddClient(Client client) { + this(Collections.singleton(client)); + } + + public ServerMessageAddClient(Set clients) { super(ServerMessageType.ADD_CLIENT); - this.clients = Collections.singleton(client); + this.clients = clients; } @Override From f43277b50df6cf8ae3a233cf1e63d0abf63c8d53 Mon Sep 17 00:00:00 2001 From: stzups Date: Sat, 3 Apr 2021 18:03:01 -0400 Subject: [PATCH 14/35] fix board-room starting up before db --- docker-compose.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 65f200a9..44b721f8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,6 +6,8 @@ services: network: host ports: - "8080:8080" + depends_on: + - database environment: board.ssl: "false" board.postgres: "true" From dfbae992eeb46eae24efe989c95c3aa3668e6628 Mon Sep 17 00:00:00 2001 From: stzups Date: Sun, 4 Apr 2021 09:14:34 -0400 Subject: [PATCH 15/35] change db user --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 44b721f8..9a8d05d5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,8 +11,8 @@ services: environment: board.ssl: "false" board.postgres: "true" - board.postgres.url: "jdbc:postgresql://database:5432/postgres" - board.postgres.user: "postgres" + board.postgres.url: "jdbc:postgresql://database:5432/board" + board.postgres.user: "board" board.postgres.password: "changeme" board-frontend: image: board-frontend From d27248fa75092a7eeb18398bd1b30b241ffa3354 Mon Sep 17 00:00:00 2001 From: stzups Date: Sun, 4 Apr 2021 10:07:55 -0400 Subject: [PATCH 16/35] rework db --- board-database/Dockerfile | 2 ++ board-database/init.sql | 2 ++ {frontend => board-frontend}/Dockerfile | 0 .../html/assets/default.png | Bin {frontend => board-frontend}/html/favicon.ico | Bin {frontend => board-frontend}/html/index.css | 0 {frontend => board-frontend}/html/index.html | 0 {frontend => board-frontend}/html/scripts/Board.js | 0 {frontend => board-frontend}/html/scripts/Client.js | 0 .../html/scripts/Document.js | 0 .../html/scripts/SidebarItem.js | 0 {frontend => board-frontend}/html/scripts/User.js | 0 .../html/scripts/canvas/Canvas.js | 0 .../html/scripts/canvas/CanvasObject.js | 0 .../html/scripts/canvas/CanvasObjectType.js | 0 .../html/scripts/canvas/CanvasObjectWrapper.js | 0 .../html/scripts/canvas/canvasObjects/Shape.js | 0 {frontend => board-frontend}/html/scripts/main.js | 0 .../html/scripts/protocol/BufferReader.js | 0 .../html/scripts/protocol/BufferWriter.js | 0 .../html/scripts/protocol/WebSocketHandler.js | 0 .../html/scripts/protocol/WebSocketHandlerType.js | 0 .../html/scripts/protocol/client/ClientMessage.js | 0 .../scripts/protocol/client/ClientMessageType.js | 0 .../client/messages/ClientMessageCreateDocument.js | 0 .../client/messages/ClientMessageHandshake.js | 0 .../client/messages/ClientMessageOpenDocument.js | 0 .../client/messages/ClientMessageUpdateCanvas.js | 0 .../html/scripts/protocol/server/ServerMessage.js | 0 .../scripts/protocol/server/ServerMessageType.js | 0 .../server/messages/ServerMessageAddClient.js | 0 .../server/messages/ServerMessageAddDocument.js | 0 .../server/messages/ServerMessageAddUser.js | 0 .../server/messages/ServerMessageHandshake.js | 0 .../server/messages/ServerMessageOpenDocument.js | 0 .../server/messages/ServerMessageRemoveClient.js | 0 .../server/messages/ServerMessageUpdateCanvas.js | 0 {frontend => board-frontend}/html/style.css | 0 {frontend => board-frontend}/nginx.conf | 0 docker-compose.yml | 11 ++++++----- 40 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 board-database/Dockerfile create mode 100644 board-database/init.sql rename {frontend => board-frontend}/Dockerfile (100%) rename {frontend => board-frontend}/html/assets/default.png (100%) rename {frontend => board-frontend}/html/favicon.ico (100%) rename {frontend => board-frontend}/html/index.css (100%) rename {frontend => board-frontend}/html/index.html (100%) rename {frontend => board-frontend}/html/scripts/Board.js (100%) rename {frontend => board-frontend}/html/scripts/Client.js (100%) rename {frontend => board-frontend}/html/scripts/Document.js (100%) rename {frontend => board-frontend}/html/scripts/SidebarItem.js (100%) rename {frontend => board-frontend}/html/scripts/User.js (100%) rename {frontend => board-frontend}/html/scripts/canvas/Canvas.js (100%) rename {frontend => board-frontend}/html/scripts/canvas/CanvasObject.js (100%) rename {frontend => board-frontend}/html/scripts/canvas/CanvasObjectType.js (100%) rename {frontend => board-frontend}/html/scripts/canvas/CanvasObjectWrapper.js (100%) rename {frontend => board-frontend}/html/scripts/canvas/canvasObjects/Shape.js (100%) rename {frontend => board-frontend}/html/scripts/main.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/BufferReader.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/BufferWriter.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/WebSocketHandler.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/WebSocketHandlerType.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/client/ClientMessage.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/client/ClientMessageType.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/client/messages/ClientMessageCreateDocument.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/client/messages/ClientMessageHandshake.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/client/messages/ClientMessageOpenDocument.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/client/messages/ClientMessageUpdateCanvas.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/server/ServerMessage.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/server/ServerMessageType.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/server/messages/ServerMessageAddClient.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/server/messages/ServerMessageAddDocument.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/server/messages/ServerMessageAddUser.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/server/messages/ServerMessageHandshake.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/server/messages/ServerMessageOpenDocument.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/server/messages/ServerMessageRemoveClient.js (100%) rename {frontend => board-frontend}/html/scripts/protocol/server/messages/ServerMessageUpdateCanvas.js (100%) rename {frontend => board-frontend}/html/style.css (100%) rename {frontend => board-frontend}/nginx.conf (100%) diff --git a/board-database/Dockerfile b/board-database/Dockerfile new file mode 100644 index 00000000..22fb88e8 --- /dev/null +++ b/board-database/Dockerfile @@ -0,0 +1,2 @@ +FROM postgres +COPY init.sql /docker-entrypoint-initdb.d/ \ No newline at end of file diff --git a/board-database/init.sql b/board-database/init.sql new file mode 100644 index 00000000..722e40c9 --- /dev/null +++ b/board-database/init.sql @@ -0,0 +1,2 @@ +CREATE USER board PASSWORD 'changeme'; +CREATE DATABASE board; diff --git a/frontend/Dockerfile b/board-frontend/Dockerfile similarity index 100% rename from frontend/Dockerfile rename to board-frontend/Dockerfile diff --git a/frontend/html/assets/default.png b/board-frontend/html/assets/default.png similarity index 100% rename from frontend/html/assets/default.png rename to board-frontend/html/assets/default.png diff --git a/frontend/html/favicon.ico b/board-frontend/html/favicon.ico similarity index 100% rename from frontend/html/favicon.ico rename to board-frontend/html/favicon.ico diff --git a/frontend/html/index.css b/board-frontend/html/index.css similarity index 100% rename from frontend/html/index.css rename to board-frontend/html/index.css diff --git a/frontend/html/index.html b/board-frontend/html/index.html similarity index 100% rename from frontend/html/index.html rename to board-frontend/html/index.html diff --git a/frontend/html/scripts/Board.js b/board-frontend/html/scripts/Board.js similarity index 100% rename from frontend/html/scripts/Board.js rename to board-frontend/html/scripts/Board.js diff --git a/frontend/html/scripts/Client.js b/board-frontend/html/scripts/Client.js similarity index 100% rename from frontend/html/scripts/Client.js rename to board-frontend/html/scripts/Client.js diff --git a/frontend/html/scripts/Document.js b/board-frontend/html/scripts/Document.js similarity index 100% rename from frontend/html/scripts/Document.js rename to board-frontend/html/scripts/Document.js diff --git a/frontend/html/scripts/SidebarItem.js b/board-frontend/html/scripts/SidebarItem.js similarity index 100% rename from frontend/html/scripts/SidebarItem.js rename to board-frontend/html/scripts/SidebarItem.js diff --git a/frontend/html/scripts/User.js b/board-frontend/html/scripts/User.js similarity index 100% rename from frontend/html/scripts/User.js rename to board-frontend/html/scripts/User.js diff --git a/frontend/html/scripts/canvas/Canvas.js b/board-frontend/html/scripts/canvas/Canvas.js similarity index 100% rename from frontend/html/scripts/canvas/Canvas.js rename to board-frontend/html/scripts/canvas/Canvas.js diff --git a/frontend/html/scripts/canvas/CanvasObject.js b/board-frontend/html/scripts/canvas/CanvasObject.js similarity index 100% rename from frontend/html/scripts/canvas/CanvasObject.js rename to board-frontend/html/scripts/canvas/CanvasObject.js diff --git a/frontend/html/scripts/canvas/CanvasObjectType.js b/board-frontend/html/scripts/canvas/CanvasObjectType.js similarity index 100% rename from frontend/html/scripts/canvas/CanvasObjectType.js rename to board-frontend/html/scripts/canvas/CanvasObjectType.js diff --git a/frontend/html/scripts/canvas/CanvasObjectWrapper.js b/board-frontend/html/scripts/canvas/CanvasObjectWrapper.js similarity index 100% rename from frontend/html/scripts/canvas/CanvasObjectWrapper.js rename to board-frontend/html/scripts/canvas/CanvasObjectWrapper.js diff --git a/frontend/html/scripts/canvas/canvasObjects/Shape.js b/board-frontend/html/scripts/canvas/canvasObjects/Shape.js similarity index 100% rename from frontend/html/scripts/canvas/canvasObjects/Shape.js rename to board-frontend/html/scripts/canvas/canvasObjects/Shape.js diff --git a/frontend/html/scripts/main.js b/board-frontend/html/scripts/main.js similarity index 100% rename from frontend/html/scripts/main.js rename to board-frontend/html/scripts/main.js diff --git a/frontend/html/scripts/protocol/BufferReader.js b/board-frontend/html/scripts/protocol/BufferReader.js similarity index 100% rename from frontend/html/scripts/protocol/BufferReader.js rename to board-frontend/html/scripts/protocol/BufferReader.js diff --git a/frontend/html/scripts/protocol/BufferWriter.js b/board-frontend/html/scripts/protocol/BufferWriter.js similarity index 100% rename from frontend/html/scripts/protocol/BufferWriter.js rename to board-frontend/html/scripts/protocol/BufferWriter.js diff --git a/frontend/html/scripts/protocol/WebSocketHandler.js b/board-frontend/html/scripts/protocol/WebSocketHandler.js similarity index 100% rename from frontend/html/scripts/protocol/WebSocketHandler.js rename to board-frontend/html/scripts/protocol/WebSocketHandler.js diff --git a/frontend/html/scripts/protocol/WebSocketHandlerType.js b/board-frontend/html/scripts/protocol/WebSocketHandlerType.js similarity index 100% rename from frontend/html/scripts/protocol/WebSocketHandlerType.js rename to board-frontend/html/scripts/protocol/WebSocketHandlerType.js diff --git a/frontend/html/scripts/protocol/client/ClientMessage.js b/board-frontend/html/scripts/protocol/client/ClientMessage.js similarity index 100% rename from frontend/html/scripts/protocol/client/ClientMessage.js rename to board-frontend/html/scripts/protocol/client/ClientMessage.js diff --git a/frontend/html/scripts/protocol/client/ClientMessageType.js b/board-frontend/html/scripts/protocol/client/ClientMessageType.js similarity index 100% rename from frontend/html/scripts/protocol/client/ClientMessageType.js rename to board-frontend/html/scripts/protocol/client/ClientMessageType.js diff --git a/frontend/html/scripts/protocol/client/messages/ClientMessageCreateDocument.js b/board-frontend/html/scripts/protocol/client/messages/ClientMessageCreateDocument.js similarity index 100% rename from frontend/html/scripts/protocol/client/messages/ClientMessageCreateDocument.js rename to board-frontend/html/scripts/protocol/client/messages/ClientMessageCreateDocument.js diff --git a/frontend/html/scripts/protocol/client/messages/ClientMessageHandshake.js b/board-frontend/html/scripts/protocol/client/messages/ClientMessageHandshake.js similarity index 100% rename from frontend/html/scripts/protocol/client/messages/ClientMessageHandshake.js rename to board-frontend/html/scripts/protocol/client/messages/ClientMessageHandshake.js diff --git a/frontend/html/scripts/protocol/client/messages/ClientMessageOpenDocument.js b/board-frontend/html/scripts/protocol/client/messages/ClientMessageOpenDocument.js similarity index 100% rename from frontend/html/scripts/protocol/client/messages/ClientMessageOpenDocument.js rename to board-frontend/html/scripts/protocol/client/messages/ClientMessageOpenDocument.js diff --git a/frontend/html/scripts/protocol/client/messages/ClientMessageUpdateCanvas.js b/board-frontend/html/scripts/protocol/client/messages/ClientMessageUpdateCanvas.js similarity index 100% rename from frontend/html/scripts/protocol/client/messages/ClientMessageUpdateCanvas.js rename to board-frontend/html/scripts/protocol/client/messages/ClientMessageUpdateCanvas.js diff --git a/frontend/html/scripts/protocol/server/ServerMessage.js b/board-frontend/html/scripts/protocol/server/ServerMessage.js similarity index 100% rename from frontend/html/scripts/protocol/server/ServerMessage.js rename to board-frontend/html/scripts/protocol/server/ServerMessage.js diff --git a/frontend/html/scripts/protocol/server/ServerMessageType.js b/board-frontend/html/scripts/protocol/server/ServerMessageType.js similarity index 100% rename from frontend/html/scripts/protocol/server/ServerMessageType.js rename to board-frontend/html/scripts/protocol/server/ServerMessageType.js diff --git a/frontend/html/scripts/protocol/server/messages/ServerMessageAddClient.js b/board-frontend/html/scripts/protocol/server/messages/ServerMessageAddClient.js similarity index 100% rename from frontend/html/scripts/protocol/server/messages/ServerMessageAddClient.js rename to board-frontend/html/scripts/protocol/server/messages/ServerMessageAddClient.js diff --git a/frontend/html/scripts/protocol/server/messages/ServerMessageAddDocument.js b/board-frontend/html/scripts/protocol/server/messages/ServerMessageAddDocument.js similarity index 100% rename from frontend/html/scripts/protocol/server/messages/ServerMessageAddDocument.js rename to board-frontend/html/scripts/protocol/server/messages/ServerMessageAddDocument.js diff --git a/frontend/html/scripts/protocol/server/messages/ServerMessageAddUser.js b/board-frontend/html/scripts/protocol/server/messages/ServerMessageAddUser.js similarity index 100% rename from frontend/html/scripts/protocol/server/messages/ServerMessageAddUser.js rename to board-frontend/html/scripts/protocol/server/messages/ServerMessageAddUser.js diff --git a/frontend/html/scripts/protocol/server/messages/ServerMessageHandshake.js b/board-frontend/html/scripts/protocol/server/messages/ServerMessageHandshake.js similarity index 100% rename from frontend/html/scripts/protocol/server/messages/ServerMessageHandshake.js rename to board-frontend/html/scripts/protocol/server/messages/ServerMessageHandshake.js diff --git a/frontend/html/scripts/protocol/server/messages/ServerMessageOpenDocument.js b/board-frontend/html/scripts/protocol/server/messages/ServerMessageOpenDocument.js similarity index 100% rename from frontend/html/scripts/protocol/server/messages/ServerMessageOpenDocument.js rename to board-frontend/html/scripts/protocol/server/messages/ServerMessageOpenDocument.js diff --git a/frontend/html/scripts/protocol/server/messages/ServerMessageRemoveClient.js b/board-frontend/html/scripts/protocol/server/messages/ServerMessageRemoveClient.js similarity index 100% rename from frontend/html/scripts/protocol/server/messages/ServerMessageRemoveClient.js rename to board-frontend/html/scripts/protocol/server/messages/ServerMessageRemoveClient.js diff --git a/frontend/html/scripts/protocol/server/messages/ServerMessageUpdateCanvas.js b/board-frontend/html/scripts/protocol/server/messages/ServerMessageUpdateCanvas.js similarity index 100% rename from frontend/html/scripts/protocol/server/messages/ServerMessageUpdateCanvas.js rename to board-frontend/html/scripts/protocol/server/messages/ServerMessageUpdateCanvas.js diff --git a/frontend/html/style.css b/board-frontend/html/style.css similarity index 100% rename from frontend/html/style.css rename to board-frontend/html/style.css diff --git a/frontend/nginx.conf b/board-frontend/nginx.conf similarity index 100% rename from frontend/nginx.conf rename to board-frontend/nginx.conf diff --git a/docker-compose.yml b/docker-compose.yml index 9a8d05d5..7181d627 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,21 +7,22 @@ services: ports: - "8080:8080" depends_on: - - database + - board-database environment: board.ssl: "false" board.postgres: "true" - board.postgres.url: "jdbc:postgresql://database:5432/board" + board.postgres.url: "jdbc:postgresql://board-database:5432/board" board.postgres.user: "board" board.postgres.password: "changeme" board-frontend: image: board-frontend build: - context: frontend + context: board-frontend ports: - "80:80" - database: - image: postgres + board-database: + build: + context: board-database environment: POSTGRES_PASSWORD: "changeme" ports: From 8d353da8a602c4a5dde29fbaef2f7321c8be5adb Mon Sep 17 00:00:00 2001 From: stzups Date: Sun, 4 Apr 2021 10:44:49 -0400 Subject: [PATCH 17/35] add users table --- board-database/init.sql | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/board-database/init.sql b/board-database/init.sql index 722e40c9..2dc71ea9 100644 --- a/board-database/init.sql +++ b/board-database/init.sql @@ -1,2 +1,11 @@ CREATE USER board PASSWORD 'changeme'; CREATE DATABASE board; + +-- Connect to board database (currently on default postgres database) +\c board +CREATE TABLE users( + id bigint NOT NULL, + owned_documents bytea[] NOT NULL, + shared_documents bytea[] NOT NULL, + PRIMARY KEY(id) +) \ No newline at end of file From b5957394f84730414130dfa7f619f8fd43b4cb66 Mon Sep 17 00:00:00 2001 From: stzups Date: Sun, 4 Apr 2021 11:38:06 -0400 Subject: [PATCH 18/35] add more tables, lock down permissions --- board-database/init.sql | 44 +++++++++++++++++++++++++++++++++++------ docker-compose.yml | 2 +- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/board-database/init.sql b/board-database/init.sql index 2dc71ea9..9ef4dd13 100644 --- a/board-database/init.sql +++ b/board-database/init.sql @@ -1,11 +1,43 @@ -CREATE USER board PASSWORD 'changeme'; +CREATE USER board_room PASSWORD 'changeme'; CREATE DATABASE board; -- Connect to board database (currently on default postgres database) \c board +REVOKE CONNECT FROM PUBLIC; +REVOKE ALL ON SCHEMA public FROM PUBLIC; +-- CREATE SCHEMA board; +-- GRANT USAGE ON SCHEMA board TO board_room; todo use schema and put tables on it? +GRANT CONNECT TO board_room; +GRANT USAGE TO board_room; + +-- Create tables and grant permissions CREATE TABLE users( - id bigint NOT NULL, - owned_documents bytea[] NOT NULL, - shared_documents bytea[] NOT NULL, - PRIMARY KEY(id) -) \ No newline at end of file + id BIGINT NOT NULL, + owned_documents BIGINT[] NOT NULL, + shared_documents BIGINT[] NOT NULL, + PRIMARY KEY (id) +); +GRANT SELECT, INSERT, UPDATE ON users TO board_room; + +CREATE TABLE documents( + id BIGINT NOT NULL, + owner BIGINT NOT NULL, + name CHAR NOT NULL, + PRIMARY KEY (id) +); +GRANT SELECT, INSERT, UPDATE ON documents TO board_room; + +CREATE TABLE canvases( + document BIGINT NOT NULL, + data bytea NOT NULL, + PRIMARY KEY (document) +); +GRANT SELECT, INSERT, UPDATE ON canvases TO board_room; + +CREATE TABLE persistent_user_sessions( + id BIGINT NOT NULL, + creation_time BIGINT NOT NULL, + hashed_token bytea NOT NULL, + PRIMARY KEY (id) +); +GRANT SELECT, INSERT, DELETE ON persistent_user_sessions TO board_room; \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 7181d627..27d8402c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,7 @@ services: board.ssl: "false" board.postgres: "true" board.postgres.url: "jdbc:postgresql://board-database:5432/board" - board.postgres.user: "board" + board.postgres.user: "board-room" board.postgres.password: "changeme" board-frontend: image: board-frontend From 469d75463851ff41a13e8639d0a1675467bcfdb9 Mon Sep 17 00:00:00 2001 From: stzups Date: Sun, 4 Apr 2021 12:32:00 -0400 Subject: [PATCH 19/35] improve error handling --- CHANGELOG.md | 3 ++- board-room/src/main/java/net/stzups/board/BoardRoom.java | 2 +- .../src/main/java/net/stzups/board/server/Server.java | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bf0be64..dcf04813 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -94,4 +94,5 @@ Rework db, implement document persistence - Fix changes not being saved on canvas close - Fix canvas serialization -- Fix connected clients list \ No newline at end of file +- Fix connected clients list +- Check db into version control \ No newline at end of file diff --git a/board-room/src/main/java/net/stzups/board/BoardRoom.java b/board-room/src/main/java/net/stzups/board/BoardRoom.java index 79572a01..5e58a35c 100644 --- a/board-room/src/main/java/net/stzups/board/BoardRoom.java +++ b/board-room/src/main/java/net/stzups/board/BoardRoom.java @@ -42,7 +42,7 @@ public static void main(String[] args) throws Exception { Boolean postgres = config.getBoolean("postgres"); if (postgres == null) { - throw new RuntimeException("Failed to specify required runtime variable --postgres"); + throw new IllegalArgumentException("Failed to specify required runtime variable --postgres"); } else { if (postgres) { logger.info("Connecting to Postgres database..."); diff --git a/board-room/src/main/java/net/stzups/board/server/Server.java b/board-room/src/main/java/net/stzups/board/server/Server.java index 1d83208c..415dfffb 100644 --- a/board-room/src/main/java/net/stzups/board/server/Server.java +++ b/board-room/src/main/java/net/stzups/board/server/Server.java @@ -38,7 +38,7 @@ public ChannelFuture start() throws Exception { Boolean ssl = BoardRoom.getConfig().getBoolean("ssl"); if (ssl == null) { - throw new RuntimeException("Failed to set required runtime variable --ssl. Perhaps you meant to explicitly disable encrypted sockets over HTTPS using --ssl false"); + throw new IllegalArgumentException("Failed to set required runtime variable --ssl. Perhaps you meant to explicitly disable encrypted sockets over HTTPS using --ssl false"); } if (!ssl) { @@ -63,13 +63,13 @@ public ChannelFuture start() throws Exception { .build(); port = HTTPS_PORT; } catch (IOException | GeneralSecurityException e) { - throw new RuntimeException("Exception while getting SSL context", e); + throw new Exception("Exception while getting SSL context", e); } } else { - throw new RuntimeException("Failed to specify SSL passphrase from --ssl.passphrase flag."); + throw new IllegalArgumentException("Failed to specify SSL passphrase from --ssl.passphrase flag."); } } else { - throw new RuntimeException("Failed to set specify SSL keystore path from --ssl.keystore.path flag."); + throw new IllegalArgumentException("Failed to set specify SSL keystore path from --ssl.keystore.path flag."); } } From c7008f9674c274a03b3b611dee22be00ac612d99 Mon Sep 17 00:00:00 2001 From: stzups Date: Sun, 4 Apr 2021 15:26:36 -0400 Subject: [PATCH 20/35] Overhaul config --- CHANGELOG.md | 4 +- .../net/stzups/board/BoardConfigKeys.java | 16 ++++ .../main/java/net/stzups/board/BoardRoom.java | 17 ++-- .../java/net/stzups/board/config/Config.java | 77 ------------------- .../java/net/stzups/board/server/Server.java | 44 ++++------- .../board/server/ServerInitializer.java | 6 +- .../stzups/board/{ => util}/LogFactory.java | 2 +- .../stzups/board/{ => util}/RandomString.java | 2 +- .../net/stzups/board/util/config/Config.java | 65 ++++++++++++++++ .../{ => util}/config/ConfigBuilder.java | 2 +- .../stzups/board/util/config/ConfigKey.java | 17 ++++ .../{ => util}/config/ConfigProvider.java | 2 +- .../board/util/config/OptionalConfigKey.java | 17 ++++ .../board/util/config/RequiredConfigKey.java | 16 ++++ .../config/configs/ArgumentConfig.java | 4 +- .../configs/EnvironmentVariableConfig.java | 4 +- .../config/configs/PropertiesConfig.java | 4 +- 17 files changed, 174 insertions(+), 125 deletions(-) create mode 100644 board-room/src/main/java/net/stzups/board/BoardConfigKeys.java delete mode 100644 board-room/src/main/java/net/stzups/board/config/Config.java rename board-room/src/main/java/net/stzups/board/{ => util}/LogFactory.java (97%) rename board-room/src/main/java/net/stzups/board/{ => util}/RandomString.java (94%) create mode 100644 board-room/src/main/java/net/stzups/board/util/config/Config.java rename board-room/src/main/java/net/stzups/board/{ => util}/config/ConfigBuilder.java (92%) create mode 100644 board-room/src/main/java/net/stzups/board/util/config/ConfigKey.java rename board-room/src/main/java/net/stzups/board/{ => util}/config/ConfigProvider.java (63%) create mode 100644 board-room/src/main/java/net/stzups/board/util/config/OptionalConfigKey.java create mode 100644 board-room/src/main/java/net/stzups/board/util/config/RequiredConfigKey.java rename board-room/src/main/java/net/stzups/board/{ => util}/config/configs/ArgumentConfig.java (93%) rename board-room/src/main/java/net/stzups/board/{ => util}/config/configs/EnvironmentVariableConfig.java (78%) rename board-room/src/main/java/net/stzups/board/{ => util}/config/configs/PropertiesConfig.java (91%) diff --git a/CHANGELOG.md b/CHANGELOG.md index dcf04813..2274bc07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -91,8 +91,10 @@ Rework db, implement document persistence - Rework user authentication ### v0.3.4 +Bugfixes, improve db creation, improve exceptions, overhaul config - Fix changes not being saved on canvas close - Fix canvas serialization - Fix connected clients list -- Check db into version control \ No newline at end of file +- Add db creation scripts into version control +- Overhaul config - improve exceptions \ No newline at end of file diff --git a/board-room/src/main/java/net/stzups/board/BoardConfigKeys.java b/board-room/src/main/java/net/stzups/board/BoardConfigKeys.java new file mode 100644 index 00000000..3de122ed --- /dev/null +++ b/board-room/src/main/java/net/stzups/board/BoardConfigKeys.java @@ -0,0 +1,16 @@ +package net.stzups.board; + +import net.stzups.board.util.config.ConfigKey; +import net.stzups.board.util.config.OptionalConfigKey; +import net.stzups.board.util.config.RequiredConfigKey; + +public class BoardConfigKeys { + public static final ConfigKey POSTGRES = new RequiredConfigKey<>("postgres"); + public static final ConfigKey POSTGRES_URL = new RequiredConfigKey<>("postgres.url"); + public static final ConfigKey POSTGRES_USER = new RequiredConfigKey<>("postgres.user"); + public static final ConfigKey POSTGRES_PASSWORD = new RequiredConfigKey<>("postgres.password"); + public static final ConfigKey SSL = new RequiredConfigKey<>("ssl"); + public static final ConfigKey SSL_KEYSTORE_PATH = new RequiredConfigKey<>("ssl.keystore.path"); + public static final ConfigKey SSL_KEYSTORE_PASSPHRASE = new RequiredConfigKey<>("ssl.keystore.passphrase"); + public static final ConfigKey DEBUG_LOG_TRAFFIC = new OptionalConfigKey<>("debug.log.traffic", false); +} diff --git a/board-room/src/main/java/net/stzups/board/BoardRoom.java b/board-room/src/main/java/net/stzups/board/BoardRoom.java index 5e58a35c..32ae089f 100644 --- a/board-room/src/main/java/net/stzups/board/BoardRoom.java +++ b/board-room/src/main/java/net/stzups/board/BoardRoom.java @@ -1,11 +1,12 @@ package net.stzups.board; import io.netty.channel.ChannelFuture; -import net.stzups.board.config.Config; -import net.stzups.board.config.ConfigBuilder; -import net.stzups.board.config.configs.ArgumentConfig; -import net.stzups.board.config.configs.EnvironmentVariableConfig; -import net.stzups.board.config.configs.PropertiesConfig; +import net.stzups.board.util.config.Config; +import net.stzups.board.util.config.ConfigBuilder; +import net.stzups.board.util.LogFactory; +import net.stzups.board.util.config.configs.ArgumentConfig; +import net.stzups.board.util.config.configs.EnvironmentVariableConfig; +import net.stzups.board.util.config.configs.PropertiesConfig; import net.stzups.board.data.database.Database; import net.stzups.board.data.database.memory.MemoryDatabase; import net.stzups.board.data.database.postgres.PostgresDatabase; @@ -40,13 +41,15 @@ public static void main(String[] args) throws Exception { .addConfig(new EnvironmentVariableConfig("board.")) .build(); - Boolean postgres = config.getBoolean("postgres"); + Boolean postgres = BoardRoom.getConfig().getBoolean(BoardConfigKeys.POSTGRES); if (postgres == null) { throw new IllegalArgumentException("Failed to specify required runtime variable --postgres"); } else { if (postgres) { logger.info("Connecting to Postgres database..."); - database = new PostgresDatabase(BoardRoom.getConfig().get("postgres.url"), BoardRoom.getConfig().get("postgres.user"), BoardRoom.getConfig().get("postgres.password")); + database = new PostgresDatabase(BoardRoom.getConfig().getString(BoardConfigKeys.POSTGRES_URL), + BoardRoom.getConfig().getString(BoardConfigKeys.POSTGRES_USER), + BoardRoom.getConfig().getString(BoardConfigKeys.POSTGRES_PASSWORD)); logger.info("Connected to Postgres database"); } else { logger.warning("Using debug only runtime database. No data will be persisted."); diff --git a/board-room/src/main/java/net/stzups/board/config/Config.java b/board-room/src/main/java/net/stzups/board/config/Config.java deleted file mode 100644 index 9a359e90..00000000 --- a/board-room/src/main/java/net/stzups/board/config/Config.java +++ /dev/null @@ -1,77 +0,0 @@ -package net.stzups.board.config; - -import java.util.List; - -/** - * Used to store and retrieve key-value pairs by finding the first result from many different strategies. - */ -public class Config {//todo probably needs a better name - private List configProviders; - - /** - * Constructs a new ConfigProvider from its builder - */ - Config(List configProviders) { - this.configProviders = configProviders; - } - - /** - * Gets a String value for a String key from any config provider - */ - public String get(String key) { - for (ConfigProvider configProvider : configProviders) { - String value = configProvider.get(key); - if (value != null) { - return value; - } - } - - return null; - } - - //todo @Nullable annotations? - public Integer getInt(String key) { - try { - return Integer.parseInt(get(key)); - } catch (NumberFormatException e) { - return null; - } - } - - public int getInt(String key, int defaultValue) { - try { - return Integer.parseInt(get(key)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - public Boolean getBoolean(String key) { - String value = get(key); - if (value != null) { - if (value.equalsIgnoreCase("true")) { - return true; - } else if (value.equalsIgnoreCase("false")) { - return false; - } - } - return null; - } - - public boolean getBoolean(String key, boolean defaultValue) { - String value = get(key); - if (value == null) { - return defaultValue; - } else { - return Boolean.parseBoolean(value); - } - } - - public String get(String key, String defaultValue) { - String value = get(key); - if (value == null) { - return defaultValue; - } - return value; - } -} diff --git a/board-room/src/main/java/net/stzups/board/server/Server.java b/board-room/src/main/java/net/stzups/board/server/Server.java index 415dfffb..38dcc802 100644 --- a/board-room/src/main/java/net/stzups/board/server/Server.java +++ b/board-room/src/main/java/net/stzups/board/server/Server.java @@ -10,8 +10,9 @@ import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslProvider; +import net.stzups.board.BoardConfigKeys; import net.stzups.board.BoardRoom; -import net.stzups.board.LogFactory; +import net.stzups.board.util.LogFactory; import javax.net.ssl.KeyManagerFactory; import java.io.FileInputStream; @@ -36,40 +37,29 @@ public ChannelFuture start() throws Exception { SslContext sslContext; int port; - Boolean ssl = BoardRoom.getConfig().getBoolean("ssl"); - if (ssl == null) { - throw new IllegalArgumentException("Failed to set required runtime variable --ssl. Perhaps you meant to explicitly disable encrypted sockets over HTTPS using --ssl false"); - } + Boolean ssl = BoardRoom.getConfig().getBoolean(BoardConfigKeys.SSL); if (!ssl) { BoardRoom.getLogger().warning("Starting server using insecure http:// protocol without SSL"); sslContext = null;//otherwise sslEngine is null and program continues with unencrypted sockets port = HTTP_PORT; } else { - String keystorePath = BoardRoom.getConfig().get("ssl.keystore.path"); - if (keystorePath != null) {//must not be null - String passphrase = BoardRoom.getConfig().get("ssl.passphrase"); - if (passphrase != null) {//can be null if value of keystore is http - try (FileInputStream fileInputStream = new FileInputStream(keystorePath)) { - KeyStore keyStore = KeyStore.getInstance("PKCS12"); - keyStore.load(fileInputStream, passphrase.toCharArray()); + String keystorePath = BoardRoom.getConfig().getString(BoardConfigKeys.SSL_KEYSTORE_PATH); + String passphrase = BoardRoom.getConfig().getString(BoardConfigKeys.SSL_KEYSTORE_PASSPHRASE); + try (FileInputStream fileInputStream = new FileInputStream(keystorePath)) { + KeyStore keyStore = KeyStore.getInstance("PKCS12"); + keyStore.load(fileInputStream, passphrase.toCharArray()); - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - keyManagerFactory.init(keyStore, passphrase.toCharArray()); + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, passphrase.toCharArray()); - //SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); - sslContext = SslContextBuilder.forServer(keyManagerFactory) - .sslProvider(SslProvider.JDK) - .build(); - port = HTTPS_PORT; - } catch (IOException | GeneralSecurityException e) { - throw new Exception("Exception while getting SSL context", e); - } - } else { - throw new IllegalArgumentException("Failed to specify SSL passphrase from --ssl.passphrase flag."); - } - } else { - throw new IllegalArgumentException("Failed to set specify SSL keystore path from --ssl.keystore.path flag."); + //SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); + sslContext = SslContextBuilder.forServer(keyManagerFactory) + .sslProvider(SslProvider.JDK) + .build(); + port = HTTPS_PORT; + } catch (IOException | GeneralSecurityException e) { + throw new Exception("Exception while getting SSL context", e); } } diff --git a/board-room/src/main/java/net/stzups/board/server/ServerInitializer.java b/board-room/src/main/java/net/stzups/board/server/ServerInitializer.java index 57152241..8d86715b 100644 --- a/board-room/src/main/java/net/stzups/board/server/ServerInitializer.java +++ b/board-room/src/main/java/net/stzups/board/server/ServerInitializer.java @@ -13,8 +13,9 @@ import io.netty.handler.traffic.GlobalTrafficShapingHandler; import io.netty.handler.traffic.TrafficCounter; import io.netty.util.AttributeKey; +import net.stzups.board.BoardConfigKeys; import net.stzups.board.BoardRoom; -import net.stzups.board.LogFactory; +import net.stzups.board.util.LogFactory; import net.stzups.board.server.websocket.protocol.MessageDecoder; import net.stzups.board.server.websocket.protocol.MessageEncoder; @@ -30,12 +31,11 @@ public class ServerInitializer extends ChannelInitializer { public static final AttributeKey LOGGER = AttributeKey.valueOf(ServerInitializer.class, "LOGGER"); private static final String WEB_SOCKET_PATH = "/websocket"; - private static final boolean DEBUG_LOG_TRAFFIC = BoardRoom.getConfig().getBoolean("debug.log.traffic", false); private GlobalTrafficShapingHandler globalTrafficShapingHandler = new GlobalTrafficShapingHandler(Executors.newSingleThreadScheduledExecutor(), 0, 0, 1000) { @Override protected void doAccounting(TrafficCounter counter) { - if (DEBUG_LOG_TRAFFIC) System.out.print("\rread " + (double) counter.lastReadThroughput() / 1000 * 8 + "kb/s, write " + (double) counter.lastWriteThroughput() / 1000 * 8 + "kb/s"); + if (BoardRoom.getConfig().getBoolean(BoardConfigKeys.DEBUG_LOG_TRAFFIC)) System.out.print("\rread " + (double) counter.lastReadThroughput() / 1000 * 8 + "kb/s, write " + (double) counter.lastWriteThroughput() / 1000 * 8 + "kb/s"); } }; diff --git a/board-room/src/main/java/net/stzups/board/LogFactory.java b/board-room/src/main/java/net/stzups/board/util/LogFactory.java similarity index 97% rename from board-room/src/main/java/net/stzups/board/LogFactory.java rename to board-room/src/main/java/net/stzups/board/util/LogFactory.java index 7923a74f..72c75d13 100644 --- a/board-room/src/main/java/net/stzups/board/LogFactory.java +++ b/board-room/src/main/java/net/stzups/board/util/LogFactory.java @@ -1,4 +1,4 @@ -package net.stzups.board; +package net.stzups.board.util; import java.sql.Timestamp; import java.text.SimpleDateFormat; diff --git a/board-room/src/main/java/net/stzups/board/RandomString.java b/board-room/src/main/java/net/stzups/board/util/RandomString.java similarity index 94% rename from board-room/src/main/java/net/stzups/board/RandomString.java rename to board-room/src/main/java/net/stzups/board/util/RandomString.java index d5571aea..a47b73f0 100644 --- a/board-room/src/main/java/net/stzups/board/RandomString.java +++ b/board-room/src/main/java/net/stzups/board/util/RandomString.java @@ -1,4 +1,4 @@ -package net.stzups.board; +package net.stzups.board.util; import java.util.Random; diff --git a/board-room/src/main/java/net/stzups/board/util/config/Config.java b/board-room/src/main/java/net/stzups/board/util/config/Config.java new file mode 100644 index 00000000..f35d661c --- /dev/null +++ b/board-room/src/main/java/net/stzups/board/util/config/Config.java @@ -0,0 +1,65 @@ +package net.stzups.board.util.config; + +import java.util.List; + +/** + * Used to store and retrieve key-value pairs by finding the first result from many different strategies. + */ +public class Config {//todo probably needs a better name + private List configProviders; + + /** + * Constructs a new ConfigProvider from its builder + */ + Config(List configProviders) { + this.configProviders = configProviders; + } + + /** + * Gets a String value for a String key from any config provider + */ + private String find(ConfigKey key) { + for (ConfigProvider configProvider : configProviders) { + String value = configProvider.get(key.getKey()); + if (value != null) { + return value; + } + } + + return null; + } + + public String getString(ConfigKey key) { + String value = find(key); + if (value != null) { + return value; + } + return key.getDefaultValue(null); + } + + public int getInt(ConfigKey key) { + String value = find(key); + if (value != null) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + return key.getDefaultValue(e); + } + } + return key.getDefaultValue(null); + } + + public Boolean getBoolean(ConfigKey key) { + String value = find(key); + if (value != null) { + if (value.equalsIgnoreCase("true")) { + return true; + } else if (value.equalsIgnoreCase("false")) { + return false; + } else { + return key.getDefaultValue(new IllegalArgumentException(value + " is not true or false")); + } + } + return key.getDefaultValue(null); + } +} diff --git a/board-room/src/main/java/net/stzups/board/config/ConfigBuilder.java b/board-room/src/main/java/net/stzups/board/util/config/ConfigBuilder.java similarity index 92% rename from board-room/src/main/java/net/stzups/board/config/ConfigBuilder.java rename to board-room/src/main/java/net/stzups/board/util/config/ConfigBuilder.java index 884384e4..484b408a 100644 --- a/board-room/src/main/java/net/stzups/board/config/ConfigBuilder.java +++ b/board-room/src/main/java/net/stzups/board/util/config/ConfigBuilder.java @@ -1,4 +1,4 @@ -package net.stzups.board.config; +package net.stzups.board.util.config; import java.util.ArrayList; import java.util.List; diff --git a/board-room/src/main/java/net/stzups/board/util/config/ConfigKey.java b/board-room/src/main/java/net/stzups/board/util/config/ConfigKey.java new file mode 100644 index 00000000..1a59b9fe --- /dev/null +++ b/board-room/src/main/java/net/stzups/board/util/config/ConfigKey.java @@ -0,0 +1,17 @@ +package net.stzups.board.util.config; + +public class ConfigKey { + private String key; + + ConfigKey(String key) { + this.key = key; + } + + String getKey() { + return key; + } + + T getDefaultValue(Exception e) { + throw new UnsupportedOperationException("Method should be overridden"); + } +} diff --git a/board-room/src/main/java/net/stzups/board/config/ConfigProvider.java b/board-room/src/main/java/net/stzups/board/util/config/ConfigProvider.java similarity index 63% rename from board-room/src/main/java/net/stzups/board/config/ConfigProvider.java rename to board-room/src/main/java/net/stzups/board/util/config/ConfigProvider.java index b892a205..464f50a9 100644 --- a/board-room/src/main/java/net/stzups/board/config/ConfigProvider.java +++ b/board-room/src/main/java/net/stzups/board/util/config/ConfigProvider.java @@ -1,4 +1,4 @@ -package net.stzups.board.config; +package net.stzups.board.util.config; public interface ConfigProvider { String get(String key); diff --git a/board-room/src/main/java/net/stzups/board/util/config/OptionalConfigKey.java b/board-room/src/main/java/net/stzups/board/util/config/OptionalConfigKey.java new file mode 100644 index 00000000..cf9c3a25 --- /dev/null +++ b/board-room/src/main/java/net/stzups/board/util/config/OptionalConfigKey.java @@ -0,0 +1,17 @@ +package net.stzups.board.util.config; + +public class OptionalConfigKey extends ConfigKey { + private T defaultValue; + + public OptionalConfigKey(String key, T defaultValue) { + super(key); + this.defaultValue = defaultValue; + } + + T getDefaultValue(Exception e) { + if (e != null) { + new Exception("Non fatal exception while parsing value for key \"" + getKey() + "\", default value will be used", e).printStackTrace(); + } + return defaultValue; + } +} diff --git a/board-room/src/main/java/net/stzups/board/util/config/RequiredConfigKey.java b/board-room/src/main/java/net/stzups/board/util/config/RequiredConfigKey.java new file mode 100644 index 00000000..b829b0ac --- /dev/null +++ b/board-room/src/main/java/net/stzups/board/util/config/RequiredConfigKey.java @@ -0,0 +1,16 @@ +package net.stzups.board.util.config; + +public class RequiredConfigKey extends ConfigKey { + public RequiredConfigKey(String key) { + super(key); + } + + @Override + T getDefaultValue(Exception e) { + if (e != null) { + throw new IllegalArgumentException("Parsing value for required config key \"" + getKey() + "\" caused exception", e); + } else { + throw new IllegalArgumentException("Missing value for required config key \"" + getKey() + "\""); + } + } +} diff --git a/board-room/src/main/java/net/stzups/board/config/configs/ArgumentConfig.java b/board-room/src/main/java/net/stzups/board/util/config/configs/ArgumentConfig.java similarity index 93% rename from board-room/src/main/java/net/stzups/board/config/configs/ArgumentConfig.java rename to board-room/src/main/java/net/stzups/board/util/config/configs/ArgumentConfig.java index b7d0c911..c59dd1d8 100644 --- a/board-room/src/main/java/net/stzups/board/config/configs/ArgumentConfig.java +++ b/board-room/src/main/java/net/stzups/board/util/config/configs/ArgumentConfig.java @@ -1,6 +1,6 @@ -package net.stzups.board.config.configs; +package net.stzups.board.util.config.configs; -import net.stzups.board.config.ConfigProvider; +import net.stzups.board.util.config.ConfigProvider; import java.util.Arrays; import java.util.HashMap; diff --git a/board-room/src/main/java/net/stzups/board/config/configs/EnvironmentVariableConfig.java b/board-room/src/main/java/net/stzups/board/util/config/configs/EnvironmentVariableConfig.java similarity index 78% rename from board-room/src/main/java/net/stzups/board/config/configs/EnvironmentVariableConfig.java rename to board-room/src/main/java/net/stzups/board/util/config/configs/EnvironmentVariableConfig.java index 3fcd067c..db710f9a 100644 --- a/board-room/src/main/java/net/stzups/board/config/configs/EnvironmentVariableConfig.java +++ b/board-room/src/main/java/net/stzups/board/util/config/configs/EnvironmentVariableConfig.java @@ -1,6 +1,6 @@ -package net.stzups.board.config.configs; +package net.stzups.board.util.config.configs; -import net.stzups.board.config.ConfigProvider; +import net.stzups.board.util.config.ConfigProvider; import java.util.Objects; diff --git a/board-room/src/main/java/net/stzups/board/config/configs/PropertiesConfig.java b/board-room/src/main/java/net/stzups/board/util/config/configs/PropertiesConfig.java similarity index 91% rename from board-room/src/main/java/net/stzups/board/config/configs/PropertiesConfig.java rename to board-room/src/main/java/net/stzups/board/util/config/configs/PropertiesConfig.java index a918299a..6482c3e1 100644 --- a/board-room/src/main/java/net/stzups/board/config/configs/PropertiesConfig.java +++ b/board-room/src/main/java/net/stzups/board/util/config/configs/PropertiesConfig.java @@ -1,6 +1,6 @@ -package net.stzups.board.config.configs; +package net.stzups.board.util.config.configs; -import net.stzups.board.config.ConfigProvider; +import net.stzups.board.util.config.ConfigProvider; import java.io.File; import java.io.FileInputStream; From bf014449db22a15748ed3c3d55aa0c2d5da31aa3 Mon Sep 17 00:00:00 2001 From: stzups Date: Sun, 4 Apr 2021 16:53:49 -0400 Subject: [PATCH 21/35] quick refactor --- .../main/java/net/stzups/board/BoardRoom.java | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/board-room/src/main/java/net/stzups/board/BoardRoom.java b/board-room/src/main/java/net/stzups/board/BoardRoom.java index 32ae089f..a5a2c4b9 100644 --- a/board-room/src/main/java/net/stzups/board/BoardRoom.java +++ b/board-room/src/main/java/net/stzups/board/BoardRoom.java @@ -41,20 +41,15 @@ public static void main(String[] args) throws Exception { .addConfig(new EnvironmentVariableConfig("board.")) .build(); - Boolean postgres = BoardRoom.getConfig().getBoolean(BoardConfigKeys.POSTGRES); - if (postgres == null) { - throw new IllegalArgumentException("Failed to specify required runtime variable --postgres"); + if (BoardRoom.getConfig().getBoolean(BoardConfigKeys.POSTGRES)) { + logger.info("Connecting to Postgres database..."); + database = new PostgresDatabase(BoardRoom.getConfig().getString(BoardConfigKeys.POSTGRES_URL), + BoardRoom.getConfig().getString(BoardConfigKeys.POSTGRES_USER), + BoardRoom.getConfig().getString(BoardConfigKeys.POSTGRES_PASSWORD)); + logger.info("Connected to Postgres database"); } else { - if (postgres) { - logger.info("Connecting to Postgres database..."); - database = new PostgresDatabase(BoardRoom.getConfig().getString(BoardConfigKeys.POSTGRES_URL), - BoardRoom.getConfig().getString(BoardConfigKeys.POSTGRES_USER), - BoardRoom.getConfig().getString(BoardConfigKeys.POSTGRES_PASSWORD)); - logger.info("Connected to Postgres database"); - } else { - logger.warning("Using debug only runtime database. No data will be persisted."); - database = new MemoryDatabase(); - } + logger.warning("Using debug only runtime database. No data will be persisted."); + database = new MemoryDatabase(); } Server server = new Server(); From 35eebc81fe4adf6e5548902ca7db2df45f5092b3 Mon Sep 17 00:00:00 2001 From: stzups Date: Sun, 4 Apr 2021 17:11:30 -0400 Subject: [PATCH 22/35] improve MessageDigest --- .../main/java/net/stzups/board/BoardRoom.java | 7 ------- .../data/objects/PersistentUserSession.java | 17 ++++++++++++++--- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/board-room/src/main/java/net/stzups/board/BoardRoom.java b/board-room/src/main/java/net/stzups/board/BoardRoom.java index a5a2c4b9..f494f740 100644 --- a/board-room/src/main/java/net/stzups/board/BoardRoom.java +++ b/board-room/src/main/java/net/stzups/board/BoardRoom.java @@ -22,7 +22,6 @@ public class BoardRoom { private static Config config; private static final SecureRandom secureRandom = new SecureRandom(); private static final Random random = new Random(); - private static MessageDigest SHA256MessageDigest; private static Database database;//user id -> user @@ -33,8 +32,6 @@ public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); - SHA256MessageDigest = MessageDigest.getInstance("SHA-256"); - config = new ConfigBuilder() .addConfig(new ArgumentConfig(args)) .addConfig(new PropertiesConfig("board.properties")) @@ -84,10 +81,6 @@ public static SecureRandom getSecureRandom() { return secureRandom; } - public static MessageDigest getSHA256MessageDigest() { - return SHA256MessageDigest; - } - public static Random getRandom() { return random; } diff --git a/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java b/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java index d73050ab..47e69df2 100644 --- a/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java +++ b/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java @@ -3,10 +3,21 @@ import io.netty.buffer.Unpooled; import net.stzups.board.BoardRoom; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.Arrays; public class PersistentUserSession { - private static final int MAX_USER_SESSION_AGE = 10000000;//todo + private static final int MAX_USER_SESSION_AGE = 0;//todo + private static MessageDigest messageDigest; + static { + try { + messageDigest = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + private long id; private long user; private long creationTime; @@ -28,7 +39,7 @@ public PersistentUserSession(long id, long user, long creationTime, byte[] hashe /** should be called once after instance creation */ public long generateToken() { long token = BoardRoom.getSecureRandom().nextLong(); - hashedToken = BoardRoom.getSHA256MessageDigest().digest(Unpooled.copyLong(token).array()); + hashedToken = messageDigest.digest(Unpooled.copyLong(token).array()); return token; } @@ -49,7 +60,7 @@ public byte[] getHashedToken() { } public boolean validate(long token) { - byte[] hashedToken = BoardRoom.getSHA256MessageDigest().digest(Unpooled.copyLong(token).array()); + byte[] hashedToken = messageDigest.digest(Unpooled.copyLong(token).array()); boolean validate = (System.currentTimeMillis() - creationTime) < MAX_USER_SESSION_AGE && Arrays.equals(this.hashedToken, hashedToken); //this session will have already been deleted in db and should be garbage collected right after this, but just in case zero the hashes so it won't work again Arrays.fill(this.hashedToken, (byte) 0); From 69b8b7bd82dcfb153f9afd98556403b0b7816e24 Mon Sep 17 00:00:00 2001 From: stzups Date: Sun, 4 Apr 2021 17:20:10 -0400 Subject: [PATCH 23/35] probably improved SecureRandom but idk --- board-room/src/main/java/net/stzups/board/BoardRoom.java | 5 ----- .../main/java/net/stzups/board/data/objects/Document.java | 2 +- .../stzups/board/data/objects/PersistentUserSession.java | 8 +++++--- .../src/main/java/net/stzups/board/data/objects/User.java | 2 +- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/board-room/src/main/java/net/stzups/board/BoardRoom.java b/board-room/src/main/java/net/stzups/board/BoardRoom.java index f494f740..6d244c7a 100644 --- a/board-room/src/main/java/net/stzups/board/BoardRoom.java +++ b/board-room/src/main/java/net/stzups/board/BoardRoom.java @@ -20,7 +20,6 @@ public class BoardRoom { private static Logger logger; private static Config config; - private static final SecureRandom secureRandom = new SecureRandom(); private static final Random random = new Random(); private static Database database;//user id -> user @@ -77,10 +76,6 @@ public static Database getDatabase() { return database; } - public static SecureRandom getSecureRandom() { - return secureRandom; - } - public static Random getRandom() { return random; } diff --git a/board-room/src/main/java/net/stzups/board/data/objects/Document.java b/board-room/src/main/java/net/stzups/board/data/objects/Document.java index 3aad86e9..4200a7ee 100644 --- a/board-room/src/main/java/net/stzups/board/data/objects/Document.java +++ b/board-room/src/main/java/net/stzups/board/data/objects/Document.java @@ -16,7 +16,7 @@ public class Document { * New document */ public Document(User owner) { - this.id = BoardRoom.getSecureRandom().nextLong(); + this.id = BoardRoom.getRandom().nextLong(); this.owner = owner; owner.getOwnedDocuments().add(id); this.name = DEFAULT_DOCUMENT_NAME; diff --git a/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java b/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java index 47e69df2..9a8f14c0 100644 --- a/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java +++ b/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java @@ -5,11 +5,13 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.util.Arrays; public class PersistentUserSession { private static final int MAX_USER_SESSION_AGE = 0;//todo - private static MessageDigest messageDigest; + private static final SecureRandom secureRandom = new SecureRandom(); + private static final MessageDigest messageDigest; static { try { messageDigest = MessageDigest.getInstance("SHA-256"); @@ -24,7 +26,7 @@ public class PersistentUserSession { private byte[] hashedToken; public PersistentUserSession(User user) { - this.id = BoardRoom.getSecureRandom().nextLong();//todo secure random or regular random? + this.id = BoardRoom.getRandom().nextLong();//todo secure random or regular random? this.user = user.getId(); this.creationTime = System.currentTimeMillis(); } @@ -38,7 +40,7 @@ public PersistentUserSession(long id, long user, long creationTime, byte[] hashe /** should be called once after instance creation */ public long generateToken() { - long token = BoardRoom.getSecureRandom().nextLong(); + long token = secureRandom.nextLong(); hashedToken = messageDigest.digest(Unpooled.copyLong(token).array()); return token; } diff --git a/board-room/src/main/java/net/stzups/board/data/objects/User.java b/board-room/src/main/java/net/stzups/board/data/objects/User.java index d88bf31c..3061cf9d 100644 --- a/board-room/src/main/java/net/stzups/board/data/objects/User.java +++ b/board-room/src/main/java/net/stzups/board/data/objects/User.java @@ -11,7 +11,7 @@ public class User { private List sharedDocuments; public User() { - id = BoardRoom.getSecureRandom().nextLong(); + id = BoardRoom.getRandom().nextLong(); ownedDocuments = new ArrayList<>(); //ownedDocuments.add(Document.createDocument(this).getId()); todo do somewhere else sharedDocuments = new ArrayList<>(); From 3a594b6bdc37edb97557975d542a91d9143bc8c1 Mon Sep 17 00:00:00 2001 From: stzups Date: Sun, 4 Apr 2021 17:58:44 -0400 Subject: [PATCH 24/35] fix db creation --- board-database/init.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/board-database/init.sql b/board-database/init.sql index 9ef4dd13..231a39e2 100644 --- a/board-database/init.sql +++ b/board-database/init.sql @@ -3,12 +3,12 @@ CREATE DATABASE board; -- Connect to board database (currently on default postgres database) \c board -REVOKE CONNECT FROM PUBLIC; +REVOKE CONNECT ON DATABASE board FROM PUBLIC; REVOKE ALL ON SCHEMA public FROM PUBLIC; -- CREATE SCHEMA board; -- GRANT USAGE ON SCHEMA board TO board_room; todo use schema and put tables on it? -GRANT CONNECT TO board_room; -GRANT USAGE TO board_room; +GRANT CONNECT ON DATABASE board TO board_room; +GRANT USAGE ON SCHEMA public TO board_room; -- Create tables and grant permissions CREATE TABLE users( @@ -36,7 +36,7 @@ GRANT SELECT, INSERT, UPDATE ON canvases TO board_room; CREATE TABLE persistent_user_sessions( id BIGINT NOT NULL, - creation_time BIGINT NOT NULL, + creation_time TIMESTAMP NOT NULL, hashed_token bytea NOT NULL, PRIMARY KEY (id) ); From 19c071d62bed7e935fd0367c90f0ce305be4ad4c Mon Sep 17 00:00:00 2001 From: stzups Date: Sun, 4 Apr 2021 17:59:34 -0400 Subject: [PATCH 25/35] remove unnecessary file --- board-room/src/main/resources/META-INF/mime.types | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 board-room/src/main/resources/META-INF/mime.types diff --git a/board-room/src/main/resources/META-INF/mime.types b/board-room/src/main/resources/META-INF/mime.types deleted file mode 100644 index a2de552d..00000000 --- a/board-room/src/main/resources/META-INF/mime.types +++ /dev/null @@ -1,5 +0,0 @@ -application/javascript js -text/css css -image/x-icon ico -text/html htm html -image/png png \ No newline at end of file From b9320f0ac86aacfeca27b2eba8bb87a8df0fbdda Mon Sep 17 00:00:00 2001 From: stzups Date: Sun, 4 Apr 2021 19:57:43 -0400 Subject: [PATCH 26/35] add domains to db, change names --- board-database/init.sql | 27 ++++++++++--------- .../database/postgres/PostgresDatabase.java | 4 +-- .../data/objects/PersistentUserSession.java | 22 ++++++++------- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/board-database/init.sql b/board-database/init.sql index 231a39e2..a2175bb2 100644 --- a/board-database/init.sql +++ b/board-database/init.sql @@ -1,42 +1,45 @@ -CREATE USER board_room PASSWORD 'changeme'; CREATE DATABASE board; -- Connect to board database (currently on default postgres database) \c board REVOKE CONNECT ON DATABASE board FROM PUBLIC; REVOKE ALL ON SCHEMA public FROM PUBLIC; --- CREATE SCHEMA board; --- GRANT USAGE ON SCHEMA board TO board_room; todo use schema and put tables on it? + +CREATE USER board_room PASSWORD 'changeme'; GRANT CONNECT ON DATABASE board TO board_room; GRANT USAGE ON SCHEMA public TO board_room; +CREATE DOMAIN user_id AS bigint; +CREATE DOMAIN document_id AS bigint; +CREATE DOMAIN persistent_user_session_id AS bigint; -- Create tables and grant permissions CREATE TABLE users( - id BIGINT NOT NULL, - owned_documents BIGINT[] NOT NULL, - shared_documents BIGINT[] NOT NULL, + id user_id NOT NULL, + owned_documents document_id[] NOT NULL, + shared_documents document_id[] NOT NULL, PRIMARY KEY (id) ); GRANT SELECT, INSERT, UPDATE ON users TO board_room; CREATE TABLE documents( - id BIGINT NOT NULL, - owner BIGINT NOT NULL, - name CHAR NOT NULL, + id document_id NOT NULL, + owner user_id NOT NULL, + name varchar(64) not null, PRIMARY KEY (id) ); GRANT SELECT, INSERT, UPDATE ON documents TO board_room; CREATE TABLE canvases( - document BIGINT NOT NULL, + document document_id NOT NULL, data bytea NOT NULL, PRIMARY KEY (document) ); GRANT SELECT, INSERT, UPDATE ON canvases TO board_room; CREATE TABLE persistent_user_sessions( - id BIGINT NOT NULL, - creation_time TIMESTAMP NOT NULL, + id persistent_user_session_id NOT NULL, + "user" user_id NOT NULL, + creation_time timestamp, hashed_token bytea NOT NULL, PRIMARY KEY (id) ); diff --git a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java index 4ef6b060..defaab46 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java +++ b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java @@ -153,7 +153,7 @@ public void addUserSession(PersistentUserSession persistentUserSession) { PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO persistent_user_sessions(id, \"user\", creation_time, hashed_token) VALUES (?, ?, ?, ?)"); preparedStatement.setLong(1, persistentUserSession.getId()); preparedStatement.setLong(2, persistentUserSession.getUser()); - preparedStatement.setLong(3, persistentUserSession.getCreationTime()); + preparedStatement.setTimestamp(3, persistentUserSession.getCreation()); preparedStatement.setBinaryStream(4, new ByteArrayInputStream(persistentUserSession.getHashedToken())); preparedStatement.execute(); } catch (SQLException e) { @@ -173,7 +173,7 @@ public PersistentUserSession removeUserSession(long id) { if (!resultSet.next()) { return null; } - PersistentUserSession persistentUserSession = new PersistentUserSession(id, resultSet.getLong("user"), resultSet.getLong("creation_time"), resultSet.getBinaryStream("hashed_token").readAllBytes()); + PersistentUserSession persistentUserSession = new PersistentUserSession(id, resultSet.getLong("user"), resultSet.getTimestamp("creation_time"), resultSet.getBinaryStream("hashed_token").readAllBytes()); preparedStatement = connection.prepareStatement("DELETE FROM persistent_user_sessions WHERE id=?"); preparedStatement.setLong(1, id); preparedStatement.execute(); diff --git a/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java b/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java index 9a8f14c0..4d891536 100644 --- a/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java +++ b/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java @@ -6,10 +6,14 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import java.sql.Timestamp; +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.TemporalAmount; import java.util.Arrays; public class PersistentUserSession { - private static final int MAX_USER_SESSION_AGE = 0;//todo + private static final TemporalAmount MAX_USER_SESSION_AGE = Duration.ofDays(90);//todo private static final SecureRandom secureRandom = new SecureRandom(); private static final MessageDigest messageDigest; static { @@ -22,19 +26,19 @@ public class PersistentUserSession { private long id; private long user; - private long creationTime; + private Timestamp creation; private byte[] hashedToken; public PersistentUserSession(User user) { this.id = BoardRoom.getRandom().nextLong();//todo secure random or regular random? this.user = user.getId(); - this.creationTime = System.currentTimeMillis(); + this.creation = new Timestamp(Instant.now().toEpochMilli()); } - public PersistentUserSession(long id, long user, long creationTime, byte[] hashedToken) { + public PersistentUserSession(long id, long user, Timestamp creation, byte[] hashedToken) { this.id = id; this.user = user; - this.creationTime = creationTime; + this.creation = creation; this.hashedToken = hashedToken; } @@ -53,8 +57,8 @@ public long getUser() { return user; } - public long getCreationTime() { - return creationTime; + public Timestamp getCreation() { + return creation; } public byte[] getHashedToken() { @@ -63,7 +67,7 @@ public byte[] getHashedToken() { public boolean validate(long token) { byte[] hashedToken = messageDigest.digest(Unpooled.copyLong(token).array()); - boolean validate = (System.currentTimeMillis() - creationTime) < MAX_USER_SESSION_AGE && Arrays.equals(this.hashedToken, hashedToken); + boolean validate = Instant.now().isBefore(creation.toInstant().plus(MAX_USER_SESSION_AGE)) && Arrays.equals(this.hashedToken, hashedToken); //this session will have already been deleted in db and should be garbage collected right after this, but just in case zero the hashes so it won't work again Arrays.fill(this.hashedToken, (byte) 0); return validate; @@ -71,7 +75,7 @@ public boolean validate(long token) { @Override public String toString() { - return "UserSession{id=" + id + ",user" + user + ",creationTime=" + creationTime + "}"; + return "UserSession{id=" + id + ",user" + user + ",creationTime=" + creation + "}"; } @Override From 183b01c9e6fcf4a73cd69a67dd0ff8d8ac2ccd88 Mon Sep 17 00:00:00 2001 From: stzups Date: Sun, 4 Apr 2021 20:16:51 -0400 Subject: [PATCH 27/35] probably clean up db code, doesn't work --- .../database/postgres/PostgresDatabase.java | 100 ++++++++++-------- 1 file changed, 54 insertions(+), 46 deletions(-) diff --git a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java index defaab46..6b48e76d 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java +++ b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java @@ -2,6 +2,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import net.stzups.board.BoardRoom; import net.stzups.board.data.database.Database; import net.stzups.board.data.objects.Document; import net.stzups.board.data.objects.PersistentUserSession; @@ -33,8 +34,7 @@ public PostgresDatabase(String url, String user, String password) throws Excepti @Override public void addUser(User user) { - try { - PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO users(id, owned_documents, shared_documents) VALUES (?, ?, ?)"); + try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO users(id, owned_documents, shared_documents) VALUES (?, ?, ?)")) { preparedStatement.setLong(1, user.getId()); preparedStatement.setArray(2, connection.createArrayOf("bigint", user.getOwnedDocuments().toArray())); preparedStatement.setArray(3, connection.createArrayOf("bigint", user.getSharedDocuments().toArray())); @@ -47,31 +47,32 @@ public void addUser(User user) { @Override public User getUser(long id) { - try { - User user = users.get(id); - if (user == null) { - PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM users WHERE id=?"); + User user = users.get(id); + if (user == null) { + try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM users WHERE id=?")) { preparedStatement.setLong(1, id); ResultSet resultSet = preparedStatement.executeQuery(); - if (!resultSet.next()) { - System.out.println("user does not exist"); + if (resultSet.next()) { + user = new User(id, + new ArrayList<>(Arrays.asList((Long[]) resultSet.getArray("owned_documents").getArray())), + new ArrayList<>(Arrays.asList((Long[]) resultSet.getArray("shared_documents").getArray()))); + users.put(user.getId(), user); + } else { + BoardRoom.getLogger().warning("User with id " + id + " does not exist"); return null; } - user = new User(id, new ArrayList<>(Arrays.asList((Long[]) resultSet.getArray("owned_documents").getArray())), new ArrayList<>(Arrays.asList((Long[]) resultSet.getArray("shared_documents").getArray()))); - users.put(user.getId(), user); + } catch (SQLException e) { + e.printStackTrace(); + return null; } - return user; - } catch (SQLException e) { - e.printStackTrace(); - return null; } + return user; } @Override public Document createDocument(User owner) { Document document = new Document(owner); - try { - PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO documents(id, owner, name) VALUES (?, ?, ?)"); + try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO documents(id, owner, name) VALUES (?, ?, ?)")){ preparedStatement.setLong(1, document.getId()); preparedStatement.setLong(2, document.getOwner().getId()); preparedStatement.setString(3, document.getName()); @@ -86,35 +87,36 @@ public Document createDocument(User owner) { @Override public Document getDocument(long id) { - try { - Document document = documents.get(id); - if (document == null) { - PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM documents WHERE id=?"); + Document document = documents.get(id); + if (document == null) { + try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM documents WHERE id=?")) { preparedStatement.setLong(1, id); ResultSet resultSet = preparedStatement.executeQuery(); - if (!resultSet.next()) { - System.out.println("document does not exist"); - return null; - } - User user = getUser(resultSet.getLong("owner")); - if (user == null) { - System.out.println("no owner for document"); + if (resultSet.next()) { + long userId = resultSet.getLong("owner"); + User user = getUser(userId); + if (user == null) { + BoardRoom.getLogger().warning("Document with id " + id + " has no owner with id " + userId); + return null; + } + document = new Document(id, user, resultSet.getString("name")); + documents.put(document.getId(), document); + } else { + BoardRoom.getLogger().warning("Document with id " + id + " does not exist"); return null; + } - document = new Document(id, user, resultSet.getString("name")); - documents.put(document.getId(), document); + } catch (SQLException e) { + e.printStackTrace(); + return null; } - return document; - } catch (SQLException e) { - e.printStackTrace(); - return null; } + return document; } @Override public Canvas getCanvas(Document document) { - try { - PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM canvases WHERE document=?"); + try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM canvases WHERE document=?")) { preparedStatement.setLong(1, document.getId()); ResultSet resultSet = preparedStatement.executeQuery(); if (resultSet.next()) { @@ -124,14 +126,13 @@ public Canvas getCanvas(Document document) { } } catch (SQLException | IOException e) { e.printStackTrace(); + return null;//todo error handling?? } - return null;//todo error handling?? } @Override public void saveCanvas(Canvas canvas) { - try { - PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO canvases(document, data) VALUES(?, ?) ON CONFLICT (document) DO UPDATE SET data=excluded.data"); + try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO canvases(document, data) VALUES(?, ?) ON CONFLICT (document) DO UPDATE SET data=excluded.data")) { preparedStatement.setLong(1, canvas.getDocument().getId()); ByteBuf byteBuf = Unpooled.buffer(); canvas.serialize(byteBuf); @@ -149,8 +150,7 @@ public void saveDocument(Document document) { @Override public void addUserSession(PersistentUserSession persistentUserSession) { - try { - PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO persistent_user_sessions(id, \"user\", creation_time, hashed_token) VALUES (?, ?, ?, ?)"); + try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO persistent_user_sessions(id, \"user\", creation_time, hashed_token) VALUES (?, ?, ?, ?)")) { preparedStatement.setLong(1, persistentUserSession.getId()); preparedStatement.setLong(2, persistentUserSession.getUser()); preparedStatement.setTimestamp(3, persistentUserSession.getCreation()); @@ -166,19 +166,27 @@ public void addUserSession(PersistentUserSession persistentUserSession) { */ @Override public PersistentUserSession removeUserSession(long id) { - try { - PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM persistent_user_sessions WHERE id=?"); + PersistentUserSession persistentUserSession; + + try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM persistent_user_sessions WHERE id=?")) { preparedStatement.setLong(1, id); ResultSet resultSet = preparedStatement.executeQuery(); - if (!resultSet.next()) { + if (resultSet.next()) { + persistentUserSession = new PersistentUserSession(id, resultSet.getLong("user"), resultSet.getTimestamp("creation_time"), resultSet.getBinaryStream("hashed_token").readAllBytes()); + } else { + BoardRoom.getLogger().warning("PersistentUserSession with id " + id + " does not exist"); return null; } - PersistentUserSession persistentUserSession = new PersistentUserSession(id, resultSet.getLong("user"), resultSet.getTimestamp("creation_time"), resultSet.getBinaryStream("hashed_token").readAllBytes()); - preparedStatement = connection.prepareStatement("DELETE FROM persistent_user_sessions WHERE id=?"); + } catch (SQLException | IOException e) { + e.printStackTrace(); + return null; + } + + try (PreparedStatement preparedStatement = connection.prepareStatement("DELETE FROM persistent_user_sessions WHERE id=?")) { preparedStatement.setLong(1, id); preparedStatement.execute(); return persistentUserSession; - } catch (SQLException | IOException e) { + } catch (SQLException e) { e.printStackTrace(); return null; } From 217432ce3818e84137a3a187d961e77f9e8ec2a7 Mon Sep 17 00:00:00 2001 From: stzups Date: Sun, 4 Apr 2021 23:15:13 -0400 Subject: [PATCH 28/35] remove domains because domain arrays are broken --- board-database/init.sql | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/board-database/init.sql b/board-database/init.sql index a2175bb2..10a9381b 100644 --- a/board-database/init.sql +++ b/board-database/init.sql @@ -9,36 +9,33 @@ CREATE USER board_room PASSWORD 'changeme'; GRANT CONNECT ON DATABASE board TO board_room; GRANT USAGE ON SCHEMA public TO board_room; -CREATE DOMAIN user_id AS bigint; -CREATE DOMAIN document_id AS bigint; -CREATE DOMAIN persistent_user_session_id AS bigint; -- Create tables and grant permissions CREATE TABLE users( - id user_id NOT NULL, - owned_documents document_id[] NOT NULL, - shared_documents document_id[] NOT NULL, + id bigint NOT NULL, + owned_documents bigint[] NOT NULL, + shared_documents bigint[] NOT NULL, PRIMARY KEY (id) ); GRANT SELECT, INSERT, UPDATE ON users TO board_room; CREATE TABLE documents( - id document_id NOT NULL, - owner user_id NOT NULL, + id bigint NOT NULL, + owner bigint NOT NULL, name varchar(64) not null, PRIMARY KEY (id) ); GRANT SELECT, INSERT, UPDATE ON documents TO board_room; CREATE TABLE canvases( - document document_id NOT NULL, + document bigint NOT NULL, data bytea NOT NULL, PRIMARY KEY (document) ); GRANT SELECT, INSERT, UPDATE ON canvases TO board_room; CREATE TABLE persistent_user_sessions( - id persistent_user_session_id NOT NULL, - "user" user_id NOT NULL, + id bigint NOT NULL, + "user" bigint NOT NULL, creation_time timestamp, hashed_token bytea NOT NULL, PRIMARY KEY (id) From 113c2e670a828e7641d45f8b8b921a9e1d77aa12 Mon Sep 17 00:00:00 2001 From: stzups Date: Sun, 4 Apr 2021 23:22:22 -0400 Subject: [PATCH 29/35] maybe not? remove user cache --- board-database/init.sql | 19 +++++----- .../database/postgres/PostgresDatabase.java | 35 ++++++++----------- 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/board-database/init.sql b/board-database/init.sql index 10a9381b..a2175bb2 100644 --- a/board-database/init.sql +++ b/board-database/init.sql @@ -9,33 +9,36 @@ CREATE USER board_room PASSWORD 'changeme'; GRANT CONNECT ON DATABASE board TO board_room; GRANT USAGE ON SCHEMA public TO board_room; +CREATE DOMAIN user_id AS bigint; +CREATE DOMAIN document_id AS bigint; +CREATE DOMAIN persistent_user_session_id AS bigint; -- Create tables and grant permissions CREATE TABLE users( - id bigint NOT NULL, - owned_documents bigint[] NOT NULL, - shared_documents bigint[] NOT NULL, + id user_id NOT NULL, + owned_documents document_id[] NOT NULL, + shared_documents document_id[] NOT NULL, PRIMARY KEY (id) ); GRANT SELECT, INSERT, UPDATE ON users TO board_room; CREATE TABLE documents( - id bigint NOT NULL, - owner bigint NOT NULL, + id document_id NOT NULL, + owner user_id NOT NULL, name varchar(64) not null, PRIMARY KEY (id) ); GRANT SELECT, INSERT, UPDATE ON documents TO board_room; CREATE TABLE canvases( - document bigint NOT NULL, + document document_id NOT NULL, data bytea NOT NULL, PRIMARY KEY (document) ); GRANT SELECT, INSERT, UPDATE ON canvases TO board_room; CREATE TABLE persistent_user_sessions( - id bigint NOT NULL, - "user" bigint NOT NULL, + id persistent_user_session_id NOT NULL, + "user" user_id NOT NULL, creation_time timestamp, hashed_token bytea NOT NULL, PRIMARY KEY (id) diff --git a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java index 6b48e76d..2a288c6a 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java +++ b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java @@ -24,7 +24,6 @@ public class PostgresDatabase implements Database { private Connection connection; - private Map users = new HashMap<>(); private Map documents = new HashMap<>(); public PostgresDatabase(String url, String user, String password) throws Exception { @@ -36,10 +35,9 @@ public PostgresDatabase(String url, String user, String password) throws Excepti public void addUser(User user) { try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO users(id, owned_documents, shared_documents) VALUES (?, ?, ?)")) { preparedStatement.setLong(1, user.getId()); - preparedStatement.setArray(2, connection.createArrayOf("bigint", user.getOwnedDocuments().toArray())); - preparedStatement.setArray(3, connection.createArrayOf("bigint", user.getSharedDocuments().toArray())); + preparedStatement.setArray(2, connection.createArrayOf("document_id", user.getOwnedDocuments().toArray())); + preparedStatement.setArray(3, connection.createArrayOf("document_id", user.getSharedDocuments().toArray())); preparedStatement.execute(); - users.put(user.getId(), user); } catch (SQLException e) { e.printStackTrace(); } @@ -47,26 +45,21 @@ public void addUser(User user) { @Override public User getUser(long id) { - User user = users.get(id); - if (user == null) { - try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM users WHERE id=?")) { - preparedStatement.setLong(1, id); - ResultSet resultSet = preparedStatement.executeQuery(); - if (resultSet.next()) { - user = new User(id, - new ArrayList<>(Arrays.asList((Long[]) resultSet.getArray("owned_documents").getArray())), - new ArrayList<>(Arrays.asList((Long[]) resultSet.getArray("shared_documents").getArray()))); - users.put(user.getId(), user); - } else { - BoardRoom.getLogger().warning("User with id " + id + " does not exist"); - return null; - } - } catch (SQLException e) { - e.printStackTrace(); + try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM users WHERE id=?")) { + preparedStatement.setLong(1, id); + ResultSet resultSet = preparedStatement.executeQuery(); + if (resultSet.next()) { + return new User(id, + new ArrayList<>(Arrays.asList((Long[]) resultSet.getArray("owned_documents").getArray())), + new ArrayList<>(Arrays.asList((Long[]) resultSet.getArray("shared_documents").getArray()))); + } else { + BoardRoom.getLogger().warning("User with id " + id + " does not exist"); return null; } + } catch (SQLException e) { + e.printStackTrace(); + return null; } - return user; } @Override From 1752fbbcf3ed96ff79f7354fbc0e625afcf486a7 Mon Sep 17 00:00:00 2001 From: stzups Date: Mon, 5 Apr 2021 00:07:24 -0400 Subject: [PATCH 30/35] postgres is bad --- .../stzups/board/data/database/Database.java | 2 +- .../data/database/memory/MemoryDatabase.java | 6 ++++- .../database/postgres/PostgresDatabase.java | 22 +++++++++++++++---- .../net/stzups/board/data/objects/User.java | 12 +--------- .../server/websocket/MessageHandler.java | 3 +-- 5 files changed, 26 insertions(+), 19 deletions(-) diff --git a/board-room/src/main/java/net/stzups/board/data/database/Database.java b/board-room/src/main/java/net/stzups/board/data/database/Database.java index b0199bb1..5f499e3f 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/Database.java +++ b/board-room/src/main/java/net/stzups/board/data/database/Database.java @@ -6,7 +6,7 @@ import net.stzups.board.data.objects.canvas.Canvas; public interface Database { - void addUser(User user); + User createUser(); User getUser(long id); Document createDocument(User owner); diff --git a/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java b/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java index be986b3a..c1cd0d0a 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java +++ b/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java @@ -1,11 +1,13 @@ package net.stzups.board.data.database.memory; +import net.stzups.board.BoardRoom; import net.stzups.board.data.database.Database; import net.stzups.board.data.objects.Document; import net.stzups.board.data.objects.User; import net.stzups.board.data.objects.PersistentUserSession; import net.stzups.board.data.objects.canvas.Canvas; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -18,8 +20,10 @@ public class MemoryDatabase implements Database { private Map users = new HashMap<>(); @Override - public void addUser(User user) { + public User createUser() { + User user = new User(BoardRoom.getRandom().nextLong(), new ArrayList<>(), new ArrayList<>()); users.put(user.getId(), user); + return user; } @Override diff --git a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java index 2a288c6a..c9f05c15 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java +++ b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java @@ -8,9 +8,11 @@ import net.stzups.board.data.objects.PersistentUserSession; import net.stzups.board.data.objects.User; import net.stzups.board.data.objects.canvas.Canvas; +import org.postgresql.util.PGobject; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.sql.Array; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; @@ -32,7 +34,8 @@ public PostgresDatabase(String url, String user, String password) throws Excepti } @Override - public void addUser(User user) { + public User createUser() { + User user = new User(BoardRoom.getRandom().nextLong(), new ArrayList<>(), new ArrayList<>()); try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO users(id, owned_documents, shared_documents) VALUES (?, ?, ?)")) { preparedStatement.setLong(1, user.getId()); preparedStatement.setArray(2, connection.createArrayOf("document_id", user.getOwnedDocuments().toArray())); @@ -41,6 +44,7 @@ public void addUser(User user) { } catch (SQLException e) { e.printStackTrace(); } + return user; } @Override @@ -50,8 +54,8 @@ public User getUser(long id) { ResultSet resultSet = preparedStatement.executeQuery(); if (resultSet.next()) { return new User(id, - new ArrayList<>(Arrays.asList((Long[]) resultSet.getArray("owned_documents").getArray())), - new ArrayList<>(Arrays.asList((Long[]) resultSet.getArray("shared_documents").getArray()))); + new ArrayList<>(Arrays.asList(convertPostgresDomainArrayToLongArray(resultSet.getArray("owned_documents")))), + new ArrayList<>(Arrays.asList(convertPostgresDomainArrayToLongArray(resultSet.getArray("shared_documents"))))); } else { BoardRoom.getLogger().warning("User with id " + id + " does not exist"); return null; @@ -62,6 +66,17 @@ public User getUser(long id) { } } + // normally (Long[]) resultSet.getArray("something").getArray()) fails with custom domain types + private Long[] convertPostgresDomainArrayToLongArray(Array longArray) throws SQLException { + Object[] objects = (Object[]) longArray.getArray(); + Long[] longs = new Long[objects.length]; + for (int i = 0; i < objects.length; i++) { + //objects is actually an array of PGobject + longs[i] = Long.parseLong(((PGobject) objects[i]).getValue()); + } + return longs; + } + @Override public Document createDocument(User owner) { Document document = new Document(owner); @@ -97,7 +112,6 @@ public Document getDocument(long id) { } else { BoardRoom.getLogger().warning("Document with id " + id + " does not exist"); return null; - } } catch (SQLException e) { e.printStackTrace(); diff --git a/board-room/src/main/java/net/stzups/board/data/objects/User.java b/board-room/src/main/java/net/stzups/board/data/objects/User.java index 3061cf9d..db349c66 100644 --- a/board-room/src/main/java/net/stzups/board/data/objects/User.java +++ b/board-room/src/main/java/net/stzups/board/data/objects/User.java @@ -1,8 +1,5 @@ package net.stzups.board.data.objects; -import net.stzups.board.BoardRoom; - -import java.util.ArrayList; import java.util.List; public class User { @@ -10,13 +7,6 @@ public class User { private List ownedDocuments; private List sharedDocuments; - public User() { - id = BoardRoom.getRandom().nextLong(); - ownedDocuments = new ArrayList<>(); - //ownedDocuments.add(Document.createDocument(this).getId()); todo do somewhere else - sharedDocuments = new ArrayList<>(); - } - public User(long id, List ownedDocuments, List sharedDocuments) { this.id = id; this.ownedDocuments = ownedDocuments; @@ -37,7 +27,7 @@ public List getSharedDocuments() { @Override public String toString() { - return "User{id=" + id + "}"; + return "User{id=" + id + ",ownedDocuments=" + ownedDocuments + ",sharedDocuments=" + sharedDocuments + "}"; } @Override diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java index e6e13e64..5ff382ba 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java @@ -113,8 +113,7 @@ protected void channelRead0(ChannelHandlerContext ctx, ClientMessage message) { private static Client createUserSession(ChannelHandlerContext ctx, User user) { Client client; if (user == null) { - client = new Client(new User(), ctx.channel()); - BoardRoom.getDatabase().addUser(client.getUser()); + client = new Client(BoardRoom.getDatabase().createUser(), ctx.channel()); } else { client = new Client(user, ctx.channel()); } From 1d6b03df6285864b4c8334cc05ad6ace517b83ab Mon Sep 17 00:00:00 2001 From: stzups Date: Mon, 5 Apr 2021 09:31:15 -0400 Subject: [PATCH 31/35] return to monke --- board-database/init.sql | 19 ++++++++----------- .../database/postgres/PostgresDatabase.java | 12 ++++++------ 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/board-database/init.sql b/board-database/init.sql index a2175bb2..10a9381b 100644 --- a/board-database/init.sql +++ b/board-database/init.sql @@ -9,36 +9,33 @@ CREATE USER board_room PASSWORD 'changeme'; GRANT CONNECT ON DATABASE board TO board_room; GRANT USAGE ON SCHEMA public TO board_room; -CREATE DOMAIN user_id AS bigint; -CREATE DOMAIN document_id AS bigint; -CREATE DOMAIN persistent_user_session_id AS bigint; -- Create tables and grant permissions CREATE TABLE users( - id user_id NOT NULL, - owned_documents document_id[] NOT NULL, - shared_documents document_id[] NOT NULL, + id bigint NOT NULL, + owned_documents bigint[] NOT NULL, + shared_documents bigint[] NOT NULL, PRIMARY KEY (id) ); GRANT SELECT, INSERT, UPDATE ON users TO board_room; CREATE TABLE documents( - id document_id NOT NULL, - owner user_id NOT NULL, + id bigint NOT NULL, + owner bigint NOT NULL, name varchar(64) not null, PRIMARY KEY (id) ); GRANT SELECT, INSERT, UPDATE ON documents TO board_room; CREATE TABLE canvases( - document document_id NOT NULL, + document bigint NOT NULL, data bytea NOT NULL, PRIMARY KEY (document) ); GRANT SELECT, INSERT, UPDATE ON canvases TO board_room; CREATE TABLE persistent_user_sessions( - id persistent_user_session_id NOT NULL, - "user" user_id NOT NULL, + id bigint NOT NULL, + "user" bigint NOT NULL, creation_time timestamp, hashed_token bytea NOT NULL, PRIMARY KEY (id) diff --git a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java index c9f05c15..5d3e900a 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java +++ b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java @@ -38,8 +38,8 @@ public User createUser() { User user = new User(BoardRoom.getRandom().nextLong(), new ArrayList<>(), new ArrayList<>()); try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO users(id, owned_documents, shared_documents) VALUES (?, ?, ?)")) { preparedStatement.setLong(1, user.getId()); - preparedStatement.setArray(2, connection.createArrayOf("document_id", user.getOwnedDocuments().toArray())); - preparedStatement.setArray(3, connection.createArrayOf("document_id", user.getSharedDocuments().toArray())); + preparedStatement.setArray(2, connection.createArrayOf("bigint", user.getOwnedDocuments().toArray())); + preparedStatement.setArray(3, connection.createArrayOf("bigint", user.getSharedDocuments().toArray())); preparedStatement.execute(); } catch (SQLException e) { e.printStackTrace(); @@ -54,8 +54,8 @@ public User getUser(long id) { ResultSet resultSet = preparedStatement.executeQuery(); if (resultSet.next()) { return new User(id, - new ArrayList<>(Arrays.asList(convertPostgresDomainArrayToLongArray(resultSet.getArray("owned_documents")))), - new ArrayList<>(Arrays.asList(convertPostgresDomainArrayToLongArray(resultSet.getArray("shared_documents"))))); + new ArrayList<>(Arrays.asList((Long[]) (resultSet.getArray("owned_documents").getArray()))), + new ArrayList<>(Arrays.asList((Long[]) (resultSet.getArray("shared_documents").getArray())))); } else { BoardRoom.getLogger().warning("User with id " + id + " does not exist"); return null; @@ -65,7 +65,7 @@ public User getUser(long id) { return null; } } - +/* // normally (Long[]) resultSet.getArray("something").getArray()) fails with custom domain types private Long[] convertPostgresDomainArrayToLongArray(Array longArray) throws SQLException { Object[] objects = (Object[]) longArray.getArray(); @@ -75,7 +75,7 @@ private Long[] convertPostgresDomainArrayToLongArray(Array longArray) throws SQL longs[i] = Long.parseLong(((PGobject) objects[i]).getValue()); } return longs; - } + }*/ @Override public Document createDocument(User owner) { From 9500413f9a356e7226c31c59103975a1a7d33bd6 Mon Sep 17 00:00:00 2001 From: stzups Date: Mon, 5 Apr 2021 10:02:55 -0400 Subject: [PATCH 32/35] rework user owned documents, now persisted --- .../stzups/board/data/database/Database.java | 1 + .../data/database/memory/MemoryDatabase.java | 7 ++++- .../database/postgres/PostgresDatabase.java | 26 +++++++++++++----- .../stzups/board/data/objects/Document.java | 1 - .../net/stzups/board/data/objects/User.java | 27 ++++++++++++++----- .../server/websocket/MessageHandler.java | 2 +- 6 files changed, 48 insertions(+), 16 deletions(-) diff --git a/board-room/src/main/java/net/stzups/board/data/database/Database.java b/board-room/src/main/java/net/stzups/board/data/database/Database.java index 5f499e3f..f2d7cfc7 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/Database.java +++ b/board-room/src/main/java/net/stzups/board/data/database/Database.java @@ -8,6 +8,7 @@ public interface Database { User createUser(); User getUser(long id); + void updateUser(User user); Document createDocument(User owner); Document getDocument(long id); diff --git a/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java b/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java index c1cd0d0a..1d564a14 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java +++ b/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java @@ -21,7 +21,7 @@ public class MemoryDatabase implements Database { @Override public User createUser() { - User user = new User(BoardRoom.getRandom().nextLong(), new ArrayList<>(), new ArrayList<>()); + User user = new User(BoardRoom.getRandom().nextLong(), new Long[0], new Long[0]); users.put(user.getId(), user); return user; } @@ -31,6 +31,11 @@ public User getUser(long id) { return users.get(id); } + @Override + public void updateUser(User user) { + + } + @Override public Document getDocument(long id) { return documents.get(id); diff --git a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java index 5d3e900a..0cb86e57 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java +++ b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java @@ -35,11 +35,11 @@ public PostgresDatabase(String url, String user, String password) throws Excepti @Override public User createUser() { - User user = new User(BoardRoom.getRandom().nextLong(), new ArrayList<>(), new ArrayList<>()); + User user = new User(BoardRoom.getRandom().nextLong(), new Long[0], new Long[0]); try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO users(id, owned_documents, shared_documents) VALUES (?, ?, ?)")) { preparedStatement.setLong(1, user.getId()); - preparedStatement.setArray(2, connection.createArrayOf("bigint", user.getOwnedDocuments().toArray())); - preparedStatement.setArray(3, connection.createArrayOf("bigint", user.getSharedDocuments().toArray())); + preparedStatement.setArray(2, connection.createArrayOf("bigint", user.getOwnedDocuments())); + preparedStatement.setArray(3, connection.createArrayOf("bigint", user.getSharedDocuments())); preparedStatement.execute(); } catch (SQLException e) { e.printStackTrace(); @@ -54,8 +54,8 @@ public User getUser(long id) { ResultSet resultSet = preparedStatement.executeQuery(); if (resultSet.next()) { return new User(id, - new ArrayList<>(Arrays.asList((Long[]) (resultSet.getArray("owned_documents").getArray()))), - new ArrayList<>(Arrays.asList((Long[]) (resultSet.getArray("shared_documents").getArray())))); + (Long[]) (resultSet.getArray("owned_documents").getArray()), + (Long[]) (resultSet.getArray("shared_documents").getArray())); } else { BoardRoom.getLogger().warning("User with id " + id + " does not exist"); return null; @@ -65,6 +65,18 @@ public User getUser(long id) { return null; } } + + @Override + public void updateUser(User user) { + try (PreparedStatement preparedStatement = connection.prepareStatement("UPDATE users SET owned_documents=?, shared_documents=? WHERE id=?")){ + preparedStatement.setArray(1, connection.createArrayOf("bigint", user.getOwnedDocuments())); + preparedStatement.setArray(2, connection.createArrayOf("bigint", user.getSharedDocuments())); + preparedStatement.setLong(3, user.getId()); + preparedStatement.execute(); + } catch (SQLException e) { + e.printStackTrace(); + } + } /* // normally (Long[]) resultSet.getArray("something").getArray()) fails with custom domain types private Long[] convertPostgresDomainArrayToLongArray(Array longArray) throws SQLException { @@ -86,11 +98,13 @@ public Document createDocument(User owner) { preparedStatement.setString(3, document.getName()); preparedStatement.execute(); documents.put(document.getId(), document); - return document; } catch (SQLException e) { e.printStackTrace(); return null; } + owner.addOwnedDocument(document); + updateUser(owner); + return document; } @Override diff --git a/board-room/src/main/java/net/stzups/board/data/objects/Document.java b/board-room/src/main/java/net/stzups/board/data/objects/Document.java index 4200a7ee..2506a464 100644 --- a/board-room/src/main/java/net/stzups/board/data/objects/Document.java +++ b/board-room/src/main/java/net/stzups/board/data/objects/Document.java @@ -18,7 +18,6 @@ public class Document { public Document(User owner) { this.id = BoardRoom.getRandom().nextLong(); this.owner = owner; - owner.getOwnedDocuments().add(id); this.name = DEFAULT_DOCUMENT_NAME; } diff --git a/board-room/src/main/java/net/stzups/board/data/objects/User.java b/board-room/src/main/java/net/stzups/board/data/objects/User.java index db349c66..2e8ad615 100644 --- a/board-room/src/main/java/net/stzups/board/data/objects/User.java +++ b/board-room/src/main/java/net/stzups/board/data/objects/User.java @@ -1,13 +1,11 @@ package net.stzups.board.data.objects; -import java.util.List; - public class User { private long id; - private List ownedDocuments; - private List sharedDocuments; + private Long[] ownedDocuments; + private Long[] sharedDocuments; - public User(long id, List ownedDocuments, List sharedDocuments) { + public User(long id, Long[] ownedDocuments, Long[] sharedDocuments) { this.id = id; this.ownedDocuments = ownedDocuments; this.sharedDocuments = sharedDocuments; @@ -17,14 +15,29 @@ public long getId() { return id; } - public List getOwnedDocuments() { + public Long[] getOwnedDocuments() { return ownedDocuments; } - public List getSharedDocuments() { + public void addOwnedDocument(Document document) { + ownedDocuments = addElement(ownedDocuments, document); + } + + public Long[] getSharedDocuments() { return sharedDocuments; } + public void addSharedDocument(Document document) { + sharedDocuments = addElement(sharedDocuments, document); + } + + private Long[] addElement(Long[] oldLongs, Document element) { + Long[] newLongs = new Long[oldLongs.length + 1]; + System.arraycopy(oldLongs, 0, newLongs, 0, oldLongs.length); + newLongs[newLongs.length - 1] = element.getId(); + return newLongs; + } + @Override public String toString() { return "User{id=" + id + ",ownedDocuments=" + ownedDocuments + ",sharedDocuments=" + sharedDocuments + "}"; diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java index 5ff382ba..86a0b52e 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java @@ -94,7 +94,7 @@ protected void channelRead0(ChannelHandlerContext ctx, ClientMessage message) { } } client.queueMessage(new ServerMessageAddUser(client.getUser())); - if (client.getUser().getOwnedDocuments().size() == 0) { + if (client.getUser().getOwnedDocuments().length == 0) { client.queueMessage(new ServerMessageAddDocument(BoardRoom.getDatabase().createDocument(client.getUser())));//todo } else { for (long id : client.getUser().getOwnedDocuments()) { From 12d48b12f538cdf60eb92019559c96ed9f08152a Mon Sep 17 00:00:00 2001 From: stzups Date: Mon, 5 Apr 2021 12:38:06 -0400 Subject: [PATCH 33/35] add/remove document, probably doesn't work --- CHANGELOG.md | 5 +- board-database/init.sql | 4 +- board-frontend/html/scripts/Document.js | 32 ++++---- board-frontend/html/scripts/User.js | 12 +-- .../html/scripts/protocol/SocketEventType.js | 5 ++ .../html/scripts/protocol/WebSocketHandler.js | 74 +++++-------------- .../scripts/protocol/WebSocketHandlerType.js | 5 -- .../protocol/client/ClientMessageType.js | 2 + .../messages/ClientMessageDeleteDocument.js | 18 +++++ .../messages/ClientMessageOpenDocument.js | 5 +- .../messages/ClientMessageUpdateDocument.js | 19 +++++ .../scripts/protocol/server/ServerMessage.js | 2 +- .../protocol/server/ServerMessageType.js | 49 +++++++++++- .../messages/ServerMessageDeleteDocument.js | 9 +++ .../messages/ServerMessageOpenDocument.js | 4 +- ...ment.js => ServerMessageUpdateDocument.js} | 4 +- .../stzups/board/data/database/Database.java | 3 +- .../data/database/memory/MemoryDatabase.java | 7 +- .../database/postgres/PostgresDatabase.java | 33 ++++++--- .../stzups/board/data/objects/Document.java | 9 +++ .../data/objects/PersistentUserSession.java | 5 ++ .../net/stzups/board/data/objects/User.java | 6 ++ .../board/data/objects/canvas/Canvas.java | 12 --- .../server/websocket/MessageHandler.java | 52 +++++++++++-- .../websocket/protocol/MessageDecoder.java | 32 ++------ .../protocol/client/ClientMessage.java | 44 +++++++++++ .../protocol/client/ClientMessageType.java | 2 + .../messages/ClientMessageCreateDocument.java | 3 +- .../messages/ClientMessageDeleteDocument.java | 18 +++++ .../messages/ClientMessageUpdateDocument.java | 24 ++++++ .../protocol/server/ServerMessageType.java | 5 +- .../messages/ServerMessageDeleteDocument.java | 21 ++++++ ....java => ServerMessageUpdateDocument.java} | 6 +- 33 files changed, 371 insertions(+), 160 deletions(-) create mode 100644 board-frontend/html/scripts/protocol/SocketEventType.js delete mode 100644 board-frontend/html/scripts/protocol/WebSocketHandlerType.js create mode 100644 board-frontend/html/scripts/protocol/client/messages/ClientMessageDeleteDocument.js create mode 100644 board-frontend/html/scripts/protocol/client/messages/ClientMessageUpdateDocument.js create mode 100644 board-frontend/html/scripts/protocol/server/messages/ServerMessageDeleteDocument.js rename board-frontend/html/scripts/protocol/server/messages/{ServerMessageAddDocument.js => ServerMessageUpdateDocument.js} (64%) create mode 100644 board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageDeleteDocument.java create mode 100644 board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageUpdateDocument.java create mode 100644 board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageDeleteDocument.java rename board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/{ServerMessageAddDocument.java => ServerMessageUpdateDocument.java} (76%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2274bc07..cc3ea145 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -91,10 +91,11 @@ Rework db, implement document persistence - Rework user authentication ### v0.3.4 -Bugfixes, improve db creation, improve exceptions, overhaul config +Document update/delete operations, overhaul db and config - Fix changes not being saved on canvas close - Fix canvas serialization - Fix connected clients list - Add db creation scripts into version control -- Overhaul config - improve exceptions \ No newline at end of file +- Overhaul config - improve exceptions +- Add document update and delete functionality \ No newline at end of file diff --git a/board-database/init.sql b/board-database/init.sql index 10a9381b..0334f60a 100644 --- a/board-database/init.sql +++ b/board-database/init.sql @@ -24,14 +24,14 @@ CREATE TABLE documents( name varchar(64) not null, PRIMARY KEY (id) ); -GRANT SELECT, INSERT, UPDATE ON documents TO board_room; +GRANT SELECT, INSERT, UPDATE, DELETE ON documents TO board_room; CREATE TABLE canvases( document bigint NOT NULL, data bytea NOT NULL, PRIMARY KEY (document) ); -GRANT SELECT, INSERT, UPDATE ON canvases TO board_room; +GRANT SELECT, INSERT, UPDATE, DELETE ON canvases TO board_room; CREATE TABLE persistent_user_sessions( id bigint NOT NULL, diff --git a/board-frontend/html/scripts/Document.js b/board-frontend/html/scripts/Document.js index 1b8367ad..2fe24ccd 100644 --- a/board-frontend/html/scripts/Document.js +++ b/board-frontend/html/scripts/Document.js @@ -7,11 +7,11 @@ import ClientMessageOpenDocument from "./protocol/client/messages/ClientMessageO import ClientMessageCreateDocument from "./protocol/client/messages/ClientMessageCreateDocument.js"; import ClientMessageHandshake from "./protocol/client/messages/ClientMessageHandshake.js"; import ServerMessageType from "./protocol/server/ServerMessageType.js"; -import WebSocketHandlerType from "./protocol/WebSocketHandlerType.js"; import ClientMessageUpdateCanvas from "./protocol/client/messages/ClientMessageUpdateCanvas.js"; import Shape from "./canvas/canvasObjects/Shape.js"; import {CanvasObjectType} from "./canvas/CanvasObjectType.js"; import CanvasObjectWrapper from "./canvas/CanvasObjectWrapper.js"; +import SocketEventType from "./protocol/SocketEventType.js"; const documents = new Map(); let activeDocument = null; @@ -29,7 +29,7 @@ class Document { activeDocument = this; activeDocument.open(); - socket.send(new ClientMessageOpenDocument(this.id)); + socket.send(new ClientMessageOpenDocument(this)); } else { console.log('id was null', this); } @@ -99,34 +99,34 @@ function draw(now) { } window.requestAnimationFrame(draw); -socket.addMessageListener(ServerMessageType.ADD_CLIENT, (event) => { - event.clients.forEach((value) => { +socket.addMessageListener(ServerMessageType.ADD_CLIENT, (serverMessageAddClient) => { + serverMessageAddClient.clients.forEach((value) => { let client = new Client(value.id, User.getUser(value.userId)); activeDocument.addClient(client); console.log('Add client ', client); }) }); -socket.addMessageListener(ServerMessageType.REMOVE_CLIENT, (event) => { - console.log('Remove client ', activeDocument.removeClient(event.id)); +socket.addMessageListener(ServerMessageType.REMOVE_CLIENT, (serverMessageRemoveClient) => { + console.log('Remove client ', activeDocument.removeClient(serverMessageRemoveClient.id)); }); -socket.addMessageListener(ServerMessageType.UPDATE_CANVAS, (event) => { +socket.addMessageListener(ServerMessageType.UPDATE_CANVAS, (serverMessageUpdateCanvas) => { if (activeDocument != null) { - activeDocument.canvas.updateMultiple(event.canvasObjectWrappers); + activeDocument.canvas.updateMultiple(serverMessageUpdateCanvas.canvasObjectWrappers); } else { console.warn('oops'); } }); -socket.addMessageListener(ServerMessageType.ADD_DOCUMENT, (event) => { - documents.set(event.id, new Document(event.name, event.id)); +socket.addMessageListener(ServerMessageType.UPDATE_DOCUMENT, (serverMessageUpdateDocument) => { + documents.set(serverMessageUpdateDocument.id, new Document(serverMessageUpdateDocument.name, serverMessageUpdateDocument.id)); }); -socket.addMessageListener(ServerMessageType.HANDSHAKE, (event) => { - window.localStorage.setItem('id', event.id.toString()); - window.localStorage.setItem('token', event.token.toString()); +socket.addMessageListener(ServerMessageType.HANDSHAKE, (serverMessageHandshake) => { + window.localStorage.setItem('id', serverMessageHandshake.id.toString()); + window.localStorage.setItem('token', serverMessageHandshake.token.toString()); }) -socket.addMessageListener(ServerMessageType.OPEN_DOCUMENT, (event) => { - activeDocument.canvas = event.canvas; +socket.addMessageListener(ServerMessageType.OPEN_DOCUMENT, (serverMessageOpenDocument) => { + activeDocument.canvas = serverMessageOpenDocument.canvas; }) -socket.addEventListener(WebSocketHandlerType.OPEN, () => { +socket.addEventListener(SocketEventType.OPEN, () => { let id = window.localStorage.getItem('id'); if (id != null) { id = BigInt(id); diff --git a/board-frontend/html/scripts/User.js b/board-frontend/html/scripts/User.js index 62e8aee8..708e7a3d 100644 --- a/board-frontend/html/scripts/User.js +++ b/board-frontend/html/scripts/User.js @@ -19,13 +19,13 @@ class User { } } -socket.addMessageListener(ServerMessageType.HANDSHAKE, (event) => { - user = new User(event.userId); +socket.addMessageListener(ServerMessageType.HANDSHAKE, (serverMessageHandshake) => { + user = new User(serverMessageHandshake.userId); }) -socket.addMessageListener(ServerMessageType.ADD_USER, (event) => { - let user = users.get(event.user.id); +socket.addMessageListener(ServerMessageType.ADD_USER, (serverMessageAddUser) => { + let user = users.get(serverMessageAddUser.user.id); if (user == null) { - user = new User(event.user.id); + user = new User(serverMessageAddUser.user.id); } - Object.assign(user, event.user); + Object.assign(user, serverMessageAddUser.user); }); \ No newline at end of file diff --git a/board-frontend/html/scripts/protocol/SocketEventType.js b/board-frontend/html/scripts/protocol/SocketEventType.js new file mode 100644 index 00000000..18abff39 --- /dev/null +++ b/board-frontend/html/scripts/protocol/SocketEventType.js @@ -0,0 +1,5 @@ +let SocketEventType; +export default SocketEventType = { + OPEN:0, + CLOSE:1, +}; \ No newline at end of file diff --git a/board-frontend/html/scripts/protocol/WebSocketHandler.js b/board-frontend/html/scripts/protocol/WebSocketHandler.js index 309f5ac2..90aafc10 100644 --- a/board-frontend/html/scripts/protocol/WebSocketHandler.js +++ b/board-frontend/html/scripts/protocol/WebSocketHandler.js @@ -1,28 +1,22 @@ import BufferReader from './BufferReader.js' import BufferWriter from "./BufferWriter.js"; -import ServerMessageAddClient from "./server/messages/ServerMessageAddClient.js"; -import ServerMessageRemoveClient from "./server/messages/ServerMessageRemoveClient.js"; -import ServerMessageOpenDocument from "./server/messages/ServerMessageOpenDocument.js"; -import ServerMessageUpdateCanvas from "./server/messages/ServerMessageUpdateCanvas.js"; -import ServerMessageAddDocument from "./server/messages/ServerMessageAddDocument.js"; -import ServerMessageHandshake from "./server/messages/ServerMessageHandshake.js"; -import ServerMessageAddUser from "./server/messages/ServerMessageAddUser.js"; import ServerMessageType from "./server/ServerMessageType.js"; -import WebSocketHandlerType from "./WebSocketHandlerType.js"; +import SocketEventType from "./SocketEventType.js"; +import {getServerMessage} from "./server/ServerMessageType.js"; const HTTP_PORT = 8080; const HTTPS_PORT = 443; class WebSocketHandler { constructor() { - this.events = {}; - Object.keys(WebSocketHandlerType).forEach((key, value) => { - this.events[value] = []; + this.socketEvents = {}; + Object.keys(SocketEventType).forEach((key, value) => { + this.socketEvents[value] = []; }); - this.messageEvents = {}; + this.serverMessageEvents = {}; Object.keys(ServerMessageType).forEach((key, value) => { - this.messageEvents[value] = []; + this.serverMessageEvents[value] = []; }); let webSocketUrl; @@ -38,12 +32,12 @@ class WebSocketHandler { this.socket.addEventListener('open', (event) => { console.log('WebSocket connection opened'); - this.dispatchEvent(WebSocketHandlerType.OPEN); + this.dispatchEvent(SocketEventType.OPEN); }); this.socket.addEventListener('close', (event) => { console.log('WebSocket connection closed'); - this.dispatchEvent(WebSocketHandlerType.CLOSE); + this.dispatchEvent(SocketEventType.CLOSE); }); this.socket.addEventListener('message', (event) => { @@ -53,35 +47,7 @@ class WebSocketHandler { } else { let reader = new BufferReader(event.data); while (reader.hasNext()) { - let type = reader.readUint8(); - let message; - switch (type) { - case ServerMessageType.ADD_CLIENT: - message = new ServerMessageAddClient(reader); - break; - case ServerMessageType.REMOVE_CLIENT: - message = new ServerMessageRemoveClient(reader); - break; - case ServerMessageType.UPDATE_CANVAS: - message = new ServerMessageUpdateCanvas(reader); - break; - case ServerMessageType.OPEN_DOCUMENT: - message = new ServerMessageOpenDocument(reader); - break; - case ServerMessageType.ADD_DOCUMENT: - message = new ServerMessageAddDocument(reader); - break; - case ServerMessageType.HANDSHAKE: - message = new ServerMessageHandshake(reader); - break; - case ServerMessageType.ADD_USER: - message = new ServerMessageAddUser(reader) - break; - default: - console.error('unknown payload type ' + type + ', offset ' + reader.position + ', event ', event); - break; - } - this.dispatchMessageEvent(message.type, message); + this.dispatchMessageEvent(getServerMessage(reader.readUint8(), reader)); } } }); @@ -91,22 +57,22 @@ class WebSocketHandler { }); } - addEventListener(type, onevent) { - this.events[type].push(onevent); + addEventListener(socketEventType, onSocketEvent) { + this.socketEvents[socketEventType].push(onSocketEvent); } - dispatchEvent(type, event) { - console.log('recv', type, event); - this.events[type].forEach(onevent => onevent(event)); + dispatchEvent(socketEventType, socketEvent) { + console.log('recv', socketEventType, socketEvent); + this.socketEvents[socketEventType].forEach(onSocketEvent => onSocketEvent(socketEvent)); } - addMessageListener(type, onevent) { - this.messageEvents[type].push(onevent); + addMessageListener(serverMessageType, onServerMessage) { + this.serverMessageEvents[serverMessageType].push(onServerMessage); } - dispatchMessageEvent(type, event) { - console.log('recv', type, event); - this.messageEvents[type].forEach(onevent => onevent(event)); + dispatchMessageEvent(serverMessage) { + console.log('recv', serverMessage.type, serverMessage); + this.serverMessageEvents[serverMessage.type].forEach(onServerMessage => onServerMessage(serverMessage)); } send(message) { diff --git a/board-frontend/html/scripts/protocol/WebSocketHandlerType.js b/board-frontend/html/scripts/protocol/WebSocketHandlerType.js deleted file mode 100644 index bc0c4784..00000000 --- a/board-frontend/html/scripts/protocol/WebSocketHandlerType.js +++ /dev/null @@ -1,5 +0,0 @@ -let WebSocketHandlerType; -export default WebSocketHandlerType = { - OPEN:0, - CLOSE:1, -}; \ No newline at end of file diff --git a/board-frontend/html/scripts/protocol/client/ClientMessageType.js b/board-frontend/html/scripts/protocol/client/ClientMessageType.js index 80f21c41..2fe861ca 100644 --- a/board-frontend/html/scripts/protocol/client/ClientMessageType.js +++ b/board-frontend/html/scripts/protocol/client/ClientMessageType.js @@ -3,5 +3,7 @@ const ClientMessageType = { UPDATE_CANVAS:1, CREATE_DOCUMENT:2, HANDSHAKE:3, + DELETE_DOCUMENT:4, + UPDATE_DOCUMENT:5 }; export default ClientMessageType; \ No newline at end of file diff --git a/board-frontend/html/scripts/protocol/client/messages/ClientMessageDeleteDocument.js b/board-frontend/html/scripts/protocol/client/messages/ClientMessageDeleteDocument.js new file mode 100644 index 00000000..8a7a5709 --- /dev/null +++ b/board-frontend/html/scripts/protocol/client/messages/ClientMessageDeleteDocument.js @@ -0,0 +1,18 @@ +import ClientMessageType from "../ClientMessageType.js"; +import ClientMessage from "../ClientMessage.js"; + +export default class ClientMessageDeleteDocument extends ClientMessage { + constructor(document) { + super(ClientMessageType.DELETE_DOCUMENT); + this.id = document.id; + } + + getBufferSize() { + return super.getBufferSize() + 8; + } + + serialize(writer) { + super.serialize(writer); + writer.writeBigInt64(this.id); + } +} \ No newline at end of file diff --git a/board-frontend/html/scripts/protocol/client/messages/ClientMessageOpenDocument.js b/board-frontend/html/scripts/protocol/client/messages/ClientMessageOpenDocument.js index 0768ad3e..ce8abb3a 100644 --- a/board-frontend/html/scripts/protocol/client/messages/ClientMessageOpenDocument.js +++ b/board-frontend/html/scripts/protocol/client/messages/ClientMessageOpenDocument.js @@ -2,9 +2,9 @@ import ClientMessageType from "../ClientMessageType.js"; import ClientMessage from "../ClientMessage.js"; export default class ClientMessageOpenDocument extends ClientMessage { - constructor(id) { + constructor(document) { super(ClientMessageType.OPEN_DOCUMENT); - this.id = id; + this.id = document.id; } getBufferSize() { @@ -13,7 +13,6 @@ export default class ClientMessageOpenDocument extends ClientMessage { serialize(writer) { super.serialize(writer); - writer.writeBigInt64(this.id); } } \ No newline at end of file diff --git a/board-frontend/html/scripts/protocol/client/messages/ClientMessageUpdateDocument.js b/board-frontend/html/scripts/protocol/client/messages/ClientMessageUpdateDocument.js new file mode 100644 index 00000000..86d8c24f --- /dev/null +++ b/board-frontend/html/scripts/protocol/client/messages/ClientMessageUpdateDocument.js @@ -0,0 +1,19 @@ +import ClientMessageType from "../ClientMessageType.js"; +import ClientMessage from "../ClientMessage.js"; + +export default class ClientMessageUpdateDocument extends ClientMessage { + constructor(document) { + super(ClientMessageType.UPDATE_DOCUMENT); + this.id = document.id; + this.name = document.name; + } + + getBufferSize() { + return super.getBufferSize() + 8; + } + + serialize(writer) { + super.serialize(writer); + writer.writeBigInt64(this.id); + } +} \ No newline at end of file diff --git a/board-frontend/html/scripts/protocol/server/ServerMessage.js b/board-frontend/html/scripts/protocol/server/ServerMessage.js index b55cbc06..8ec6a032 100644 --- a/board-frontend/html/scripts/protocol/server/ServerMessage.js +++ b/board-frontend/html/scripts/protocol/server/ServerMessage.js @@ -2,4 +2,4 @@ export default class ServerMessage { constructor(type) { this.type = type; } -} \ No newline at end of file +} diff --git a/board-frontend/html/scripts/protocol/server/ServerMessageType.js b/board-frontend/html/scripts/protocol/server/ServerMessageType.js index 0c32e1f1..a83e9541 100644 --- a/board-frontend/html/scripts/protocol/server/ServerMessageType.js +++ b/board-frontend/html/scripts/protocol/server/ServerMessageType.js @@ -1,10 +1,55 @@ +import ServerMessageAddClient from "./messages/ServerMessageAddClient.js"; +import ServerMessageRemoveClient from "./messages/ServerMessageRemoveClient.js"; +import ServerMessageUpdateCanvas from "./messages/ServerMessageUpdateCanvas.js"; +import ServerMessageOpenDocument from "./messages/ServerMessageOpenDocument.js"; +import ServerMessageHandshake from "./messages/ServerMessageHandshake.js"; +import ServerMessageAddUser from "./messages/ServerMessageAddUser.js"; +import ServerMessageDeleteDocument from "./messages/ServerMessageDeleteDocument.js"; +import ServerMessageUpdateDocument from "./messages/ServerMessageUpdateDocument.js"; + const ServerMessageType = { ADD_CLIENT:0, REMOVE_CLIENT:1, UPDATE_CANVAS:2, OPEN_DOCUMENT:3, - ADD_DOCUMENT:4, + UPDATE_DOCUMENT:4, HANDSHAKE:5, ADD_USER:6, + DELETE_DOCUMENT:7 }; -export default ServerMessageType; \ No newline at end of file +export default ServerMessageType; + + +export function getServerMessage(type, reader) { + let message; + switch (type) { + case ServerMessageType.ADD_CLIENT: + message = new ServerMessageAddClient(reader); + break; + case ServerMessageType.REMOVE_CLIENT: + message = new ServerMessageRemoveClient(reader); + break; + case ServerMessageType.UPDATE_CANVAS: + message = new ServerMessageUpdateCanvas(reader); + break; + case ServerMessageType.OPEN_DOCUMENT: + message = new ServerMessageOpenDocument(reader); + break; + case ServerMessageType.UPDATE_DOCUMENT: + message = new ServerMessageUpdateDocument(reader); + break; + case ServerMessageType.HANDSHAKE: + message = new ServerMessageHandshake(reader); + break; + case ServerMessageType.ADD_USER: + message = new ServerMessageAddUser(reader) + break; + case ServerMessageType.DELETE_DOCUMENT: + message = new ServerMessageDeleteDocument(reader); + break; + default: + console.error('unknown payload type ' + type + ', offset ' + reader.position + ', event ', event); + break; + } + return message; +} \ No newline at end of file diff --git a/board-frontend/html/scripts/protocol/server/messages/ServerMessageDeleteDocument.js b/board-frontend/html/scripts/protocol/server/messages/ServerMessageDeleteDocument.js new file mode 100644 index 00000000..00c8269d --- /dev/null +++ b/board-frontend/html/scripts/protocol/server/messages/ServerMessageDeleteDocument.js @@ -0,0 +1,9 @@ +import ServerMessage from "../ServerMessage.js"; +import ServerMessageType from "../ServerMessageType.js"; + +export default class ServerMessageDeleteDocument extends ServerMessage { + constructor(reader) { + super(ServerMessageType.DELETE_DOCUMENT); + this.id = reader.readBigInt64(); + } +} \ No newline at end of file diff --git a/board-frontend/html/scripts/protocol/server/messages/ServerMessageOpenDocument.js b/board-frontend/html/scripts/protocol/server/messages/ServerMessageOpenDocument.js index 5d69c302..7a3967be 100644 --- a/board-frontend/html/scripts/protocol/server/messages/ServerMessageOpenDocument.js +++ b/board-frontend/html/scripts/protocol/server/messages/ServerMessageOpenDocument.js @@ -1,13 +1,11 @@ import ServerMessage from "../ServerMessage.js"; import ServerMessageType from "../ServerMessageType.js"; import {Canvas} from "../../../canvas/Canvas.js" -import {CanvasObjectType} from "../../../canvas/CanvasObjectType.js"; -import CanvasObject from "../../../canvas/CanvasObject.js"; export default class ServerMessageOpenDocument extends ServerMessage { constructor(reader) { super(ServerMessageType.OPEN_DOCUMENT); - this.documentId = reader.readBigInt64(); + this.id = reader.readBigInt64(); this.canvas = new Canvas(reader); } } \ No newline at end of file diff --git a/board-frontend/html/scripts/protocol/server/messages/ServerMessageAddDocument.js b/board-frontend/html/scripts/protocol/server/messages/ServerMessageUpdateDocument.js similarity index 64% rename from board-frontend/html/scripts/protocol/server/messages/ServerMessageAddDocument.js rename to board-frontend/html/scripts/protocol/server/messages/ServerMessageUpdateDocument.js index 9b5d6e01..6922cf1d 100644 --- a/board-frontend/html/scripts/protocol/server/messages/ServerMessageAddDocument.js +++ b/board-frontend/html/scripts/protocol/server/messages/ServerMessageUpdateDocument.js @@ -1,9 +1,9 @@ import ServerMessage from "../ServerMessage.js"; import ServerMessageType from "../ServerMessageType.js"; -export default class ServerMessageAddDocument extends ServerMessage { +export default class ServerMessageUpdateDocument extends ServerMessage { constructor(reader) { - super(ServerMessageType.ADD_DOCUMENT); + super(ServerMessageType.UPDATE_DOCUMENT); this.id = reader.readBigInt64(); this.name = reader.readString(); } diff --git a/board-room/src/main/java/net/stzups/board/data/database/Database.java b/board-room/src/main/java/net/stzups/board/data/database/Database.java index f2d7cfc7..dcc85a22 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/Database.java +++ b/board-room/src/main/java/net/stzups/board/data/database/Database.java @@ -12,9 +12,10 @@ public interface Database { Document createDocument(User owner); Document getDocument(long id); + void updateDocument(Document document); + void deleteDocument(Document document); Canvas getCanvas(Document document); void saveCanvas(Canvas canvas); - void saveDocument(Document document); PersistentUserSession removeUserSession(long id); void addUserSession(PersistentUserSession persistentUserSession); diff --git a/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java b/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java index 1d564a14..30a1d357 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java +++ b/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java @@ -52,10 +52,15 @@ public void saveCanvas(Canvas canvas) { } @Override - public void saveDocument(Document document) { + public void updateDocument(Document document) { documents.put(document.getId(), document); } + @Override + public void deleteDocument(Document document) { + documents.remove(document.getId()); + } + @Override public PersistentUserSession removeUserSession(long id) { return userSessions.remove(id); diff --git a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java index 0cb86e57..63547549 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java +++ b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java @@ -8,18 +8,14 @@ import net.stzups.board.data.objects.PersistentUserSession; import net.stzups.board.data.objects.User; import net.stzups.board.data.objects.canvas.Canvas; -import org.postgresql.util.PGobject; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.sql.Array; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -135,6 +131,28 @@ public Document getDocument(long id) { return document; } + @Override + public void updateDocument(Document document) { + try (PreparedStatement preparedStatement = connection.prepareStatement("UPDATE documents SET name=? WHERE id=?")) { + preparedStatement.setString(1, document.getName()); + preparedStatement.setLong(2, document.getId()); + preparedStatement.execute(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Override + public void deleteDocument(Document document) { + try (PreparedStatement preparedStatement = connection.prepareStatement("DELETE FROM documents WHERE id=?; DELETE FROM canvases WHERE document=?")) { + preparedStatement.setLong(1, document.getId()); + preparedStatement.setLong(2, document.getId()); + preparedStatement.execute(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + @Override public Canvas getCanvas(Document document) { try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM canvases WHERE document=?")) { @@ -164,11 +182,6 @@ public void saveCanvas(Canvas canvas) { } } - @Override - public void saveDocument(Document document) { - - } - @Override public void addUserSession(PersistentUserSession persistentUserSession) { try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO persistent_user_sessions(id, \"user\", creation_time, hashed_token) VALUES (?, ?, ?, ?)")) { @@ -186,7 +199,7 @@ public void addUserSession(PersistentUserSession persistentUserSession) { * Remove a user session for a token and return the removed user session */ @Override - public PersistentUserSession removeUserSession(long id) { + public PersistentUserSession removeUserSession(long id) {//todo combine PersistentUserSession persistentUserSession; try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM persistent_user_sessions WHERE id=?")) { diff --git a/board-room/src/main/java/net/stzups/board/data/objects/Document.java b/board-room/src/main/java/net/stzups/board/data/objects/Document.java index 2506a464..dcaeb9c2 100644 --- a/board-room/src/main/java/net/stzups/board/data/objects/Document.java +++ b/board-room/src/main/java/net/stzups/board/data/objects/Document.java @@ -38,6 +38,10 @@ public String getName() { return name; } + public void setName(String name) { + this.name = name; + } + public User getOwner() { return owner; } @@ -51,4 +55,9 @@ public String toString() { public int hashCode() { return Long.hashCode(id); } + + @Override + public boolean equals(Object object) { + return object instanceof Document && id == ((Document) object).id; + } } diff --git a/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java b/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java index 4d891536..c99ce164 100644 --- a/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java +++ b/board-room/src/main/java/net/stzups/board/data/objects/PersistentUserSession.java @@ -82,4 +82,9 @@ public String toString() { public int hashCode() { return Long.hashCode(id); } + + @Override + public boolean equals(Object object) { + return object instanceof PersistentUserSession && id == ((PersistentUserSession) object).id; + } } diff --git a/board-room/src/main/java/net/stzups/board/data/objects/User.java b/board-room/src/main/java/net/stzups/board/data/objects/User.java index 2e8ad615..a4ca0b8c 100644 --- a/board-room/src/main/java/net/stzups/board/data/objects/User.java +++ b/board-room/src/main/java/net/stzups/board/data/objects/User.java @@ -47,4 +47,10 @@ public String toString() { public int hashCode() { return Long.hashCode(id); } + + + @Override + public boolean equals(Object object) { + return object instanceof User && id == ((User) object).id; + } } diff --git a/board-room/src/main/java/net/stzups/board/data/objects/canvas/Canvas.java b/board-room/src/main/java/net/stzups/board/data/objects/canvas/Canvas.java index 6f394488..24a512ab 100644 --- a/board-room/src/main/java/net/stzups/board/data/objects/canvas/Canvas.java +++ b/board-room/src/main/java/net/stzups/board/data/objects/canvas/Canvas.java @@ -49,10 +49,6 @@ public void update(Map> update } } - public void delete(Canvas canvas) { - delete(canvas.canvasObjects); - } - public void delete(Map> deleteCanvasObjects) { for (Map.Entry> entry : deleteCanvasObjects.entrySet()) { Map map = canvasObjects.get(entry.getKey()); @@ -66,10 +62,6 @@ public void delete(Map> deleteCanvasO } } - public void clear() { - canvasObjects.clear(); - } - public void serialize(ByteBuf byteBuf) { byteBuf.writeByte((byte) canvasObjects.size()); for (Map.Entry> entry : canvasObjects.entrySet()) { @@ -82,10 +74,6 @@ public void serialize(ByteBuf byteBuf) { } } - public boolean isEmpty() { - return canvasObjects.isEmpty(); - } - @Override public String toString() { return "Canvas{document=" + document + "}"; diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java index 86a0b52e..ffd238b3 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java @@ -9,10 +9,13 @@ import net.stzups.board.server.ServerInitializer; import net.stzups.board.server.websocket.protocol.client.ClientMessage; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageCreateDocument; +import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageDeleteDocument; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageHandshake; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageOpenDocument; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageUpdateCanvas; -import net.stzups.board.server.websocket.protocol.server.messages.ServerMessageAddDocument; +import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageUpdateDocument; +import net.stzups.board.server.websocket.protocol.server.messages.ServerMessageDeleteDocument; +import net.stzups.board.server.websocket.protocol.server.messages.ServerMessageUpdateDocument; import net.stzups.board.server.websocket.protocol.server.messages.ServerMessageAddUser; import net.stzups.board.server.websocket.protocol.server.messages.ServerMessageHandshake; @@ -63,7 +66,7 @@ protected void channelRead0(ChannelHandlerContext ctx, ClientMessage message) { } catch (Exception e) { e.printStackTrace(); } - client.sendMessage(new ServerMessageAddDocument(room.getDocument())); + client.sendMessage(new ServerMessageUpdateDocument(room.getDocument())); room.addClient(client); break; } @@ -71,20 +74,20 @@ protected void channelRead0(ChannelHandlerContext ctx, ClientMessage message) { ClientMessageHandshake clientPacketHandshake = (ClientMessageHandshake) message; if (client == null) { if (clientPacketHandshake.getToken() == 0) { - ctx.channel().attr(ServerInitializer.LOGGER).get().info("authenticated with blank session"); + ctx.channel().attr(ServerInitializer.LOGGER).get().info("Authenticated with blank session"); client = createUserSession(ctx, null); } else { PersistentUserSession persistentUserSession = BoardRoom.getDatabase().removeUserSession(clientPacketHandshake.getId()); if (persistentUserSession == null) { - ctx.channel().attr(ServerInitializer.LOGGER).get().warning("attempted to authenticate with non existent persistent user session"); + ctx.channel().attr(ServerInitializer.LOGGER).get().warning("Attempted to authenticate with non existent persistent user session"); client = createUserSession(ctx, null); } else if (!persistentUserSession.validate(clientPacketHandshake.getToken())) { - ctx.channel().attr(ServerInitializer.LOGGER).get().warning("attempted to authenticate with invalid persistent user session " + persistentUserSession); + ctx.channel().attr(ServerInitializer.LOGGER).get().warning("Attempted to authenticate with invalid persistent user session " + persistentUserSession); client = createUserSession(ctx, null); } else { User user = BoardRoom.getDatabase().getUser(persistentUserSession.getUser()); if (user == null) { - ctx.channel().attr(ServerInitializer.LOGGER).get().severe("somehow managed to authenticate with non existent user"); + ctx.channel().attr(ServerInitializer.LOGGER).get().severe("Somehow managed to authenticate with non existent user"); client = createUserSession(ctx, null); } else { ctx.channel().attr(ServerInitializer.LOGGER).get().info(user + " authenticated with good persistent session"); @@ -95,16 +98,49 @@ protected void channelRead0(ChannelHandlerContext ctx, ClientMessage message) { } client.queueMessage(new ServerMessageAddUser(client.getUser())); if (client.getUser().getOwnedDocuments().length == 0) { - client.queueMessage(new ServerMessageAddDocument(BoardRoom.getDatabase().createDocument(client.getUser())));//todo + client.queueMessage(new ServerMessageUpdateDocument(BoardRoom.getDatabase().createDocument(client.getUser())));//todo } else { for (long id : client.getUser().getOwnedDocuments()) { - client.queueMessage(new ServerMessageAddDocument(BoardRoom.getDatabase().getDocument(id)));//todo aggregate + client.queueMessage(new ServerMessageUpdateDocument(BoardRoom.getDatabase().getDocument(id)));//todo aggregate } } client.flushMessages(); break; } + case DELETE_DOCUMENT: { + ClientMessageDeleteDocument clientMessageDeleteDocument = (ClientMessageDeleteDocument) message; + if (clientMessageDeleteDocument.id() == room.getDocument().getId()) { + System.out.println("document is delete ROOM"); + room.sendMessage(new ServerMessageDeleteDocument(room.getDocument())); + room.end(); + BoardRoom.getDatabase().deleteDocument(room.getDocument()); + break; + } + Document document = BoardRoom.getDatabase().getDocument(clientMessageDeleteDocument.id()); + if (document == null) { + ctx.channel().attr(ServerInitializer.LOGGER).get().warning(client + " tried to delete document that does not exist"); + break; + } + if (!document.getOwner().equals(client.getUser())) { + ctx.channel().attr(ServerInitializer.LOGGER).get().warning(client + " tried to delete document they do not own"); + break; + } + System.out.println("document is delete"); + BoardRoom.getDatabase().deleteDocument(room.getDocument()); + //Room.getRoom(document); + break;//todo better update logic + } + case UPDATE_DOCUMENT: { + ClientMessageUpdateDocument clientMessageUpdateDocument = (ClientMessageUpdateDocument) message; + if (clientMessageUpdateDocument.getName().length() > 64) { + ctx.channel().attr(ServerInitializer.LOGGER).get().warning(client + " tried to change name to string that is too long (" + clientMessageUpdateDocument.getName().length() + ")"); + break; + } + room.getDocument().setName(clientMessageUpdateDocument.getName()); + BoardRoom.getDatabase().updateDocument(room.getDocument()); + break;//todo better update logic + } default: throw new UnsupportedOperationException("Unsupported message type " + message.getMessageType() + " sent by " + client); } diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageDecoder.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageDecoder.java index d498280f..fcce8a56 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageDecoder.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/MessageDecoder.java @@ -11,9 +11,11 @@ import net.stzups.board.server.websocket.protocol.client.ClientMessage; import net.stzups.board.server.websocket.protocol.client.ClientMessageType; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageCreateDocument; +import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageDeleteDocument; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageHandshake; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageOpenDocument; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageUpdateCanvas; +import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageUpdateDocument; import javax.naming.OperationNotSupportedException; import java.nio.charset.StandardCharsets; @@ -31,32 +33,10 @@ protected void decode(ChannelHandlerContext ctx, WebSocketFrame webSocketFrame, ctx.channel().attr(ServerInitializer.LOGGER).get().warning(((TextWebSocketFrame) webSocketFrame).text()); } else if (webSocketFrame instanceof BinaryWebSocketFrame) { ByteBuf byteBuf = webSocketFrame.content(); - ClientMessageType packetType = ClientMessageType.valueOf(byteBuf.readUnsignedByte()); - ClientMessage message; - switch (packetType) { - case OPEN_DOCUMENT: - message = new ClientMessageOpenDocument(byteBuf); - break; - case UPDATE_CANVAS: - message = new ClientMessageUpdateCanvas(byteBuf); - break; - case CREATE_DOCUMENT: - message = new ClientMessageCreateDocument(); - break; - case HANDSHAKE: - message = new ClientMessageHandshake(byteBuf); - break; - default: - throw new OperationNotSupportedException("Unsupported message type " + packetType + " while decoding"); - } - ctx.channel().attr(ServerInitializer.LOGGER).get().info("recv " + message.getClass().getSimpleName()); - list.add(message); + ClientMessageType clientMessageType = ClientMessageType.valueOf(byteBuf.readUnsignedByte()); + ClientMessage clientMessage = ClientMessage.getClientMessage(clientMessageType, byteBuf); + ctx.channel().attr(ServerInitializer.LOGGER).get().info("recv " + clientMessage.getClass().getSimpleName()); + list.add(clientMessage); } } - - private String readString(ByteBuf byteBuf) { - byte[] buffer = new byte[byteBuf.readUnsignedByte()]; - byteBuf.readBytes(buffer); - return new String(buffer, StandardCharsets.UTF_8); - } } diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessage.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessage.java index bc1caaa5..1549e7c3 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessage.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessage.java @@ -1,5 +1,16 @@ package net.stzups.board.server.websocket.protocol.client; +import io.netty.buffer.ByteBuf; +import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageCreateDocument; +import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageDeleteDocument; +import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageHandshake; +import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageOpenDocument; +import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageUpdateCanvas; +import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageUpdateDocument; + +import javax.naming.OperationNotSupportedException; +import java.nio.charset.StandardCharsets; + /** * Represents a packet sent by the client */ @@ -13,4 +24,37 @@ protected ClientMessage(ClientMessageType packetType) { public ClientMessageType getMessageType() { return packetType; } + + protected String readString(ByteBuf byteBuf) { + byte[] buffer = new byte[byteBuf.readUnsignedByte()]; + byteBuf.readBytes(buffer); + return new String(buffer, StandardCharsets.UTF_8); + } + + public static ClientMessage getClientMessage(ClientMessageType clientMessageType, ByteBuf byteBuf) { + ClientMessage message; + switch (clientMessageType) { + case OPEN_DOCUMENT: + message = new ClientMessageOpenDocument(byteBuf); + break; + case UPDATE_CANVAS: + message = new ClientMessageUpdateCanvas(byteBuf); + break; + case CREATE_DOCUMENT: + message = new ClientMessageCreateDocument(byteBuf); + break; + case HANDSHAKE: + message = new ClientMessageHandshake(byteBuf); + break; + case DELETE_DOCUMENT: + message = new ClientMessageDeleteDocument(byteBuf); + break; + case UPDATE_DOCUMENT: + message = new ClientMessageUpdateDocument(byteBuf); + break; + default: + throw new IllegalArgumentException("Unsupported message type " + clientMessageType + " while decoding"); + } + return message; + } } diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessageType.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessageType.java index aae41989..a9d65e23 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessageType.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessageType.java @@ -10,6 +10,8 @@ public enum ClientMessageType { UPDATE_CANVAS(1), CREATE_DOCUMENT(2), HANDSHAKE(3), + DELETE_DOCUMENT(4), + UPDATE_DOCUMENT(5), ; private static Map messageTypeMap = new IntObjectHashMap<>(); diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageCreateDocument.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageCreateDocument.java index 74c8e07f..64950f99 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageCreateDocument.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageCreateDocument.java @@ -1,10 +1,11 @@ package net.stzups.board.server.websocket.protocol.client.messages; +import io.netty.buffer.ByteBuf; import net.stzups.board.server.websocket.protocol.client.ClientMessage; import net.stzups.board.server.websocket.protocol.client.ClientMessageType; public class ClientMessageCreateDocument extends ClientMessage { - public ClientMessageCreateDocument() { + public ClientMessageCreateDocument(ByteBuf byteBuf) { super(ClientMessageType.CREATE_DOCUMENT); } } diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageDeleteDocument.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageDeleteDocument.java new file mode 100644 index 00000000..1d5fb23d --- /dev/null +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageDeleteDocument.java @@ -0,0 +1,18 @@ +package net.stzups.board.server.websocket.protocol.client.messages; + +import io.netty.buffer.ByteBuf; +import net.stzups.board.server.websocket.protocol.client.ClientMessage; +import net.stzups.board.server.websocket.protocol.client.ClientMessageType; + +public class ClientMessageDeleteDocument extends ClientMessage { + private long id; + + public ClientMessageDeleteDocument(ByteBuf byteBuf) { + super(ClientMessageType.DELETE_DOCUMENT); + this.id = byteBuf.readLong(); + } + + public long id() { + return id; + } +} diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageUpdateDocument.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageUpdateDocument.java new file mode 100644 index 00000000..d8821aa2 --- /dev/null +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageUpdateDocument.java @@ -0,0 +1,24 @@ +package net.stzups.board.server.websocket.protocol.client.messages; + +import io.netty.buffer.ByteBuf; +import net.stzups.board.server.websocket.protocol.client.ClientMessage; +import net.stzups.board.server.websocket.protocol.client.ClientMessageType; + +public class ClientMessageUpdateDocument extends ClientMessage { + private long id; + private String name; + + public ClientMessageUpdateDocument(ByteBuf byteBuf) { + super(ClientMessageType.UPDATE_DOCUMENT); + id = byteBuf.readLong(); + name = readString(byteBuf); + } + + public long getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/ServerMessageType.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/ServerMessageType.java index f0d6904c..8c7e8f9a 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/ServerMessageType.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/ServerMessageType.java @@ -10,9 +10,10 @@ public enum ServerMessageType { REMOVE_CLIENT(1), UPDATE_CANVAS(2), OPEN_DOCUMENT(3), - ADD_DOCUMENT(4), + UPDATE_DOCUMENT(4), HANDSHAKE(5), - ADD_USER(6) + ADD_USER(6), + DELETE_DOCUMENT(7) ; private static Map messageTypeMap = new IntObjectHashMap<>(); diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageDeleteDocument.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageDeleteDocument.java new file mode 100644 index 00000000..7415ea6d --- /dev/null +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageDeleteDocument.java @@ -0,0 +1,21 @@ +package net.stzups.board.server.websocket.protocol.server.messages; + +import io.netty.buffer.ByteBuf; +import net.stzups.board.data.objects.Document; +import net.stzups.board.server.websocket.protocol.server.ServerMessage; +import net.stzups.board.server.websocket.protocol.server.ServerMessageType; + +public class ServerMessageDeleteDocument extends ServerMessage { + private long id; + + public ServerMessageDeleteDocument(Document document) { + super(ServerMessageType.DELETE_DOCUMENT); + id = document.getId(); + } + + @Override + public void serialize(ByteBuf byteBuf) { + super.serialize(byteBuf); + byteBuf.writeLong(id); + } +} diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageAddDocument.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageUpdateDocument.java similarity index 76% rename from board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageAddDocument.java rename to board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageUpdateDocument.java index 8a98fb42..b84693a5 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageAddDocument.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageUpdateDocument.java @@ -5,11 +5,11 @@ import net.stzups.board.server.websocket.protocol.server.ServerMessage; import net.stzups.board.server.websocket.protocol.server.ServerMessageType; -public class ServerMessageAddDocument extends ServerMessage { +public class ServerMessageUpdateDocument extends ServerMessage { private Document document; - public ServerMessageAddDocument(Document document) { - super(ServerMessageType.ADD_DOCUMENT); + public ServerMessageUpdateDocument(Document document) { + super(ServerMessageType.UPDATE_DOCUMENT); this.document = document; } From 3efb9d57b3aafc1cf48589ebb7585cfd63154a9e Mon Sep 17 00:00:00 2001 From: stzups Date: Mon, 5 Apr 2021 14:07:56 -0400 Subject: [PATCH 34/35] fix print --- .../stzups/board/data/database/Database.java | 4 ++ .../data/database/memory/MemoryDatabase.java | 11 +++++ .../database/postgres/PostgresDatabase.java | 45 ++++++++++++++++++- .../net/stzups/board/data/objects/User.java | 4 +- .../server/websocket/MessageHandler.java | 9 ++-- .../protocol/client/ClientMessage.java | 5 ++- .../protocol/client/ClientMessageType.java | 1 + .../messages/ClientMessageGetInvite.java | 11 +++++ .../protocol/server/ServerMessageType.java | 3 +- .../messages/ServerMessageGetInvite.java | 21 +++++++++ 10 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageGetInvite.java create mode 100644 board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageGetInvite.java diff --git a/board-room/src/main/java/net/stzups/board/data/database/Database.java b/board-room/src/main/java/net/stzups/board/data/database/Database.java index dcc85a22..943a6f12 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/Database.java +++ b/board-room/src/main/java/net/stzups/board/data/database/Database.java @@ -1,6 +1,7 @@ package net.stzups.board.data.database; import net.stzups.board.data.objects.Document; +import net.stzups.board.data.objects.InviteCode; import net.stzups.board.data.objects.User; import net.stzups.board.data.objects.PersistentUserSession; import net.stzups.board.data.objects.canvas.Canvas; @@ -17,6 +18,9 @@ public interface Database { Canvas getCanvas(Document document); void saveCanvas(Canvas canvas); + InviteCode getInviteCode(String code); + InviteCode getInviteCode(Document document); + PersistentUserSession removeUserSession(long id); void addUserSession(PersistentUserSession persistentUserSession); } diff --git a/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java b/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java index 30a1d357..ba0abf28 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java +++ b/board-room/src/main/java/net/stzups/board/data/database/memory/MemoryDatabase.java @@ -3,6 +3,7 @@ import net.stzups.board.BoardRoom; import net.stzups.board.data.database.Database; import net.stzups.board.data.objects.Document; +import net.stzups.board.data.objects.InviteCode; import net.stzups.board.data.objects.User; import net.stzups.board.data.objects.PersistentUserSession; import net.stzups.board.data.objects.canvas.Canvas; @@ -51,6 +52,16 @@ public void saveCanvas(Canvas canvas) { } + @Override + public InviteCode getInviteCode(String code) { + return null; + } + + @Override + public InviteCode getInviteCode(Document document) { + return null; + } + @Override public void updateDocument(Document document) { documents.put(document.getId(), document); diff --git a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java index 63547549..24331bb8 100644 --- a/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java +++ b/board-room/src/main/java/net/stzups/board/data/database/postgres/PostgresDatabase.java @@ -5,6 +5,7 @@ import net.stzups.board.BoardRoom; import net.stzups.board.data.database.Database; import net.stzups.board.data.objects.Document; +import net.stzups.board.data.objects.InviteCode; import net.stzups.board.data.objects.PersistentUserSession; import net.stzups.board.data.objects.User; import net.stzups.board.data.objects.canvas.Canvas; @@ -144,9 +145,10 @@ public void updateDocument(Document document) { @Override public void deleteDocument(Document document) { - try (PreparedStatement preparedStatement = connection.prepareStatement("DELETE FROM documents WHERE id=?; DELETE FROM canvases WHERE document=?")) { + try (PreparedStatement preparedStatement = connection.prepareStatement("DELETE FROM documents WHERE id=?; DELETE FROM canvases WHERE document=?; DELETE FROM invite_codes WHERE document=?")) { preparedStatement.setLong(1, document.getId()); preparedStatement.setLong(2, document.getId()); + preparedStatement.setLong(3, document.getId()); preparedStatement.execute(); } catch (SQLException e) { e.printStackTrace(); @@ -182,6 +184,47 @@ public void saveCanvas(Canvas canvas) { } } + @Override + public InviteCode getInviteCode(String code) {//gets a document for an existing invite code + try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT document FROM invite_codes WHERE code=?")) { + preparedStatement.setString(1, code); + ResultSet resultSet = preparedStatement.executeQuery();//todo autocloseable try with resources + if (!resultSet.next()) { + return null; + } + return new InviteCode(code, resultSet.getLong(1)); + } catch (SQLException e) { + e.printStackTrace(); + return null; + } + } + + @Override + public InviteCode getInviteCode(Document document) {//gets an invite code for a document + //check if invite code already exists, otherwise generate a new one + try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT code FROM invite_codes WHERE document=?")) { + preparedStatement.setLong(1, document.getId()); + ResultSet resultSet = preparedStatement.executeQuery(); + if (resultSet.next()) { + return new InviteCode(resultSet.getString(1), document.getId()); + } + } catch (SQLException e) { + e.printStackTrace(); + return null; + } + //invite code does not already exist, so a new one must be made + InviteCode inviteCode = new InviteCode(document); + try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO invite_codes(code, document) VALUES (?, ?)")) { + preparedStatement.setString(1, inviteCode.getCode()); + preparedStatement.setLong(2, inviteCode.getDocument()); + preparedStatement.execute(); + return inviteCode; + } catch (SQLException e) { + e.printStackTrace(); + return null; + } + } + @Override public void addUserSession(PersistentUserSession persistentUserSession) { try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO persistent_user_sessions(id, \"user\", creation_time, hashed_token) VALUES (?, ?, ?, ?)")) { diff --git a/board-room/src/main/java/net/stzups/board/data/objects/User.java b/board-room/src/main/java/net/stzups/board/data/objects/User.java index a4ca0b8c..f99f990d 100644 --- a/board-room/src/main/java/net/stzups/board/data/objects/User.java +++ b/board-room/src/main/java/net/stzups/board/data/objects/User.java @@ -1,5 +1,7 @@ package net.stzups.board.data.objects; +import java.util.Arrays; + public class User { private long id; private Long[] ownedDocuments; @@ -40,7 +42,7 @@ private Long[] addElement(Long[] oldLongs, Document element) { @Override public String toString() { - return "User{id=" + id + ",ownedDocuments=" + ownedDocuments + ",sharedDocuments=" + sharedDocuments + "}"; + return "User{id=" + id + ",ownedDocuments=" + Arrays.toString(ownedDocuments) + ",sharedDocuments=" + Arrays.toString(sharedDocuments) + "}"; } @Override diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java index ffd238b3..4a148d34 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/MessageHandler.java @@ -8,12 +8,12 @@ import net.stzups.board.data.objects.User; import net.stzups.board.server.ServerInitializer; import net.stzups.board.server.websocket.protocol.client.ClientMessage; -import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageCreateDocument; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageDeleteDocument; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageHandshake; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageOpenDocument; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageUpdateCanvas; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageUpdateDocument; +import net.stzups.board.server.websocket.protocol.server.messages.ServerMessageGetInvite; import net.stzups.board.server.websocket.protocol.server.messages.ServerMessageDeleteDocument; import net.stzups.board.server.websocket.protocol.server.messages.ServerMessageUpdateDocument; import net.stzups.board.server.websocket.protocol.server.messages.ServerMessageAddUser; @@ -57,7 +57,6 @@ protected void channelRead0(ChannelHandlerContext ctx, ClientMessage message) { break; } case CREATE_DOCUMENT: { - ClientMessageCreateDocument clientPacketCreateDocument = (ClientMessageCreateDocument) message; if (room != null) { room.removeClient(client); } @@ -141,6 +140,10 @@ protected void channelRead0(ChannelHandlerContext ctx, ClientMessage message) { BoardRoom.getDatabase().updateDocument(room.getDocument()); break;//todo better update logic } + case GET_INVITE: { + client.sendMessage(new ServerMessageGetInvite(BoardRoom.getDatabase().getInviteCode(room.getDocument()))); + break; + } default: throw new UnsupportedOperationException("Unsupported message type " + message.getMessageType() + " sent by " + client); } @@ -153,7 +156,7 @@ private static Client createUserSession(ChannelHandlerContext ctx, User user) { } else { client = new Client(user, ctx.channel()); } - PersistentUserSession persistentUserSession = new PersistentUserSession(client.getUser()); + PersistentUserSession persistentUserSession = new PersistentUserSession(client.getUser());//todo refactor client.queueMessage(new ServerMessageHandshake(persistentUserSession)); BoardRoom.getDatabase().addUserSession(persistentUserSession); return client; diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessage.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessage.java index 1549e7c3..19f5d6b5 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessage.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessage.java @@ -2,13 +2,13 @@ import io.netty.buffer.ByteBuf; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageCreateDocument; +import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageGetInvite; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageDeleteDocument; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageHandshake; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageOpenDocument; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageUpdateCanvas; import net.stzups.board.server.websocket.protocol.client.messages.ClientMessageUpdateDocument; -import javax.naming.OperationNotSupportedException; import java.nio.charset.StandardCharsets; /** @@ -52,6 +52,9 @@ public static ClientMessage getClientMessage(ClientMessageType clientMessageType case UPDATE_DOCUMENT: message = new ClientMessageUpdateDocument(byteBuf); break; + case GET_INVITE: + message = new ClientMessageGetInvite(byteBuf); + break; default: throw new IllegalArgumentException("Unsupported message type " + clientMessageType + " while decoding"); } diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessageType.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessageType.java index a9d65e23..26f3f14c 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessageType.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/ClientMessageType.java @@ -12,6 +12,7 @@ public enum ClientMessageType { HANDSHAKE(3), DELETE_DOCUMENT(4), UPDATE_DOCUMENT(5), + GET_INVITE(6) ; private static Map messageTypeMap = new IntObjectHashMap<>(); diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageGetInvite.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageGetInvite.java new file mode 100644 index 00000000..922a1c2f --- /dev/null +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/client/messages/ClientMessageGetInvite.java @@ -0,0 +1,11 @@ +package net.stzups.board.server.websocket.protocol.client.messages; + +import io.netty.buffer.ByteBuf; +import net.stzups.board.server.websocket.protocol.client.ClientMessage; +import net.stzups.board.server.websocket.protocol.client.ClientMessageType; + +public class ClientMessageGetInvite extends ClientMessage { + public ClientMessageGetInvite(ByteBuf byteBuf) { + super(ClientMessageType.GET_INVITE); + } +} diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/ServerMessageType.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/ServerMessageType.java index 8c7e8f9a..19f32d96 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/ServerMessageType.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/ServerMessageType.java @@ -13,7 +13,8 @@ public enum ServerMessageType { UPDATE_DOCUMENT(4), HANDSHAKE(5), ADD_USER(6), - DELETE_DOCUMENT(7) + DELETE_DOCUMENT(7), + GET_INVITE(8) ; private static Map messageTypeMap = new IntObjectHashMap<>(); diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageGetInvite.java b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageGetInvite.java new file mode 100644 index 00000000..af0fac01 --- /dev/null +++ b/board-room/src/main/java/net/stzups/board/server/websocket/protocol/server/messages/ServerMessageGetInvite.java @@ -0,0 +1,21 @@ +package net.stzups.board.server.websocket.protocol.server.messages; + +import io.netty.buffer.ByteBuf; +import net.stzups.board.data.objects.InviteCode; +import net.stzups.board.server.websocket.protocol.server.ServerMessage; +import net.stzups.board.server.websocket.protocol.server.ServerMessageType; + +public class ServerMessageGetInvite extends ServerMessage { + private String code; + + public ServerMessageGetInvite(InviteCode inviteCode) { + super(ServerMessageType.GET_INVITE); + code = inviteCode.getCode(); + } + + @Override + public void serialize(ByteBuf byteBuf) { + super.serialize(byteBuf); + writeString(code, byteBuf); + } +} From 4095b92960d7ecbefb50cc9b0931fb1d13906b0b Mon Sep 17 00:00:00 2001 From: stzups Date: Mon, 5 Apr 2021 14:08:58 -0400 Subject: [PATCH 35/35] improve debug --- .../src/main/java/net/stzups/board/server/websocket/Room.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board-room/src/main/java/net/stzups/board/server/websocket/Room.java b/board-room/src/main/java/net/stzups/board/server/websocket/Room.java index a3b9f19f..4164e5e4 100644 --- a/board-room/src/main/java/net/stzups/board/server/websocket/Room.java +++ b/board-room/src/main/java/net/stzups/board/server/websocket/Room.java @@ -40,7 +40,7 @@ public void run() { Room(Document document) { this.canvas = BoardRoom.getDatabase().getCanvas(document); rooms.put(document, this); - BoardRoom.getLogger().info("Started room " + this); + BoardRoom.getLogger().info("Started " + this); } static Room getRoom(Document document) {