Skip to content

Instantly share code, notes, and snippets.

@mwilliamson
Last active February 8, 2021 14:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mwilliamson/969b9f6ee1bc5384ad38dd802a53beef to your computer and use it in GitHub Desktop.
Save mwilliamson/969b9f6ee1bc5384ad38dd802a53beef to your computer and use it in GitHub Desktop.
WebSocket server
function handleConnect(url: string) {
setState({type: "connecting"});
const socket = new WebSocket(url);
let nextMessageIndex = 0;
socket.onmessage = function (event) {
const message = JSON.parse(event.data);
if (message.index !== nextMessageIndex) {
setState({type: "sync-error"});
socket.close();
}
nextMessageIndex++;
const update = JSON.parse(message.payload) as StateUpdate;
setState(state => {
if (state.type === "connected") {
return {...state, state: updateState(state.state, update)};
} else {
return state;
}
});
};
socket.onerror = function() {
setState({type: "connection-error"});
};
socket.onopen = function() {
setState({
type: "connected",
state: initialState(),
socket: socket,
});
};
}
const http = require("http");
const url = require("url");
const serveHandler = require("serve-handler");
const uuid = require("uuid");
const WebSocket = require("ws");
const webSocketPath = "/" + (process.argv[2] || uuid.v4());
const port = process.env.PORT || 8000;
const server = http.createServer(function (request, response) {
if (/^\/static/.test(url.parse(request.url).pathname)) {
serveHandler(request, response, {
cleanUrls: false,
public: "static/build",
rewrites: [
{
"source": "/x",
"destination": "index.html"
},
{
"source": "/x/:a",
"destination": "/:a"
},
{
"source": "/x/:a/:b",
"destination": "/:a/:b"
},
{
"source": "/x/:a/:b/:c",
"destination": "/:a/:b/:c"
},
{
"source": "/x/:a/:b/:c/:d",
"destination": "/:a/:b/:c/:d"
},
],
});
} else {
response.writeHead(404, {"Content-Type": "text/plain"});
response.end("404 Not Found");
}
});
console.log(`Server URI: ws://0.0.0.0:${port}${webSocketPath}`);
const wss = new WebSocket.Server({noServer: true});
let connections = [];
const messages = [];
wss.on("connection", function connection(ws) {
connections.push(ws);
const intervalId = setInterval(() => {
ws.ping();
}, 1000);
messages.forEach(message => ws.send(message));
ws.on("close", () => {
connections = connections.filter(connection => connection != ws);
clearInterval(intervalId);
});
ws.on("message", function incoming(payload) {
const message = JSON.stringify({
index: messages.length,
payload: payload,
});
messages.push(message);
connections.forEach((ws) => ws.send(message));
});
});
server.on("upgrade", function upgrade(request, socket, head) {
const requestPath = url.parse(request.url).pathname;
if (requestPath === webSocketPath) {
wss.handleUpgrade(request, socket, head, function done(ws) {
wss.emit("connection", ws, request);
});
} else {
socket.destroy();
}
});
server.listen(port);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment