Skip to content

Commit

Permalink
Merge branch 'master' into subscription-rejection
Browse files Browse the repository at this point in the history
  • Loading branch information
lifo committed Nov 4, 2015
2 parents ee06b33 + 7c1631f commit cb4ef80
Show file tree
Hide file tree
Showing 10 changed files with 65 additions and 50 deletions.
8 changes: 6 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ rvm:

gemfile:
- Gemfile
- gemfiles/rails_4-2-stable.gemfile
- gemfiles/Gemfile.rails-4-2

matrix:
fast_finish: true
allow_failures: ruby-head
allow_failures:
- ruby-head

services:
- redis-server

notifications:
email: false
Expand Down
8 changes: 4 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
GIT
remote: git://github.com/rack/rack.git
revision: 6216a3f8a3560639ee1ddadc1e0d6bf9e5f31830
revision: 35599cfc2751e0ee611c0ff799924b8e7fe0c0b4
specs:
rack (2.0.0.alpha)
json
Expand All @@ -13,7 +13,7 @@ GIT

GIT
remote: git://github.com/rails/rails.git
revision: 960de47f0eef79d234eb3cfc47fabb470fef1529
revision: f94e328cf801fd5c8055b06c4ee5439273146833
specs:
actionpack (5.0.0.alpha)
actionview (= 5.0.0.alpha)
Expand Down Expand Up @@ -59,7 +59,7 @@ GEM
remote: https://rubygems.org/
specs:
builder (3.2.2)
celluloid (0.16.1)
celluloid (0.16.0)
timers (~> 4.0.0)
coffee-rails (4.1.0)
coffee-script (>= 2.2.0)
Expand Down Expand Up @@ -92,7 +92,7 @@ GEM
metaclass (~> 0.0.1)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
puma (2.12.2)
puma (2.14.0)
rack-test (0.6.3)
rack (>= 1.0)
rails-deprecated_sanitizer (1.0.3)
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ module ApplicationCable
end
end
```
Here `identified_by` is a connection identifier that can be used to find the specific connection again or later.
Note that anything marked as an identifier will automatically create a delegate by the same name on any channel instances created off the connection.

Then you should define your `ApplicationCable::Channel` class in Ruby. This is the place where you put
shared logic between your channels.
Expand Down Expand Up @@ -317,7 +319,7 @@ application. The recommended basic setup is as follows:

```ruby
# cable/config.ru
require ::File.expand_path('../../config/environment', __FILE__)
require ::File.expand_path('../../config/environment', __FILE__)
Rails.application.eager_load!

require 'action_cable/process/logging'
Expand All @@ -328,7 +330,7 @@ run ActionCable.server
Then you start the server using a binstub in bin/cable ala:
```
#!/bin/bash
bundle exec puma -p 28080 cable/config.ru
bundle exec puma -p 28080 cable/config.ru
```

The above will start a cable server on port 28080. Remember to point your client-side setup against that using something like:
Expand Down
File renamed without changes.
23 changes: 7 additions & 16 deletions lib/action_cable/channel/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,7 @@ class Base
SUBSCRIPTION_CONFIRMATION_INTERNAL_MESSAGE = 'confirm_subscription'.freeze
SUBSCRIPTION_REJECTION_INTERNAL_MESSAGE = 'reject_subscription'.freeze

on_subscribe :subscribed
on_unsubscribe :unsubscribed

attr_reader :params, :connection, :identifier
attr_reader :params, :connection, ::identifier
delegate :logger, to: :connection

class << self
Expand Down Expand Up @@ -147,7 +144,9 @@ def perform_action(data)
# Called by the cable connection when its cut so the channel has a chance to cleanup with callbacks.
# This method is not intended to be called directly by the user. Instead, overwrite the #unsubscribed callback.
def unsubscribe_from_channel
run_unsubscribe_callbacks
run_callbacks :unsubscribe do
unsubscribed
end
end


Expand Down Expand Up @@ -202,7 +201,9 @@ def delegate_connection_identifiers


def subscribe_to_channel
run_subscribe_callbacks
run_callbacks :subscribe do
subscribed
end

if subscription_rejected?
reject_subscription
Expand Down Expand Up @@ -238,19 +239,10 @@ def action_signature(action, data)
end
end

def run_subscribe_callbacks
self.class.on_subscribe_callbacks.each { |callback| send(callback) }
end

def run_unsubscribe_callbacks
self.class.on_unsubscribe_callbacks.each { |callback| send(callback) }
end

def transmit_subscription_confirmation
unless subscription_confirmation_sent?
logger.info "#{self.class.name} is transmitting the subscription confirmation"
connection.transmit ActiveSupport::JSON.encode(identifier: @identifier, type: SUBSCRIPTION_CONFIRMATION_INTERNAL_MESSAGE)

