Chat example in Javascript
The most trivial example. A chat based on wrapping cat(1) without any backend code.
➡ View demo online
➡ View full source on GitHub
➡ Run the example
Running the example
You can run this self-contained example using Docker.
git clone https://github.com/scalesocket/scalesocket
cd scalesocket/examples/
docker compose up --build chat
Then open http://localhost:5000/
in your browser.
Frontend code
The frontend is a single html file, index.html
, with some javascript. It connects with websockets to the server and shows a chat interface.
<!doctype html>
<html>
<head>
<title>Chat Example using ScaleSocket</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body { background-color: #e2e8f0; font-family: Arial, Helvetica, sans-serif; margin: 0; text-align: center; }
#chat { margin: 0 auto; height: 50vh; display: flex; flex-direction: column; text-align: left; max-width: 48rem; }
#messages { background-color: #f1f5f9; overflow-x: scroll; padding: 1rem; }
#message { display: flex; flex-direction: row; }
.input-rounded { display: flex; border: 0; padding: 0.25rem; margin: 0.5rem; border-radius: 0.75rem; }
.grow { flex-grow: 1; }
.shrink { flex-shrink: 1; min-width: 0; }
</style>
</head>
<body>
<div>
<h1>Multiplayer Chat Example</h1>
<p><select
onchange="let value = this.options[this.selectedIndex].value || (Math.random() + 1).toString(36).substring(7); window.location.search = `?room=${value}`;">
<option disabled selected>Change Room</option>
<option value="default">Room 0 (default)</option>
<option value="room1">Room 1</option>
<option value="room2">Room 2</option>
<option value="room3">Room 3</option>
<option value="">Create new room</option>
</select></p>
<p>Multiplayer chat, try opening multiple instances. Built with <a
href="https://www.scalesocket.org/man/examples/chat" target="_blank">ScaleSocket</a>.</p>
</div>
<div id="chat">
<div id="messages" class="grow"></div>
<div id="message">
<input name="nick" placeholder="nick" class="input-rounded shrink" value="anonymous" />
<input name="message" placeholder="connecting..." class="input-rounded grow" disabled />
</div>
</div>
<script>
const $ = document.querySelector.bind(document);
const protocol = window.location.protocol === "https:" ? "wss" : "ws";
const params = new URLSearchParams(document.location.search);
const room = params.get("room") ?? 'default';
// connect to websocket server and room based on URL
const ws = new WebSocket(`${protocol}:${window.location.host}/${room}`);
const sendMessage = (text) => {
// send outgoing message
const nick = $("input[name=nick]").value || "anonymous";
ws.send(JSON.stringify({ nick, text }));
}
const recvMessage = (message) => {
// handle incoming message
const el = $("#messages")
el.appendChild(document.createTextNode(`<${message.nick}> ${message.text}`));
el.appendChild(document.createElement('br'));
el.scrollTop = el.scrollHeight;
}
// set websocket listener
ws.addEventListener('message', e => {
const message = JSON.parse(e.data);
recvMessage(message);
});
// set input listener
$("input[name=message]").addEventListener('keyup', ({ key, target }) => {
if (key === 'Enter') {
sendMessage(target.value);
target.value = "";
target.focus();
}
});
ws.addEventListener('open', _ => {
// set input focus
$("input[name=message]").placeholder = "message...";
$("input[name=message]").disabled = false;
$("input[name=message]").focus();
});
</script>
</body>
</html>
Backend code
There is no backend code. The backend is a wrapped cat
process.
Backend server
The backend is the ScaleSocket server.
We want to:
- let participants join rooms based on URL
- start a new
cat
process when a new user connects - keep a history of 64 messages and send it to joining users
- host a static html file
To do this, start ScaleSocket using:
scalesocket --addr 0.0.0.0:5000\
--staticdir /var/www/public/\
--frame\
--cache=all:64\
cat
How does it work?
The frontend connects to the server using websockets. The backend spins up a new cat
process.
When the frontend sends a chat message, ScaleSocket passes it directly to the stdin of cat
.
Since cat
echoes all input it receives, the reply to stdout is the message itself, which ScaleSocket sends back to all connected clients.
This is obviously not a tamper-proof setup. A more complete example would utilize the _from
field, which is added by the scalesocket server when --frame=json
is specified.
Was this page helpful?