pusher.io 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []