Skip to content
This repository has been archived by the owner on Dec 12, 2021. It is now read-only.

Added Support for Redis Engine #38

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ It's not necessary to include faye.js since that will be handled automatically f

## Serving Faye over HTTPS (with Thin)

To server Faye over HTTPS you could create a thin configuration file `config/private_pub_thin.yml` similar to the following:
To serve Faye over HTTPS you could create a thin configuration file `config/private_pub_thin.yml` similar to the following:

```yaml
---
Expand All @@ -63,6 +63,21 @@ Finally start up Thin from the project root.
thin -C config/private_pub_thin.yml start
```

## Serving Faye with Redis engine

To serve Faye with Redis engine, you should create `config/private_pub_redis.yml`

```yaml
production:
host: redis_host
port: redis_port
password: redis_password
database: redis_database
namespace: '/namespace'
```

Note: database and namespace are optional.

## Usage

Use the `subscribe_to` helper method on any page to subscribe to a channel.
Expand Down
12 changes: 11 additions & 1 deletion lib/generators/private_pub/templates/private_pub.ru
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ require "bundler/setup"
require "yaml"
require "faye"
require "private_pub"
require "thin"

PrivatePub.load_config(File.expand_path("../config/private_pub.yml", __FILE__), ENV["RAILS_ENV"] || "development")
run PrivatePub.faye_app
Faye::WebSocket.load_adapter(PrivatePub.config[:adapter])

path = File.expand_path("../config/private_pub_redis.yml", __FILE__)
options = {}
if File.exist?(path)
require 'faye/redis'
options.merge(PrivatePub.load_redis_config(path, ENV['RAILS_ENV'] || 'development'))
end

run PrivatePub.faye_app(options)
3 changes: 3 additions & 0 deletions lib/generators/private_pub/templates/private_pub.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
development:
adapter: thin
server: "http://localhost:9292/faye"
secret_token: "secret"
test:
adapter: thin
server: "http://localhost:9292/faye"
secret_token: "secret"
production:
adapter: thin
server: "http://example.com/faye"
secret_token: "<%= defined?(SecureRandom) ? SecureRandom.hex(32) : ActiveSupport::SecureRandom.hex(32) %>"
signature_expiration: 3600 # one hour
19 changes: 15 additions & 4 deletions lib/private_pub.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "digest/sha1"
require "net/http"
require "yajl/json_gem"

require "private_pub/faye_extension"
require "private_pub/engine" if defined? Rails
Expand All @@ -9,19 +10,30 @@ class Error < StandardError; end

class << self
attr_reader :config
attr_reader :default_options

# Resets the configuration to the default (empty hash)
# Resets the configuration and options to the default
# configuration defaults to empty hash
def reset_config
@config = {}
@default_options = {:mount => "/faye", :timeout => 60, :extensions => [FayeExtension.new]}
end

# Loads the configuration from a given YAML file and environment (such as production)
# Loads the configuration from a given YAML file and environment (such as production)
def load_config(filename, environment)
yaml = YAML.load_file(filename)[environment.to_s]
raise ArgumentError, "The #{environment} environment does not exist in #{filename}" if yaml.nil?
yaml.each { |k, v| config[k.to_sym] = v }
end

# Loads the options from a given YAML file and environment (such as production)
def load_redis_config(filename, environment)
yaml = YAML.load_file(filename)[environment.to_s]
options = {:engine => {:type => Faye::Redis}}
yaml.each {|k, v| options[:engine][k.to_sym] = v}
options
end

# Publish the given data to a specific channel. This ends up sending
# a Net::HTTP POST request to the Faye server.
def publish_to(channel, data)
Expand Down Expand Up @@ -68,8 +80,7 @@ def signature_expired?(timestamp)
# Returns the Faye Rack application.
# Any options given are passed to the Faye::RackAdapter.
def faye_app(options = {})
options = {:mount => "/faye", :timeout => 45, :extensions => [FayeExtension.new]}.merge(options)
Faye::RackAdapter.new(options)
Faye::RackAdapter.new(@default_options.merge!(options))
end
end

