Skip to content

Instantly share code, notes, and snippets.

@Romejanic
Created August 17, 2024 14:26
Show Gist options
  • Save Romejanic/beba08c95ddbc2bdb4cd969df67b26eb to your computer and use it in GitHub Desktop.
Save Romejanic/beba08c95ddbc2bdb4cd969df67b26eb to your computer and use it in GitHub Desktop.
WebRTC Chat Room
# Built using Svelte and peerjs
<script lang="ts">
import Peer from "peerjs";
import type { DataConnection } from "peerjs";
import { onMount } from "svelte";
type Optional<T> = T | null;
interface Message {
id?: string;
text: string;
sender: string;
}
let peer: Optional<Peer> = null;
let conn: Optional<DataConnection> = null;
let clients: DataConnection[] = [];
let connected = false;
let peerID = "";
let connectID = "";
let messageText = "";
let messages: Message[] = [];
onMount(() => {
if(peer) return;
peer = new Peer();
peer.on("open", id => {
peerID = id;
});
peer.on("error", console.error);
peer.on("connection", (conn) => {
conn.on("open", () => {
clients = [...clients, conn];
sendMessage({
text: `${conn.connectionId} connected`,
sender: "System"
});
});
conn.on("close", () => {
clients = clients.filter(val => val != conn);
sendMessage({
text: `${conn.connectionId} left`,
sender: "System"
});
});
conn.on("data", data => {
sendMessage(parseMessage(data), conn);
});
});
return () => peer?.destroy();
});
function connect() {
if(!peer || connected) return;
connectID = connectID.trim();
if(connectID.length == 0) {
return alert("You must enter an ID to connect to!");
}
conn = peer.connect(connectID, { reliable: true });
conn.on("open", () => connected = true);
conn.on("close", () => {
connected = false;
conn = null;
});
conn.on("data", data => onMessageRecieved(parseMessage(data)));
}
function disconnect() {
if(conn) {
conn.close();
conn = null;
connected = false;
}
}
function sendMsg() {
sendMessage({
text: messageText,
sender: peerID
});
messageText = "";
}
function parseMessage(data: unknown) {
return JSON.parse(String(data)) as Message;
}
function sendMessage(msg: Message, except?: DataConnection) {
onMessageRecieved(msg);
if(clients.length == 0 && !conn) return;
let targetConns = clients;
if(targetConns.length == 0 && conn)
targetConns = [conn];
targetConns.forEach(conn => {
if(conn == except) return;
conn.send(JSON.stringify(msg));
});
}
function onMessageRecieved(msg: Message) {
msg.id = crypto.randomUUID();
messages = [...messages, msg];
}
</script>
<h1>ligma chat</h1>
{#if peer}
<h3>Peer ID: {peerID}</h3>
{#if !connected}
<form on:submit|preventDefault={connect}>
<input type="text" name="id" placeholder="ID to connect to" bind:value={connectID} />
<input type="submit" />
</form>
{:else}
<span>Connected to {connectID}</span>
<button on:click={disconnect}>Disconnect</button>
{/if}
<div class="messages">
{#each messages as msg (msg.id)}
<span>{msg.sender.substring(0, 6)}: {msg.text}</span>
{/each}
</div>
<form on:submit|preventDefault={sendMsg}>
<input type="text" name="msg" placeholder="Message" bind:value={messageText} />
<input type="submit" />
</form>
{:else}
<p>Peer is not established</p>
{/if}
<style>
.messages {
display: flex;
flex-direction: column;
width: 500px;
height: 500px;
overflow-y: scroll;
border: 1px solid gray;
}
</style>
<svelte:head>
<title>Test</title>
</svelte:head>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment