Permalink
Browse files

[dist] First commmit.

  • Loading branch information...
0 parents commit 2748fa1b3a1539d5b63a942ea682f5f6e45d877b @Marak Marak committed Jul 18, 2012
@@ -0,0 +1,2 @@
+.DS_Store
+node_modules/
122 README.md
@@ -0,0 +1,122 @@
+
+# sockful
+
+[![Build Status](https://secure.travis-ci.org/flatiron/sockful.png)](http://travis-ci.org/flatiron/sockful)
+
+Creates [socket.io](http://socket.io) servers and event maps for [resourceful](http://github.com/flatiron/resourceful) resources. Can be used as a stand-alone module or as a [Flatiron](http://github.com/flatiron/) plugin.
+
+# Explanation
+
+The sockful project removes the process of writing boilerplate socket.io event mapping code for interacting with [resourceful](http://github.com/flatiron/resourceful) resources. sockful uses <a href="http://en.wikipedia.org/wiki/Reflection_(computer_programming)">reflection</a> to reflect a socket.io server interface which maps all the socket.io events needed to perform basic [CRUD](http://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations with [resourceful](http://github.com/flatiron/resourceful). sockful also has the ability to expose additional arbitrary <a href="#remote">remote resource methods</a> through socket.io
+
+Through the removal of this boilerplate code, sockful creates a robust, standardized, and re-usable socket.io interface for any [resourceful](http://github.com/flatiron/resourceful) resource.
+
+# Installation
+
+ npm install sockful
+
+# Usage
+
+## As a Flatiron Plugin
+
+To use sockful as a <a href="http://github.com/flatiron/flatiron">Flatiron</a> plugin you will have to:
+
+ - Define resource(s) in your Flatiron app
+ - Use the sockful plugin in your Flatiron app
+ - Set `sockful=true` on the resource to let Flatiron know to expose it
+
+Here is a code example of using sockful as a Flatiron plugin: <a href="https://github.com/flatiron/sockful/blob/master/examples/app.js">https://github.com/flatiron/sockful/blob/master/examples/app.js</a>
+
+## As a stand-alone server
+
+To use sockful as a stand-alone server you will have to:
+
+ - Define resource(s)
+ - Create a new server based on the resource(s) using `sockful.createServer`
+
+Here is a code example of using sockful as a stand-alone server: <a href="https://github.com/flatiron/sockful/blob/master/examples/server.js">https://github.com/flatiron/sockful/blob/master/examples/server.js</a>
+
+## Core Socket.io Mappings
+
+ By default, `sockful` will map all `Resourceful` methods in the following signature:
+
+```js
+server.on(resource, action, payload, callback);
+```
+
+Example:
+
+```js
+socket.emit('creature', 'create', { id: 'bob' } , function(err, bob) {
+ console.log('created: ', bob);
+};
+```
+
+ Socket Event Action
+
+ socket.emit('creature', 'create', data, callback) => Creature.create()
+ socket.emit('creature', 'get', data, callback) => Creature.get()
+ socket.emit('creature', 'all', data, callback) => Creature.all()
+ socket.emit('creature', 'update', data, callback) => Creature.update()
+ socket.emit('creature', 'destroy', data, callback) => Creature.destroy()
+
+
+ The socket server will delegate all incoming Creature events to the resource and respond back with the appropriate result.
+
+## Relational Resources
+
+To define relational data in sockful you will have to:
+
+ - Define the relationship in the resource itself using the resourceful `Resource.parent()` API
+ - Create a new server based on the resource(s)
+
+sockful will then properly reflect the relational properties of your resources into the socket server.
+
+Here is a simple code example of using sockful with `Albums` and `Songs`: <a href="https://github.com/flatiron/sockful/blob/master/examples/server.js">https://github.com/flatiron/sockful/blob/master/examples/server.js</a>
+
+
+
+<a name"remote"></a>
+## Exposing Arbitrary Resource Methods
+
+In many cases, you'll want to expose additional methods on a Resource through socket.io outside of the included CRUD operations: `create`, `all`, `get`, `update`, `destroy`.
+
+sockful has built in support for easily exposing arbitrary remote resource methods.
+
+Consider the example of a `Creature`. We've already defined all the sockful CRUD events, but a Creature also needs to eat!
+
+Simply create a new method on the `Creature` resource called `feed`.
+
+```js
+Creature.feed = function (_id, options, callback) {
+ callback(null, 'I have been fed');
+}
+```
+This `feed` method is consider private by default, in that it will not be exposed to the web unless it's set to a `remote` function. To set a resource method to remote, simply:
+
+```js
+Creature.feed.remote = true
+```
+
+It's easy as that! By setting the `feed` method to remote, the following events will exist in the `socket.io` server.
+
+ socket.emit('creature', 'feed', data, callback) => Creature.feed()
+
+
+## Resource Security
+
+There are several ways to provide security and authorization for accessing resource methods exposed with sockful. The recommended pattern for authorization is to use resourceful's ability for `before` and `after` hooks. In these hooks, you can add additional business logic to restrict access to the resource's methods.
+
+**TL;DR; For security and authorization, you should use resourceful's `before` and `after` hooks.**
+
+# Tests
+
+ npm test
+
+# TODO
+
+ - Full `resourceful` property type support ( numeric, boolean, array, object )
+ - Full `resourceful` nested property schema support
+ - Add ability to specify schemas for remote method argument payloads
+ - Improve Tests
+ - Add better error support via `errs` library
@@ -0,0 +1,33 @@
+/*
+ * app.js
+ *
+ * (C) 2012, Nodejitsu Inc.
+ *
+ */
+
+var flatiron = require('flatiron'),
+ fixtures = require('../test/fixtures'),
+ ecstatic = require('ecstatic'),
+ sockful = require('../lib/sockful'),
+ resourceful = require('resourceful');
+
+var app = module.exports = flatiron.app;
+app.resources = {};
+app.resources.Creature = fixtures.Creature;
+app.resources.Album = fixtures.Album;
+
+app.use(flatiron.plugins.http, {
+ headers: {
+ 'x-powered-by': 'flatiron ' + flatiron.version
+ },
+ before: [
+ ecstatic(__dirname + '/public')
+ ]
+});
+//app.use(sockful);
+app.start(8000);
+
+sockful.createServer([app.resources.Creature], { server: app.server });
+
+console.log(' > http server started on port 8000');
+console.log(' > visit: http://localhost:8000/ ');
@@ -0,0 +1,20 @@
+<html>
+ <head>
+ <script src="/socket.io/socket.io.js" type="text/javascript"></script>
+ <script>
+ var socket = io.connect('http://localhost');
+ var name = prompt('creature name?');
+ var type = prompt('creature type?');
+ socket.emit('creatures', 'create', { id: name, type: type }, function(err, result) {
+ if(err) {
+ alert('Error \n\n' + JSON.stringify(err, true, 2));
+ } else {
+ alert('Created creature! \n\n' + JSON.stringify(result, true, 2));
+ }
+ })
+ </script>
+ </head>
+ <body>
+ <h1>View Source to reveal</h1>
+ </body>
+</html>
@@ -0,0 +1,18 @@
+/*
+ * server.js: Simple http server with `sockful` server
+ *
+ * (C) 2012, Nodejitsu Inc.
+ *
+ */
+
+var http = require('http'),
+ fixtures = require('../test/fixtures'),
+ sockful = require('../lib/sockful'),
+ resourceful = require('resourceful');
+
+//
+// Create a new socket server based on defined resources
+//
+var server = sockful.createServer([fixtures.Creature, fixtures.Album]);
+
+console.log(' > socket server started on port 8000');
@@ -0,0 +1 @@
+// TODO: Add engine for https://github.com/substack/dnode
@@ -0,0 +1 @@
+// TODO: Add engine for https://github.com/nodejitsu/nssocket
@@ -0,0 +1,58 @@
+var engine = exports;
+
+engine.createServer = function (resources, options, callback) {
+ var io = require('socket.io').listen(options.server || 8000, function(){
+ callback(null, io);
+ });
+ io.sockets.on('connection', function (socket) {
+
+ //
+ // Extend CRUD methods
+ //
+ resources.forEach(function(resource) {
+ socket.on(resource.lowerResource + 's', function (action, payload, callback) {
+
+ if(typeof engine[action] === 'function') {
+ return engine[action](resource, payload, callback);
+ }
+
+ if(typeof resource[action] === 'function' && resource[action].remote) {
+ return resource[action](payload.id, payload, callback);
+ }
+
+ return callback(new Error(action + ' is not a valid action.'));
+
+ });
+ });
+
+
+ //
+ // Extend abritrary remote methods
+ //
+
+ socket.on('disconnect', function () {
+ console.log('got a disconnect');
+ });
+ });
+ return io;
+};
+
+engine.create = function (resource, payload, callback) {
+ resource.create(payload, callback);
+};
+
+engine.get = function (resource, payload, callback) {
+ resource.get(payload, callback);
+};
+
+engine.all = function (resource, payload, callback) {
+ resource.all(callback);
+};
+
+engine.update = function (resource, payload, callback) {
+ resource.update(payload.id, payload, callback);
+};
+
+engine.destroy = function (resource, payload, callback) {
+ resource.destroy(payload.id, callback);
+};
@@ -0,0 +1,51 @@
+/*
+ * sockful.js: creates socket.io event maps to resourceful
+ *
+ * (C) 2012, Nodejitsu Inc.
+ *
+ */
+
+var sockful = exports,
+ resourceful = require('resourceful'),
+ util = require('util'),
+ utile = require('utile'),
+ http = require('http');
+
+exports.engines = {
+ "socket.io": require('../lib/engines/socketio')
+};
+
+//
+// ### function createServer (resources)
+// #### @resources {resourceful.Resource} Resource(s) to use for the server.
+//
+// Responds with an `http.Server` instance with a `sockfulRouter` for the
+// specified `resources`.
+//
+exports.createServer = function (resources, options, callback) {
+ options = options || {};
+ options.engine = options.engine || 'socket.io';
+ if (!Array.isArray(resources)){
+ resources = [resources];
+ }
+ return sockful.engines[options.engine].createServer(resources, options, callback);
+};
+
+//
+// Name this `broadway` plugin.
+//
+exports.name = 'sockful';
+
+//
+// ### function init ()
+// Initializes the `sockful` plugin with the App.
+//
+exports.init = function (done) {
+ var app = this;
+
+ if (app.resources) {
+ //sockful.createServer(app.resources);
+ }
+
+ done();
+};
@@ -0,0 +1,28 @@
+{
+ "name": "sockful",
+ "description": "creates socket.io event maps for resourceful.",
+ "author": "Nodejitsu Inc. <info@nodejitsu.com>",
+ "maintainers": [
+ { "name": "Marak Squires", "email": "marak@nodejitsu.com" }
+ ],
+ "version": "0.3.0",
+ "main": "./lib/sockful",
+ "dependencies": {
+ "socket.io": "0.9.x",
+ "resourceful": "0.3.x",
+ "utile": "0.1.x"
+ },
+ "devDependencies": {
+ "vows": "0.6.x",
+ "socket.io-client": "0.9.x"
+ },
+ "bundleDependencies": ["resourceful"],
+ "optionalDependencies": {},
+ "engines": {
+ "node": "0.6.x || 0.8.x"
+ },
+ "scripts": {
+ "test": "vows --spec --isolate",
+ "start": "node examples/server.js"
+ }
+}
Oops, something went wrong.

0 comments on commit 2748fa1

Please sign in to comment.