websocket-rails 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/CHANGELOG.md +11 -0
  2. data/Gemfile +7 -0
  3. data/README.md +15 -16
  4. data/lib/assets/javascripts/websocket_rails/channel.js +35 -0
  5. data/lib/assets/javascripts/websocket_rails/http_connection.js +68 -0
  6. data/lib/assets/javascripts/websocket_rails/main.js +4 -0
  7. data/lib/assets/javascripts/websocket_rails/websocket_connection.js +38 -0
  8. data/lib/assets/javascripts/websocket_rails/websocket_rails.js +100 -0
  9. data/lib/generators/websocket_rails/install/install_generator.rb +32 -0
  10. data/lib/generators/websocket_rails/install/templates/events.rb +14 -0
  11. data/lib/websocket-rails.rb +4 -0
  12. data/lib/websocket_rails/base_controller.rb +4 -2
  13. data/lib/websocket_rails/channel.rb +35 -0
  14. data/lib/websocket_rails/channel_manager.rb +28 -0
  15. data/lib/websocket_rails/connection_adapters.rb +35 -4
  16. data/lib/websocket_rails/connection_manager.rb +3 -1
  17. data/lib/websocket_rails/dispatcher.rb +22 -12
  18. data/lib/websocket_rails/event.rb +31 -17
  19. data/lib/websocket_rails/event_map.rb +14 -6
  20. data/lib/websocket_rails/event_queue.rb +27 -0
  21. data/lib/websocket_rails/internal_events.rb +19 -0
  22. data/lib/websocket_rails/version.rb +1 -1
  23. data/spec/dummy/config/initializers/events.rb +5 -5
  24. data/spec/dummy/log/test.log +180 -0
  25. data/spec/integration/connection_manager_spec.rb +21 -8
  26. data/spec/support/helper_methods.rb +2 -2
  27. data/spec/support/mock_web_socket.rb +4 -0
  28. data/spec/unit/channel_manager_spec.rb +29 -0
  29. data/spec/unit/channel_spec.rb +46 -0
  30. data/spec/unit/connection_adapters_spec.rb +20 -0
  31. data/spec/unit/dispatcher_spec.rb +13 -2
  32. data/spec/unit/event_map_spec.rb +2 -2
  33. data/spec/unit/event_queue_spec.rb +36 -0
  34. data/spec/unit/event_spec.rb +26 -3
  35. metadata +24 -28
  36. data/assets/javascripts/http_dispatcher.js +0 -78
  37. data/assets/javascripts/websocket_dispatcher.js +0 -66
@@ -0,0 +1,28 @@
1
+ module WebsocketRails
2
+
3
+ class << self
4
+
5
+ def channel_manager
6
+ @channel_manager ||= ChannelManager.new
7
+ end
8
+
9
+ def [](channel)
10
+ channel_manager[channel]
11
+ end
12
+
13
+ end
14
+
15
+ class ChannelManager
16
+
17
+ attr_reader :channels
18
+
19
+ def initialize
20
+ @channels = Hash.new.with_indifferent_access
21
+ end
22
+
23
+ def [](channel)
24
+ @channels[channel] ||= Channel.new channel
25
+ end
26
+
27
+ end
28
+ end
@@ -24,17 +24,18 @@ module WebsocketRails
24
24
  ConnectionAdapters.register adapter
25
25
  end
26
26
 
27
- attr_accessor :dispatcher
27
+ attr_reader :dispatcher, :queue
28
28
 
29
29
  def initialize(env,dispatcher)
30
- @env = env
30
+ @env = env
31
+ @queue = EventQueue.new
31
32
  @dispatcher = dispatcher
32
33
  end
33
34
 
34
35
  def on_open(data=nil)
35
36
  event = Event.new_on_open( self, data )
36
37
  dispatch event
37
- send event.serialize
38
+ trigger event
38
39
  end
39
40
 
40
41
  def on_message(encoded_data)
@@ -51,7 +52,29 @@ module WebsocketRails
51
52
  dispatch event
52
53
  on_close event.data
53
54
  end
54
-
55
+
56
+ def enqueue(event)
57
+ @queue << event
58
+ end
59
+
60
+ def trigger(event)
61
+ enqueue event
62
+ unless flush_scheduled
63
+ EM.next_tick { flush; flush_scheduled = false }
64
+ flush_scheduled = true
65
+ end
66
+ end
67
+
68
+ def flush
69
+ message = "["
70
+ @queue.flush do |event|
71
+ message << event.serialize
72
+ message << "," unless event == @queue.last
73
+ end
74
+ message << "]"
75
+ send message
76
+ end
77
+
55
78
  def send(message)
