faye_shards 0.1.0

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/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.6.4"
12
+ gem "rcov", ">= 0"
13
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,20 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ git (1.2.5)
5
+ jeweler (1.6.4)
6
+ bundler (~> 1.0)
7
+ git (>= 1.2.5)
8
+ rake
9
+ rake (0.9.2.2)
10
+ rcov (0.9.10)
11
+ shoulda (2.11.3)
12
+
13
+ PLATFORMS
14
+ ruby
15
+
16
+ DEPENDENCIES
17
+ bundler (~> 1.0.0)
18
+ jeweler (~> 1.6.4)
19
+ rcov
20
+ shoulda
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Alex Kazeko
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,97 @@
1
+ = faye_shards
2
+
3
+ * Provides some useful methods to push data from Ruby on Rails to Faye (by jcoglan, http://faye.jcoglan.com).
4
+ * Designed to work with both HTTP and HTTPS connections (RoR pushes via HTTP, client can be connected using HTTPS). Check out http://rails-alex.blogspot.com/2011/10/ssl-support-for-high-loaded-faye-nodejs.html to see how to configure Stunnel in front of Faye to enable HTTPS.
5
+
6
+ == Comments
7
+
8
+ This gem will be helpful if you are planning to run more than one instance of Faye (doesn't matter on 1 server or on many).
9
+ If users in your application are subscribed to unique channels (eg. "/#{current_user.id}") - faye_shards will fit all your needs.
10
+ If you have global channels (which you use widely) and many instances of Faye - this game is not a perfect solution for you, but it will work.
11
+ It doesn't matter if you use Redis as data storage or not.
12
+
13
+ Check out these posts/discussions about Faye sharding:
14
+ * http://rails-alex.blogspot.com/2011/10/high-performance-publishsubscribe.html
15
+ * https://groups.google.com/forum/#!topic/faye-users/1B6pSKBZKFQ
16
+
17
+ == Installing
18
+
19
+ Simply add
20
+
21
+ <code> gem 'faye_shards'</code>
22
+
23
+ to your Gemfile
24
+
25
+ == Configuration
26
+
27
+ All you need to configure gem is to create file faye.yml in config folder. Here is an example:
28
+
29
+
30
+ development:
31
+ shards:
32
+ -
33
+ port: 42000
34
+ host: 127.0.0.1
35
+ -
36
+ port: 42001
37
+ host: 127.0.0.1
38
+ production:
39
+ shards:
40
+ -
41
+ local_host: 10.1.1.1
42
+ port: 42000
43
+ host: server1.myapp.com
44
+ secured: true
45
+ secured_port: 32000
46
+ -
47
+ local_host: 10.1.1.1
48
+ port: 42001
49
+ host: server1.myapp.com
50
+ secured: true
51
+ secured_port: 32001
52
+
53
+ Required options:
54
+ * <tt>host</tt> - IP or domain name where instance of Faye is running
55
+ * <tt>port</tt> - port, instance of Faye is listening to
56
+
57
+ Optional params:
58
+ * <tt>local_host</tt> - local IP of server. Used for pushes from Rails instead of <tt>host</tt> if specified. Just to communicate via local interfaces.
59
+ * <tt>secured</tt> - <tt>true/false</tt>. Specifies if there is a SSL Offloading configured for Faye instance.
60
+ * <tt>secured_port</tt> - Required if secured is set to <tt>true</tt>.
61
+
62
+ So, in my example for production I have 2 Faye instances listening to ports 42000 and 42001 using HTTP + Stunnel configured to listen 32000 and 32001.
63
+
64
+ == Usage
65
+
66
+ URL for Faye's client-side JS (unless you store it somewhere on diff storage) is returned by this methos:
67
+ FayeShards.shard(current_user.id).js_url
68
+
69
+ Module <code>FayeShard::User::Faye</code> which can be included to your User model provides method <tt>faye_channel</tt> which returns unique channel id for user. If you do not want to include module to your model - you need to manage unique channels for users yourself.
70
+
71
+ On client side, subscription should look like:
72
+ client = new Faye.Client(<%= raw FayeShards.shard(current_user.id).url(request.ssl?).inspect %>);
73
+ fayeSubscription = client.subscribe(<%= raw current_user.faye_channel.inspect %>, function(data) {});
74
+
75
+ or
76
+ fayeSubscription = client.subscribe(<%= raw my_own_method_for_channel_id.inspect %>, function(data) {});
77
+
78
+
79
+ Pushing data to user's channel also depends on your decision to include module <code>FayeShard::User::Faye</code>. So, 2 options:
80
+ current_user.push_to_faye(data) # Sends data to channel, returned by current_user.faye_channel
81
+ or
82
+ FayeShards.shard(1).push(my_own_method_for_channel_id, data)
83
+
84
+ Extensions can be passed as an additional hash after <tt>data</tt>
85
+
86
+ How to push to global channel and more information about gem can be found here: TODO.
87
+
88
+ == Roadmap / TODO
89
+ * UT
90
+ * Add example Rails app which uses faye_shards.
91
+ * GOD scripts to start/monitor Faye instances based on faye.yml
92
+
93
+ == Copyright
94
+
95
+ Copyright (c) 2011 Alex Kazeko. See LICENSE.txt for
96
+ further details.
97
+
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "faye_shards"
18
+ gem.homepage = "http://github.com/alexkazeko/faye_shards"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Provides support for easy communication with Faye shards}
21
+ gem.description = %Q{Provides support for easy communication with Faye shards}
22
+ gem.email = "alexandr.temp@gmail.com"
23
+ gem.authors = ["Alex Kazeko"]
24
+ gem.files.exclude 'tmp'
25
+ gem.files.include 'lib/faye_shard/*.rb'
26
+ # dependencies defined in Gemfile
27
+ end
28
+ Jeweler::RubygemsDotOrgTasks.new
29
+
30
+ require 'rake/testtask'
31
+ Rake::TestTask.new(:test) do |test|
32
+ test.libs << 'lib' << 'test'
33
+ test.pattern = 'test/**/test_*.rb'
34
+ test.verbose = true
35
+ end
36
+
37
+ require 'rcov/rcovtask'
38
+ Rcov::RcovTask.new do |test|
39
+ test.libs << 'test'
40
+ test.pattern = 'test/**/test_*.rb'
41
+ test.verbose = true
42
+ test.rcov_opts << '--exclude "gems/*"'
43
+ end
44
+
45
+ task :default => :test
46
+
47
+ require 'rake/rdoctask'
48
+ Rake::RDocTask.new do |rdoc|
49
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "faye_shards #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,25 @@
1
+ development:
2
+ shards:
3
+ -
4
+ port: 42000
5
+ host: 127.0.0.1
6
+ secured: false
7
+ -
8
+ port: 42001
9
+ host: 127.0.0.1
10
+ secured: false
11
+
12
+ production:
13
+ shards:
14
+ -
15
+ local_host: 10.1.1.1
16
+ port: 42000
17
+ host: server1.myapp.com
18
+ secured: true
19
+ secured_port: 32000
20
+ -
21
+ local_host: 10.1.1.1
22
+ port: 42001
23
+ host: server1.myapp.com
24
+ secured: true
25
+ secured_port: 32001
@@ -0,0 +1,63 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{faye_shards}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Alex Kazeko"]
12
+ s.date = %q{2011-11-01}
13
+ s.description = %q{Provides support for easy communication with Faye shards}
14
+ s.email = %q{alexandr.temp@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE.txt",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "examples/config/faye.yml",
28
+ "faye_shards.gemspec",
29
+ "lib/faye_shard/shard.rb",
30
+ "lib/faye_shard/user/faye.rb",
31
+ "lib/faye_shards.rb",
32
+ "test/helper.rb",
33
+ "test/test_faye_shards.rb"
34
+ ]
35
+ s.homepage = %q{http://github.com/alexkazeko/faye_shards}
36
+ s.licenses = ["MIT"]
37
+ s.require_paths = ["lib"]
38
+ s.rubygems_version = %q{1.3.7}
39
+ s.summary = %q{Provides support for easy communication with Faye shards}
40
+
41
+ if s.respond_to? :specification_version then
42
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
43
+ s.specification_version = 3
44
+
45
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
46
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
47
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
48
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
49
+ s.add_development_dependency(%q<rcov>, [">= 0"])
50
+ else
51
+ s.add_dependency(%q<shoulda>, [">= 0"])
52
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
53
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
54
+ s.add_dependency(%q<rcov>, [">= 0"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<shoulda>, [">= 0"])
58
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
59
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
60
+ s.add_dependency(%q<rcov>, [">= 0"])
61
+ end
62
+ end
63
+
@@ -0,0 +1,54 @@
1
+ module FayeShard
2
+
3
+ class Shard
4
+
5
+ attr_accessor :configuration
6
+
7
+ # Creates a shard instance and assigns the config to it.
8
+ #
9
+ # * <tt>config</tt>:: Config to use.
10
+ #
11
+ def initialize(config)
12
+ self.configuration = config.with_indifferent_access
13
+ end
14
+
15
+ # Returns URL for client.
16
+ #
17
+ # * <tt>https</tt>:: Specifies whether to use SSL connection or not
18
+ #
19
+ def url(https = false)
20
+ secured = (configuration['secured'] || false) & https
21
+ port = secured ? configuration["secured_port"] : configuration["port"]
22
+ "http#{secured ? 's' : ''}://#{configuration["host"]}:#{port}/faye"
23
+ end
24
+
25
+ # Returns default client JS url
26
+ #
27
+ def js_url
28
+ url + '.js'
29
+ end
30
+
31
+ # Local url, needed for RoR <-> Faye communication
32
+ #
33
+ def local_url
34
+ host = configuration["local_host"] || configuration["host"]
35
+ "http://#{host}:#{configuration["port"]}/faye"
36
+ end
37
+
38
+ # Pushes data to a Faye shard
39
+ #
40
+ # * <tt>channel</tt>:: User's channel
41
+ # * <tt>data</tt>:: Data to push
42
+ # * <tt>ext</tt>:: Faye extensions, eg. auth_token
43
+ #
44
+ def push(channel, data, ext = {})
45
+ uri = URI.parse(self.local_url)
46
+ http = Net::HTTP.new(uri.host, uri.port)
47
+ req = Net::HTTP::Post.new uri.path
48
+ req.set_form_data('message' => {'channel' => channel, 'data' => data, 'ext' => ext}.to_json)
49
+ http.request req
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,29 @@
1
+ module FayeShard
2
+
3
+ module User
4
+
5
+ # Module which is designed to be included to User model.
6
+ # It provides helper method to get token and method to push data to user's shard.
7
+ #
8
+ module Faye
9
+
10
+ # Returns channel for a user, which is basically /ID
11
+ #
12
+ def faye_channel
13
+ "/#{self.id}"
14
+ end
15
+
16
+ # Pushes data to User's Faye shard
17
+ #
18
+ # * <tt>data</tt>:: Data to push
19
+ # * <tt>ext</tt>:: Faye extensions, eg. auth_token
20
+ #
21
+ def push_to_faye(data, ext = {})
22
+ FayeShards.shard(self.id).push(self.faye_channel, data, ext)
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,38 @@
1
+ require 'faye_shard/shard'
2
+ require 'faye_shard/user/faye'
3
+
4
+ class FayeShards
5
+
6
+ class << self
7
+
8
+ # Returns configuration for current Rails environment.
9
+ #
10
+ # * <tt>env</tt>:: Rails environment, defaults to +Rails.env+.
11
+ #
12
+ def config
13
+ @config ||= YAML.load(File.read(Rails.root.to_s + "/config/faye.yml"))
14
+ @config[Rails.env]
15
+ end
16
+
17
+ # Returns the object which represents a connection to a specific shard. The object is effectively
18
+ # an instance of +FayeShards::Shard+ class which can be found in this gem.
19
+ #
20
+ # * <tt>id</tt>:: Id (an integer, string of whatever) to perform sharding based on.
21
+ #
22
+ def shard(id)
23
+ @shards ||= {}
24
+
25
+ shard_configs = config["shards"]
26
+
27
+ @shards[id % shard_configs.size] ||= FayeShard::Shard.new(shard_configs[id % shard_configs.size])
28
+ end
29
+
30
+ # Returns all configured shards
31
+ #
32
+ def all_shards
33
+ @shards ||= config["shards"].map{ |shard_config| FayeShard::Shard.new(shard_config) }
34
+ end
35
+
36
+ end
37
+
38
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'faye_shards'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestFayeShards < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: faye_shards
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Alex Kazeko
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-11-01 00:00:00 +03:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ hash: 3
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ requirement: *id001
32
+ prerelease: false
33
+ type: :development
34
+ name: shoulda
35
+ - !ruby/object:Gem::Dependency
36
+ version_requirements: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ hash: 23
42
+ segments:
43
+ - 1
44
+ - 0
45
+ - 0
46
+ version: 1.0.0
47
+ requirement: *id002
48
+ prerelease: false
49
+ type: :development
50
+ name: bundler
51
+ - !ruby/object:Gem::Dependency
52
+ version_requirements: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ hash: 7
58
+ segments:
59
+ - 1
60
+ - 6
61
+ - 4
62
+ version: 1.6.4
63
+ requirement: *id003
64
+ prerelease: false
65
+ type: :development
66
+ name: jeweler
67
+ - !ruby/object:Gem::Dependency
68
+ version_requirements: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ requirement: *id004
78
+ prerelease: false
79
+ type: :development
80
+ name: rcov
81
+ description: Provides support for easy communication with Faye shards
82
+ email: alexandr.temp@gmail.com
83
+ executables: []
84
+
85
+ extensions: []
86
+
87
+ extra_rdoc_files:
88
+ - LICENSE.txt
89
+ - README.rdoc
90
+ files:
91
+ - .document
92
+ - Gemfile
93
+ - Gemfile.lock
94
+ - LICENSE.txt
95
+ - README.rdoc
96
+ - Rakefile
97
+ - VERSION
98
+ - examples/config/faye.yml
99
+ - faye_shards.gemspec
100
+ - lib/faye_shard/shard.rb
101
+ - lib/faye_shard/user/faye.rb
102
+ - lib/faye_shards.rb
103
+ - test/helper.rb
104
+ - test/test_faye_shards.rb
105
+ has_rdoc: true
106
+ homepage: http://github.com/alexkazeko/faye_shards
107
+ licenses:
108
+ - MIT
109
+ post_install_message:
110
+ rdoc_options: []
111
+
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ hash: 3
120
+ segments:
121
+ - 0
122
+ version: "0"
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ hash: 3
129
+ segments:
130
+ - 0
131
+ version: "0"
132
+ requirements: []
133
+
134
+ rubyforge_project:
135
+ rubygems_version: 1.3.7
136
+ signing_key:
137
+ specification_version: 3
138
+ summary: Provides support for easy communication with Faye shards
139
+ test_files: []
140
+