pusher.io 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pusher.io.gemspec
4
+ gemspec
5
+
6
+ gem 'rake'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 yury
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # pusher.io gem
2
+
3
+ This is very basic implementation of pusherapp.com api subset on top of socket.io.
4
+
5
+ ## Setup
6
+
7
+ Add the gem to your Gemfile and run the bundle command to install it.
8
+
9
+ gem 'pusher.io'
10
+
11
+ Run the generator to create the initial files.
12
+
13
+ $ rails g pusher.io:install
14
+
15
+ Next, start up pusher.io.
16
+
17
+ $ node pusher.io.js
18
+
19
+ For production
20
+
21
+ $ NODE_ENV=production node pusher.io.js
22
+
23
+ Add the JavaScript file to your application.js file manifest.
24
+
25
+ // require pusher.io/client
26
+
27
+ ## Usage
28
+
29
+ Include pusher io tags in your html head:
30
+
31
+ <%= pusher_io_tags %>
32
+
33
+ ## Contributing
34
+
35
+ 1. Fork it
36
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
37
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
38
+ 4. Push to the branch (`git push origin my-new-feature`)
39
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,61 @@
1
+ pusher = {}
2
+
3
+ !function ($) {
4
+
5
+ "use strict";
6
+
7
+ var channels = {};
8
+
9
+ var Channel = function (name, socket_uri) {
10
+ this.socket = io.connect(socket_uri);
11
+ this.channelName = name;
12
+ this.subscribed = false;
13
+ }
14
+
15
+ Channel.prototype.subscribe = function() {
16
+ if (this.subscribed) {
17
+ return this;
18
+ }
19
+
20
+ this.socket.emit('subscribe', {channel: this.channelName});
21
+ this.subscribed = true;
22
+ return this;
23
+ }
24
+
25
+ Channel.prototype.unsubscribe = function () {
26
+ if (!this.subscribed) {
27
+ return this;
28
+ }
29
+
30
+ this.socket.emit('unsubscribe', {channel: this.channelName})
31
+ this.subscribed = false;
32
+ delete channels[this.channelName];
33
+ return this;
34
+ }
35
+
36
+ Channel.prototype.bind = function (event, callback) {
37
+ this.socket.on('pusher:' + event, callback);
38
+ }
39
+
40
+ Channel.prototype.unbind = function (event) {
41
+ this.socket.off('pusher:' + event);
42
+ }
43
+
44
+ pusher.channel = function (name) {
45
+ var channel = channels[name];
46
+ if (!channel) {
47
+ var socket_uri = $('meta[name="socket_uri"]').attr('content');
48
+ channel = channels[name] = new Channel(name, socket_uri);
49
+ }
50
+ return channel;
51
+ }
52
+
53
+ pusher.subscribe = function (name) {
54
+ return this.channel(name).subscribe();
55
+ }
56
+
57
+ pusher.unsubscribe = function (name) {
58
+ return this.channel(name).unsubscribe();
59
+ }
60
+
61
+ }(window.jQuery);
data/lib/capistrano.rb ADDED
@@ -0,0 +1,10 @@
1
+ # Capistrano task for npm install.
2
+ #
3
+ # Just add "require 'pusher.io/capistrano'" in your Capistrano deploy.rb, and
4
+ # Pusher will be activated after each new deployment.
5
+
6
+ Capistrano::Configuration.instance(:must_exist).load do
7
+ before "deploy:finalize_update", "pusher.io:install" do
8
+ run "npm install"
9
+ end
10
+ end
@@ -0,0 +1,23 @@
1
+ module Pusher::IO
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ def self.namespace
5
+ "pusher.io:install"
6
+ end
7
+
8
+ def self.source_root
9
+ File.dirname(__FILE__) + '/templates'
10
+ end
11
+
12
+ def copy_files
13
+ template 'pusher.io.yml', 'config/pusher.io.yml'
14
+ copy_file 'pusher.io.js', 'pusher.io.js'
15
+ copy_file 'package.json', 'package.json'
16
+ end
17
+
18
+ def npm_install
19
+ run "npm install"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "pusher.io",
3
+ "description": "Pusher server",
4
+ "version": "0.0.1",
5
+ "private": true,
6
+ "dependencies": {
7
+ "express": "3.x",
8
+ "socket.io": "0.9.x",
9
+ "js-yaml": "*"
10
+ }
11
+ }
@@ -0,0 +1,100 @@
1
+ require('js-yaml');
2
+
3
+ env = process.env.NODE_ENV || 'development'
4
+
5
+ var cfg = require('./config/pusher.io.yml')[env];
6
+
7
+ var crypto = require('crypto')
8
+ , hmac
9
+ , signature
10
+
11
+ var psignature = function(params) {
12
+ hmac = crypto.createHmac("sha1", cfg.secret);
13
+ hmac.update(params.join("\n"))
14
+ return hmac.digest("hex");
15
+ }
16
+
17
+ var fs = require('fs')
18
+ , express = require('express')
19
+ , app = express()
20
+ , server
21
+ , io
22
+
23
+ if (cfg['ssl_key'] && cfg['ssl_cert']) {
24
+
25
+ server = require('https').createServer({
26
+ key: fs.readFileSync(cfg['ssl_key']),
27
+ cert: fs.readFileSync(cfg['ssl_cert'])
28
+ }, app);
29
+
30
+ } else {
31
+ server = require('http').createServer(app);
32
+ }
33
+
34
+ io = require('socket.io').listen(server);
35
+
36
+ app.use(express.bodyParser());
37
+
38
+ app.post('/events', function(req, res) {
39
+ b = req.body
40
+ var params = [
41
+ 'POST',
42
+ 'events',
43
+ b.app_id,
44
+ b.channel,
45
+ b.event,
46
+ b.timestamp,
47
+ cfg.key,
48
+ cfg.host
49
+ ];
50
+
51
+ if (psignature(params) == b.signature) {
52
+ io.sockets.in(b.channel).emit('pusher:' + b.event, b.data);
53
+ res.send({});
54
+ } else {
55
+ res.send(401);
56
+ }
57
+ });
58
+
59
+ io.configure(function () {
60
+ io.set('authorization', function (handshakeData, callback) {
61
+ var params = [
62
+ 'auth',
63
+ handshakeData.query.app_id,
64
+ handshakeData.query.timestamp,
65
+ cfg.key
66
+ ];
67
+ if (psignature(params) == handshakeData.query.signature) {
68
+ callback(null, true);
69
+ } else {
70
+ callback(null, false);
71
+ }
72
+ });
73
+ });
74
+
75
+ io.configure('production', function(){
76
+ io.enable('browser client minification'); // send minified client
77
+ io.enable('browser client etag'); // apply etag caching logic based on version number
78
+ io.enable('browser client gzip'); // gzip the file
79
+ io.set('log level', 1);
80
+
81
+ io.set('transports', [
82
+ 'websocket'
83
+ , 'flashsocket'
84
+ , 'htmlfile'
85
+ , 'xhr-polling'
86
+ , 'jsonp-polling'
87
+ ]);
88
+ });
89
+
90
+ io.sockets.on('connection', function (socket) {
91
+ socket.on('subscribe', function(data) {
92
+ socket.join(data.channel);
93
+ });
94
+ socket.on('unsubscribe', function(data) {
95
+ socket.leave(data.channel);
96
+ });
97
+ });
98
+
99
+ server.listen(cfg.port);
100
+ console.log('started pusher.io ', env, cfg.host + ':' + cfg.port);
@@ -0,0 +1,20 @@
1
+ development:
2
+ app_id: "<%= Rails.application.class.parent_name %>"
3
+ host: "localhost"
4
+ port: 9292
5
+ key: dev123
6
+ secret: "secret"
7
+ test:
8
+ app_id: "<%= Rails.application.class.parent_name %>"
9
+ host: "localhost"
10
+ port: 9293
11
+ key: test123
12
+ secret: "secret"
13
+ production:
14
+ app_id: "<%= Rails.application.class.parent_name %>"
15
+ host: "0.0.0.0"
16
+ port: 4443
17
+ ssl_key: "/path/to/server.pem"
18
+ ssl_cert: "/path/to/certificate_chain.pem"
19
+ key: "<%= defined?(SecureRandom) ? SecureRandom.hex(32) : ActiveSupport::SecureRandom.hex(32) %>"
20
+ secret: "<%= defined?(SecureRandom) ? SecureRandom.hex(32) : ActiveSupport::SecureRandom.hex(32) %>"
data/lib/pusher.io.rb ADDED
@@ -0,0 +1,105 @@
1
+ require 'pusher.io/version'
2
+ require 'openssl'
3
+ require 'net/http'
4
+ require 'net/https'
5
+
6
+ require "pusher.io/engine" if defined? Rails
7
+
8
+ module Pusher
9
+ module IO
10
+
11
+ class Channel
12
+ attr_reader :name
13
+
14
+ def initialize name
15
+ @name = name.to_s
16
+ end
17
+
18
+ def trigger event, data={}
19
+ cfg = Pusher::IO.config
20
+
21
+ msg = {
22
+ app_id: cfg[:app_id].to_s,
23
+ channel: name,
24
+ event: event.to_s,
25
+ data: data,
26
+ timestamp: Time.now.utc.to_i
27
+ }
28
+
29
+ sig = Pusher::IO.psignature([
30
+ 'POST',
31
+ 'events',
32
+ msg[:app_id],
33
+ msg[:channel],
34
+ msg[:event],
35
+ msg[:timestamp],
36
+ cfg[:key],
37
+ cfg[:host]
38
+ ])
39
+
40
+ msg[:signature] = sig
41
+
42
+ form = Net::HTTP::Post.new('/events')
43
+ form["Content-Type"] = "application/json"
44
+ form.body = msg.to_json
45
+
46
+ http = Net::HTTP.new(cfg[:host], cfg[:port])
47
+ http.use_ssl = cfg[:ssl_key].present?
48
+ http.start {|h| h.request(form)}
49
+ end
50
+ end
51
+
52
+ class << self
53
+ def config
54
+ @config ||= begin
55
+ cfg = {}
56
+ filename = "#{Rails.root}/config/pusher.io.yml"
57
+ yaml = YAML.load_file(filename)[Rails.env]
58
+ raise ArgumentError, "The #{Rails.env} environment does not exist in #{filename}" if yaml.nil?
59
+ yaml.each { |k, v| cfg[k.to_sym] = v }
60
+ cfg
61
+ end
62
+ end
63
+
64
+ def psignature(params)
65
+ OpenSSL::HMAC.hexdigest('sha1', config[:secret], params.join("\n"))
66
+ end
67
+
68
+ def io_auth_query
69
+ args = [
70
+ 'auth',
71
+ config[:app_id],
72
+ Time.now.utc.to_i,
73
+ config[:key]
74
+ ]
75
+ sign = psignature(args)
76
+ args << sign
77
+ query = ""
78
+ [:pusher, :app_id, :timestamp, :key, :signature].zip(args) do |key, value|
79
+ query << "&#{key}=#{value}"
80
+ end
81
+ query
82
+ end
83
+
84
+ def socket_base_uri
85
+ uri = config[:ssl_key].present? ? "https" : "http"
86
+ uri << "://#{config[:host]}"
87
+ uri << ":#{config[:port]}" if config[:port] && config[:port] != 80
88
+ uri
89
+ end
90
+
91
+ def socket_uri
92
+ socket_base_uri + "?#{io_auth_query}"
93
+ end
94
+
95
+ def socket_js_uri
96
+ socket_base_uri + "/socket.io/socket.io.js"
97
+ end
98
+
99
+ def [] channel_name
100
+ Channel.new channel_name
101
+ end
102
+ end
103
+ end
104
+ end
105
+
@@ -0,0 +1,10 @@
1
+ require 'pusher.io/view_helpers'
2
+
3
+ module Pusher::IO
4
+ class Engine < Rails::Engine
5
+ # Adds the ViewHelpers into ActionView::Base
6
+ initializer "pusher_io.view_helpers" do
7
+ ActionView::Base.send :include, ViewHelpers
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ module Pusher
2
+ module IO
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,18 @@
1
+ module Pusher::IO
2
+ module ViewHelpers
3
+ def pusher_io_tags
4
+ [
5
+ pusher_io_socket_uri,
6
+ pusher_io_socket_client
7
+ ].join().html_safe
8
+ end
9
+
10
+ def pusher_io_socket_client
11
+ javascript_include_tag Pusher::IO.socket_js_uri
12
+ end
13
+
14
+ def pusher_io_socket_uri
15
+ tag :meta, name: 'socket_uri', content: Pusher::IO.socket_uri
16
+ end
17
+ end
18
+ end
data/pusher.io.gemspec ADDED
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pusher.io/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "pusher.io"
8
+ gem.version = Pusher::IO::VERSION
9
+ gem.authors = ["yury"]
10
+ gem.email = ["yury.korolev@gmail.com"]
11
+ gem.description = %q{Very basic implementation of pusherapp.com api subset on top of socket.io.}
12
+ gem.summary = %q{Socket.io for rails}
13
+ gem.homepage = "https://github.com/anjlab/pusher.io"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pusher.io
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - yury
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-30 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Very basic implementation of pusherapp.com api subset on top of socket.io.
15
+ email:
16
+ - yury.korolev@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - Gemfile
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - app/assets/javascripts/pusher.io/client.js
27
+ - lib/capistrano.rb
28
+ - lib/generators/pusher.io/install_generator.rb
29
+ - lib/generators/pusher.io/templates/package.json
30
+ - lib/generators/pusher.io/templates/pusher.io.js
31
+ - lib/generators/pusher.io/templates/pusher.io.yml
32
+ - lib/pusher.io.rb
33
+ - lib/pusher.io/engine.rb
34
+ - lib/pusher.io/version.rb
35
+ - lib/pusher.io/view_helpers.rb
36
+ - pusher.io.gemspec
37
+ homepage: https://github.com/anjlab/pusher.io
38
+ licenses: []
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ segments:
49
+ - 0
50
+ hash: -2552341684975811669
51
+ none: false
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ segments:
58
+ - 0
59
+ hash: -2552341684975811669
60
+ none: false
61
+ requirements: []
62
+ rubyforge_project:
63
+ rubygems_version: 1.8.24
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: Socket.io for rails
67
+ test_files: []