56
79
  raise NotImplementedError, "Override this method in the connection specific adapter class"
57
80
  end
@@ -73,6 +96,14 @@ module WebsocketRails
73
96
  def close_connection
74
97
  dispatcher.connection_manager.close_connection self
75
98
  end
99
+
100
+ def flush_scheduled
101
+ @flush_scheduled
102
+ end
103
+
104
+ def flush_scheduled=(value)
105
+ @flush_scheduled = value
106
+ end
76
107
  end
77
108
 
78
109
  end
@@ -21,17 +21,19 @@ module WebsocketRails
21
21
 
22
22
  def initialize
23
23
  @connections = []
24
- @dispatcher = Dispatcher.new( self )
24
+ @dispatcher = Dispatcher.new( self )
25
25
  end
26
26
 
27
27
  # Primary entry point for the Rack application
28
28
  def call(env)
29
29
  request = Rack::Request.new env
30
+
30
31
  if request.post?
31
32
  response = parse_incoming_event request.params
32
33
  else
33
34
  response = open_connection env
34
35
  end
36
+
35
37
  response
36
38
  rescue InvalidConnectionError
37
39
  BadRequestResponse
@@ -19,6 +19,28 @@ module WebsocketRails
19
19
  end
20
20
 
21
21
  def dispatch(event)
22
+ if event.is_channel?
23
+ WebsocketRails[event.channel].trigger_event event
24
+ else
25
+ route event
26
+ end
27
+ end
28
+
29
+ def send_message(event)
30
+ puts "sending message: #{event.serialize}"
31
+ event.connection.trigger event
32
+ end
33
+
34
+ def broadcast_message(event)
35
+ puts "broadcasting message: #{event.serialize}"
36
+ connection_manager.connections.map do |connection|
37
+ connection.trigger event
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def route(event)
22
44
  actions = []
23
45
  event_map.routes_for event do |controller,method|
24
46
  actions << Fiber.new do
@@ -33,18 +55,6 @@ module WebsocketRails
33
55
  end
34
56
  execute actions
35
57
  end
36
-
37
- def send_message(event)
38
- event.connection.send event.serialize
39
- end
40
-
41
- def broadcast_message(event)
42
- connection_manager.connections.map do |connection|
43
- connection.send event.serialize
44
- end
45
- end
46
-
47
- private
48
58
 
49
59
  def execute(actions)
50
60
  actions.map do |action|
@@ -4,36 +4,48 @@ module WebsocketRails
4
4
  class Event
5
5
 
6
6
  def self.new_from_json(encoded_data,connection)
7
- event_name, data, namespace = decode encoded_data
8
- Event.new event_name, data, connection, namespace: namespace
7
+ event_name, data, namespace, channel = decode encoded_data
8
+ Event.new event_name, data,
9
+ :connection => connection,
10
+ :namespace => namespace,
11
+ :channel => channel
9
12
  end
10
13
 
11
14
  def self.new_on_open(connection,data=nil)
12
15
  connection_id = { :connection_id => connection.id }
13
16
  on_open_data = data.is_a?(Hash) ? data.merge(connection_id) : connection_id
14
17
 
15
- Event.new :client_connected, on_open_data, connection
18
+ Event.new :client_connected, on_open_data, :connection => connection
16
19
  end
17
20
 
18
21
  def self.new_on_close(connection,data=nil)
19
- Event.new :client_disconnected, data, connection
22
+ Event.new :client_disconnected, data, :connection => connection
20
23
  end
21
24
 
22
25
  def self.new_on_error(connection,data=nil)
23
- Event.new :client_error, data, connection
26
+ Event.new :client_error, data, :connection => connection
24
27
  end
25
28
 
26
- attr_reader :name, :data, :connection, :namespace
29
+ attr_reader :name, :data, :connection, :namespace, :channel
27
30
 
28
- def initialize(event_name,data,connection,options={})
29
- @name = event_name.to_sym
30
- @data = data.is_a?(Hash) ? data.with_indifferent_access : data
31
- @connection = connection
32
- validate_namespace options[:namespace]
31
+ def initialize(event_name,data,options={})
32
+ @name = event_name.to_sym
33
+ @data = data.is_a?(Hash) ? data.with_indifferent_access : data
34
+ @channel = options[:channel]
35
+ @connection = options[:connection]
36
+ @namespace = validate_namespace options[:namespace]
33
37
  end
34
38
 
35
39
  def serialize
