mrpin-rocketamf 1.0.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.rdoc +1 -1
  3. data/Rakefile +7 -7
  4. data/benchmark.rb +44 -37
  5. data/ext/rocketamf_ext/class_mapping.c +11 -11
  6. data/ext/rocketamf_ext/remoting.c +1 -1
  7. data/lib/rocketamf.rb +41 -98
  8. data/lib/rocketamf/constants.rb +20 -20
  9. data/lib/rocketamf/errors.rb +2 -0
  10. data/lib/rocketamf/errors/amf_error.rb +5 -0
  11. data/lib/rocketamf/errors/amf_error_incomplete.rb +5 -0
  12. data/lib/rocketamf/ext.rb +0 -6
  13. data/lib/rocketamf/extensions.rb +4 -4
  14. data/lib/rocketamf/{class_mapping.rb → mapping/class_mapping.rb} +70 -103
  15. data/lib/rocketamf/mapping/mapping_set.rb +63 -0
  16. data/lib/rocketamf/pure.rb +1 -9
  17. data/lib/rocketamf/pure/deserializer.rb +234 -262
  18. data/lib/rocketamf/pure/helpers/io_helper_base.rb +19 -0
  19. data/lib/rocketamf/pure/helpers/io_helper_read.rb +67 -0
  20. data/lib/rocketamf/pure/helpers/io_helper_write.rb +48 -0
  21. data/lib/rocketamf/pure/helpers/object_cache.rb +20 -0
  22. data/lib/rocketamf/pure/helpers/string_cache.rb +14 -0
  23. data/lib/rocketamf/pure/serializer.rb +138 -271
  24. data/lib/rocketamf/types.rb +1 -0
  25. data/lib/rocketamf/{values → types}/typed_hash.rb +12 -2
  26. data/mrpin-rocketamf.gemspec +27 -16
  27. data/spec/class_mapping_spec.rb +59 -52
  28. data/spec/deserializer_spec.rb +164 -328
  29. data/spec/fast_class_mapping_spec.rb +52 -46
  30. data/spec/helpers/class_mapping_test.rb +4 -0
  31. data/spec/helpers/class_mapping_test2.rb +3 -0
  32. data/spec/helpers/externalizable_test.rb +24 -0
  33. data/spec/helpers/fixtures.rb +28 -0
  34. data/spec/helpers/other_class.rb +4 -0
  35. data/spec/helpers/ruby_class.rb +4 -0
  36. data/spec/helpers/test_ruby_class.rb +4 -0
  37. data/spec/serializer_spec.rb +248 -339
  38. data/spec/spec_helper.rb +4 -49
  39. metadata +47 -53
  40. data/lib/rocketamf/pure/io_helpers.rb +0 -94
  41. data/lib/rocketamf/pure/remoting.rb +0 -117
  42. data/lib/rocketamf/remoting.rb +0 -196
  43. data/lib/rocketamf/values/messages.rb +0 -214
  44. data/spec/fixtures/objects/amf0-boolean.bin +0 -1
  45. data/spec/fixtures/objects/amf0-complex-encoded-string.bin +0 -0
  46. data/spec/fixtures/objects/amf0-date.bin +0 -0
  47. data/spec/fixtures/objects/amf0-ecma-ordinal-array.bin +0 -0
  48. data/spec/fixtures/objects/amf0-empty-string-key-hash.bin +0 -0
  49. data/spec/fixtures/objects/amf0-hash.bin +0 -0
  50. data/spec/fixtures/objects/amf0-null.bin +0 -1
  51. data/spec/fixtures/objects/amf0-number.bin +0 -0
  52. data/spec/fixtures/objects/amf0-object.bin +0 -0
  53. data/spec/fixtures/objects/amf0-ref-test.bin +0 -0
  54. data/spec/fixtures/objects/amf0-strict-array.bin +0 -0
  55. data/spec/fixtures/objects/amf0-string.bin +0 -0
  56. data/spec/fixtures/objects/amf0-time.bin +0 -0
  57. data/spec/fixtures/objects/amf0-typed-object.bin +0 -0
  58. data/spec/fixtures/objects/amf0-undefined.bin +0 -1
  59. data/spec/fixtures/objects/amf0-untyped-object.bin +0 -0
  60. data/spec/fixtures/objects/amf0-xml-doc.bin +0 -0
  61. data/spec/messages_spec.rb +0 -39
  62. data/spec/remoting_spec.rb +0 -196
@@ -1,214 +0,0 @@
1
- module RocketAMF
2
- module Values #:nodoc:
3
- # Base class for all special AS3 response messages. Maps to
4
- # <tt>flex.messaging.messages.AbstractMessage</tt>.
5
- class AbstractMessage
6
- EXTERNALIZABLE_FIELDS = [
7
- %w[ body clientId destination headers messageId timestamp timeToLive ],
8
- %w[ clientIdBytes messageIdBytes ]
9
- ]
10
- attr_accessor :clientId
11
- attr_accessor :destination
12
- attr_accessor :messageId
13
- attr_accessor :timestamp
14
- attr_accessor :timeToLive
15
- attr_accessor :headers
16
- attr_accessor :body
17
-
18
- def clientIdBytes= bytes
19
- @clientId = pretty_uuid(bytes) unless bytes.nil?
20
- end
21
-
22
- def messageIdBytes= bytes
23
- @messageId = pretty_uuid(bytes) unless bytes.nil?
24
- end
25
-
26
- def read_external des
27
- read_external_fields des, EXTERNALIZABLE_FIELDS
28
- end
29
-
30
- private
31
- def rand_uuid
32
- [8,4,4,4,12].map {|n| rand_hex_3(n)}.join('-').to_s
33
- end
34
-
35
- def rand_hex_3(l)
36
- "%0#{l}x" % rand(1 << l*4)
37
- end
38
-
39
- def pretty_uuid bytes
40
- "%08x-%04x-%04x-%04x-%08x%04x" % bytes.string.unpack("NnnnNn")
41
- end
42
-
43
- def read_external_fields des, fields
44
- # Read flags
45
- flags = []
46
- loop do
47
- flags << des.source.read(1).unpack('C').first
48
- break if flags.last < 128
49
- end
50
-
51
- # Read fields and any remaining unmapped fields in a byte-set
52
- fields.each_with_index do |list, i|
53
- break if flags[i].nil?
54
-
55
- list.each_with_index do |name, j|
56
- if flags[i] & 2**j != 0
57
- send("#{name}=", des.read_object)
58
- end
59
- end
60
-
61
- # Read remaining flags even though we don't recognize them
62
- # Zero out high bit, as it's the has-next-field marker
63
- f = (flags[i] & ~128) >> list.length
64
- while f > 0
65
- des.read_object if (f & 1) != 0
66
- f >>= 1
67
- end
68
- end
69
- end
70
- end
71
-
72
- # Maps to <tt>flex.messaging.messages.RemotingMessage</tt>
73
- class RemotingMessage < AbstractMessage
74
- # The name of the service to be called including package name
75
- attr_accessor :source
76
-
77
- # The name of the method to be called
78
- attr_accessor :operation
79
-
80
- def initialize
81
- @clientId = nil
82
- @destination = nil
83
- @messageId = rand_uuid
84
- @timestamp = Time.new.to_i*100
85
- @timeToLive = 0
86
- @headers = {}
87
- @body = nil
88
- end
89
- end
90
-
91
- # Maps to <tt>flex.messaging.messages.AsyncMessage</tt>
92
- class AsyncMessage < AbstractMessage
93
- EXTERNALIZABLE_FIELDS = [
94
- %w[ correlationId correlationIdBytes]
95
- ]
96
- attr_accessor :correlationId
97
-
98
- def correlationIdBytes= bytes
99
- @correlationId = pretty_uuid(bytes) unless bytes.nil?
100
- end
101
-
102
- def read_external des
103
- super des
104
- read_external_fields des, EXTERNALIZABLE_FIELDS
105
- end
106
- end
107
-
108
- class AsyncMessageExt < AsyncMessage #:nodoc:
109
- end
110
-
111
- # Maps to <tt>flex.messaging.messages.CommandMessage</tt>
112
- class CommandMessage < AsyncMessage
113
- SUBSCRIBE_OPERATION = 0
114
- UNSUSBSCRIBE_OPERATION = 1
115
- POLL_OPERATION = 2
116
- CLIENT_SYNC_OPERATION = 4
117
- CLIENT_PING_OPERATION = 5
118
- CLUSTER_REQUEST_OPERATION = 7
119
- LOGIN_OPERATION = 8
120
- LOGOUT_OPERATION = 9
121
- SESSION_INVALIDATE_OPERATION = 10
122
- MULTI_SUBSCRIBE_OPERATION = 11
123
- DISCONNECT_OPERATION = 12
124
- UNKNOWN_OPERATION = 10000
125
-
126
- EXTERNALIZABLE_FIELDS = [
127
- %w[ operation ]
128
- ]
129
- attr_accessor :operation
130
-
131
- def initialize
132
- @operation = UNKNOWN_OPERATION
133
- end
134
-
135
- def read_external des
136
- super des
137
- read_external_fields des, EXTERNALIZABLE_FIELDS
138
- end
139
- end
140
-
141
- class CommandMessageExt < CommandMessage #:nodoc:
142
- end
143
-
144
- # Maps to <tt>flex.messaging.messages.AcknowledgeMessage</tt>
145
- class AcknowledgeMessage < AsyncMessage
146
- EXTERNALIZABLE_FIELDS = [[]]
147
-
148
- def initialize message=nil
149
- @clientId = rand_uuid
150
- @destination = nil
151
- @messageId = rand_uuid
152
- @timestamp = Time.new.to_i*100
153
- @timeToLive = 0
154
- @headers = {}
155
- @body = nil
156
-
157
- if message.is_a?(AbstractMessage)
158
- @correlationId = message.messageId
159
- end
160
- end
161
-
162
- def read_external des
163
- super des
164
- read_external_fields des, EXTERNALIZABLE_FIELDS
165
- end
166
- end
167
-
168
- class AcknowledgeMessageExt < AcknowledgeMessage #:nodoc:
169
- end
170
-
171
- # Maps to <tt>flex.messaging.messages.ErrorMessage</tt> in AMF3 mode
172
- class ErrorMessage < AcknowledgeMessage
173
- # Extended data that will facilitate custom error processing on the client
174
- attr_accessor :extendedData
175
-
176
- # The fault code for the error, which defaults to the class name of the
177
- # causing exception
178
- attr_accessor :faultCode
179
-
180
- # Detailed description of what caused the error
181
- attr_accessor :faultDetail
182
-
183
- # A simple description of the error
184
- attr_accessor :faultString
185
-
186
- # Optional "root cause" of the error
187
- attr_accessor :rootCause
188
-
189
- def initialize message=nil, exception=nil
190
- super message
191
-
192
- unless exception.nil?
193
- @e = exception
194
- @faultCode = @e.class.name
195
- @faultDetail = @e.backtrace.join("\n")
196
- @faultString = @e.message
197
- end
198
- end
199
-
200
- def encode_amf serializer
201
- if serializer.version == 0
202
- data = {
203
- :faultCode => @faultCode,
204
- :faultDetail => @faultDetail,
205
- :faultString => @faultString
206
- }
207
- serializer.write_object(data)
208
- else
209
- serializer.write_object(self)
210
- end
211
- end
212
- end
213
- end
214
- end
@@ -1 +0,0 @@
1
- 
Binary file
Binary file
@@ -1 +0,0 @@
1
- 
Binary file
Binary file
Binary file
Binary file
@@ -1 +0,0 @@
1
- 
Binary file
@@ -1,39 +0,0 @@
1
- require "spec_helper.rb"
2
-
3
- describe RocketAMF::Values::AbstractMessage do
4
- before :each do
5
- @message = RocketAMF::Values::AbstractMessage.new
6
- end
7
-
8
- it "should generate conforming uuids" do
9
- @message.send(:rand_uuid).should =~ /[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}/i
10
- end
11
-
12
- it "should read externalized shortened BlazeDS messages" do
13
- env = create_envelope('blaze-response.bin')
14
- msg = env.messages[0].data
15
- msg.class.name.should == "RocketAMF::Values::AcknowledgeMessageExt"
16
- msg.clientId.should == "8814a067-fe0d-3a9c-a274-4aaed9bd7b0b"
17
- msg.body.should =~ /xmlsoap\.org/
18
- end
19
- end
20
-
21
- describe RocketAMF::Values::ErrorMessage do
22
- before :each do
23
- @e = Exception.new('Error message')
24
- @e.set_backtrace(['Backtrace 1', 'Backtrace 2'])
25
- @message = RocketAMF::Values::ErrorMessage.new(nil, @e)
26
- end
27
-
28
- it "should serialize as a hash in AMF0" do
29
- response = RocketAMF::Envelope.new
30
- response.messages << RocketAMF::Message.new('1/onStatus', '', @message)
31
- response.serialize.should == request_fixture('amf0-error-response.bin')
32
- end
33
-
34
- it "should extract exception properties correctly" do
35
- @message.faultCode.should == 'Exception'
36
- @message.faultString.should == 'Error message'
37
- @message.faultDetail.should == "Backtrace 1\nBacktrace 2"
38
- end
39
- end
@@ -1,196 +0,0 @@
1
- require "spec_helper.rb"
2
-
3
- describe RocketAMF::Envelope do
4
- describe 'deserializer' do
5
- it "should handle remoting message from remote object" do
6
- req = create_envelope("remotingMessage.bin")
7
-
8
- req.headers.length.should == 0
9
- req.messages.length.should == 1
10
- message = req.messages[0].data
11
- message.should be_a(RocketAMF::Values::RemotingMessage)
12
- message.messageId.should == "FE4AF2BC-DD3C-5470-05D8-9971D51FF89D"
13
- message.body.should == [true]
14
- end
15
-
16
- it "should handle command message from remote object" do
17
- req = create_envelope("commandMessage.bin")
18
-
19
- req.headers.length.should == 0
20
- req.messages.length.should == 1
21
- message = req.messages[0].data
22
- message.should be_a(RocketAMF::Values::CommandMessage)
23
- message.messageId.should == "7B0ACE15-8D57-6AE5-B9D4-99C2D32C8246"
24
- message.body.should == {}
25
- end
26
- end
27
-
28
- describe 'request builder' do
29
- it "should create simple call" do
30
- req = RocketAMF::Envelope.new
31
- req.call('TestController.test', 'first_arg', 'second_arg')
32
-
33
- expected = request_fixture('simple-request.bin')
34
- req.serialize.should == expected
35
- end
36
-
37
- it "should allow multiple simple calls" do
38
- req = RocketAMF::Envelope.new
39
- req.call('TestController.test', 'first_arg', 'second_arg')
40
- req.call('TestController.test2', 'first_arg', 'second_arg')
41
-
42
- expected = request_fixture('multiple-simple-request.bin')
43
- req.serialize.should == expected
44
- end
45
-
46
- it "should create flex remoting call" do
47
- req = RocketAMF::Envelope.new :amf_version => 3
48
- req.call_flex('TestController.test', 'first_arg', 'second_arg')
49
- req.messages[0].data.timestamp = 0
50
- req.messages[0].data.messageId = "9D108E33-B591-BE79-210D-F1A72D06B578"
51
-
52
- expected = request_fixture('flex-request.bin')
53
- req.serialize.should == expected
54
- end
55
-
56
- it "should require AMF version 3 for remoting calls" do
57
- req = RocketAMF::Envelope.new :amf_version => 0
58
- lambda {
59
- req.call_flex('TestController.test')
60
- }.should raise_error("Cannot use flex remoting calls with AMF0")
61
- end
62
-
63
- it "should require all calls be the same type" do
64
- req = RocketAMF::Envelope.new :amf_version => 0
65
- lambda {
66
- req.call('TestController.test')
67
- req.call_flex('TestController.test')
68
- }.should raise_error("Cannot use different call types")
69
- end
70
- end
71
-
72
- describe 'serializer' do
73
- it "should serialize response when converted to string" do
74
- res = RocketAMF::Envelope.new
75
- res.should_receive(:serialize).and_return('serialized')
76
- res.to_s.should == 'serialized'
77
- end
78
-
79
- it "should serialize a simple call" do
80
- res = RocketAMF::Envelope.new :amf_version => 3
81
- res.messages << RocketAMF::Message.new('/1/onResult', '', 'hello')
82
-
83
- expected = request_fixture('simple-response.bin')
84
- res.serialize.should == expected
85
- end
86
-
87
- it "should serialize a AcknowledgeMessage response" do
88
- ak = RocketAMF::Values::AcknowledgeMessage.new
89
- ak.clientId = "7B0ACE15-8D57-6AE5-B9D4-99C2D32C8246"
90
- ak.messageId = "7B0ACE15-8D57-6AE5-B9D4-99C2D32C8246"
91
- ak.timestamp = 0
92
- res = RocketAMF::Envelope.new :amf_version => 3
93
- res.messages << RocketAMF::Message.new('/1/onResult', '', ak)
94
-
95
- expected = request_fixture('acknowledge-response.bin')
96
- res.serialize.should == expected
97
- end
98
- end
99
-
100
- describe 'message handler' do
101
- it "should respond to ping command" do
102
- res = RocketAMF::Envelope.new
103
- req = create_envelope('commandMessage.bin')
104
- res.each_method_call req do |method, args|
105
- nil
106
- end
107
-
108
- res.messages.length.should == 1
109
- res.messages[0].data.should be_a(RocketAMF::Values::AcknowledgeMessage)
110
- end
111
-
112
- it "should fail on unsupported command" do
113
- res = RocketAMF::Envelope.new
114
- req = create_envelope('unsupportedCommandMessage.bin')
115
- res.each_method_call req do |method, args|
116
- nil
117
- end
118
-
119
- res.messages.length.should == 1
120
- res.messages[0].data.should be_a(RocketAMF::Values::ErrorMessage)
121
- res.messages[0].data.faultString.should == "CommandMessage 10000 not implemented"
122
- end
123
-
124
- it "should handle RemotingMessages properly" do
125
- res = RocketAMF::Envelope.new
126
- req = create_envelope('remotingMessage.bin')
127
- res.each_method_call req do |method, args|
128
- method.should == 'WritesController.save'
129
- args.should == [true]
130
- true
131
- end
132
-
133
- res.messages.length.should == 1
134
- res.messages[0].data.should be_a(RocketAMF::Values::AcknowledgeMessage)
135
- res.messages[0].data.body.should == true
136
- end
137
-
138
- it "should catch exceptions properly" do
139
- res = RocketAMF::Envelope.new
140
- req = create_envelope('remotingMessage.bin')
141
- res.each_method_call req do |method, args|
142
- raise 'Error in call'
143
- end
144
-
145
- res.messages.length.should == 1
146
- res.messages[0].data.should be_a(RocketAMF::Values::ErrorMessage)
147
- res.messages[0].target_uri.should =~ /onStatus$/
148
- end
149
-
150
- it "should not crash if source missing on RemotingMessage" do
151
- res = RocketAMF::Envelope.new
152
- req = create_envelope('remotingMessage.bin')
153
- req.messages[0].data.instance_variable_set("@source", nil)
154
- lambda {
155
- res.each_method_call req do |method,args|
156
- true
157
- end
158
- }.should_not raise_error
159
- end
160
- end
161
-
162
- describe 'response parser' do
163
- it "should return the result of a simple response" do
164
- req = RocketAMF::Envelope.new
165
- req.call('TestController.test', 'first_arg', 'second_arg')
166
- res = RocketAMF::Envelope.new
167
- res.each_method_call req do |method, args|
168
- ['a', 'b']
169
- end
170
-
171
- res.result.should == ['a', 'b']
172
- end
173
-
174
- it "should return the results of multiple simple response in a single request" do
175
- req = RocketAMF::Envelope.new
176
- req.call('TestController.test', 'first_arg', 'second_arg')
177
- req.call('TestController.test2', 'first_arg', 'second_arg')
178
- res = RocketAMF::Envelope.new
179
- res.each_method_call req do |method, args|
180
- ['a', 'b']
181
- end
182
-
183
- res.result.should == [['a', 'b'], ['a', 'b']]
184
- end
185
-
186
- it "should return the results of a flex response" do
187
- req = RocketAMF::Envelope.new :amf_version => 3
188
- req.call_flex('TestController.test', 'first_arg', 'second_arg')
189
- res = RocketAMF::Envelope.new
190
- res.each_method_call req do |method, args|
191
- ['a', 'b']
192
- end
193
- res.result.should == ['a', 'b']
194
- end
195
- end
196
- end