diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b81caf8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/lib"] + path = src/lib + url = https://github.com/Toby222/web-drs-lib.git diff --git a/echo-server.mjs b/echo-server.mjs deleted file mode 100644 index 94059d0..0000000 --- a/echo-server.mjs +++ /dev/null @@ -1,25 +0,0 @@ -import { WebSocketServer } from "ws"; - -const port = 8989; -const wss = new WebSocketServer({ port: port }); - -console.log("listening on port: " + port); - -wss.on("connection", function connection(ws) { - ws.on("message", function (message) { - console.log("message: " + message); - ws.send( - JSON.stringify({ - date: Date.now(), - author: "ECHO Service", - content: message.toString("utf-8"), - }) - ); - }); - ws.on("close", function close() { - console.log("closed a connection"); - }); - - console.log("new client connected!"); - ws.send("connected!"); -}); diff --git a/next.config.js b/next.config.js index a240dda..5bc66b9 100644 --- a/next.config.js +++ b/next.config.js @@ -1,6 +1,7 @@ module.exports = { eslint: { ignoreDuringBuilds: true, + reactStrictMode: true, }, webpack(config, { dev }) { if (!dev) { diff --git a/package.json b/package.json index 136d293..5fad6dc 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "next": "^11.0.1", "preact": "^10.5.14", "react-use-websocket": "^2.9.1", + "sass": "^1.46.0", "typescript": "^4.3.5" }, "devDependencies": { @@ -39,8 +40,7 @@ "pre-commit": "^1.2.2", "prettier": "^2.3.2", "react": "^17.0.2", - "react-dom": "^17.0.2", - "ws": "^8.4.0" + "react-dom": "^17.0.2" }, "pre-commit": "test", "license": "MIT" diff --git a/src/components/Message.tsx b/src/components/Message.tsx new file mode 100644 index 0000000..5aa1ddb --- /dev/null +++ b/src/components/Message.tsx @@ -0,0 +1,16 @@ +import { FunctionComponent } from "react"; +import { TextMessage } from "src/lib/types/ServerMessage"; + +type Props = { + message: TextMessage; +}; + +const MessageComponent: FunctionComponent = ({ message }) => { + return ( + + {new Date(message.date).toISOString()} + {message.content} + + ); +}; +export default MessageComponent; diff --git a/src/lib b/src/lib new file mode 160000 index 0000000..9fc4e8f --- /dev/null +++ b/src/lib @@ -0,0 +1 @@ +Subproject commit 9fc4e8f80d335abc3ab02bfc24d64afcc91f3567 diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 63a60fc..9a46910 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,3 +1,3 @@ -import "./styles.css"; +import "../styles.scss"; export { default } from "next/app"; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index bba9f10..399fd65 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,83 +1,108 @@ import { useCallback, useState } from "react"; import useWebSocket, { + ReadyState, ReadyState as WebSocketReadyState, } from "react-use-websocket"; - -import type { Message } from "../util/types/Message"; +import MessageComponent from "src/components/Message"; +import { MessageType, TextMessage } from "src/lib/types/ServerMessage"; +import { isServerMessage, isTextMessage } from "src/lib/types/ServerMessage"; export default function Index(): JSX.Element { + const [enableSSL, setEnableSSL] = useState(true); + const protocol = enableSSL ? "wss" : "ws"; + const [count, setCount] = useState(0); - const [messageHistory, setMessageHistory] = useState([]); - const [socketUrl, setSocketUrl] = useState( - "wss://toby222-web-drs-4gjg49gj355qq-8989.githubpreview.dev/" - ); + const [messageHistory, setMessageHistory] = useState([]); + const [socketUrl, setSocketUrl] = useState("localhost:8989/"); function onMessage(event: MessageEvent): void { - const message: Message = JSON.parse(event.data); + const message = JSON.parse(event.data); - setMessageHistory([message, ...messageHistory]); + if (!isServerMessage(message)) { + console.log("DEBUG: ", message); + throw new Error(`Server sent unexpected message \`${event.data}}\``); + } + + if (isTextMessage(message)) { + setMessageHistory([message, ...messageHistory]); + } } - const websocket = useWebSocket(socketUrl, { + let keepAliveInterval: NodeJS.Timeout; + const websocket = useWebSocket(protocol + ":" + socketUrl, { onMessage, + onOpen() { + keepAliveInterval = setInterval(() => { + websocket.sendJsonMessage({ + type: MessageType.ACK, + date: Date.now(), + }); + }, 1000); + }, + onClose() { + clearInterval(keepAliveInterval); + }, }); const handleClickSendMessage = useCallback(() => { setCount(count + 1); - websocket.sendMessage(`${count + 1}`); + const message: TextMessage = { + author: "AUTHOR NOT IMPLEMENTED YET", + type: MessageType.TEXT, + date: Date.now(), + content: `Hello, world! ${count}`, + }; + websocket.sendJsonMessage(message); }, [count, websocket]); - const connectionStatus = { - [WebSocketReadyState.CONNECTING]: "Connecting", - [WebSocketReadyState.OPEN]: "Open", - [WebSocketReadyState.CLOSING]: "Closing", - [WebSocketReadyState.CLOSED]: "Closed", - [WebSocketReadyState.UNINSTANTIATED]: "Uninstantiated", - }[websocket.readyState]; + const trySetSocketUrl = useCallback( + (url: string) => { + try { + console.log(new URL(protocol + ":" + url), url); + setSocketUrl(url); + } catch (e) { + console.debug("Invalid URL"); + // Invalid URL, don't do anything + } finally { + if (websocket.readyState === WebSocketReadyState.OPEN) { + websocket.getWebSocket()?.close(); + } + } + }, + [websocket, protocol] + ); - function trySetSocketUrl(url: string) { - try { - console.log(new URL("wss:" + url), url); - setSocketUrl("wss:" + url); - } catch (e) { - // Invalid URL, don't do anything - } finally { - websocket.getWebSocket()?.close(); - } - } + const toggleSSL = useCallback(() => { + setEnableSSL(!enableSSL); + trySetSocketUrl(socketUrl.replace(/^wss?/, protocol)); + }, [enableSSL, socketUrl, trySetSocketUrl, protocol]); return ( <> + + Ready state: {ReadyState[websocket.readyState]} ({websocket.readyState}) +
- {/* DEBUG -
-

Last messages:

- {websocket.lastMessage?.data.toString() ?? "No message received"} -
-

Ready state:

- {connectionStatus} ({websocket.readyState}) -
- */} -
    +
    {messageHistory.map((message, idx) => { - return ( - - {new Date(message.date).toISOString()} - {" - "} - {message.content} -
    -
    - ); + return ; })} -
-
+
+
trySetSocketUrl(e.target.value)} /> + +