What is Web-events?
That is a easy way to create event-oriented WebSocket connection between client and server.
Support IE 10+ and all modern browsers
Examples
Download
There are two different part of this library - server and client.
First, consider the server part.
How to install server part
Use npm:
npm i web-events-server --save
Using:
var events = require('web-events-server');
var base = events(server, {
connection(ws, req) {
...
},
headers(headers, req) {
...
},
customEvent1(arg1, arg2, ..., argN) {
...
},
...
customEventN(arg1, arg2, ..., argN) {
...
},
close(code, reason) {
...
}
});
Note: Don't forget to separate the handlers of the object using comma.
The return value from events
is the database object of all active connections like this.base
in a handler.
You can use it to send messages to users outside the handlers.
How to install client part
Here is also two ways to use this library:
1) Just a direct connection in the HTML file:
Common | web-events-client.js |
Minified | web-events-client.min.js |
<script src="web-events-client.js"></script>
After that you can use global variable events or webEvents if the first was already taken.
2) Using requireJS modules (that's useful for webpack, for example):
Install client part through npm:
npm i web-events-client --save
Then import module in your code:
var events = require('web-events-client');
Using client part:
var events = require('web-events-server');
var socket = events({
connection(ws, req) {
...
},
customEvent1(arg1, arg2, ..., argN) {
...
},
...
customEventN(arg1, arg2, ..., argN) {
...
},
close(code, reason) {
...
}
});
Note: Don't forget to separate the handlers of the object using comma.
Return value is a object which has three methods to manage a connection:
socket.emit(eventName, arg1, ..., argN) // Triggers the event on the server
socket.disconnect() // Closes the connection to the server
socket.reconnect() // Closes the connection and then again opens it
Example: simple chat
Let's create simple common chat.
Server
const
http = require('http'),
express = require('express'),
events = require('web-events-server'); // connect web-events-server
// Creating basic file server on http
let app = express()
.use(express.static(__dirname + '/client'));
// Creating HTTP-server
let server = http.createServer(app);
// Binding event handlers to the server
events(server, {
/*
This handler will be called when new user
connects to the your server (Special event)
*/
connection() {
console.log(`New user: ${this.uid}`);
/*
Send the 'printToChat' event to the client
This event will be triggered by user as soon as
he receives it.
*/
this.emit('printToChat', 'You have been connected to a chat');
},
// Client triggered custom event named 'chat' on the server (Custom event)
chat(message) {
// Client wants to send his message to the everybody active users
console.log(`From ${this.uid} recieves a message "${message}"`);
// Send this broadcast message
this.base.forEach(client => client.emit('printToChat', message));
// If user sent a message like 'kick me' then disconnect him from chat
if (message == 'kick me')
this.close();
},
// This event will be triggered when user has been disconnected (Special event)
close(code, reason) {
console.log(`Close connection ${this.uid}`);
}
});
// Start server on port 80
server.listen(80);
Client
Markup
<h1>Chat</h1>
<textarea id="chat-box" cols="30" rows="10" disabled></textarea>
<div>
<input id="textbox" type="text"><button id="send">Send</button>
</div>
<!-- Connect client part of web-events -->
<script src="web-events-client.js"></script>
<!-- Connect client logic -->
<script src="client-logic.js"></script>
client-logic.js
var textbox = document.getElementById('textbox'),
sendButton = document.getElementById('send'),
chatBox = document.getElementById('chat-box');
/*
Establishes a connection to the server
You can use return value later to trigger custom event on the server
*/
var socket = events({
// Connection is established successfully (Special event)
connection() {
console.log('Connection is established successfully!');
},
// Received message from another user (Custom event)
printToChat(message) {
// print this message to the chat
chatBox.value += message + '\n';
},
// Connection has been closed (Special event)
close() {
console.log('You have been disconnected!');
}
});
// Adding click handler on send button
sendButton.onclick = function() {
// Calling 'chat' event on the server with textbox.value argument
socket.emit('chat', textbox.value);
// Clear input field
textbox.value = '';
};
If you want to try use it visit download page
To get more information visit documentation page
Example: RPG
Now let's create small textual RPG-simulator.
You connect to the game server which give you 100 HP and list of your enemies (they are also really gamers and have online status).
Game client have to display your currently HP and list of enemies with 'hit' button.
After press this button the enemy will taken a damage around 3-43 HP.
Between attacks every gamer have to waiting for 5 seconds before next attack.
If your HP is zero your client has to display message with the text "Game over" and breaks connection.
Server
const
http = require('http'),
express = require('express'),
events = require('web-events-server'); // connect web-events-server
// Passing the client files to the users
let app = express()
.use('/', express.static('client'));
// Creating HTTP-server
let server = http.createServer(app);
// Binding event handlers to the server
events(server, {
/*
This handler will be called when new user
connects to the our server (Special event)
*/
connection() {
/*** At the moment, the enumeration methods of this.base ignore this user ***/
console.log(`New gamer: ${this.uid}`);
// Set a new user HP = 100
this.hp = 100;
// Set time of last hit of this user
this.lastHit = new Date(0);
/*
Trigger the 'newUser' event to all active players.
Pass uid of client and his started hp
*/
this.base.forEach(client => client.emit('newUser', this.uid, 100));
// The array of information about active players
let players = this.base.map(client => ({
name: client.uid,
hp: client.hp
}));
// Sending the data about all active players to the new player
this.emit('startedData', this.uid, ...players);
},
// Client triggered custom event named 'hit' on the server (Custom event)
hit(target_uid) {
// Let's see if this gamer can attack someone
if (Date.now() - this.lastHit < 5 * 1000)
return; // Ignoring the hit request
// Getting client object of target from base
let target = this.base[target_uid];
// Checking the existence of the target
if (!target)
return; // Ignoring the hit request
// Checking if the target player is alive
if (target.hp <= 0)
return; // Ignoring the hit request
// Obtaining a random damage between 3 and 43
let damage = Math.round(3 + 40 * Math.random());
console.log(`User ${this.uid} attacks ${target.uid} — ${damage} HP`);
// Subtract HP
target.hp -= damage;
// Remembering the last hit time
this.lastHit = Date.now();
/*
If player hasn't HP to continue the game,
sending to everybody players 'game over' event.
Otherwise, sending updated HP data to everybody active players.
*/
if (target.hp <= 0) {
this.base.forEach(client => client.emit('gameOver', target.uid));
target.close(); // Closing connection
} else {
this.base.forEach(client => client.emit('attacked', target.uid, target.hp));
}
},
// This event will be triggered when user has been disconnected (Special event)
close(code, reason) {
/*** You are no longer in the this.base ***/
console.log(`Close connection: ${this.uid}`);
/*
If gamer close connection then send to
everybody active user the message 'gameOver'
with uid of this gamer.
*/
this.base.forEach(client => client.emit('gameOver', this.uid));
}
});
// Start server on port 80
server.listen(80);
Client
Markup
<h1>RPG</h1>
<div id="my-hp">100</div>
<script src="jquery.js"></script>
<script src="web-events-client.js"></script>
<script src="client-logic.js"></script>
client-logic.js
function createPlayer(name, hp) {
return $(
'<div class="player" uid="' + name + '">' +
'<button>Hit</button>' +
'<span>' + name + '</span>' +
'<span>HP: ' + hp + '</span>' +
'</div>'
);
}
var my_uid = null;
var socket = events({
// Received data on all active players and your unique id
startedData(myUID, ...players) {
// Saving my uid
my_uid = myUID;
// Placing each received player in the <body>
for (let player of players)
createPlayer(player.name, player.hp)
.appendTo('body');
},
// Received the data about a new user
newUser(name, hp) {
createPlayer(name, hp) // Create Markup
.appendTo('body'); // put it in <body>
},
// Someone was attacked (name is target uid, hp is new HP)
attacked(name, hp) {
// If I am the target
if (name == my_uid)
$('#my-hp')
.text(hp);
else
$('[uid="' + name + '"]')
.children()
.last()
.text(hp); // Updating hp value
},
// The player whose name is the first argument is lost
gameOver(name) {
if (name == my_uid) {
$('#my-hp')
.text(0);
alert('GAME OVER');
}
else
$('[uid="' + name + '"]')
.children()
.first()
.prop('disabled', true) // Blocking the hit button
.end()
.last()
.text(0); // Setting hp is zero
}
});
// Hit handler
$('body')
.on('click', 'button', function() {
var name = $(this).next().text();
socket.emit('hit', name);
});
If you want to try use it visit download page
To get more information visit documentation page
Documentation
This documentation consist of two parts. First part describes how to use web-events-server, the second - web-events-client.
For more information on how to install them, see download page.
Server
Server always are connected through module import:
var events = require('web-events-server');
After that you need create HTTP-server and pass it to the events
function as first argument. The second argument is an object with event handlers.
var base = events(server, {
event1() { ... },
...
eventN() { ... }
});
event1
, ..., eventN
- are custom event names. You can trigger any of them from any client by using emit
function about which will be discussed later.
There are two types of event handlers:
1) Special events - which can not be overridden. They are trigger automatically when special actions occur. In addition, the signature (arguments) of such events can not be redefined either.
At the moment there are three such events:
- connection(webSocket, reqest) - occurs when a new client connected to the server. Gets as arguments the Web-Socket object and object of the request. At the time when the event handler of this event is called the client object it will still not be available in
this.base
. Because of this, the new client will be ignored by methods such asforEach
ormap
ofthis.base
object. - checkHeaders(headers, reqest) - occurs before a connection is established. Here you can read or set HTTP-headers before start connection. In this handler
this
isnull
. The first argument is a array of response headers (each is string). You can add header to the this array to send cookie for example. You can read cookie fromreqest.headers.cookie
. - close(code, reason) - occurs when user disconnected from the server. The arguments are exactly the same as in the 'ws' package.
2) Custom events - are exactly what you need to love this library for. You can name your custom event as you want. You can define the list of arguments of the handler for this event as you like.
Properties of this
for server
Inside each an event handler (except checkHeaders) you can use methods of this
to interact with the user.
this
points to object of current client which triggered the event.
Structure of the client object (this
in a handler):
-
emit(eventName, arg1, ..., argN) - triggers the custom event named "eventName" and passes arguments.
You can pass several arguments one at a time, in this case their order is preserved when received:// Server var base = events(server, { connection() { ... // Sending initial data to the new client this.emit('startGame', hp, name, attack); } })
// Client var socket = events({ startGame(hp, name, attack) { // Working with data } })
- close() - closes the connection with the client.
- uid - unique identifier of the client. At the one time, each active client has its own unique id.
-
ignore - a boolean variable that determines whether to ignore the current user when using the methods of enumerating all users, which will be described a little later.
When a special "connection" event is activated, this property is set to "false", but if you need to consider this new user when iterating, you can set this property to "true". -
base - base of all active users. Access to the object of a specific client occurs by uid.
In addition, this object has additional methods for enumerating all active users:- base.forEach(function(client) { ... }) - performing a callback for each client. The argument client is a client object.
- base.map(function(client) { ... }) - simulates the behavior of the array method of the same name. The return values generate an array, and then return it as a result. The argument client is a client object.
The server-side method events(sever, {...})
returns the base
that you can you use to interact with all active users outside the event handler.
Client
Connection:
var socket = events({
// Special events
connection() { ... },
close() { ... },
// Custom events
customEvent1(arg1, ..., argN) { ... },
...,
customEventX(arg1, ..., argN) { ... }
})
Note: Don't forget to separate the handlers of the object using comma.
The client also has two types of events. These are special and custom events.
1) Special events are only two - connection and close. You don't need to always specify them. Do it only if you need it. Both events don't take arguments.
2) Custom events can have any name and take any number of arguments.
Socket object
This object allows you to manage you connection. Inside the handlers, this object is available as this
. Also, this object is returned from events({ ... })
to trigger events outside the handlers.
Structure of socket object
- emit(eventName, arg1, ..., argN) - triggers the custom event named "eventName" and passes arguments. Completely similar to the server
emit
. - disconnect() - close connection to the server.
- reconnect() - reconnect to the server.
Returned emit
From any handler you can return a special value that will be interpreted as an implicit call to this.emit
.
-
You can return an array. The first argument is the name of the custom event. Others are arguments.
customEventHandler() { return ['setState', 100, 50, 'Hello World!']; // This is equivalent of this.emit('setState', 100, 50, 'Hello World!') }
-
You can return an object. Type property
type
is a event name.customEventHandler() { return { type: 'setState', name: 'Jack', health: 100 }; /* This is equivalent of this.emit('setState', { name: 'Jack', health: 100 }); */ }