Expand Down
6 changes: 6 additions & 0 deletions lib/private_pub/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ class Engine < Rails::Engine
PrivatePub.load_config(path, Rails.env) if path.exist?
end

# Loads the private_pub_redis.yml file if it exists.
initializer "private_pub.redis_config" do
path = Rails.root.join("config/private_pub_redis.yml")
PrivatePub.load_redis_config(path, Rails.env) if path.exist?
end

# Adds the ViewHelpers into ActionView::Base
initializer "private_pub.view_helpers" do
ActionView::Base.send :include, ViewHelpers
Expand Down
2 changes: 1 addition & 1 deletion lib/private_pub/view_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def publish_to(channel, data = nil, &block)
def subscribe_to(channel)
subscription = PrivatePub.subscription(:channel => channel)
content_tag "script", :type => "text/javascript" do
raw("PrivatePub.sign(#{subscription.to_json});")
raw("if (typeof PrivatePub != 'undefined') { PrivatePub.sign(#{subscription.to_json}) }")
end
end
end
Expand Down
3 changes: 2 additions & 1 deletion private_pub.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ Gem::Specification.new do |s|
s.files = Dir["{app,lib,spec}/**/*", "[A-Z]*", "init.rb"] - ["Gemfile.lock"]
s.require_path = "lib"

s.add_dependency 'faye'
s.add_dependency 'faye', '>= 0.8.0'
s.add_dependency 'faye-redis'

s.add_development_dependency 'rake'
s.add_development_dependency 'rspec', '~> 2.8.0'
Expand Down
2 changes: 2 additions & 0 deletions spec/fixtures/private_pub.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
development:
adapter: thin
server: http://dev.local:9292/faye
secret_token: DEVELOPMENT_SECRET_TOKEN
signature_expiration: 600
production:
adapter: thin
server: http://example.com/faye
secret_token: PRODUCTION_SECRET_TOKEN
signature_expiration: 600
6 changes: 6 additions & 0 deletions spec/fixtures/private_pub_redis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
test:
host: redis_host
port: redis_port
password: redis_password
database: redis_database
namespace: '/namespace'
34 changes: 34 additions & 0 deletions spec/private_pub_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,40 @@
PrivatePub.config[:server].should eq("http://example.com/faye")
PrivatePub.config[:secret_token].should eq("PRODUCTION_SECRET_TOKEN")
PrivatePub.config[:signature_expiration].should eq(600)
PrivatePub.config[:adapter].should eq('thin')
end

context "when redis config exists" do
before do
@options = PrivatePub.load_redis_config("spec/fixtures/private_pub_redis.yml", "test")
end

it "passes redis config to faye engine options" do
@options[:engine][:type].should eq Faye::Redis
@options[:engine][:host].should eq 'redis_host'
@options[:engine][:port].should eq 'redis_port'
@options[:engine][:password].should eq 'redis_password'
@options[:engine][:database].should eq 'redis_database'
@options[:engine][:namespace].should eq '/namespace'
end

it "should pass redis config and default options to faye" do
Faye::RackAdapter.should_receive(:new) do |options|
options[:engine].should eq @options[:engine]
options[:mount].should eq '/faye'
end
PrivatePub.faye_app(@options)
end
end

context "when redis config does not exist" do
it "should not have :engine inside of options hash" do
PrivatePub.default_options.should_not include :engine
end

it "should have mount point" do
PrivatePub.default_options[:mount].should eq '/faye'
end
end

it "raises an exception if an invalid environment is passed to load_config" do
Expand Down
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'rubygems'
require 'bundler/setup'
require 'faye'
require 'faye/redis'
Bundler.require(:default)

RSpec.configure do |config|
Expand Down