diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d14563b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +demo/www/jam/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..64d2369 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2012 ajax.org B.V + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..9e016da --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +architect-smith-transport +========================= + +[Smith](https://github.com/c9/smith)-based transport layer (via [engine.io](https://github.com/LearnBoost/engine.io)) +for [architect](https://github.com/c9/architect). + +Features: + + * Architect server plugin + * `requirejs` compatible browser client module + * Architect browser plugin (**COMING SOON**) + * WebSockets by default with long-poll fallback + * Automatic reconnect + * `socket.io` compatible API + * All major browsers supported (**TO BE VERIFIED**) + +Development +=========== + + npm install + cd demo + npm install + node server + open http://localhost:8080/ diff --git a/demo/package.json b/demo/package.json new file mode 100644 index 0000000..e18ec75 --- /dev/null +++ b/demo/package.json @@ -0,0 +1,20 @@ +{ + "name": "architect-smith-transport-demo", + "version": "0.0.1", + "main": "server-plugin.js", + "private": true, + "plugin": { + "provides": [], + "consumes": [ + "smith.transport.server", + "connect" + ] + }, + "dependencies": { + "architect": "0.1.x", + "connect-architect": "0.0.x" + }, + "scripts": { + "postinstall": "cd www && jam install smith events msgpack-js" + } +} \ No newline at end of file diff --git a/demo/server.js b/demo/server.js new file mode 100644 index 0000000..9fb1456 --- /dev/null +++ b/demo/server.js @@ -0,0 +1,50 @@ +#!/usr/bin/env node + +const PATH = require("path"); +const ARCHITECT = require("architect"); + +var port = process.env.PORT || 8080; + +var plugins = [ + { + packagePath: "connect-architect/connect", + host: "localhost", + port: port + }, + { + packagePath: "connect-architect/connect.session", + key: "connect.architect." + port, + secret: "1234" + }, + { + packagePath: "connect-architect/connect.session.memory" + }, + { + packagePath: "architect/plugins/architect.log" + }, + { + packagePath: "./../server-plugin", + prefix: "/transport/server" + }, + { + provides: [], + consumes: [ + "smith.transport.server", + "connect" + ], + setup: function(options, imports, register) { + + imports.connect.useStart(imports.connect.getModule().static(PATH.join(__dirname, "www"))); + + register(null, {}); + } + } +]; + +ARCHITECT.createApp(ARCHITECT.resolveConfig(plugins, __dirname), function (err, app) { + if (err) { + console.error("While starting!"); + throw err; + } + console.log("Started!"); +}); diff --git a/demo/www/app.js b/demo/www/app.js new file mode 100644 index 0000000..b00fadd --- /dev/null +++ b/demo/www/app.js @@ -0,0 +1,25 @@ + +require(["transport/client"], function (TRANSPORT_CLIENT) { + + console.log("Connecting"); + + TRANSPORT_CLIENT.connect({ + host: "localhost", + port: 8080, + prefix: "/transport/server" + }, function(err, transport) { + + console.log("Connected"); + + transport.on("channel1", function(data) { + console.log("Channel 1 message", data); + transport.emit("channel1", data); + }); + transport.on("channel2", function(data) { + console.log("Channel 2 message", data); + transport.emit("channel2", data); + }); + + }); + +}); diff --git a/demo/www/index.html b/demo/www/index.html new file mode 100644 index 0000000..5e3d64d --- /dev/null +++ b/demo/www/index.html @@ -0,0 +1,20 @@ + + + + Smith Transport Demo + + +

Smith Transport Demo

+ + + +

Check your console for messages.

+ + \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..3e1aed8 --- /dev/null +++ b/package.json @@ -0,0 +1,9 @@ +{ + "name": "architect-smith-transport", + "version": "0.0.1", + "dependencies": { + "smith": "~0.1.7", + "engine.io": "~0.1.2", + "engine.io-client": "~0.2.0" + } +} \ No newline at end of file diff --git a/server-plugin/package.json b/server-plugin/package.json new file mode 100644 index 0000000..540e8cd --- /dev/null +++ b/server-plugin/package.json @@ -0,0 +1,14 @@ +{ + "name": "architect-smith-transport-server-plugin", + "version": "0.0.1", + "main": "plugin.js", + "private": true, + "plugin": { + "provides": ["smith.transport.server"], + "consumes": [ + "log", + "http", + "connect" + ] + } +} \ No newline at end of file diff --git a/server-plugin/plugin.js b/server-plugin/plugin.js new file mode 100644 index 0000000..4693bd9 --- /dev/null +++ b/server-plugin/plugin.js @@ -0,0 +1,61 @@ + +const PATH = require("path"); +const FS = require("fs"); +const SMITH = require("smith"); +const ENGINE_IO = require("engine.io"); + + +module.exports = function startup(options, imports, register) { + + var channels = options.channels || {}; + var sources = { + "client": FS.readFileSync(PATH.join(__dirname, "www", "client.js")), + "engine.io": FS.readFileSync(require.resolve("engine.io-client/dist/engine.io.js")) + }; + + var prefix = (options.prefix || "/"); + + imports.connect.useSession(imports.connect.getModule().router(function(app) { + + // Serve the transport client. + app.get(prefix + "/client.js", function(req, res) { + res.writeHead(200, { + "Content-Type": "application/javascript" + }); + res.end(sources["client"]); + }); + + // Serve transport dependencies. + app.get(prefix + "/engine.io.js", function(req, res) { + res.writeHead(200, { + "Content-Type": "application/javascript" + }); + res.end(sources["engine.io"]); + }); + })); + + + var engine = ENGINE_IO.attach(imports.http.getServer(), { + path: prefix + }); + engine.on("connection", function (socket) { + + var transport = new SMITH.EngineIoTransport(socket); + + transport.send({hello:"World"}); + + transport.on("legacy", function (message) { + console.log("legacy", message); + }); + + transport.on("message", function (message) { + console.log("message", message); + }) + + }); + + + register(null, { + "smith.transport.server": {} + }); +}; diff --git a/server-plugin/www/client.js b/server-plugin/www/client.js new file mode 100644 index 0000000..482f5c0 --- /dev/null +++ b/server-plugin/www/client.js @@ -0,0 +1,60 @@ + +define(function(require, exports, module) { + + var ENGINE_IO = require("./engine.io"); + var SMITH = require("smith"); + + + var Transport = function(options, connectedCallback) { + this.options = options; + this.options.path = this.options.prefix; + delete this.options.prefix; + this.connect(connectedCallback); + } + Transport.prototype.connect = function(callback) { + var _self = this; + + // NOTE: `eio` comes from `require("./engine.io");`. + _self.socket = new eio.Socket(_self.options); + _self.socket.on("open", function () { + + var transport = new SMITH.EngineIoTransport(_self.socket); + + transport.on("message", function (message) { + console.log("message", message); + }); + + transport.on("legacy", function (message) { + console.log("legacy", message); + + transport.send([message]); + }); + + transport.on("disconnect", function (reason) { + + console.log("disconnect", reason); + console.log("TODO: Reconnect!"); + + }); + }); + } + Transport.prototype.emit = function(channel, message) { + + console.log("Sending", message, "to channel", channel); + + } + Transport.prototype.on = function(channel, handler) { + + console.log("Registering handler", handler, "for channel", channel); + + } + + var connections = {}; + exports.connect = function(options, callback) { + if (connections[options.prefix]) { + return callback(null, connections[options.prefix]); + } + connections[options.prefix] = new Transport(options, callback); + } + +});