Skip to content

Instantly share code, notes, and snippets.

@thekid
Last active January 19, 2025 12:20
Show Gist options
  • Save thekid/f933e8ffbc59b35af5e639bdd6f538c2 to your computer and use it in GitHub Desktop.
Save thekid/f933e8ffbc59b35af5e639bdd6f538c2 to your computer and use it in GitHub Desktop.
Websockets example
<?php
use util\Bytes;
use web\Application;
use web\handler\WebSocket;
class Ws extends Application {
public function routes() {
return [
'/ws' => new WebSocket(function($conn, $payload) {
$conn->send('You said: '.$payload);
// https://www.php.net/favicon-32x32.png
$conn->send(new Bytes(base64_decode('iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAllBMVEVPW5NPW5NPW5NPW5NPW5NPW5MAAABPW5NPW5P///9ocZ5sdaBNWpP8/f3b3OVbZZlSXpXy8/bf4OjX2eJfaJtWYZbr6/Hq6u++wdGcoLr6+/z4+Pr19vju7/PO0Nyhpb1kbZzj5OvDxdSws8err8SkqMB0fKTl5uzU1eDR097KzNm6vc63usyVmraQlbOFi62AhqpgapveRBF2AAAACHRSTlMp9PPwsbAAKE/4cekAAAEoSURBVDjLzZPXboNAFETXNTNbwKa4YMAdl8Qp//9zuYCFZMmGtyjn6Uqc3RkBV43VsIcX9IbyWA3QwkCpIVoZqR5a6St08PdCFE1aBeOc3yosOXsasdFab8q7FwzrwdeCb++CnVJI3wGPwiqPsaOQeKYWDOkFGbnGlNtgXg4B597JMayFJTMAAXNN9wOxjjblJ3DgagJVJwM4M5eOFnHC74L0y4N3waPE24z7Bc/AF1fxmrPq4AlQVccbcGSiPX4Ae27tjhfATLkXoe4YSrWDmJKc81p2DLcJg0klLCm42bE0fdg5D0gppFcfIlQdjYksEBsNQJu4oCvMpnmTZfIj0lH8RsjcDY/s3AWN8OwT+1HczP/in+xanM7V61reN9nvUf/l/SM1/gUJjiokQLn8cAAAAABJRU5ErkJggg==')));
}),
'/' => function($request, $response) {
$html= <<<'HTML'
<!DOCTYPE html>
<html>
<head>
<title>Websocket echo</title>
<style>
* { font-family: system-ui; font-size: 1.5rem; }
body { display: flex; flex-direction: column; gap: .5rem; justify-content: center; align-items: center; height: 100dvh; }
output { display: flex; gap: .5ch; height: 1lh; align-items: center; img { height: 0.8lh; } }
</style>
</head>
<body>
<form id="message">
<input name="input" autocomplete="off" type="text">
</form>
<output id="response">Type in something above!</output>
<script type="module">
class Connection {
#ws = null;
#listeners = {};
/** Creates a new connection with a given WebSocket URI */
constructor(uri) {
this.uri = uri;
}
/** Adds a listener for a connection event */
addEventListener(name, handler) {
if (name in this.#listeners) {
this.#listeners[name].push(handler);
} else {
this.#listeners[name] = [handler];
}
}
/** Dispatches an event */
dispatch(event) {
if (event.type in this.#listeners) {
for (const handler of this.#listeners[event.type]) {
handler(event);
}
}
}
/** Establishes connection */
connect() {
if (null === this.#ws) {
this.#ws = new WebSocket(this.uri);
this.#ws.onmessage = e => this.dispatch(e);
this.#ws.onerror = e => this.dispatch(e);
this.#ws.onclose = e => {
this.dispatch(e);
this.#ws = null;
};
}
}
/** Transmits message. Reconnects if necessary */
transmit(message) {
if (null === this.#ws) {
this.connect();
this.#ws.onopen = e => this.#ws.send(message);
} else {
this.#ws.send(message);
}
}
/** Closes connection */
close() {
this.#ws.close();
this.#ws = null;
}
}
const $response = document.getElementById('response');
const conn = new Connection(`ws://${location.host}/ws`);
conn.addEventListener('close', e => console.warn('Disconnected:', e));
conn.addEventListener('message', e => {
if (e.data instanceof Blob) {
const $img = document.createElement('img');
const url = URL.createObjectURL(new Blob([e.data], { type: 'image/png' }));
$img.src = url;
$img.onload = () => URL.revokeObjectURL(url);
$response.append($img);
} else {
$response.append(document.createTextNode(e.data));
}
});
conn.connect();
const $form = document.getElementById('message');
$form.onsubmit = e => {
const $input = $form.elements['input'];
e.preventDefault();
$response.innerText = '';
conn.transmit($input.value);
$input.value = '';
};
</script>
</body>
</html>
HTML;
$response->send($html, 'text/html; charset=utf-8');
}
];
}
}
@thekid
Copy link
Author

thekid commented Jan 12, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment