maarteNNNN / sc-underrated-framework-part2
A repo that represents the code from an article I wrote on dev.to
Part 2: A simple example
Recap
In Part 1 we gave an introduction to what SocketCluster is, does and which projects/companies use it.
Setting up the SocketCluster project.
NOTE
In this article I will focus solely on SocketCluster and not implement Vue yet. We will do some vanilla client js in theindex.html
file served by SocketCluster.
We'll need the socketcluster-cli
to be able to scaffold a project. Install it by executing npm i -g socketcluster
. Initiating a project can be done with socketcluster create <project-name>
. Let's open our code editor and take a look at what we have. The project consists of two directories kubernetes
and public
and some files. kubernetes
is where all the config files to deploy as a kubernetes
service. We will discuss this in a later article. public
is a directory served by Express and upon firing up SocketCluster it will be accessible by navigating localhost:8000. Let's fire up SocketCluster and see what we can do by running npm run start
. The default port is 8000
.
Let's take a look where the magic happens. The server.js
file. The server.js
consists of some sections, the beginning are mostly constants to environment variables. Then it creates two servers. One is the httpServer
and the other is the agServer
. The agServer
handles the sockets. The httpServer
is a HTTP server wrapped in eetase. Which basically adds a request to a queue to be able to run for await (let ... of asyncQueueIterable) { ...logic... }
loop on the requests. Then comes the Express part. It defines which directory to serve and provides a /health-check
route to see if the server is operational.
// HTTP request handling loop.
(async () => {
for await (let requestData of httpServer.listener('request')) {
expressApp.apply(null, requestData);
}
})();
This piece of code calls every request asynchronously to the expressApp
variable and passes the requestData as the first argument, basically handling the request. This is where the eetase
comes in handy to queue up requests and carefully execute them one by one.
Let's create an endpoint
We will create an endpoint in the server.js
first. This is the entrypoint for every socket connection. Let's add some code:
for await (let { socket } of agServer.listener('connection')) {
...
for await (let request of socket.procedure('test')) {
console.log(request.data);
request.end({ message: 'Data received, thanks client!' });
}
...
}
...
This will handle any request on the test
procedure. Log the given data to the console and respond with the message Data received, thanks client!
.
Now let's add some code to actually test this route on the client. Let's use the index.html
in the public
folder so we can do some basic testing. Add a button below the iframe
block in the HTML:
...
<!-- IFRAME BLOCK -->
<button onclick="send()">Test</button>
...
And add some JavaScript logic below let socket = socketClusterClient.create();
const send = async () => {
console.log('sending to the server...');
const response = await socket.invoke('test', {
message: 'This is our first message from the client to the server',
});
console.log(response);
};
Restart the server and go to localhost:8000, open your developer console and hit the button Test
. Upon clicking you should receive the Data received, thanks client!
in the browser and when going to the terminal it should show This is our first message from the client to the server
.
Now you succesfully created an endpoint from the client
to the server
. Now you can do some cool things but let me show you that you can do it the other way around as well. Unlike REST, SocketCluster lets you handle messages both from the server
to the client
as well as from the client
to the server
. Let's make a quick example sending an interval
to the client.
On the server we will add the interval
of 10 seconds:
...
const send = async () => {
console.log('sending to the server...')
const response = await socket.invoke(
'test',
{ message: 'This is our first message from the client to the server' },
);
console.log(response)
}
setInterval(async () => {
console.log('sending data to client...');
const data = await socket.invoke('from-server', {
message: 'This is sent from the server to the client',
});
console.log(data);
}, 10000);
...
And on the client we will listen to the procedure:
...
const send = async () => {
console.log('sending to the server...')
const response = await socket.invoke(
'test',
'This is our first message from the client to the server',
);
console.log(response)
}
(async () => {
for await (let request of socket.procedure('from-server')) {
console.log(request.data);
// return this message to the server, it could just be request.end() to terminate it
request.end({ message: 'Thanks server, message received' });
}
})();
...
Restart the server and refresh the browser window. You should receive the message This is sent from the server to the client
every 10 seconds.
Top comments (0)