128 lines
3.4 KiB
TypeScript
128 lines
3.4 KiB
TypeScript
import CBOR from "cbor";
|
|
import { useEffect, useState } from "react";
|
|
import useWebSocket, { ReadyState } from "react-use-websocket";
|
|
import * as Automerge from "@automerge/automerge";
|
|
import * as uuid from "uuid";
|
|
import { wsUrl } from "./constants";
|
|
import { Tab, Tabs } from "react-bootstrap";
|
|
import Upload from "./Upload";
|
|
import Chat from "./Chat";
|
|
import Grub from "./Grub";
|
|
import { RoomContext } from "./lib/roomContext";
|
|
import { Wifi } from "react-bootstrap-icons";
|
|
|
|
const connectionStatusMap = {
|
|
[ReadyState.CONNECTING]: "Connecting",
|
|
[ReadyState.OPEN]: "Open",
|
|
[ReadyState.CLOSING]: "Closing",
|
|
[ReadyState.CLOSED]: "Closed",
|
|
[ReadyState.UNINSTANTIATED]: "Uninstantiated",
|
|
};
|
|
|
|
export default function Room({ roomId }) {
|
|
const [readyState, setReadyState] = useState(ReadyState.CLOSED);
|
|
const [connectedClients, setConnectedClients] = useState([]);
|
|
const [clientId, setClientId] = useState<string | null>(null);
|
|
|
|
const {
|
|
sendMessage,
|
|
lastJsonMessage,
|
|
readyState: newReadyState,
|
|
} = useWebSocket(wsUrl, {
|
|
share: true,
|
|
onOpen: ({}) => {
|
|
console.log("Shiet, connected.");
|
|
},
|
|
onMessage: async (event) => {
|
|
const data = CBOR.decode(await event.data.arrayBuffer());
|
|
console.log("received", data);
|
|
|
|
if (data.type === "ServerHello") {
|
|
setClientId(uuid.stringify(data.client_id));
|
|
}
|
|
|
|
if (data.type === "RoomClientList") {
|
|
setConnectedClients(data.clients.map((x) => uuid.stringify(x)));
|
|
}
|
|
|
|
if (data.type === "Automerge") {
|
|
const [nextDoc, nextSyncState, patch] = Automerge.receiveSyncMessage(
|
|
doc,
|
|
syncState,
|
|
data.message[1]
|
|
);
|
|
setDoc(nextDoc);
|
|
setSyncState(nextSyncState);
|
|
console.log("patch", patch);
|
|
}
|
|
},
|
|
});
|
|
|
|
function sendWtfMessage(data) {
|
|
let cbor = CBOR.encode(data);
|
|
console.log(
|
|
"cbor-encoded",
|
|
[...new Uint8Array(cbor)]
|
|
.map((x) => x.toString(16).padStart(2, "0"))
|
|
.join(" ")
|
|
);
|
|
sendMessage(cbor);
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (
|
|
readyState === ReadyState.CONNECTING &&
|
|
newReadyState === ReadyState.OPEN
|
|
) {
|
|
// On Open
|
|
sendWtfMessage({ type: "JoinRoom", room_id: roomId });
|
|
console.log("Sent connection message");
|
|
}
|
|
setReadyState(newReadyState);
|
|
}, [newReadyState]);
|
|
|
|
const connectionStatus = connectionStatusMap[readyState];
|
|
|
|
if (newReadyState !== ReadyState.OPEN) return <>Connecting...</>;
|
|
|
|
return (
|
|
<RoomContext.Provider value={{ roomId, clientId }}>
|
|
<p>Room Id: {roomId}</p>
|
|
<p>
|
|
Connection status: <ConnectionStatus readyState={readyState} />
|
|
</p>
|
|
Connected:
|
|
<ul>
|
|
{connectedClients.map((x) => (
|
|
<li key={x}>{x}</li>
|
|
))}
|
|
</ul>
|
|
<Tabs
|
|
defaultActiveKey="file-transfer"
|
|
id="uncontrolled-tab-example"
|
|
className="mb-3"
|
|
>
|
|
<Tab eventKey="file-transfer" title="File Transfer">
|
|
<Upload />
|
|
</Tab>
|
|
<Tab eventKey="grocery-tracking" title="Grocery Tracking">
|
|
<Grub />
|
|
</Tab>
|
|
<Tab eventKey="chat" title="Chat">
|
|
<Chat />
|
|
</Tab>
|
|
</Tabs>
|
|
</RoomContext.Provider>
|
|
);
|
|
}
|
|
|
|
function ConnectionStatus({ readyState }) {
|
|
switch (readyState) {
|
|
case ReadyState.CONNECTING:
|
|
return <Wifi color="yellow" />;
|
|
case ReadyState.OPEN:
|
|
return <Wifi color="green" />;
|
|
default:
|
|
return null;
|
|
}
|
|
}
|