mrpin-rocketamf 1.0.4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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