Skip to content

Commit

Permalink
Split channels per application
Browse files Browse the repository at this point in the history
  • Loading branch information
imanel committed Apr 3, 2011
1 parent 5b2b249 commit bb853a3
Show file tree
Hide file tree
Showing 11 changed files with 41 additions and 38 deletions.
1 change: 0 additions & 1 deletion TODO.md
@@ -1,6 +1,5 @@
# TODO

- separate channels per application
- save and use channel rights
- allow sending messages
- checking format of events/channel names
Expand Down
16 changes: 6 additions & 10 deletions lib/socky/server/channel.rb
Expand Up @@ -9,24 +9,20 @@ class Channel
autoload :Public, "#{ROOT}/channel/public"
autoload :Stub, "#{ROOT}/channel/stub"

# Find or create by channel by name
# @param [String] name name of channel
# Find or create by application and channel by name
# @param [String] application_name name of application
# @param [String] channel_name name of channel
# @return [Channel::Base] channel instance
def self.find_or_create(channel_name)
return Stub.new(channel_name) unless (1..30).include?(channel_name.size)
def self.find_or_create(application_name, channel_name)
return Stub.new(application_name, channel_name) unless (1..30).include?(channel_name.size)

channel_type = case channel_name.match(/\A\w+/).to_s
when 'private' then Private
when 'presence' then Presence
else Public
end

channel_type.find_or_create(channel_name)
end

# Alias for self.find_or_create
def self.[](channel_name)
self.find_or_create(channel_name)
channel_type.find_or_create(application_name, channel_name)
end

end
Expand Down
20 changes: 12 additions & 8 deletions lib/socky/server/channel/base.rb
Expand Up @@ -3,26 +3,30 @@ module Server
class Channel
class Base

attr_accessor :name
attr_accessor :application, :name

class << self
# List of all already registered channels of current type
# namespaces by application name
def list
@list ||= {}
@list ||= Hash.new{ |hash, key| hash[key] = Hash.new }
end

# Find channel or create new
# @param [String] name name for channel
# @param [String] application_name name of application
# @param [String] channel_name name for channel
# @return [Base] channel instance
def find_or_create(name)
self.list[name] ||= self.new(name)
def find_or_create(application_name, channel_name)
self.list[application_name][channel_name] ||= self.new(application_name, channel_name)
end
end

# Initialize new channel
# @param [String] name name for channel
def initialize(name)
@name = name
# @param [String] application_name name of application
# @param [String] channel_name name for channel
def initialize(application_name, channel_name)
@application = Application.find(application_name)
@name = channel_name
end

def subscribers
Expand Down
2 changes: 1 addition & 1 deletion lib/socky/server/channel/private.rb
Expand Up @@ -10,7 +10,7 @@ def check_auth(connection, message)

hash = self.hash_from_message(connection, message)
begin
auth = Socky::Authenticator.new(hash, true, connection.application.secret)
auth = Socky::Authenticator.new(hash, true, self.application.secret)
auth.salt = message.auth.split(':',2)[0]
auth = auth.result
rescue ArgumentError => e
Expand Down
4 changes: 2 additions & 2 deletions lib/socky/server/message.rb
Expand Up @@ -12,8 +12,8 @@ def initialize(connection, data)

def dispath
case self.event
when 'socky:subscribe' then Channel[self.channel].subscribe(@connection, self)
when 'socky:unsubscribe' then Channel[self.channel].unsubscribe(@connection, self)
when 'socky:subscribe' then Channel.find_or_create(@connection.application.name, self.channel).subscribe(@connection, self)
when 'socky:unsubscribe' then Channel.find_or_create(@connection.application.name, self.channel).unsubscribe(@connection, self)
end
end

Expand Down
2 changes: 1 addition & 1 deletion spec/integration/ws_channels_spec.rb
Expand Up @@ -6,7 +6,7 @@
after { Socky::Server::Application.list.delete('test_application') }

context "connected to application" do
subject { mock_connection(@application.name) }
subject { mock_websocket(@application.name) }
before { subject.on_open({'PATH_INFO' => @application.name}); subject.connection.id = "1234567890" }
after { subject.on_close({}) }

Expand Down
4 changes: 2 additions & 2 deletions spec/integration/ws_connection_spec.rb
Expand Up @@ -6,7 +6,7 @@
after { Socky::Server::Application.list.delete('test_application') }

context 'Valid application' do
subject { mock_connection(@application.name) }
subject { mock_websocket(@application.name) }

it "should receive confirmation on connection" do
subject.should_receive(:send_data).with(hash_including( 'event' => 'socky:connection:established' ))
Expand All @@ -26,7 +26,7 @@
end