@subscription_confirmation_sent = true
end
end
Expand All @@ -264,7 +256,6 @@ def transmit_subscription_rejection
logger.info "#{self.class.name} is transmitting the subscription rejection"
connection.transmit ActiveSupport::JSON.encode(identifier: @identifier, type: SUBSCRIPTION_REJECTION_INTERNAL_MESSAGE)
end

end
end
end
37 changes: 22 additions & 15 deletions lib/action_cable/channel/callbacks.rb
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
require 'active_support/callbacks'

module ActionCable
module Channel
module Callbacks
extend ActiveSupport::Concern
extend ActiveSupport::Concern
include ActiveSupport::Callbacks

included do
class_attribute :on_subscribe_callbacks, :on_unsubscribe_callbacks, instance_reader: false

self.on_subscribe_callbacks = []
self.on_unsubscribe_callbacks = []
define_callbacks :subscribe
define_callbacks :unsubscribe
end

module ClassMethods
# Name methods that should be called when the channel is subscribed to.
# (These methods should be private, so they're not callable by the user).
def on_subscribe(*methods)
self.on_subscribe_callbacks += methods
class_methods do
def before_subscribe(*methods, &block)
set_callback(:subscribe, :before, *methods, &block)
end

def after_subscribe(*methods, &block)
set_callback(:subscribe, :after, *methods, &block)
end
alias_method :on_subscribe, :after_subscribe

def before_unsubscribe(*methods, &block)
set_callback(:unsubscribe, :before, *methods, &block)
end

# Name methods that should be called when the channel is unsubscribed from.
# (These methods should be private, so they're not callable by the user).
def on_unsubscribe(*methods)
self.on_unsubscribe_callbacks += methods
def after_unsubscribe(*methods, &block)
set_callback(:unsubscribe, :after, *methods, &block)
end
alias_method :on_unsubscribe, :after_unsubscribe
end
end
end
end
end
6 changes: 3 additions & 3 deletions lib/action_cable/channel/periodic_timers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ module PeriodicTimers
class_attribute :periodic_timers, instance_reader: false
self.periodic_timers = []

on_subscribe :start_periodic_timers
on_unsubscribe :stop_periodic_timers
after_subscribe :start_periodic_timers
after_unsubscribe :stop_periodic_timers
end

module ClassMethods
Expand Down Expand Up @@ -38,4 +38,4 @@ def stop_periodic_timers
end
end
end
end
end
11 changes: 7 additions & 4 deletions lib/action_cable/connection/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class Base
def initialize(server, env)
@server, @env = server, env

@logger = new_tagged_logger
@logger = new_tagged_logger || server.logger

@websocket = ActionCable::Connection::WebSocket.new(env)
@subscriptions = ActionCable::Connection::Subscriptions.new(self)
Expand Down Expand Up @@ -151,7 +151,6 @@ def on_open
server.add_connection(self)
rescue ActionCable::Connection::Authorization::UnauthorizedError
respond_to_invalid_request
close
end

def on_message(message)
Expand Down Expand Up @@ -186,15 +185,19 @@ def respond_to_successful_request
end

def respond_to_invalid_request
close if websocket.alive?

logger.info finished_request_message
[ 404, { 'Content-Type' => 'text/plain' }, [ 'Page not found' ] ]
end


# Tags are declared in the server but computed in the connection. This allows us per-connection tailored tags.
def new_tagged_logger
TaggedLoggerProxy.new server.logger,
tags: server.config.log_tags.map { |tag| tag.respond_to?(:call) ? tag.call(request) : tag.to_s.camelize }
if server.logger.respond_to?(:tagged)
TaggedLoggerProxy.new server.logger,
tags: server.config.log_tags.map { |tag| tag.respond_to?(:call) ? tag.call(request) : tag.to_s.camelize }
end
end

def started_request_message
Expand Down
4 changes: 2 additions & 2 deletions test/channel/base_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ def chatters

class ChatChannel < BasicChannel
attr_reader :room, :last_action
on_subscribe :toggle_subscribed
on_unsubscribe :toggle_subscribed
after_subscribe :toggle_subscribed
after_unsubscribe :toggle_subscribed

def initialize(*)
@subscribed = false
Expand Down
12 changes: 10 additions & 2 deletions test/connection/authorization_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,25 @@ class Connection < ActionCable::Connection::Base
def connect
reject_unauthorized_connection
end

def send_async(method, *args)
# Bypass Celluloid
send method, *args
end
end

test "unauthorized connection" do
run_in_eventmachine do
server = TestServer.new
env = Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket'
server.config.allowed_request_origins = %w( http://rubyonrails.com )

env = Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket',
'HTTP_ORIGIN' => 'http://rubyonrails.com'

connection = Connection.new(server, env)
connection.websocket.expects(:close)

connection.process
connection.send :on_open
end
end
end

0 comments on commit cb4ef80

Please sign in to comment.