Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

razorframe

Package Overview
Dependencies
Maintainers
2
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

razorframe - npm Package Compare versions

Comparing version 1.0.14 to 1.0.15

rz-logo.png

188

lib/Razorframe.js

@@ -0,4 +1,4 @@

const LinkedList = require('./LinkedList');
const { EventEmitter } = require('events');
const LinkedList = require('./LinkedList');
const express = require('express');
const cluster = require('cluster');

@@ -12,11 +12,11 @@ var os = require('os');

const app = express();
/**Razorframe constructor
*
* MSG parameters
* @param {string} MSG.contents => the message value
* @param {string} MSG.eventOut => the outbound event name
* @param {string} MSG.channel => the channel name
/** @constructs Razorframe
* @method {function} enqueue - adds event to storage
* @method {function} dequeue - removes event from storage (FIFO)
*
* MSG properties
* @property {string} MSG.contents - the message value
* @property {string} MSG.eventOut - the outbound event name
* @property {string} MSG.channel - the channel name
*/

@@ -30,8 +30,7 @@ class Razorframe {

enqueue(MSG) {
console.log('enqueue has run');
console.log(`Enqueue has run.`);
if (!MSG) console.error('Error: must pass in valid msg object!');
else if (!MSG.contents) console.error('Error: contents should not be null');
else if (!MSG.eventOut) console.error("Error: MSG object must contain valid outbound event name");
if (!MSG) console.error(`Error: must pass in valid MSG object!`);
else if (!MSG.contents) console.error(`Error: MSG.contents should not be null!`);
else if (!MSG.eventOut) console.error(`Error: MSG.eventOut must contain valid outbound event name!`);
else {

@@ -44,4 +43,4 @@ this.storage.push(MSG);

dequeue() {
console.log('dequeue has run.');
if (this.storage.length === 0) console.error('Error: message queue is currently empty!');
console.log(`Dequeue has run.`);
if (this.storage.length === 0) console.error(`Error: message queue is currently empty!`);
else {

@@ -59,52 +58,72 @@ let MSG = this.storage.pop();

init(http, config) {
/** @function init - Initializes socket connections and Node clusters
*
* @param {number} http - defined in server.js
* @param {object} rzConfig - defined in server.js
* @param {object} dbConfig - defined in server.js
*/
init(http, rzConfig, dbConfig) {
io = require('socket.io')(http);
if (!listen(http, config.port)) {
/*
* Master code area
*/
io.adapter(redisAdapter(REDIS_URL));
// If Node clusters are enabled...
if (rzConfig.cluster) {
if (!listen(http, rzConfig.port)) {
/*
* Master code area
*/
io.adapter(redisAdapter(REDIS_URL));
// Error listeners for Redis adapter
redisAdapter(REDIS_URL).pubClient.on('error', (err) => {
console.error(`[Master] Issue connecting Redis adapter to Pub Client: ${err}`);
});
redisAdapter(REDIS_URL).subClient.on('error', (err) => {
console.error(`[Master] Issue connecting Redis adapter to Sub Client: ${err}`);
});
// Error listeners for Redis adapter
redisAdapter(REDIS_URL).pubClient.on('error', (err) => {
console.error(`[Master] Issue connecting Redis adapter to Pub Client: ${err}`);
});
redisAdapter(REDIS_URL).subClient.on('error', (err) => {
console.error(`[Master] Issue connecting Redis adapter to Sub Client: ${err}`);
});
http.once('listening', function () {
console.log('server started on 3000 port');
});
http.once('listening', function () {
console.log(`✌️ Server started on PORT 3000!`);
});
} else {
/*
* Worker code area
*/
io.adapter(redisAdapter(REDIS_URL));
handleSockets(dbConfig);
// Error listeners for Redis adapter
redisAdapter(REDIS_URL).pubClient.on('error', (err) => {
console.error(`[Worker ${process.pid}] Issue connecting Redis adapter to Pub Client: ${err}`);
});
redisAdapter(REDIS_URL).subClient.on('error', (err) => {
console.error(`[Worker ${process.pid}] Issue connecting Redis adapter to Sub Client: ${err}`);
});
}
// If Node clusters are disabled...
} else {
/*
* Worker code area
*/
io.adapter(redisAdapter(REDIS_URL));
handleSockets(config);
console.log(`👻 clusters are off!`);
// Error listeners for Redis adapter
redisAdapter(REDIS_URL).pubClient.on('error', (err) => {
console.error(`[Worker ${process.pid}] Issue connecting Redis adapter to Pub Client: ${err}`);
handleSockets(dbConfig);
process.on('uncaughtException', (err) => {
console.error(`(Process Error) There was an error with event emitter communication: ${err}`);
});
redisAdapter(REDIS_URL).subClient.on('error', (err) => {
console.error(`[Worker ${process.pid}] Issue connecting Redis adapter to Sub Client: ${err}`);
});
http.listen(process.env.PORT || rzConfig.port, () => console.log(`✌️ on ${rzConfig.port}`));
}
},
/**
* Error function for failed DB query
*
* @param {object} MSG object,
* refer to Razorframe constructor for keys
* @param {number} user-definable, defaults to count=2
* @returns {boolean}, true if successful retry
/** @function onError - Handles failed DB query
*
* @param {object} - MSG object: refer to Razorframe constructor for properties
* @param {number} - user-definable, defaults to count = 2
* @returns {boolean} - true if successful retry
*/
onError(MSG, count = 2) {
if (MSG.error === count) {
console.log('inside error function with msg:', MSG.contents);
console.log(`inside error function with msg: ${MSG.contents}`);
io.to(MSG.id).emit('error', `There was an error writing "${MSG.contents}" to the database.`);

@@ -120,12 +139,11 @@ } else {

/**
* Sticky session function to bind clients to workers
const Master = require('./Master');
/** @function listen - Enables sticky sessions to bind clients to workers
*
* @param {variable} Express server
* @param {number} port number
* @param {variable} server - Express server
* @param {number} port - port number
* @returns {boolean}
*/
const Master = require('./Master');
const listen = (server, port) => {
function listen(server, port) {
if (cluster.isMaster) {

@@ -160,26 +178,29 @@ const workerCount = os.cpus().length || 1;

});
process.on('uncaughtException', (err) => {
console.error(`(Process: Uncaught Exception) There was an error with event emitter communication: ${err}`);
});
return true;
}
/**
* Worker logic for socket connections and event listeners
*
* @param {object} config
* user configurable object to pass in functions to rz
/** @function handleSockets - Worker logic for socket connections and event listeners
*
* @param {object} dbConfig - user configurable object to pass in functions to rz
*/
const handleSockets = (config) => {
const { write, show } = config;
function handleSockets(dbConfig) {
const { write, show } = dbConfig;
io.on('connection', (socket) => {
console.log('a user connected! 💃');
console.log(`a user connected! 💃`);
show(socket);
socket.on('disconnect', function () {
console.log(socket.id + ' disconnect (' + socket.client.conn.transport.constructor.name + ')');
console.log(`${socket.id} disconnect: ${socket.client.conn.transport.constructor.name}`);
});
// Client listeners----------------------
// Client listeners----------------------------------
socket.on('msgSent', (MSG, id) => {
console.log('message recieved!------------------');
console.log(`message recieved!`);
MSG.id = socket.id;

@@ -190,12 +211,13 @@ rz.razorframe.enqueue(MSG);

// Server-side listeners----------------------
// Server-side listeners-------------------------------
// Node error listener + reporter
rz.razorframe.notification.on('error', (err) => {
console.error('There was an error with event emitter communication: ' + err);
console.error(`There was an error with event emitter communication: ${err}`);
});
// Process error listener + reporter (move to after line 154???)
process.on('uncaughtException', (err) => {
console.error('(Process Error) There was an error with event emitter communication: ' + err);
});
// We moveed this area to around line 154. SO possibly take this out...
// Process error listener + reporter
// process.on('uncaughtException', (err) => {
// console.error('(Process Error) There was an error with event emitter communication: ' + err);
// });

@@ -222,3 +244,3 @@ rz.razorframe.notification.on('enq', (data) => {

default:
console.log('no action provided!');
console.log(`no action provided!`);
break;

@@ -232,3 +254,3 @@ }

} else if (!MSG.eventOut) {
console.log('No eventOut provided! No client emission executed.');
console.log(`No eventOut provided! No client emission executed.`);
} else {

@@ -246,7 +268,7 @@ io.emit(MSG.eventOut, MSG.contents);

/**
* Messaging queue module for razorframe.
* Razorframe: A back-end library for scalable, real-time web apps.
*
* @author - Travis Huff (https://github.com/travishuff)
* @author - Eddie Park (https://github.com/parkedwards)
* @author - Michael Sotkin ('Mr. Moustache')
* @author - Travis Huff (https://github.com/travishuff)
* @author - Eddie Park (https://github.com/parkedwards)
* @author - Michael Sotkin (https://github.com/msotkin)
*/
{
"name": "razorframe",
"version": "1.0.14",
"version": "1.0.15",
"description": "Empowering real-time databases in Node.js",

@@ -5,0 +5,0 @@ "main": "./lib/Razorframe.js",

@@ -1,16 +0,23 @@

# razorframe<sup>(beta)</sup> [![npm version](https://badge.fury.io/js/razorframe.svg)](https://badge.fury.io/js/razorframe)
#razorframe
**Version**
[![npm version](https://badge.fury.io/js/razorframe.svg)](https://badge.fury.io/js/razorframe)
####*Empowering scalable, real-time web apps in Node.js*
####*Empowering real-time databases in Node.js*
###Visit us at: [http://razorfra.me](http://www.razorfra.me)
<p align="center">
<img src="rz-logo.png" />
</p>
____________________________________________________________________
###Description
Razorframe is a Javascript library built on Node.js which enables developers to build a real-time client experience while maintaining traditional database implementations such as SQL.
##Description
Razorframe is a Javascript library built on Node.js which enables developers to build a real-time client experience while maintaining scalable, async back-end operations.
Socket.io powers real-time client updates on the front-end, while Node clusters and event emitters in conjunction with a custom messaging queue process highly concurrent and asynchronous operations on the back-end.
We use a messaging queue, called a razorframe, that intercepts incoming user interactions over a two-way socket channel. Those interactions are held in the queue only as long as the server needs before dequeuing. The dequeuing process then triggers an event that both updates the client UI and launches an asynchronous back-end process such as a database write.
We use a messaging queue, called razorframe, that intercepts incoming user interactions over a two-way socket channel. Those interactions are held in the queue only as long as the server needs before dequeuing. The dequeuing process then triggers an event that both updates the client UI and launches a back-end process such as a database write.
Our tests have shown this process keeps the client UI updating in sub 100ms "real-time" fashion at scale while maintaining accurate database writes.
###Installation
Using npm:
##Installation
**Using npm:**

@@ -21,64 +28,103 @@ ```

###Example
**server.js:**
##How to Use
###Server-side module:
1) Require razorframe.
2) Specify rzConfig object to set up server processes by declaring:
* `rzConfig.port`: port where your server is listening.
* `rzConfig.cluster`: true or false depending on whether you want to enable Node clusters.
(Even though our config automatically accounts for 1 process if not specified, you'll still get better performance if you turn off Node clusters if you know you won't be using more than one CPU.)
3) Specify dbConfig object to define your back-end callbacks.
* `dbConfig.write`: 'create' function for database.
* `dbConfig.show`: 'read' function for database.
* `dbConfig.update`: 'update' function for database.
* `dbConfig.delete`: 'delete' function for databse.
4) Initialize razorframe while passing in http (for your server) and the configurations.
```
const rz = require('razorframe');
/**
* config parameters - passes into rb any user-defined callbacks
* @param - {Object} http => instantiate an http server
* @param - {Function} write => a DB write callback (user-defined)
* @param - {Function} show => a DB pull callback (user-defined)
*/
const config = {
const rzConfig = {
port: process.env.PORT || 3000,
cluster: true
};
const dbConfig = {
write: addToDb,
show: showAll,
update: null,
delete: null,
};
/**
* Instantiate razorframe passing in Node's http object
* (to connect with your server) as well as the config object
* which contains all the user-defined callbacks
*/
rz(http, config);
rz.init(http, rzConfig, dbConfig);
```
**client.html:**
###Client-side module:
**HTML**
Import 2 libraries: socket.io and razorframe into your HTML.
Grab the client-side import file from our website [razorfra.me](http://www.razorfra.me).
```
<script src="/socket.io/socket.io.js"></script>
<script src="/razorframe.js"></script>
```
**client.js:**
**Javascript**
Contains 2 methods:
1) `rz.publish` - publishes a data payload to a particular event and specifies a back-end callback
Specify arguments:
* **contents:** message data
* **function name (as a string):** a back-end operation you want to perform as defined in dbConfig.
* **event name:** name the event you can then subscribe to.
```
const socket = io();
/**
* MSG parameters
* @param {string} MSG.contents => the message value
* @param {string} MSG.eventOut => the outbound event name
* @param {string} MSG.channel => the channel name
*/
textForm.addEventListener('submit', (e) => {
e.preventDefault();
e.preventDefault();
const contents = textInput.value;
rz.publish(contents, 'write', 'chatMsg')
textInput.value = '';
});
```
const contents = textInput.value;
const eventOut = 'msgSent';
const channel = 'message-channel';
socket.emit('msgSent', { contents, eventOut, channel });
textInput.value = '';
2) `rz.subscribe` - listens for an event coming from the server
Specify arguments:
* **event name:** the event you want to listen for.
* **callback function:** any function you want to call on the payload from the event.
```
rz.subscribe('dbOnLoad', (data) => {
data.reverse().forEach(item => {
node = document.createElement('LI');
textNode = document.createTextNode(JSON.parse(item));
node.appendChild(textNode);
chatMsg.appendChild(node);
});
});
```
###Platform
**Error Handling:**
Razorframe enables error handling on the back-end if your database fails to query.
Within the error callback on your database controller, use the method:
```
if (err) rz.onError(MSG, 2);
```
where 'MSG' is the task being sent to the database and the second argument, in this case '2', specifies the number of attempts to do the query. Razorframe will re-enqueue the task 'n' number of times with a default of 2 total attempts. If the event fails to query after all attempts, a message is sent to the user that enqueued the event that the event has failed to write and will be dropped.
##Demo App
Check out our demo app for more usage examples at: [RZ-Demo](https://github.com/team-emt/rz_demo)
##Platform
[Node.js](https://nodejs.org/)
###Dependencies
##Dependencies
[Socket.io](https://www.npmjs.com/package/socket.io)
###Authors
##Authors
[Travis Huff](huff.travis@gmail.com)

@@ -88,11 +134,11 @@ [Eddie Park](ed.sh.park@gmail.com)

###Support
##Support
Tested in Chrome 55 & Node 6/7.
GitHub Issues: <https://github.com/team-emt/razorframe/issues>
###Contributions
##Contributions
❤️ Contributions welcome!
Please see out GitHub repo at: <https://github.com/team-emt/razorframe>
###License
##License
[MIT](https://github.com/travishuff/razorframe/blob/master/LICENSE)
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc