amf_socket 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/Gemfile.lock +42 -1
- data/Guardfile +5 -0
- data/Rakefile +10 -5
- data/amf_socket.gemspec +7 -0
- data/lib/amf_socket/amf_rpc_connection.rb +61 -3
- data/lib/amf_socket/heartbeat.rb +51 -0
- data/lib/amf_socket/rpc_message.rb +7 -0
- data/lib/amf_socket/rpc_received_request.rb +2 -0
- data/lib/amf_socket/rpc_request.rb +38 -2
- data/lib/amf_socket/version.rb +1 -1
- data/lib/amf_socket.rb +32 -0
- data/spec/amf_socket/amf_connection_spec.rb +8 -0
- data/spec/amf_socket/amf_rpc_connection_spec.rb +196 -0
- data/spec/amf_socket/heartbeat_spec.rb +4 -0
- data/spec/amf_socket/rpc_message_spec.rb +29 -0
- data/spec/amf_socket/rpc_received_message_spec.rb +25 -0
- data/spec/amf_socket/rpc_received_request_spec.rb +35 -0
- data/spec/amf_socket/rpc_request_spec.rb +67 -0
- data/spec/amf_socket/rpc_response_spec.rb +20 -0
- data/spec/amf_socket/serializer_spec.rb +11 -0
- data/spec/amf_socket_spec.rb +7 -0
- data/spec/spec_helper.rb +30 -0
- metadata +126 -5
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
amf_socket (0.
|
4
|
+
amf_socket (0.3.0)
|
5
5
|
RocketAMF (>= 0.2.1)
|
6
6
|
eventmachine (>= 0.12.10)
|
7
7
|
|
@@ -9,10 +9,51 @@ GEM
|
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
11
|
RocketAMF (0.2.1)
|
12
|
+
columnize (0.3.6)
|
13
|
+
debugger (1.2.0)
|
14
|
+
columnize (>= 0.3.1)
|
15
|
+
debugger-linecache (~> 1.1.1)
|
16
|
+
debugger-ruby_core_source (~> 1.1.3)
|
17
|
+
debugger-linecache (1.1.2)
|
18
|
+
debugger-ruby_core_source (>= 1.1.1)
|
19
|
+
debugger-ruby_core_source (1.1.3)
|
20
|
+
diff-lcs (1.1.3)
|
12
21
|
eventmachine (0.12.10)
|
22
|
+
ffi (1.1.5)
|
23
|
+
growl (1.0.3)
|
24
|
+
guard (1.3.2)
|
25
|
+
listen (>= 0.4.2)
|
26
|
+
thor (>= 0.14.6)
|
27
|
+
guard-rspec (1.2.1)
|
28
|
+
guard (>= 1.1)
|
29
|
+
listen (0.4.7)
|
30
|
+
rb-fchange (~> 0.0.5)
|
31
|
+
rb-fsevent (~> 0.9.1)
|
32
|
+
rb-inotify (~> 0.8.8)
|
33
|
+
rake (0.9.2.2)
|
34
|
+
rb-fchange (0.0.5)
|
35
|
+
ffi
|
36
|
+
rb-fsevent (0.9.1)
|
37
|
+
rb-inotify (0.8.8)
|
38
|
+
ffi (>= 0.5.0)
|
39
|
+
rspec (2.11.0)
|
40
|
+
rspec-core (~> 2.11.0)
|
41
|
+
rspec-expectations (~> 2.11.0)
|
42
|
+
rspec-mocks (~> 2.11.0)
|
43
|
+
rspec-core (2.11.1)
|
44
|
+
rspec-expectations (2.11.2)
|
45
|
+
diff-lcs (~> 1.1.3)
|
46
|
+
rspec-mocks (2.11.2)
|
47
|
+
thor (0.16.0)
|
13
48
|
|
14
49
|
PLATFORMS
|
15
50
|
ruby
|
16
51
|
|
17
52
|
DEPENDENCIES
|
18
53
|
amf_socket!
|
54
|
+
debugger (= 1.2.0)
|
55
|
+
growl (= 1.0.3)
|
56
|
+
guard (= 1.3.2)
|
57
|
+
guard-rspec (= 1.2.1)
|
58
|
+
rake (= 0.9.2.2)
|
59
|
+
rspec (= 2.11.0)
|
data/Guardfile
ADDED
data/Rakefile
CHANGED
@@ -3,11 +3,6 @@
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'bundler/gem_tasks'
|
5
5
|
|
6
|
-
begin
|
7
|
-
require 'debugger'
|
8
|
-
rescue Exception
|
9
|
-
end
|
10
|
-
|
11
6
|
begin
|
12
7
|
Bundler.setup(:default, :development)
|
13
8
|
rescue Bundler::BundlerError => e
|
@@ -16,6 +11,8 @@ rescue Bundler::BundlerError => e
|
|
16
11
|
exit e.status_code
|
17
12
|
end
|
18
13
|
|
14
|
+
require 'debugger'
|
15
|
+
|
19
16
|
task :environment do
|
20
17
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
21
18
|
require 'amf_socket'
|
@@ -30,6 +27,14 @@ task :console => :environment do
|
|
30
27
|
IRB.start
|
31
28
|
end
|
32
29
|
|
30
|
+
desc 'Run all specs'
|
31
|
+
task :spec do
|
32
|
+
puts 'Running rspec:'
|
33
|
+
system 'rspec spec'
|
34
|
+
end
|
35
|
+
|
36
|
+
task :default => :spec
|
37
|
+
|
33
38
|
desc 'Start a test server'
|
34
39
|
task :harness => :environment do
|
35
40
|
EM.run do
|
data/amf_socket.gemspec
CHANGED
@@ -17,4 +17,11 @@ Gem::Specification.new do |gem|
|
|
17
17
|
|
18
18
|
gem.add_dependency('eventmachine', ['>= 0.12.10'])
|
19
19
|
gem.add_dependency('RocketAMF', ['>= 0.2.1'])
|
20
|
+
|
21
|
+
gem.add_development_dependency('rake', ['= 0.9.2.2'])
|
22
|
+
gem.add_development_dependency('rspec', ['= 2.11.0'])
|
23
|
+
gem.add_development_dependency('guard', ['= 1.3.2'])
|
24
|
+
gem.add_development_dependency('guard-rspec', ['= 1.2.1'])
|
25
|
+
gem.add_development_dependency('growl', ['= 1.0.3'])
|
26
|
+
gem.add_development_dependency('debugger', ['= 1.2.0'])
|
20
27
|
end
|
@@ -1,14 +1,20 @@
|
|
1
1
|
class AmfSocket::AmfRpcConnection < AmfSocket::AmfConnection
|
2
|
+
PING_INTERVAL = 5 # Seconds.
|
3
|
+
|
4
|
+
attr_reader :latency
|
5
|
+
|
2
6
|
def send_request(command, params = {}, &block)
|
3
7
|
request = AmfSocket::RpcRequest.new(command, params)
|
4
8
|
block.call(request)
|
5
9
|
@sent_requests[request.message_id] = request
|
6
10
|
send_object(request.to_hash)
|
11
|
+
request.send(:sent)
|
7
12
|
end
|
8
13
|
|
9
14
|
def send_message(command, params = {})
|
10
15
|
message = AmfSocket::RpcMessage.new(command, params)
|
11
16
|
send_object(message.to_hash)
|
17
|
+
message.send(:sent)
|
12
18
|
end
|
13
19
|
|
14
20
|
#
|
@@ -17,7 +23,11 @@ class AmfSocket::AmfRpcConnection < AmfSocket::AmfConnection
|
|
17
23
|
|
18
24
|
def post_init
|
19
25
|
super
|
26
|
+
|
20
27
|
@sent_requests = {}
|
28
|
+
@next_ping = Time.now.utc
|
29
|
+
|
30
|
+
AmfSocket.heartbeat.add(self)
|
21
31
|
end
|
22
32
|
|
23
33
|
def receive_object(object)
|
@@ -42,6 +52,8 @@ class AmfSocket::AmfRpcConnection < AmfSocket::AmfConnection
|
|
42
52
|
end
|
43
53
|
|
44
54
|
def unbind
|
55
|
+
AmfSocket.heartbeat.remove(self)
|
56
|
+
|
45
57
|
@sent_requests.each do |message_id, request|
|
46
58
|
if request.failed_callback.is_a?(Proc)
|
47
59
|
request.failed_callback.call('disconnected')
|
@@ -66,13 +78,59 @@ class AmfSocket::AmfRpcConnection < AmfSocket::AmfConnection
|
|
66
78
|
|
67
79
|
def receive_response(response_object)
|
68
80
|
raise AmfSocket::InvalidObject unless (message_id = response_object[:response][:messageId])
|
69
|
-
|
81
|
+
|
82
|
+
return unless (request = @sent_requests[message_id]) # Ignore timed out requests.
|
70
83
|
|
71
84
|
response = AmfSocket::RpcResponse.new(request, response_object)
|
72
85
|
@sent_requests.delete(message_id)
|
73
86
|
|
74
|
-
|
75
|
-
request.succeeded_callback.
|
87
|
+
AmfSocket.try do
|
88
|
+
if request.succeeded_callback.is_a?(Proc)
|
89
|
+
request.succeeded_callback.call(response)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def heartbeat
|
95
|
+
timeout_requests
|
96
|
+
ping
|
97
|
+
end
|
98
|
+
|
99
|
+
#
|
100
|
+
# Private Methods.
|
101
|
+
#
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def timeout_requests
|
106
|
+
@sent_requests.each do |message_id, request|
|
107
|
+
if request.timed_out?
|
108
|
+
AmfSocket.try do
|
109
|
+
if request.failed_callback.is_a?(Proc)
|
110
|
+
request.failed_callback.call('timed_out')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
@sent_requests.delete(message_id)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def ping
|
120
|
+
return if @next_ping > Time.now.utc
|
121
|
+
|
122
|
+
send_request('amf_socket_ping', :time => Time.now.utc, :latency => @latency.to_f) do |request|
|
123
|
+
@next_ping = Time.now.utc + PING_INTERVAL
|
124
|
+
|
125
|
+
request.timeout = 10
|
126
|
+
|
127
|
+
request.succeeded do |response|
|
128
|
+
@latency = Time.now.utc - request.sent_at
|
129
|
+
end
|
130
|
+
|
131
|
+
request.failed do |reason|
|
132
|
+
close_connection if reason == 'timed_out'
|
133
|
+
end
|
76
134
|
end
|
77
135
|
end
|
78
136
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class AmfSocket::Heartbeat
|
2
|
+
INTERVAL = 1 # Seconds.
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@objects = Set.new
|
6
|
+
start unless AmfSocket.test_mode?
|
7
|
+
end
|
8
|
+
|
9
|
+
def start
|
10
|
+
return false unless @timer.nil?
|
11
|
+
|
12
|
+
@timer = EM::PeriodicTimer.new(INTERVAL, method(:timer_handler))
|
13
|
+
|
14
|
+
return true
|
15
|
+
end
|
16
|
+
|
17
|
+
def stop
|
18
|
+
return false unless @timer
|
19
|
+
|
20
|
+
@timer.cancel
|
21
|
+
@timer = nil
|
22
|
+
|
23
|
+
return true
|
24
|
+
end
|
25
|
+
|
26
|
+
def add(object)
|
27
|
+
return false if @objects.include?(object)
|
28
|
+
|
29
|
+
@objects.add(object)
|
30
|
+
|
31
|
+
return true
|
32
|
+
end
|
33
|
+
|
34
|
+
def remove(object)
|
35
|
+
return false unless @objects.include?(object)
|
36
|
+
|
37
|
+
@objects.delete(object)
|
38
|
+
|
39
|
+
return true
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def timer_handler
|
45
|
+
@objects.each do |object|
|
46
|
+
AmfSocket.try do
|
47
|
+
object.send(:heartbeat) if object.respond_to?(:heartbeat, true)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -2,6 +2,7 @@ class AmfSocket::RpcMessage
|
|
2
2
|
attr_reader :message_id
|
3
3
|
attr_reader :command
|
4
4
|
attr_reader :params
|
5
|
+
attr_reader :sent_at
|
5
6
|
|
6
7
|
def initialize(command, params = {})
|
7
8
|
raise AmfSocket::InvalidArg.new('Command must be a String.') unless command.is_a?(String)
|
@@ -23,4 +24,10 @@ class AmfSocket::RpcMessage
|
|
23
24
|
|
24
25
|
return object
|
25
26
|
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def sent
|
31
|
+
@sent_at = Time.now.utc
|
32
|
+
end
|
26
33
|
end
|
@@ -1,12 +1,15 @@
|
|
1
1
|
class AmfSocket::RpcRequest
|
2
|
-
attr_reader :state # Valid states: :initialized, :sent, :responded.
|
2
|
+
attr_reader :state # Valid states: :initialized, :sent, :responded, :failed.
|
3
3
|
attr_reader :message_id
|
4
4
|
attr_reader :command
|
5
5
|
attr_reader :params
|
6
|
+
attr_reader :sent_at
|
7
|
+
attr_reader :timeout_at
|
6
8
|
|
7
9
|
attr_accessor :succeeded_callback
|
8
10
|
attr_accessor :failed_callback
|
9
|
-
|
11
|
+
|
12
|
+
TIMEOUT = 30 # Seconds.
|
10
13
|
|
11
14
|
def initialize(command, params = {})
|
12
15
|
raise AmfSocket::InvalidArg.new('Command must be a String.') unless command.is_a?(String)
|
@@ -16,13 +19,18 @@ class AmfSocket::RpcRequest
|
|
16
19
|
@params = params
|
17
20
|
@state = :initialized
|
18
21
|
@message_id = SecureRandom.hex
|
22
|
+
@timeout = TIMEOUT
|
19
23
|
end
|
20
24
|
|
21
25
|
def succeeded(&block)
|
26
|
+
require_state(:initialized)
|
27
|
+
|
22
28
|
@succeeded_callback = block
|
23
29
|
end
|
24
30
|
|
25
31
|
def failed(&block)
|
32
|
+
require_state(:initialized)
|
33
|
+
|
26
34
|
@failed_callback = block
|
27
35
|
end
|
28
36
|
|
@@ -37,4 +45,32 @@ class AmfSocket::RpcRequest
|
|
37
45
|
|
38
46
|
return object
|
39
47
|
end
|
48
|
+
|
49
|
+
def timeout=(seconds)
|
50
|
+
require_state(:initialized)
|
51
|
+
|
52
|
+
@timeout = seconds
|
53
|
+
end
|
54
|
+
|
55
|
+
def timeout
|
56
|
+
return @timeout
|
57
|
+
end
|
58
|
+
|
59
|
+
def timed_out?
|
60
|
+
return Time.now.utc >= @timeout_at
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def sent
|
66
|
+
require_state(:initialized)
|
67
|
+
|
68
|
+
@state = :sent
|
69
|
+
@sent_at = Time.now.utc
|
70
|
+
@timeout_at = @sent_at + timeout
|
71
|
+
end
|
72
|
+
|
73
|
+
def require_state(s)
|
74
|
+
raise 'Invalid state' unless @state == s
|
75
|
+
end
|
40
76
|
end
|
data/lib/amf_socket/version.rb
CHANGED
data/lib/amf_socket.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'eventmachine'
|
2
2
|
require 'rocketamf'
|
3
3
|
require 'securerandom'
|
4
|
+
require 'thread'
|
4
5
|
|
5
6
|
module AmfSocket; end
|
6
7
|
|
@@ -14,3 +15,34 @@ require 'amf_socket/rpc_received_request'
|
|
14
15
|
require 'amf_socket/rpc_received_message'
|
15
16
|
require 'amf_socket/serializer'
|
16
17
|
require 'amf_socket/exceptions'
|
18
|
+
require 'amf_socket/heartbeat'
|
19
|
+
|
20
|
+
module AmfSocket
|
21
|
+
def self.heartbeat
|
22
|
+
@heartbeat ||= AmfSocket::Heartbeat.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.exception_handler=(handler)
|
26
|
+
@exception_handler = handler
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.exception_handler
|
30
|
+
return @exception_handler
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.try(&block)
|
34
|
+
begin
|
35
|
+
block.call
|
36
|
+
rescue Exception => e
|
37
|
+
@exception_handler.call(e) if @exception_handler
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.enable_test_mode
|
42
|
+
@test_mode = true
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.test_mode?
|
46
|
+
return !!@test_mode
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class AmfRpcConnTestable < AmfSocket::AmfRpcConnection
|
4
|
+
attr_accessor :sent_requests
|
5
|
+
attr_accessor :sent_objects
|
6
|
+
attr_accessor :received_requests
|
7
|
+
attr_accessor :received_messages
|
8
|
+
|
9
|
+
def self.new
|
10
|
+
allocate.instance_eval do
|
11
|
+
initialize
|
12
|
+
post_init
|
13
|
+
self
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@sent_objects = []
|
19
|
+
@received_requests = []
|
20
|
+
@received_messages = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def send_object(object)
|
24
|
+
@sent_objects << object
|
25
|
+
end
|
26
|
+
|
27
|
+
def receive_request(request)
|
28
|
+
@received_requests << request
|
29
|
+
end
|
30
|
+
|
31
|
+
def receive_message(message)
|
32
|
+
@received_messages << message
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe AmfSocket::AmfRpcConnection do
|
37
|
+
context 'when sending requests' do
|
38
|
+
before(:each) do
|
39
|
+
@conn = AmfRpcConnTestable.new
|
40
|
+
@command = 'hello'
|
41
|
+
@params = { :foo => 'bar' }
|
42
|
+
@request = AmfSocket::RpcRequest.new(@command, @params)
|
43
|
+
@flag = false
|
44
|
+
@block = proc do |request|
|
45
|
+
@flag = true
|
46
|
+
@block_arg = request
|
47
|
+
end
|
48
|
+
|
49
|
+
AmfSocket::RpcRequest.should_receive(:new).with(@command, @params).and_return(@request)
|
50
|
+
|
51
|
+
@conn.send_request(@command, @params) { |request| @block.call(request) }
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should send the request as a simple hash object' do
|
55
|
+
@conn.sent_objects.first.should == @request.to_hash
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should execute the block and pass it a request object' do
|
59
|
+
@flag.should == true
|
60
|
+
@block_arg.class.should == AmfSocket::RpcRequest
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should register the request in order to handle the response' do
|
64
|
+
@conn.sent_requests.first[0].should == @request.message_id
|
65
|
+
@conn.sent_requests.first[1].should == @request
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when sending messages' do
|
70
|
+
before(:each) do
|
71
|
+
@conn = AmfRpcConnTestable.new
|
72
|
+
@command = 'hello'
|
73
|
+
@params = { :foo => 'bar' }
|
74
|
+
@message = AmfSocket::RpcMessage.new(@command, @params)
|
75
|
+
|
76
|
+
AmfSocket::RpcMessage.should_receive(:new).with(@command, @params).and_return(@message)
|
77
|
+
|
78
|
+
@conn.send_message(@command, @params)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should send the message as a simple hash object' do
|
82
|
+
@conn.sent_objects.first.should == @message.to_hash
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when receiving objects' do
|
87
|
+
before(:each) do
|
88
|
+
@conn = AmfRpcConnTestable.new
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should handle received requests' do
|
92
|
+
object = {
|
93
|
+
:type => 'rpcRequest',
|
94
|
+
:request => {
|
95
|
+
:messageId => '123',
|
96
|
+
:command => 'hello',
|
97
|
+
:params => {
|
98
|
+
:foo => 'bar'
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
@conn.receive_object(object)
|
104
|
+
|
105
|
+
@conn.received_requests.length.should == 1
|
106
|
+
|
107
|
+
request = @conn.received_requests.first
|
108
|
+
|
109
|
+
request.class.should == AmfSocket::RpcReceivedRequest
|
110
|
+
request.message_id.should == '123'
|
111
|
+
request.command.should == 'hello'
|
112
|
+
request.params.should == { :foo => 'bar' }
|
113
|
+
request.connection.should == @conn
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should handle recevied messages' do
|
117
|
+
object = {
|
118
|
+
:type => 'rpcMessage',
|
119
|
+
:message => {
|
120
|
+
:messageId => '123',
|
121
|
+
:command => 'hello',
|
122
|
+
:params => {
|
123
|
+
:foo => 'bar'
|
124
|
+
}
|
125
|
+
}
|
126
|
+
}
|
127
|
+
|
128
|
+
@conn.receive_object(object)
|
129
|
+
|
130
|
+
@conn.received_messages.length.should == 1
|
131
|
+
|
132
|
+
message = @conn.received_messages.first
|
133
|
+
|
134
|
+
message.class.should == AmfSocket::RpcReceivedMessage
|
135
|
+
message.message_id.should == '123'
|
136
|
+
message.command.should == 'hello'
|
137
|
+
message.params.should == { :foo => 'bar' }
|
138
|
+
message.connection.should == @conn
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should handle responses for sent requests' do
|
142
|
+
flag = false
|
143
|
+
req = nil
|
144
|
+
res = nil
|
145
|
+
|
146
|
+
@conn.send_request('hello', :foo => 'bar') do |request|
|
147
|
+
req = request
|
148
|
+
|
149
|
+
request.succeeded do |response|
|
150
|
+
flag = true
|
151
|
+
res = response
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
object = {
|
156
|
+
:type => 'rpcResponse',
|
157
|
+
:response => {
|
158
|
+
:messageId => req.message_id,
|
159
|
+
:result => 'happy ending'
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
@conn.receive_object(object)
|
164
|
+
|
165
|
+
flag.should == true
|
166
|
+
res.result.should == 'happy ending'
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'when a socket gets disconnected' do
|
171
|
+
before(:each) do
|
172
|
+
@conn = AmfRpcConnTestable.new
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'should trigger failure on app pending requests' do
|
176
|
+
flag = false
|
177
|
+
req = nil
|
178
|
+
reas = nil
|
179
|
+
|
180
|
+
@conn.send_request('hello', :foo => 'bar') do |request|
|
181
|
+
req = request
|
182
|
+
|
183
|
+
request.failed do |reason|
|
184
|
+
flag = true
|
185
|
+
reas = reason
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
@conn.unbind
|
190
|
+
|
191
|
+
flag.should == true
|
192
|
+
reas.should == 'disconnected'
|
193
|
+
@conn.sent_requests.length.should == 0
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AmfSocket::RpcMessage do
|
4
|
+
it 'should construct properly' do
|
5
|
+
SecureRandom.should_receive(:hex).and_return('random id')
|
6
|
+
|
7
|
+
message = AmfSocket::RpcMessage.new('hello', :foo => 'bar')
|
8
|
+
|
9
|
+
message.message_id.should == 'random id'
|
10
|
+
message.command.should == 'hello'
|
11
|
+
message.params.should == { :foo => 'bar' }
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should convert to a hash' do
|
15
|
+
message = AmfSocket::RpcMessage.new('hello', :foo => 'bar')
|
16
|
+
|
17
|
+
expected = {
|
18
|
+
:type => 'rpcMessage',
|
19
|
+
:message => {
|
20
|
+
:messageId => message.message_id,
|
21
|
+
:command => 'hello',
|
22
|
+
:params => { :foo => 'bar'
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
message.to_hash.should == expected
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AmfSocket::RpcReceivedMessage do
|
4
|
+
it 'should construct properly' do
|
5
|
+
object = {
|
6
|
+
:type => 'rpcMessage',
|
7
|
+
:message => {
|
8
|
+
:messageId => 'random id',
|
9
|
+
:command => 'hello',
|
10
|
+
:params => {
|
11
|
+
:foo => 'bar'
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
conn = stub
|
17
|
+
|
18
|
+
message = AmfSocket::RpcReceivedMessage.new(object, conn)
|
19
|
+
|
20
|
+
message.connection.should == conn
|
21
|
+
message.message_id.should == 'random id'
|
22
|
+
message.command.should == 'hello'
|
23
|
+
message.params.should == { :foo => 'bar' }
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AmfSocket::RpcReceivedRequest do
|
4
|
+
before(:each) do
|
5
|
+
@object = {
|
6
|
+
:type => 'rpcRequest',
|
7
|
+
:request => {
|
8
|
+
:messageId => 'random id',
|
9
|
+
:command => 'hello',
|
10
|
+
:params => {
|
11
|
+
:foo => 'bar'
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
@conn = stub
|
17
|
+
|
18
|
+
@request = AmfSocket::RpcReceivedRequest.new(@object, @conn)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should construct properly' do
|
22
|
+
@request.state.should == :initialized
|
23
|
+
@request.connection.should == @conn
|
24
|
+
@request.message_id.should == 'random id'
|
25
|
+
@request.command.should == 'hello'
|
26
|
+
@request.params.should == { :foo => 'bar' }
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should reply properly' do
|
30
|
+
@conn.should_receive(:send_object).exactly(:once)
|
31
|
+
@request.reply('foo bar').should == true
|
32
|
+
@request.state.should == :replied
|
33
|
+
@request.reply('foo bar again').should == false
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AmfSocket::RpcRequest do
|
4
|
+
it 'should construct properly' do
|
5
|
+
SecureRandom.should_receive(:hex).and_return('random id')
|
6
|
+
|
7
|
+
request = AmfSocket::RpcRequest.new('hello', :foo => 'bar')
|
8
|
+
|
9
|
+
request.message_id.should == 'random id'
|
10
|
+
request.command.should == 'hello'
|
11
|
+
request.params.should == { :foo => 'bar' }
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should convert to a hash' do
|
15
|
+
request = AmfSocket::RpcRequest.new('hello', :foo => 'bar')
|
16
|
+
|
17
|
+
expected = {
|
18
|
+
:type=> 'rpcRequest',
|
19
|
+
:request => {
|
20
|
+
:messageId => request.message_id,
|
21
|
+
:command => 'hello',
|
22
|
+
:params=> { :foo => 'bar'
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
request.to_hash.should == expected
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should store the succeeded callback' do
|
31
|
+
request = AmfSocket::RpcRequest.new('hello', :foo => 'bar')
|
32
|
+
|
33
|
+
flag = false
|
34
|
+
|
35
|
+
request.succeeded { flag = true }
|
36
|
+
request.succeeded_callback.call
|
37
|
+
|
38
|
+
flag.should == true
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should store the failed callback' do
|
42
|
+
request = AmfSocket::RpcRequest.new('hello', :foo => 'bar')
|
43
|
+
|
44
|
+
flag = false
|
45
|
+
|
46
|
+
request.failed { flag = true }
|
47
|
+
request.failed_callback.call
|
48
|
+
|
49
|
+
flag.should == true
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should convert to a hash' do
|
53
|
+
message = AmfSocket::RpcRequest.new('hello', :foo => 'bar')
|
54
|
+
|
55
|
+
expected = {
|
56
|
+
:type => 'rpcRequest',
|
57
|
+
:request => {
|
58
|
+
:messageId => message.message_id,
|
59
|
+
:command => 'hello',
|
60
|
+
:params => { :foo => 'bar'
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
message.to_hash.should == expected
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AmfSocket::RpcResponse do
|
4
|
+
it 'should construct properly' do
|
5
|
+
request = stub
|
6
|
+
|
7
|
+
response_object = {
|
8
|
+
:type => 'rpcResponse',
|
9
|
+
:response => {
|
10
|
+
:messageId => 'random id',
|
11
|
+
:result => 'foobar'
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
response = AmfSocket::RpcResponse.new(request, response_object)
|
16
|
+
|
17
|
+
response.request.should == request
|
18
|
+
response.result.should == 'foobar'
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AmfSocket::Serializer do
|
4
|
+
it 'should dump an object to AMF format' do
|
5
|
+
AmfSocket::Serializer.dump({ :foo => 'bar' }).should == "\n\v\x01\afoo\x06\abar\x01"
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should load an object from AMF format' do
|
9
|
+
AmfSocket::Serializer.load("\n\v\x01\afoo\x06\abar\x01").should == { :foo => 'bar' }
|
10
|
+
end
|
11
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'bundler'
|
6
|
+
require 'debugger'
|
7
|
+
|
8
|
+
begin
|
9
|
+
Bundler.setup(:default, :development)
|
10
|
+
rescue Bundler::BundlerError => e
|
11
|
+
$stderr.puts(e.message)
|
12
|
+
$stderr.puts("Run `bundle install` to install missing gems")
|
13
|
+
exit e.status_code
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'benchmark'
|
17
|
+
require 'amf_socket'
|
18
|
+
|
19
|
+
AmfSocket.enable_test_mode
|
20
|
+
|
21
|
+
AmfSocket.exception_handler do |ue|
|
22
|
+
puts "UNHANDLED EXCEPTION #{ue.class} (#{ue.message.chomp})\n#{ue.backtrace.join("\n")}\n--"
|
23
|
+
end
|
24
|
+
|
25
|
+
# Requires supporting files with custom matchers and macros, etc,
|
26
|
+
# in ./support/ and its subdirectories.
|
27
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
28
|
+
|
29
|
+
RSpec.configure do |config|
|
30
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amf_socket
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-09-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: eventmachine
|
@@ -43,6 +43,102 @@ dependencies:
|
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: 0.2.1
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - '='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.9.2.2
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.9.2.2
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - '='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 2.11.0
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - '='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.11.0
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: guard
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - '='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.3.2
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - '='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.3.2
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: guard-rspec
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - '='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.2.1
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - '='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.2.1
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: growl
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - '='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.0.3
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - '='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 1.0.3
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: debugger
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - '='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 1.2.0
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - '='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 1.2.0
|
46
142
|
description: Ruby implementation of AMF Socket (https://github.com/chadrem/amf_socket)
|
47
143
|
email:
|
48
144
|
- chad@remesch.com
|
@@ -51,8 +147,10 @@ extensions: []
|
|
51
147
|
extra_rdoc_files: []
|
52
148
|
files:
|
53
149
|
- .gitignore
|
150
|
+
- .rspec
|
54
151
|
- Gemfile
|
55
152
|
- Gemfile.lock
|
153
|
+
- Guardfile
|
56
154
|
- LICENSE.txt
|
57
155
|
- README.md
|
58
156
|
- Rakefile
|
@@ -61,6 +159,7 @@ files:
|
|
61
159
|
- lib/amf_socket/amf_connection.rb
|
62
160
|
- lib/amf_socket/amf_rpc_connection.rb
|
63
161
|
- lib/amf_socket/exceptions.rb
|
162
|
+
- lib/amf_socket/heartbeat.rb
|
64
163
|
- lib/amf_socket/rpc_message.rb
|
65
164
|
- lib/amf_socket/rpc_received_message.rb
|
66
165
|
- lib/amf_socket/rpc_received_request.rb
|
@@ -68,6 +167,17 @@ files:
|
|
68
167
|
- lib/amf_socket/rpc_response.rb
|
69
168
|
- lib/amf_socket/serializer.rb
|
70
169
|
- lib/amf_socket/version.rb
|
170
|
+
- spec/amf_socket/amf_connection_spec.rb
|
171
|
+
- spec/amf_socket/amf_rpc_connection_spec.rb
|
172
|
+
- spec/amf_socket/heartbeat_spec.rb
|
173
|
+
- spec/amf_socket/rpc_message_spec.rb
|
174
|
+
- spec/amf_socket/rpc_received_message_spec.rb
|
175
|
+
- spec/amf_socket/rpc_received_request_spec.rb
|
176
|
+
- spec/amf_socket/rpc_request_spec.rb
|
177
|
+
- spec/amf_socket/rpc_response_spec.rb
|
178
|
+
- spec/amf_socket/serializer_spec.rb
|
179
|
+
- spec/amf_socket_spec.rb
|
180
|
+
- spec/spec_helper.rb
|
71
181
|
homepage: https://github.com/chadrem/observation
|
72
182
|
licenses: []
|
73
183
|
post_install_message:
|
@@ -82,7 +192,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
82
192
|
version: '0'
|
83
193
|
segments:
|
84
194
|
- 0
|
85
|
-
hash: -
|
195
|
+
hash: -2517453312073385127
|
86
196
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
197
|
none: false
|
88
198
|
requirements:
|
@@ -91,7 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
201
|
version: '0'
|
92
202
|
segments:
|
93
203
|
- 0
|
94
|
-
hash: -
|
204
|
+
hash: -2517453312073385127
|
95
205
|
requirements: []
|
96
206
|
rubyforge_project:
|
97
207
|
rubygems_version: 1.8.24
|
@@ -99,4 +209,15 @@ signing_key:
|
|
99
209
|
specification_version: 3
|
100
210
|
summary: AMF Socket is a bi-directional RPC system for Adobe Flash (Actionscript)
|
101
211
|
programs.
|
102
|
-
test_files:
|
212
|
+
test_files:
|
213
|
+
- spec/amf_socket/amf_connection_spec.rb
|
214
|
+
- spec/amf_socket/amf_rpc_connection_spec.rb
|
215
|
+
- spec/amf_socket/heartbeat_spec.rb
|
216
|
+
- spec/amf_socket/rpc_message_spec.rb
|
217
|
+
- spec/amf_socket/rpc_received_message_spec.rb
|
218
|
+
- spec/amf_socket/rpc_received_request_spec.rb
|
219
|
+
- spec/amf_socket/rpc_request_spec.rb
|
220
|
+
- spec/amf_socket/rpc_response_spec.rb
|
221
|
+
- spec/amf_socket/serializer_spec.rb
|
222
|
+
- spec/amf_socket_spec.rb
|
223
|
+
- spec/spec_helper.rb
|