Web-events

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
DOWNLOAD SOURCE

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

DOWNLOAD SOURCE

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:

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):

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

Returned emit

From any handler you can return a special value that will be interpreted as an implicit call to this.emit.

404 Not Found