Commit c8eeb7ca authored by Alex Hultman's avatar Alex Hultman

Move nodejs addon to its own repository (bindings repo)

parent 1b86feac
......@@ -6,7 +6,7 @@
* Autobahn tests [all pass](http://htmlpreview.github.io/?https://github.com/uWebSockets/uWebSockets/blob/master/misc/autobahn/index.html).
* One million WebSockets require ~111mb of user space memory (104 bytes per WebSocket).
* By far one of the fastest in both HTTP and WebSocket throughput (see table below).
* Linux, OS X, Windows & [Node.js](nodejs) support.
* Linux, OS X, Windows & [Node.js](http://github.com/uWebSockets/bindings) support.
* Runs with raw epoll, libuv or ASIO (C++17-ready).
* Valgrind & AddressSanitizer clean.
* Permessage-deflate, SSL/TLS support & integrates with foreign HTTP(S) servers.
......
CPP_SHARED := -DUSE_LIBUV -std=c++11 -O3 -I ../src -shared -fPIC ../src/Extensions.cpp ../src/Group.cpp ../src/WebSocketImpl.cpp ../src/Networking.cpp ../src/Hub.cpp ../src/Node.cpp ../src/WebSocket.cpp ../src/HTTPSocket.cpp ../src/Socket.cpp ../src/Epoll.cpp src/addon.cpp
CPP_OSX := -stdlib=libc++ -mmacosx-version-min=10.7 -undefined dynamic_lookup
default:
make targets
NODE=targets/node-v4.4.3 ABI=46 make `(uname -s)`
NODE=targets/node-v5.11.0 ABI=47 make `(uname -s)`
NODE=targets/node-v6.0.0 ABI=48 make `(uname -s)`
NODE=targets/node-v7.1.0 ABI=51 make `(uname -s)`
cp ../README.md dist/README.md
cp ../LICENSE dist/LICENSE
cp -r ../src dist/
cp src/addon.cpp dist/src/addon.cpp
cp src/addon.h dist/src/addon.h
cp src/http.h dist/src/http.h
cp src/uws.js dist/uws.js
for f in dist/*.node; do chmod +x $$f; done
targets:
mkdir targets
curl https://nodejs.org/dist/v4.4.3/node-v4.4.3-headers.tar.gz | tar xz -C targets
curl https://nodejs.org/dist/v5.11.0/node-v5.11.0-headers.tar.gz | tar xz -C targets
curl https://nodejs.org/dist/v6.0.0/node-v6.0.0-headers.tar.gz | tar xz -C targets
curl https://nodejs.org/dist/v7.1.0/node-v7.1.0-headers.tar.gz | tar xz -C targets
Linux:
g++ $(CPP_SHARED) -static-libstdc++ -static-libgcc -I $$NODE/include/node -s -o dist/uws_linux_$$ABI.node
Darwin:
g++ $(CPP_SHARED) $(CPP_OSX) -I $$NODE/include/node -o dist/uws_darwin_$$ABI.node
.PHONY: clean
clean:
rm -f dist/README.md
rm -f dist/LICENSE
rm -f dist/uws_*.node
rm -f dist/uws.js
rm -rf dist/src
rm -rf targets
## Usage
`uws` tries to mimic `ws` as closely as possible without sacrificing too much performance. In most cases you simply swap `require('ws')` with `require('uws')`:
```javascript
var WebSocketServer = require('uws').Server;
var wss = new WebSocketServer({ port: 3000 });
function onMessage(message) {
console.log('received: ' + message);
}
wss.on('connection', function(ws) {
ws.on('message', onMessage);
ws.send('something');
});
```
##### Deviations from ws
There are some important incompatibilities with `ws` though, we aim to be ~90% compatible but will never implement behavior that is deemed too inefficient:
* Binary data is passed zero-copy as an `ArrayBuffer`. This means you need to copy it to keep it past the callback. It also means you need to convert it with `Buffer.from(message)` if you expect a `Node.js Buffer`.
* `webSocket._socket` is not a `net.Socket`, it is just a getter function with very basic functionalities.
* `webSocket._socket.remote...` might fail, you need to cache it at connection.
* `webSocket` acts like an `EventEmitter` with one listener per event maximum.
* `webSocket.upgradeReq` is only valid during execution of the connection handler. If you want to keep properties of the upgradeReq for the entire lifetime of the webSocket you better attach that specific property to the webSocket at connection.
## Installation
[![](https://nodei.co/npm/uws.png)](https://www.npmjs.com/package/uws)
At installation `uws` will try to recompile itself using the system's C++11 compiler (GCC 4.8+, Clang 3.3, VC++ 2015+).
If this fails it will silently fall back to using the precompiled binaries.
NPM installation will never fail but `require('uws')` will throw if it cannot properly load the binary module.
{
'targets': [
{
'target_name': 'uws',
'sources': [
'src/Extensions.cpp',
'src/Group.cpp',
'src/WebSocketImpl.cpp',
'src/Networking.cpp',
'src/Hub.cpp',
'src/Node.cpp',
'src/WebSocket.cpp',
'src/HTTPSocket.cpp',
'src/Socket.cpp',
'src/addon.cpp'
],
'conditions': [
['OS=="linux"', {
'cflags_cc': [ '-std=c++11', '-DUSE_LIBUV' ],
'cflags_cc!': [ '-fno-exceptions', '-std=gnu++0x', '-fno-rtti' ],
'cflags!': [ '-fno-omit-frame-pointer' ],
'ldflags!': [ '-rdynamic' ],
'ldflags': [ '-s' ]
}],
['OS=="mac"', {
'xcode_settings': {
'MACOSX_DEPLOYMENT_TARGET': '10.7',
'CLANG_CXX_LANGUAGE_STANDARD': 'c++11',
'CLANG_CXX_LIBRARY': 'libc++',
'GCC_GENERATE_DEBUGGING_SYMBOLS': 'NO',
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
'GCC_THREADSAFE_STATICS': 'YES',
'GCC_OPTIMIZATION_LEVEL': '3',
'GCC_ENABLE_CPP_RTTI': 'YES',
'OTHER_CFLAGS!': [ '-fno-strict-aliasing' ],
'OTHER_CPLUSPLUSFLAGS': [ '-DUSE_LIBUV' ]
}
}],
['OS=="win"', {
'cflags_cc': [ '/DUSE_LIBUV' ],
'cflags_cc!': []
}]
]
},
{
'target_name': 'action_after_build',
'type': 'none',
'dependencies': [ 'uws' ],
'conditions': [
['OS!="win"', {
'actions': [
{
'action_name': 'move_lib',
'inputs': [
'<@(PRODUCT_DIR)/uws.node'
],
'outputs': [
'uws'
],
'action': ['cp', '<@(PRODUCT_DIR)/uws.node', 'uws_<!@(node -p process.platform)_<!@(node -p process.versions.modules).node']
}
]}
],
['OS=="win"', {
'actions': [
{
'action_name': 'move_lib',
'inputs': [
'<@(PRODUCT_DIR)/uws.node'
],
'outputs': [
'uws'
],
'action': ['copy', '<@(PRODUCT_DIR)/uws.node', 'uws_<!@(node -p process.platform)_<!@(node -p process.versions.modules).node']
}
]}
]
]
}
]
}
{
"name": "uws",
"version": "0.14.0",
"scripts": {
"install": "node-gyp rebuild > build_log.txt 2>&1 || exit 0"
},
"main": "uws.js",
"description": "Tiny WebSockets",
"engines": {
"node": ">=4"
},
"keywords": [
"tiny",
"websockets"
],
"homepage": "https://github.com/uWebSockets/uWebSockets",
"license": "Zlib",
"author": "Alex Hultman <alexhultman@gmail.com> (https://github.com/alexhultman)",
"repository": {
"type": "git",
"url": "https://github.com/uWebSockets/uWebSockets.git"
}
}
var WebSocket = require('./dist/uws');
var ws = new WebSocket('ws://echo.websocket.org');
ws.on('open', function open() {
console.log('Connected!');
ws.send('This will be sent!');
});
ws.on('error', function error() {
console.log('Error connecting!');
});
ws.on('message', function(data, flags) {
console.log('Message: ' + data);
});
ws.on('close', function(code, message) {
console.log('Disconnection: ' + code + ', ' + message);
});
'use strict';
const WebSocketServer = require('./dist/uws').Server;
const wss = new WebSocketServer({ port: 3000 });
function onMessage(message) {
this.send(message);
}
wss.on('connection', function(ws) {
// warning: never attach anonymous functions to the socket!
// that will majorly harm scalability since the scope of this
// context will be taken hostage and never released causing major
// memory usage increases compared to having the function created
// outside of this context (1.2 GB vs 781 MB for 1 million connections)
ws.on('message', onMessage);
});
wss.on('error', function(error) {
console.log('Cannot start server');
});
'use strict';
const uws = require('./dist/uws');
// the page that will connect back over EventSource
const document = '<script>var es = new EventSource(\'/eventSource\'); es.onmessage = function(message) {document.write(\'<p><b>Server sent event:</b> \' + message.data + \'</p>\');};</script>';
const server = uws.http.createServer((req, res) => {
if (req.url === '/') {
res.end(document);
} else if (req.url === '/eventSource') {
// write the event-stream HTTP head so that we can send chunks back later
res.writeHead(200, {'Content-Type': 'text/event-stream'});
// start a timer that will send back events over this HTTP socket
var interval = setInterval(() => {
// important to not end the socket, but write instead!
res.write('data: Some message from server here!\n\n');
}, 1000);
// if the client disconnects we stop the timer
res.on('close', () => {
clearInterval(interval);
});
} else {
// todo: terminate
console.log('Unsupported url: ' + req.url);
res.end('Nope, nope!');
}
});
server.listen(3000);
'use strict';
const uws = require('./dist/uws');
const document = Buffer.from('Hello world!');
const server = uws.http.createServer((req, res) => {
// handle some POST data
if (req.method === 'POST') {
var postString = '';
req.on('data', (arrayBuffer) => {
postString += Buffer.from(arrayBuffer).toString();
}).on('end', () => {
res.end('You posted me this: ' + postString);
});
// handle some GET url
} else if (req.url === '/') {
res.end(document);
} else {
res.end('Unknown request by: ' + req.headers['user-agent']);
}
});
const wss = new uws.Server({server: server});
wss.on('connection', (ws) => {
ws.send('Welcome to the 10s!');
});
server.listen(3000);
'use strict';
const uws = require('./dist/uws');
const document = Buffer.from('Hello world!');
const server = uws.http.createServer((req, res) => {
// handle some POST data
if (req.method === 'POST') {
var body = [];
req.on('data', (chunk) => {
body.push(Buffer.from(chunk));
}).on('end', () => {
res.end('You posted me this: ' + Buffer.concat(body).toString());
});
// handle some GET url
} else if (req.url === '/') {
res.end(document);
} else {
res.end('Unknown request by: ' + req.headers['user-agent']);
}
});
server.listen(3000);
'use strict';
const uws = require('./dist/uws');
const document = Buffer.from('Hello world!');
const server = uws.http.createServer((req, res) => {
res.end(document);
});
server.listen(3000);
var koa = require('koa');
var app = koa();
var uhttp = require('./dist/uws').http;
app.use(function *() {
this.body = 'Hello World';
});
if (process.env.UWS_HTTP) {
uhttp.createServer(app.callback()).listen(3000);
} else {
app.listen(3000);
}
// example showing usage with different behavior on a path basis
const http = require('http');
const WebSocketServer = require('./dist/uws').Server;
const httpServer = http.createServer((request, response) => {
response.end();
});
// echo server on path /echo, echoes the verbose message
const wssEcho = new WebSocketServer({ path: 'echo', server: httpServer });
wssEcho.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
ws.send(message, { binary: Buffer.isBuffer(message) });
});
});
// scream echo server on path /scream, echoes the uppercase message
const wssScream = new WebSocketServer({ path: 'scream', server: httpServer });
wssScream.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
ws.send(message.toUpperCase(), { binary: Buffer.isBuffer(message) });
});
});
httpServer.listen(3000);
const https = require('https');
const fs = require('fs');
const wsServer = require('./dist/uws').Server;
const options = {
key: fs.readFileSync('/home/alexhultman/µWebSockets.key.pem'),
cert: fs.readFileSync('/home/alexhultman/µWebSockets.pem')
};
const httpsServer = https.createServer(options, (req, res) => {
req.socket.write('Hello there');
req.socket.end();
});
const wss = new wsServer({ server: httpsServer, path: '/' });
wss.on('connection', (ws) => {
ws.on('message', (message) => {
ws.send(message, { binary: Buffer.isBuffer(message) });
});
});
httpsServer.listen(3000);
var WebSocket = require('./dist/uws');
var ws = new WebSocket('ws://echo.websocket.org');
ws.on('open', function open() {
console.log('Connected!');
ws.send('This will be sent!');
});
ws.on('error', function error() {
console.log('Connection error');
});
ws.on('message', function(data, flags) {
console.log('Message: ' + data);
});
ws.on('close', function(code, message) {
console.log('Disconnection: ' + code + ', ' + message);
});
call "%VS140COMNTOOLS%..\..\vc\vcvarsall.bat" amd64
if not exist targets (
mkdir targets
curl https://nodejs.org/dist/v6.4.0/node-v6.4.0-headers.tar.gz | tar xz -C targets
curl https://nodejs.org/dist/v6.4.0/win-x64/node.lib > targets/node-v6.4.0/node.lib
curl https://nodejs.org/dist/v7.1.0/node-v7.1.0-headers.tar.gz | tar xz -C targets
curl https://nodejs.org/dist/v7.1.0/win-x64/node.lib > targets/node-v7.1.0/node.lib
)
cp ../README.md dist/README.md
cp ../LICENSE dist/LICENSE
cp -r ../src dist/
cp src/addon.cpp dist/src/addon.cpp
cp src/addon.h dist/src/addon.h
cp src/http.h dist/src/http.h
cp src/uws.js dist/uws.js
cl /I targets/node-v6.4.0/include/node /EHsc /Ox /LD /Fedist/uws_win32_48.node dist/src/*.cpp targets/node-v6.4.0/node.lib
cl /I targets/node-v7.1.0/include/node /EHsc /Ox /LD /Fedist/uws_win32_51.node dist/src/*.cpp targets/node-v7.1.0/node.lib
rm *.obj
rm dist/*.exp
rm dist/*.lib
#include "../src/uWS.h"
#include "addon.h"
#include "http.h"
void Main(Local<Object> exports) {
Isolate *isolate = exports->GetIsolate();
exports->Set(String::NewFromUtf8(isolate, "server"), Namespace<uWS::SERVER>(isolate).object);
exports->Set(String::NewFromUtf8(isolate, "client"), Namespace<uWS::CLIENT>(isolate).object);
exports->Set(String::NewFromUtf8(isolate, "httpServer"), HttpServer::getHttpServer(isolate));
NODE_SET_METHOD(exports, "setUserData", setUserData<uWS::SERVER>);
NODE_SET_METHOD(exports, "getUserData", getUserData<uWS::SERVER>);
NODE_SET_METHOD(exports, "clearUserData", clearUserData<uWS::SERVER>);
NODE_SET_METHOD(exports, "getAddress", getAddress<uWS::SERVER>);
NODE_SET_METHOD(exports, "transfer", transfer);
NODE_SET_METHOD(exports, "upgrade", upgrade);
NODE_SET_METHOD(exports, "connect", connect);
NODE_SET_METHOD(exports, "setNoop", setNoop);
registerCheck(isolate);
}
NODE_MODULE(uws, Main)
This diff is collapsed.
#include "uWS.h"
#include "addon.h"
#include "../env.h"
#include "../env-inl.h"
namespace node {
void Main(Local<Object> exports, Local<Value> unused, Local<Context> context) {
Environment* env = Environment::GetCurrent(context);
Isolate *isolate = exports->GetIsolate();
exports->Set(String::NewFromUtf8(isolate, "server"), Namespace<uWS::SERVER>(isolate).object);
exports->Set(String::NewFromUtf8(isolate, "client"), Namespace<uWS::CLIENT>(isolate).object);
env->SetMethod(exports, "setUserData", setUserData<uWS::SERVER>);
env->SetMethod(exports, "getUserData", getUserData<uWS::SERVER>);
env->SetMethod(exports, "clearUserData", clearUserData<uWS::SERVER>);
env->SetMethod(exports, "getAddress", getAddress<uWS::SERVER>);
env->SetMethod(exports, "transfer", transfer);
env->SetMethod(exports, "upgrade", upgrade);
env->SetMethod(exports, "connect", connect);
env->SetMethod(exports, "setNoop", setNoop);
registerCheck(isolate);
}
}
NODE_MODULE_CONTEXT_AWARE_BUILTIN(uws_builtin, node::Main)
This diff is collapsed.
This diff is collapsed.
const WebSocketServer = require('../dist/uws').Server;
const non_ssl = new WebSocketServer({ port: 3000 });
const fs = require('fs');
const https = require('https');
var non_ssl_disconnections = 0;
non_ssl.on('connection', function(ws) {
ws.on('message', function(message) {
ws.send(message);
});
ws.on('close', function() {
if (++non_ssl_disconnections == 519) {
non_ssl.close();
}
});
});
const options = {
key: fs.readFileSync('../../misc/ssl/key.pem'),
cert: fs.readFileSync('../../misc/ssl/cert.pem'),
passphrase: '1234'
};
const httpsServer = https.createServer(options, (req, res) => {
req.socket.end();
});
const ssl = new WebSocketServer({ server: httpsServer });
var ssl_disconnections = 0;
ssl.on('connection', function(ws) {
ws.on('message', function(message) {
ws.send(message);
});
ws.on('close', function() {
if (++ssl_disconnections == 519) {
ssl.close();
}
});
});
httpsServer.listen(3001);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment