1.0.3 • Published 6 years ago

@alvitrjs/server v1.0.3

Weekly downloads
-
License
MIT
Repository
github
Last release
6 years ago

If you want to create one or multiple node servers the easy way.

A package that creates a configurable http and/or https servers so you can also load balance and cluster them.

If you do not want to do this:

// httpApp.ts
import http from 'http';

const server = http.createServer(function(req, res) {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
});

export default server;

// httpsApp.ts
import https from 'http';
import fs from 'fs';

const options = {
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.cert')
};

const server = https.createServer(options, function(req, res) {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
});

export default server;

// server.ts
import cluster from 'cluster';
import os from 'os';

import httpServer from './httpApp';
import httpsServer from './httpsApp';

const numCores = os.cpus().length;

if (cluster.isMaster) {
    for (let i = 0; i < numCores; i++) {
        cluster.fork();
    }

    cluster.on('exit', () => {
        cluster.fork();
    })
} else {
    httpServer.listen(80);
    httpsServer.listen(443);
}

Do this:

// server.ts
import fs from 'fs';

import Server from '@alvitrjs/server';
import Servers from '@alvitrjs/server/Servers';
import Cluster from '@alvitrjs/server/Cluster';

const httpServer = new Server(80, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
});

const httpsServer = new Server(443, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, {
    key: fs.readFileSync('server.key'),
    cert: fs.readFileSync('server.cert'),
});

const serverObjects = {
    httpServer,
    httpsServer
}

const servers = new Servers(serverObjects);

new Cluster({
    numCores: Cluster.howManyCores(),
    restartOnExit: true
}, servers).start();

Getting Started

Prerequisites

  • NodeJS : >= 10.16.1
  • NPM : >= 6.9.0

On Windows go to NodeJS and download the LTS version, execute and that is it!

On Ubuntu you can install via NodeSource:

curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt install nodejs

On MacOS you can install via brew:

brew install node

Or you can go to NodeJS and download the LTS version, execute and that is it!

Instalation

You can use NPM or Yarn to install Server

npm i --save @alvitrjs/server
yarn add @alvitrjs/server

Usage

Using Typescript

import fs from 'fs';

import Server from '@alvitrjs/server';
import Servers from '@alvitrjs/server/Servers';
import Cluster from '@alvitrjs/server/Cluster';

const httpServer = new Server(80, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, undefined , 'localtest.test');

const httpsServer = new Server(443, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, {
    key: fs.readFileSync('server.key'),
    cert: fs.readFileSync('server.cert'),
} , 'localtest.test');

const servers = new Servers();
servers.addServer('httpServer', httpServer);
servers.addServer('httpsServer', httpsServer);

new Cluster({
    numCores: 8,
    restartOnExit: true
}, servers).start();

Using Javascript

const fs = require('fs');

const Server = require('@alvitrjs/server');
const Servers = require('@alvitrjs/server/Servers');
const Cluster = require('@alvitrjs/server/Cluster');

const httpServer = new Server(80, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, undefined , 'localtest.test');

const httpsServer = new Server(443, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, {
    key: fs.readFileSync('server.key'),
    cert: fs.readFileSync('server.cert'),
} , 'localtest.test');

const servers = new Servers();
servers.addServer('httpServer', httpServer);
servers.addServer('httpsServer', httpsServer);

new Cluster(servers, {
    numCores: 8,
    restartOnExit: true
}).start();

Table of Contents

  1. Server
    1. Customize
    2. Extending IncomingMessage and ServerResponse
  2. Servers
    1. Adding new Servers
    2. Setting Prefix and Suffix
  3. RunningServers
    1. Getting an Instance
    2. Closing All Servers
  4. Cluster
    1. Number of Cores
    2. Restart Fork on Exit
    3. How Many Cores
  5. How to Contribute
  6. In Development
  7. Authors
  8. Versions

Server

The server class is made so you can both create http and https servers and customize it.

import path from 'path';
import fs from 'fs';

import Server from '@alvitrjs/server';

// HTTP Server
const httpServer = new Server(80, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}).start();

// HTTPS Server
const httpsServer = new Server(443, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, {
    key: fs.readFileSync(path.join(path.resolve(__dirname), 'server.key')),
    cert: fs.readFileSync(path.join(path.resolve(__dirname), 'server.cert')),
}).start();

Customize

You can customize your server by passing to its constructor parameters. Server accepts: port, requestListener, options, host and cbListen.

const httpServer = new Server(80, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, {
    IncomingMessage: CustomIncommingMessage,
    ServerResponse: CustomServerResponse
}, 'server.test', () => {console.log('listening')}).start();

To create an https server you need to pass both a valid server key and certificate

const httpsServer = new Server(80, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, {
    key: fs.readFileSync(path.join(path.resolve(__dirname), 'server.key')),
    cert: fs.readFileSync(path.join(path.resolve(__dirname), 'server.cert')),
    IncomingMessage: CustomIncommingMessage,
    ServerResponse: CustomServerResponse
}, 'server.test', () => {console.log('listening')}).start();

You can change any of those parameters before starting the server by accessing its public property.

const httpsServer = new Server(80, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, {
    key: fs.readFileSync(path.join(path.resolve(__dirname), 'server.key')),
    cert: fs.readFileSync(path.join(path.resolve(__dirname), 'server.cert')),
    IncomingMessage: CustomIncommingMessage,
    ServerResponse: CustomServerResponse
}, 'server.test', () => {console.log('listening')});