36
- [encoded_name, data].to_json
40
+ if is_channel?
41
+ [channel, encoded_name, data].to_json
42
+ else
43
+ [encoded_name, data].to_json
44
+ end
45
+ end
46
+
47
+ def is_channel?
48
+ !@channel.nil?
37
49
  end
38
50
 
39
51
  private
@@ -41,7 +53,7 @@ module WebsocketRails
41
53
  def validate_namespace(namespace)
42
54
  namespace = [namespace] unless namespace.is_a?(Array)
43
55
  namespace.unshift :global unless namespace.first == :global
44
- @namespace = namespace.map(&:to_sym) rescue [:global]
56
+ namespace.map(&:to_sym) rescue [:global]
45
57
  end
46
58
 
47
59
  def encoded_name
@@ -56,15 +68,17 @@ module WebsocketRails
56
68
  end
57
69
 
58
70
  def self.decode(encoded_data)
59
- message = JSON.parse( encoded_data )
60
- event_name = message[0]
61
- data = message[1]
71
+ message = JSON.parse( encoded_data )
72
+
73
+ channel_name = message.shift if message.size == 3
74
+ event_name = message[0]
75
+ data = message[1]
62
76
 
63
77
  namespace = event_name.split('.')
64
78
  event_name = namespace.pop
65
79
 
66
80
  data['received'] = Time.now if data.is_a?(Hash)
67
- [event_name,data,namespace]
81
+ [event_name, data, namespace, channel_name]
68
82
  end
69
83
 
70
84
  end
@@ -16,10 +16,10 @@ module WebsocketRails
16
16
  # # located in config/initializers/events.rb
17
17
  # WebsocketRails::EventMap.describe do
18
18
  # subscribe :client_connected, to: ChatController, with_method: :client_connected
19
- # subscribe :new_user, to: ChatController, with_method: :new_user
19
+ # subscribe :new_user, :to => ChatController, :with_method => :new_user
20
20
  #
21
21
  # namespace :product do
22
- # subscribe :new, to: ProductController, with_method: :new
22
+ # subscribe :new, :to => ProductController, :with_method => :new
23
23
  # end
24
24
  # end
25
25
  class EventMap
@@ -32,7 +32,8 @@ module WebsocketRails
32
32
 
33
33
  def initialize(dispatcher)
34
34
  @dispatcher = dispatcher
35
- @namespace = DSL.new.evaluate WebsocketRails.route_block, dispatcher
35
+ @namespace = DSL.new(dispatcher).evaluate WebsocketRails.route_block
36
+ @namespace = DSL.new(dispatcher,@namespace).evaluate InternalEvents.events
36
37
  end
37
38
 
38
39
  def routes_for(event, &block)
@@ -41,10 +42,17 @@ module WebsocketRails
41
42
 
42
43
  # Provides the DSL methods available to the Event routes file
43
44
  class DSL
45
+
46
+ def initialize(dispatcher,namespace=nil)
47
+ if namespace
48
+ @namespace = namespace
49
+ else
50
+ @namespace = Namespace.new :global, dispatcher
51
+ end
52
+ end
44
53
 
45
- def evaluate(route_block,dispatcher)
46
- @namespace = Namespace.new :global, dispatcher
47
- instance_eval &route_block
54
+ def evaluate(route_block)
55
+ instance_eval &route_block unless route_block.nil?
48
56
  @namespace
49
57
  end
50
58
 
@@ -0,0 +1,27 @@
1
+ class EventQueue
2
+
3
+ attr_reader :queue
4
+
5
+ def initialize
6
+ @queue = []
7
+ end
8
+
9
+ def enqueue(event)
10
+ @queue << event
11
+ end
12
+ alias :<< :enqueue
13
+
14
+ def last
15
+ @queue.last
16
+ end
17
+
18
+ def flush(&block)
19
+ unless block.nil?
20
+ @queue.each do |item|
21
+ block.call item
22
+ end
23
+ end
24
+ @queue = []
25
+ end
26
+
27
+ end
@@ -0,0 +1,19 @@
1
+ module WebsocketRails
2
+ class InternalEvents
3
+ def self.events
4
+ Proc.new do
5
+ namespace :websocket_rails do
6
+ subscribe :subscribe, :to => InternalController, :with_method => :subscribe_to_channel
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ class InternalController < BaseController
13
+ def subscribe_to_channel
14
+ puts "subscribed to: #{data[:channel]}"
15
+ channel_name = data[:channel]
16
+ WebsocketRails[channel_name].subscribe connection
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,3 @@
1
1
  module WebsocketRails
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
@@ -1,7 +1,7 @@
1
1
  WebsocketRails::EventMap.describe do
2
- subscribe :client_connected, to: ChatController, with_method: :client_connected
3
- subscribe :new_message, to: ChatController, with_method: :new_message
4
- subscribe :new_user, to: ChatController, with_method: :new_user
5
- subscribe :change_username, to: ChatController, with_method: :change_username
6
- subscribe :client_disconnected, to: ChatController, with_method: :delete_user
2
+ subscribe :client_connected, :to => ChatController, :with_method => :client_connected
3
+ subscribe :new_message, :to => ChatController, :with_method => :new_message
4
+ subscribe :new_user, :to => ChatController, :with_method => :new_user
5
+ subscribe :change_username, :to => ChatController, :with_method => :change_username
6
+ subscribe :client_disconnected, :to => ChatController, :with_method => :delete_user
7
7
  end
@@ -452,3 +452,183 @@ Connecting to database specified by database.yml
452
452
  Connecting to database specified by database.yml
453
453
  Connecting to database specified by database.yml
454
454
  Connecting to database specified by database.yml
455
+ Connecting to database specified by database.yml
456
+ Connecting to database specified by database.yml
457
+ Connecting to database specified by database.yml
458
+ Connecting to database specified by database.yml
459
+ Connecting to database specified by database.yml
460
+ Connecting to database specified by database.yml
461
+ Connecting to database specified by database.yml
462
+ Connecting to database specified by database.yml
463
+ Connecting to database specified by database.yml
464
+ Connecting to database specified by database.yml
465
+ Connecting to database specified by database.yml
466
+ Connecting to database specified by database.yml
467
+ Connecting to database specified by database.yml
468
+ Connecting to database specified by database.yml
469
+ Connecting to database specified by database.yml
470
+ Connecting to database specified by database.yml
471
+ Connecting to database specified by database.yml
472
+ Connecting to database specified by database.yml
473
+ Connecting to database specified by database.yml
474
+ Connecting to database specified by database.yml
475
+ Connecting to database specified by database.yml
476
+ Connecting to database specified by database.yml
477
+ Connecting to database specified by database.yml
478
+ Connecting to database specified by database.yml
479
+ Connecting to database specified by database.yml
480
+ Connecting to database specified by database.yml
481
+ Connecting to database specified by database.yml
482
+ Connecting to database specified by database.yml
483
+ Connecting to database specified by database.yml
484
+ Connecting to database specified by database.yml
485
+ Connecting to database specified by database.yml
486
+ Connecting to database specified by database.yml
487
+ Connecting to database specified by database.yml
488
+ Connecting to database specified by database.yml
489
+ Connecting to database specified by database.yml
490
+ Connecting to database specified by database.yml
491
+ Connecting to database specified by database.yml
492
+ Connecting to database specified by database.yml
493
+ Connecting to database specified by database.yml
494
+ Connecting to database specified by database.yml
495
+ Connecting to database specified by database.yml
496
+ Connecting to database specified by database.yml
497
+ Connecting to database specified by database.yml
498
+ Connecting to database specified by database.yml
499
+ Connecting to database specified by database.yml
500
+ Connecting to database specified by database.yml
501
+ Connecting to database specified by database.yml
502
+ Connecting to database specified by database.yml
503
+ Connecting to database specified by database.yml
504
+ Connecting to database specified by database.yml
505
+ Connecting to database specified by database.yml
506
+ Connecting to database specified by database.yml
507
+ Connecting to database specified by database.yml
508
+ Connecting to database specified by database.yml
509
+ Connecting to database specified by database.yml
510
+ Connecting to database specified by database.yml
511
+ Connecting to database specified by database.yml
512
+ Connecting to database specified by database.yml
513
+ Connecting to database specified by database.yml
514
+ Connecting to database specified by database.yml
515
+ Connecting to database specified by database.yml
516
+ Connecting to database specified by database.yml
517
+ Connecting to database specified by database.yml
518
+ Connecting to database specified by database.yml
519
+ Connecting to database specified by database.yml
520
+ Connecting to database specified by database.yml
521
+ Connecting to database specified by database.yml
522
+ Connecting to database specified by database.yml
523
+ Connecting to database specified by database.yml
524
+ Connecting to database specified by database.yml
525
+ Connecting to database specified by database.yml
526
+ Connecting to database specified by database.yml
527
+ Connecting to database specified by database.yml
528
+ Connecting to database specified by database.yml
529
+ Connecting to database specified by database.yml
530
+ Connecting to database specified by database.yml
531
+ Connecting to database specified by database.yml
532
+ Connecting to database specified by database.yml
533
+ Connecting to database specified by database.yml
534
+ Connecting to database specified by database.yml
535
+ Connecting to database specified by database.yml
536
+ Connecting to database specified by database.yml
537
+ Connecting to database specified by database.yml
538
+ Connecting to database specified by database.yml
539
+ Connecting to database specified by database.yml
540
+ Connecting to database specified by database.yml
541
+ Connecting to database specified by database.yml
542
+ Connecting to database specified by database.yml
543
+ Connecting to database specified by database.yml
544
+ Connecting to database specified by database.yml
545
+ Connecting to database specified by database.yml
546
+ Connecting to database specified by database.yml
547
+ Connecting to database specified by database.yml
548
+ Connecting to database specified by database.yml
549
+ Connecting to database specified by database.yml
550
+ Connecting to database specified by database.yml
551
+ Connecting to database specified by database.yml
552
+ Connecting to database specified by database.yml
553
+ Connecting to database specified by database.yml
554
+ Connecting to database specified by database.yml
555
+ Connecting to database specified by database.yml
556
+ Connecting to database specified by database.yml
557
+ Connecting to database specified by database.yml
558
+ Connecting to database specified by database.yml
559
+ Connecting to database specified by database.yml
560
+ Connecting to database specified by database.yml
561
+ Connecting to database specified by database.yml
562
+ Connecting to database specified by database.yml
563
+ Connecting to database specified by database.yml
564
+ Connecting to database specified by database.yml
565
+ Connecting to database specified by database.yml
566
+ Connecting to database specified by database.yml
567
+ Connecting to database specified by database.yml
568
+ Connecting to database specified by database.yml
569
+ Connecting to database specified by database.yml
570
+ Connecting to database specified by database.yml
571
+ Connecting to database specified by database.yml
572
+ Connecting to database specified by database.yml
573
+ Connecting to database specified by database.yml
574
+ Connecting to database specified by database.yml
575
+ Connecting to database specified by database.yml
576
+ Connecting to database specified by database.yml
577
+ Connecting to database specified by database.yml
578
+ Connecting to database specified by database.yml
579
+ Connecting to database specified by database.yml
580
+ Connecting to database specified by database.yml
581
+ Connecting to database specified by database.yml
582
+ Connecting to database specified by database.yml
583
+ Connecting to database specified by database.yml
584
+ Connecting to database specified by database.yml
585
+ Connecting to database specified by database.yml
586
+ Connecting to database specified by database.yml
587
+ Connecting to database specified by database.yml
588
+ Connecting to database specified by database.yml
589
+ Connecting to database specified by database.yml
590
+ Connecting to database specified by database.yml
591
+ Connecting to database specified by database.yml
592
+ Connecting to database specified by database.yml
593
+ Connecting to database specified by database.yml
594
+ Connecting to database specified by database.yml
595
+ Connecting to database specified by database.yml
596
+ Connecting to database specified by database.yml
597
+ Connecting to database specified by database.yml
598
+ Connecting to database specified by database.yml
599
+ Connecting to database specified by database.yml
600
+ Connecting to database specified by database.yml
601
+ Connecting to database specified by database.yml
602
+ Connecting to database specified by database.yml
603
+ Connecting to database specified by database.yml
604
+ Connecting to database specified by database.yml
605
+ Connecting to database specified by database.yml
606
+ Connecting to database specified by database.yml
607
+ Connecting to database specified by database.yml
608
+ Connecting to database specified by database.yml
609
+ Connecting to database specified by database.yml
610
+ Connecting to database specified by database.yml
611
+ Connecting to database specified by database.yml
612
+ Connecting to database specified by database.yml
613
+ Connecting to database specified by database.yml
614
+ Connecting to database specified by database.yml
615
+ Connecting to database specified by database.yml
616
+ Connecting to database specified by database.yml
617
+ Connecting to database specified by database.yml
618
+ Connecting to database specified by database.yml
619
+ Connecting to database specified by database.yml
620
+ Connecting to database specified by database.yml
621
+ Connecting to database specified by database.yml
622
+ Connecting to database specified by database.yml
623
+ Connecting to database specified by database.yml
624
+ Connecting to database specified by database.yml
625
+ Connecting to database specified by database.yml
626
+ Connecting to database specified by database.yml
627
+ Connecting to database specified by database.yml
628
+ Connecting to database specified by database.yml
629
+ Connecting to database specified by database.yml
630
+ Connecting to database specified by database.yml
631
+ Connecting to database specified by database.yml
632
+ Connecting to database specified by database.yml
633
+ Connecting to database specified by database.yml
634
+ Connecting to database specified by database.yml