Move server & lib to separate repository
This commit is contained in:
parent
1acc2566be
commit
a47a9d7da3
12 changed files with 199 additions and 165 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "src/lib"]
|
||||
path = src/lib
|
||||
url = https://github.com/Toby222/web-drs-lib.git
|
|
@ -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!");
|
||||
});
|
|
@ -1,6 +1,7 @@
|
|||
module.exports = {
|
||||
eslint: {
|
||||
ignoreDuringBuilds: true,
|
||||
reactStrictMode: true,
|
||||
},
|
||||
webpack(config, { dev }) {
|
||||
if (!dev) {
|
||||
|
|
|
@ -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"
|
||||
|
|
16
src/components/Message.tsx
Normal file
16
src/components/Message.tsx
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { FunctionComponent } from "react";
|
||||
import { TextMessage } from "src/lib/types/ServerMessage";
|
||||
|
||||
type Props = {
|
||||
message: TextMessage;
|
||||
};
|
||||
|
||||
const MessageComponent: FunctionComponent<Props> = ({ message }) => {
|
||||
return (
|
||||
<span>
|
||||
{new Date(message.date).toISOString()}
|
||||
{message.content}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
export default MessageComponent;
|
1
src/lib
Submodule
1
src/lib
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 9fc4e8f80d335abc3ab02bfc24d64afcc91f3567
|
|
@ -1,3 +1,3 @@
|
|||
import "./styles.css";
|
||||
import "../styles.scss";
|
||||
|
||||
export { default } from "next/app";
|
||||
|
|
|
@ -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<Message[]>([]);
|
||||
const [socketUrl, setSocketUrl] = useState(
|
||||
"wss://toby222-web-drs-4gjg49gj355qq-8989.githubpreview.dev/"
|
||||
);
|
||||
const [messageHistory, setMessageHistory] = useState<TextMessage[]>([]);
|
||||
const [socketUrl, setSocketUrl] = useState("localhost:8989/");
|
||||
|
||||
function onMessage(event: MessageEvent<string>): 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 (
|
||||
<>
|
||||
<span>
|
||||
Ready state: {ReadyState[websocket.readyState]} ({websocket.readyState})
|
||||
</span>
|
||||
<main>
|
||||
{/* DEBUG
|
||||
<div>
|
||||
<h4>Last messages:</h4>
|
||||
{websocket.lastMessage?.data.toString() ?? "No message received"}
|
||||
<hr />
|
||||
<h4>Ready state:</h4>
|
||||
{connectionStatus} ({websocket.readyState})
|
||||
</div>
|
||||
*/}
|
||||
<ol>
|
||||
<div id="messages-container">
|
||||
{messageHistory.map((message, idx) => {
|
||||
return (
|
||||
<span key={messageHistory.length - idx}>
|
||||
<span>{new Date(message.date).toISOString()}</span>
|
||||
{" - "}
|
||||
<span>{message.content}</span>
|
||||
<br />
|
||||
</span>
|
||||
);
|
||||
return <MessageComponent message={message} key={idx} />;
|
||||
})}
|
||||
</ol>
|
||||
<div>
|
||||
</div>
|
||||
<div id="message-writing-area">
|
||||
<label htmlFor="ws-url">WebSocket URL:</label>
|
||||
<input
|
||||
id="ws-url"
|
||||
type={"text"}
|
||||
value={socketUrl.replace(/wss:(?:\/\/)?/, "")}
|
||||
type="text"
|
||||
value={socketUrl}
|
||||
onChange={(e) => trySetSocketUrl(e.target.value)}
|
||||
/>
|
||||
<label htmlFor="wss">Enable SSL:</label>
|
||||
<input
|
||||
id="wss"
|
||||
type="checkbox"
|
||||
checked={enableSSL}
|
||||
onChange={toggleSSL}
|
||||
/>
|
||||
<button
|
||||
disabled={websocket.readyState !== WebSocketReadyState.OPEN}
|
||||
onClick={handleClickSendMessage}
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
:root {
|
||||
--primay: black;
|
||||
--bg-primay: white;
|
||||
|
||||
--link: #2a0b0b;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 20px 0px;
|
||||
}
|
||||
|
||||
button {
|
||||
outline: none;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
padding: 10px 35px;
|
||||
|
||||
background: #845ec2;
|
||||
color: white;
|
||||
/* font-size: calc(10px + 2vmin); */
|
||||
}
|
||||
button:disabled {
|
||||
filter: brightness(30%);
|
||||
}
|
||||
button:hover {
|
||||
filter: brightness(120%);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.logo {
|
||||
animation: logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.app-header {
|
||||
background-color: #282c34;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
|
||||
background: var(--bg-primay);
|
||||
color: var(--primay);
|
||||
}
|
||||
|
||||
.link {
|
||||
color: var(--link);
|
||||
}
|
||||
|
||||
@keyframes logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
||||
monospace;
|
||||
}
|
57
src/styles.scss
Normal file
57
src/styles.scss
Normal file
|
@ -0,0 +1,57 @@
|
|||
:root {
|
||||
--primay: black;
|
||||
--bg-primay: white;
|
||||
|
||||
--link: #2a0b0b;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 20px 0px;
|
||||
}
|
||||
|
||||
button {
|
||||
outline: none;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
padding: 10px 35px;
|
||||
|
||||
background: #845ec2;
|
||||
color: white;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
filter: brightness(120%);
|
||||
cursor: pointer;
|
||||
}
|
||||
&:disabled {
|
||||
filter: brightness(30%);
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
justify-content: space-between;
|
||||
|
||||
#messages-container {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
overflow-y: scroll;
|
||||
> :nth-child(even) {
|
||||
background-color: lightgray;
|
||||
}
|
||||
}
|
||||
#message-writing-area {
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
export type Message = {
|
||||
author: string;
|
||||
content: string;
|
||||
date: number;
|
||||
};
|
52
yarn.lock
52
yarn.lock
|
@ -381,7 +381,7 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
|
|||
dependencies:
|
||||
color-convert "^2.0.1"
|
||||
|
||||
anymatch@~3.1.1:
|
||||
anymatch@~3.1.1, anymatch@~3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
|
||||
integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
|
||||
|
@ -713,6 +713,21 @@ chokidar@3.5.1:
|
|||
optionalDependencies:
|
||||
fsevents "~2.3.1"
|
||||
|
||||
"chokidar@>=3.0.0 <4.0.0":
|
||||
version "3.5.2"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75"
|
||||
integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==
|
||||
dependencies:
|
||||
anymatch "~3.1.2"
|
||||
braces "~3.0.2"
|
||||
glob-parent "~5.1.2"
|
||||
is-binary-path "~2.1.0"
|
||||
is-glob "~4.0.1"
|
||||
normalize-path "~3.0.0"
|
||||
readdirp "~3.6.0"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
|
||||
|
@ -1449,7 +1464,7 @@ fs.realpath@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||
|
||||
fsevents@~2.3.1:
|
||||
fsevents@~2.3.1, fsevents@~2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
||||
|
@ -1488,7 +1503,7 @@ get-symbol-description@^1.0.0:
|
|||
call-bind "^1.0.2"
|
||||
get-intrinsic "^1.1.1"
|
||||
|
||||
glob-parent@^5.1.2, glob-parent@~5.1.0:
|
||||
glob-parent@^5.1.2, glob-parent@~5.1.0, glob-parent@~5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
|
||||
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
|
||||
|
@ -1665,6 +1680,11 @@ image-size@1.0.0:
|
|||
dependencies:
|
||||
queue "6.0.2"
|
||||
|
||||
immutable@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23"
|
||||
integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==
|
||||
|
||||
import-fresh@^3.0.0, import-fresh@^3.2.1:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
|
||||
|
@ -2658,6 +2678,13 @@ readdirp@~3.5.0:
|
|||
dependencies:
|
||||
picomatch "^2.2.1"
|
||||
|
||||
readdirp@~3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
|
||||
integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
|
||||
dependencies:
|
||||
picomatch "^2.2.1"
|
||||
|
||||
regenerator-runtime@^0.13.4:
|
||||
version "0.13.9"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
|
||||
|
@ -2745,6 +2772,15 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
|||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
sass@^1.46.0:
|
||||
version "1.46.0"
|
||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.46.0.tgz#923117049525236026a7ede69715580eb0fac751"
|
||||
integrity sha512-Z4BYTgioAOlMmo4LU3Ky2txR8KR0GRPLXxO38kklaYxgo7qMTgy+mpNN4eKsrXDTFlwS5vdruvazG4cihxHRVQ==
|
||||
dependencies:
|
||||
chokidar ">=3.0.0 <4.0.0"
|
||||
immutable "^4.0.0"
|
||||
source-map-js ">=0.6.2 <2.0.0"
|
||||
|
||||
scheduler@^0.20.2:
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
|
||||
|
@ -2835,6 +2871,11 @@ slice-ansi@^4.0.0:
|
|||
astral-regex "^2.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
|
||||
"source-map-js@>=0.6.2 <2.0.0":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf"
|
||||
integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==
|
||||
|
||||
source-map@0.7.3:
|
||||
version "0.7.3"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
|
||||
|
@ -3323,11 +3364,6 @@ wrappy@1:
|
|||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
ws@^8.4.0:
|
||||
version "8.4.0"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.0.tgz#f05e982a0a88c604080e8581576e2a063802bed6"
|
||||
integrity sha512-IHVsKe2pjajSUIl4KYMQOdlyliovpEPquKkqbwswulszzI7r0SfQrxnXdWAEqOlDCLrVSJzo+O1hAwdog2sKSQ==
|
||||
|
||||
xtend@^4.0.0, xtend@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||
|
|
Reference in a new issue