httpsServer.port = 443;
httpsServer.requestListener = (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World From Https Server\n');
};

// This will create an https server with port 443 and the requests will end with "Hello World From Https Server".
httpsServer.start();

You can check what you can pass to options at http.ServerOptions and tls.TlsOptions.

Extending IncomingMessage and ServerResponse

By default Server will be using http.IncommingMessage for Request and http.ServerResponse for Response. But you can change this behaviour by setting an extended request and response classes.

They will be used as the injected arguments to the requestListener.

class CustomIncommingMessage extends http.IncomingMessage {};
class CustomServerResponse extends http.ServerResponse {};

const httpServer = new Server(80, (req, res) => {
    // req will be an instance of CustomIncommingMessage, and res an instance of CustomServerResponse
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, {
    IncomingMessage: CustomIncommingMessage,
    ServerResponse: CustomServerResponse
}, 'server.test').start();

Servers

If you want to load balance servers or simple want to have two different servers running, you should use the Servers class.

import Server from '@alvitrjs/server';
import Servers from '@alvitrjs/server/Servers';

const httpServer = new Server(80, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, undefined , 'localtest.test');

const httpServer2 = new Server(81, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, undefined , 'localtest.test');

const servers = new Servers({
    httpServer,
    httpServer2
}).start();

Adding new Servers

You can add your servers to be created by passing an object with name and Server to the constructor.

const servers = new Servers({
    httpServer,
    httpServer2
}).start();

You can also call addServer to add a new server to be started.

const servers = new Servers();
servers.addServer('http1', httpServer);
servers.addServer('http2', httpServer2);

All servers need to be named

Setting Prefix and Suffix

You can add a prefix or a suffix to all the servers hosts, by passing an options to the constructor. The prefix will be added to the start of the host of every server and a dot after. The suffix will be added to the end of the host of every server with a slash before.

const servers = new Servers({
    httpServer,
    httpServer2
}, {
    prefix: 'en',
    suffix: 'api'
}).start();

every server host will be: en.${host}/api in this case host will be: en.localtest.test/api

You can change options before starting the servers by accessing its public property.

const servers = new Servers({
    httpServer,
    httpServer2
}, {
    prefix: 'en',
    suffix: 'api'
});

servers.options = {
    prefix: 'en2',
    suffix: 'api2'
};

// host will be: en2.localtest.test/api2
servers.start();

Running Servers

After starting multiple servers, the result of start will be a RunningServers instance.

import Server from '@alvitrjs/server';
import Servers from '@alvitrjs/server/Servers';

const httpServer = new Server(80, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, undefined , 'localtest.test');

const httpServer2 = new Server(81, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, undefined , 'localtest.test');

const servers = new Servers({
    httpServer,
    httpServer2
}).start();

Getting an Instance

You can get your server instance by using its name, it will be an http.Server or https.Server instance.

Check NodeJS documentation about http.Server and https.Server

const httpServer = servers.getInstance('httpServer');

httpServer.on('connection', () => {
    console.log('new connection');
})

Closing All Servers

If you need to stop all server you can call closeAll. You can also pass a callback to it, if you need to know when all connections are closed.

// It will start to close all conections, and servers.
servers.closeAll();

Cluster

By default Server and Servers are a single threaded, this isn't the best when your cpu can handle 8 cores. So you can create a cluster to fully use your machine.

Cluster accepts both Server and Servers.

import path from 'path';
import fs from 'fs';

import Server from '@alvitrjs/server';
import Servers from '@alvitrjs/server/Servers';
import Cluster from '@alvitrjs/server/Cluster';

const httpServer = new Server(80, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, undefined , 'localtest.test');

const httpsServer = new Server(443, (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}, {
    key: fs.readFileSync(path.join(path.resolve(__dirname), 'server.key')),
    cert: fs.readFileSync(path.join(path.resolve(__dirname), 'server.cert')),
} , 'localtest.test');

const servers = new Servers();
servers.addServer('httpServer', httpServer);
servers.addServer('httpsServer', httpsServer);

new Cluster(servers).start();

Number of Cores

By default cluster will use all machine cores, but you can change by passing an object as a second argument, with numCores with the number of cores you need.

new Cluster(servers, {
    numCores: 8
});

Restart Fork on Exit

By default when a fork stops, it stops, but you can make it create a new fork when one dies, by passing an object as a second argument with restartOnExit to true.

new Cluster(servers, {
    numCores: 8,
    restartOnExit: true
});

You can change both options before starting the cluster by accessing its public property.

How Many Cores

If you want to know how many cores cluster will be using as default or the max your machine can run, you can call Cluster static method howManyCores.

const maxCores = Cluster.howManyCores();

How to Contribute

We at AlvitrJS would LOVE for you to contribute for our projects, we think that the more the merrier.

Please read our contribution guide lines for details on our code of conduct, and the process for submitting pull requests and issues to us.

In development

These are what I'm currently working on, and possible new features.

  • Error Handling
  • Events
  • Socket.io Servers
  • Realtime Events
  • Running Servers Events
  • Docker Integration for Load Balance
  • PM2 for Clustering
  • Performance
  • Security

Authors

You should also check the list of all the nice contributors who participated in this project.

Versions

Versions

1.0.3

6 years ago

1.0.2

6 years ago

1.0.1

6 years ago

1.0.0

6 years ago

0.0.1

6 years ago