context "Invalid application" do
subject { mock_connection('invalid_name') }
subject { mock_websocket('invalid_name') }

it "should receive 'application invalid' error" do
subject.should_receive(:send_data).with({ 'event' => 'socky:connection:error', 'reason' => 'refused' })
Expand Down
11 changes: 4 additions & 7 deletions spec/integration/ws_presence_spec.rb
Expand Up @@ -5,7 +5,7 @@
before { @application = Socky::Server::Application.new('test_application', 'test_secret')}
after { Socky::Server::Application.list.delete(@application.name) }

subject { mock_connection(@application.name) }
subject { mock_websocket(@application.name) }
before { subject.on_open({'PATH_INFO' => @application.name}); subject.connection.id = "1234567890" }
after { subject.on_close({}) }
let(:channel_name) { 'presence-test_channel' }
Expand All @@ -27,7 +27,7 @@
end

context 'other user on the same channel' do
let(:other_user) { mock_connection(@application.name) }
let(:other_user) { mock_websocket(@application.name) }
before do
other_user.on_open({'PATH_INFO' => @application.name})
other_user.connection.id = "123"
Expand Down Expand Up @@ -60,11 +60,10 @@
end

context 'other user on other channel' do
let(:other_user) { mock_connection(@application.name) }
let(:other_user) { mock_websocket(@application.name) }
before do
other_user.on_open({'PATH_INFO' => @application.name})
other_user.connection.id = "123"
# puts Socky::Authenticator.authenticate({'connection_id' => '123', 'channel' => 'presence-other_channel'}, false, 'test_secret').inspect
other_user.should_receive(:send_data).with({ 'event' => 'socky:subscribe:success', 'channel' => 'presence-other_channel', 'members' => [] })
other_user.on_message({}, { 'event' => 'socky:subscribe', 'channel' => 'presence-other_channel', 'auth' => '2f1df408b658c9f3b4aa5717a4e832bd:9df486124b4cd642e3ffb6958cb27582e8cc5c86850ea36e9503d9541d28bd72' }.to_json)
end
Expand All @@ -91,10 +90,8 @@
before { @application2 = Socky::Server::Application.new('other_application', 'other_secret')}
after { Socky::Server::Application.list.delete(@application2.name) }

let(:other_user) { mock_connection(@application2.name) }
let(:other_user) { mock_websocket(@application2.name) }
before do
pending "reimplement channels!"

other_user.on_open({'PATH_INFO' => @application2.name})
other_user.connection.id = "123"
other_user.should_receive(:send_data).with({ 'event' => 'socky:subscribe:success', 'channel' => channel_name, 'members' => [] })
Expand Down
11 changes: 9 additions & 2 deletions spec/spec_helper.rb
Expand Up @@ -4,10 +4,17 @@
require 'socky/server'
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}

def mock_connection(application)
def mock_websocket(application)
env = {}
env['PATH_INFO'] = '/websocket/' + application
connection = Socky::Server::WebSocket.new.call(env)
connection.stub!(:send_data)
connection
end
end

def mock_connection(application)
websocket = mock_websocket(application)

env = { 'PATH_INFO' => '/websocket/' + application }
websocket.on_open(env)
end
3 changes: 1 addition & 2 deletions spec/unit/socky/server/connection_spec.rb
Expand Up @@ -2,7 +2,7 @@

describe Socky::Server::Connection do

let(:websocket) { mock_connection('test_app') }
let(:websocket) { mock_websocket('test_app') }
before { @application = Socky::Server::Application.new('test_app', 'test_secret') }
after { Socky::Server::Application.list.delete(@application.name) }

Expand Down Expand Up @@ -55,7 +55,6 @@
@application.connections[subject.id].should be_nil
end
it "should remove itself from channels list" do
pending('Wait for channel reimplementation')
channels = subject.channels.dup
subject.destroy
channels.each do |channel|
Expand Down
5 changes: 3 additions & 2 deletions spec/unit/socky/server/message_spec.rb
Expand Up @@ -2,9 +2,10 @@

describe Socky::Server::Message do

let(:connection) { mock(Socky::Server::Connection) }
let(:application) { Socky::Server::Application.new('some_app', 'some_secret') }
let(:connection) { mock_connection(application.name) }
let(:channel) { mock(Socky::Server::Channel::Base, :subscribe => nil, :unsubscribe => nil) }
before { Socky::Server::Channel.stub!(:[]).and_return(channel)}
before { Socky::Server::Channel.stub!(:find_or_create).and_return(channel)}

context "#new" do
it "should get valid instance when json provided" do
Expand Down

0 comments on commit bb853a3

Please sign in to comment.