revent 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/revent/CallEvent.as +25 -0
- data/lib/revent/Client.as +95 -0
- data/lib/revent/amf3/LICENSE +22 -0
- data/lib/revent/amf3/README +6 -0
- data/lib/revent/amf3/amf3.rb +11 -0
- data/lib/revent/amf3/app/configuration.rb +79 -0
- data/lib/revent/amf3/app/fault_object.rb +13 -0
- data/lib/revent/amf3/exception/rubyamf_exception.rb +95 -0
- data/lib/revent/amf3/io/amf_deserializer.rb +315 -0
- data/lib/revent/amf3/io/amf_serializer.rb +184 -0
- data/lib/revent/amf3/io/read_write.rb +308 -0
- data/lib/revent/amf3/util/string.rb +33 -0
- data/lib/revent/amf3/util/vo_helper.rb +121 -0
- data/lib/revent/as_r.rb +178 -0
- data/lib/revent/r_r.rb +176 -0
- data/test/as_r/Document.as +63 -0
- data/test/as_r/client.fla +0 -0
- data/test/as_r/client.swf +0 -0
- data/test/as_r/server.rb +48 -0
- data/{sample → test/r_r}/client.rb +0 -0
- data/{sample → test/r_r}/server.rb +0 -0
- metadata +31 -6
- data/lib/revent.rb +0 -166
@@ -0,0 +1,184 @@
|
|
1
|
+
module RubyAMF
|
2
|
+
module IO
|
3
|
+
class AMFSerializer
|
4
|
+
|
5
|
+
require "#{File.dirname(__FILE__)}/read_write"
|
6
|
+
|
7
|
+
include RubyAMF::Configuration
|
8
|
+
include RubyAMF::IO::BinaryWriter
|
9
|
+
include RubyAMF::IO::Constants
|
10
|
+
include RubyAMF::VoHelper
|
11
|
+
|
12
|
+
attr_accessor :stream
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
reset
|
16
|
+
end
|
17
|
+
|
18
|
+
def reset
|
19
|
+
@stream = ''
|
20
|
+
reset_referencables
|
21
|
+
end
|
22
|
+
|
23
|
+
def reset_referencables
|
24
|
+
@stored_strings = {} # hash is way faster than array
|
25
|
+
@stored_strings[""] = true # add this in automatically
|
26
|
+
@write_amf3_integer_results = {} # cache the integers
|
27
|
+
@current_strings_index = 0
|
28
|
+
end
|
29
|
+
|
30
|
+
def write_amf3(value)
|
31
|
+
if !value
|
32
|
+
@stream << "\001" # represents an amf3 null
|
33
|
+
|
34
|
+
elsif (value.is_a?(TrueClass) || value.is_a?(FalseClass))
|
35
|
+
value ? (@stream << "\003") : (@stream << "\002") # represents an amf3 true and false
|
36
|
+
|
37
|
+
elsif value.is_a?(Numeric)
|
38
|
+
if value.is_a?(Integer) # Aryk: This was also incorrect before because you has Bignum check AFTER the Integer check, which means the Bignum's were getting picked up by Integers
|
39
|
+
if value.is_a?(Bignum)
|
40
|
+
@stream << "\005" # represents an amf3 complex number
|
41
|
+
write_double(value)
|
42
|
+
else
|
43
|
+
write_amf3_number(value)
|
44
|
+
end
|
45
|
+
elsif(value.is_a?(Float))
|
46
|
+
@stream << "\005" # represents an amf3 complex number
|
47
|
+
write_double(value)
|
48
|
+
elsif value.is_a?(BigDecimal) # Aryk: BigDecimal does not relate to Float, so keep it as a seperate check.
|
49
|
+
# TODO: Aryk: Not quite sure why you do value.to_s.to_f? can't you just do value.to_f?
|
50
|
+
value = value.to_s('F').to_f #this is turning a string into a Ruby Float, but because there are no further operations on it it is safe
|
51
|
+
@stream << "\005" # represents an amf3 complex number
|
52
|
+
write_double(value)
|
53
|
+
end
|
54
|
+
|
55
|
+
elsif(value.is_a?(String))
|
56
|
+
@stream << "\006" # represents an amf3 string
|
57
|
+
write_amf3_string(value)
|
58
|
+
|
59
|
+
elsif(value.is_a?(Array))
|
60
|
+
write_amf3_array(value)
|
61
|
+
|
62
|
+
elsif(value.is_a?(Hash))
|
63
|
+
write_amf3_object(value)
|
64
|
+
|
65
|
+
elsif (value.is_a?(Time)||value.is_a?(Date))
|
66
|
+
@stream << "\b" # represents an amf3 date
|
67
|
+
write_amf3_date(value)
|
68
|
+
|
69
|
+
# I know we can combine this with the last condition, but don't ; the Rexml and Beautiful Soup test is expensive, and for large record sets with many AR its better to be able to skip the next step
|
70
|
+
elsif value.is_a?(ActiveRecord::Base) # Aryk: this way, we can bypass the "['REXML::Document', 'BeautifulSoup'].include?(value.class.to_s) " operation
|
71
|
+
write_amf3_object(VoUtil.get_vo_hash_for_outgoing(value))
|
72
|
+
|
73
|
+
elsif ['REXML::Document', 'BeautifulSoup'].include?(value.class.to_s)
|
74
|
+
write_byte(AMF3_XML)
|
75
|
+
write_amf3_xml(value)
|
76
|
+
|
77
|
+
elsif value.is_a?(Object)
|
78
|
+
write_amf3_object(VoUtil.get_vo_hash_for_outgoing(value) )
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def write_amf3_integer(int)
|
83
|
+
@stream << (@write_amf3_integer_results[int] ||= (
|
84
|
+
int = int & 0x1fffffff
|
85
|
+
if(int < 0x80)
|
86
|
+
[int].pack('c')
|
87
|
+
elsif(int < 0x4000)
|
88
|
+
[int >> 7 & 0x7f | 0x80].pack('c')+
|
89
|
+
[int & 0x7f].pack('c')
|
90
|
+
elsif(int < 0x200000)
|
91
|
+
[int >> 14 & 0x7f | 0x80].pack('c')+
|
92
|
+
[int >> 7 & 0x7f | 0x80].pack('c')+
|
93
|
+
[int & 0x7f].pack('c')
|
94
|
+
else
|
95
|
+
[int >> 22 & 0x7f | 0x80].pack('c')+
|
96
|
+
[int >> 15 & 0x7f | 0x80].pack('c')+
|
97
|
+
[int >> 8 & 0x7f | 0x80].pack('c')+
|
98
|
+
[int & 0xff].pack('c')
|
99
|
+
end
|
100
|
+
))
|
101
|
+
end
|
102
|
+
|
103
|
+
def write_amf3_number(number)
|
104
|
+
if(number >= AMF3_INTEGER_MIN && number <= AMF3_INTEGER_MAX) #check valid range for 29bits
|
105
|
+
@stream << "\004" # represents an amf3 integer
|
106
|
+
write_amf3_integer(number)
|
107
|
+
else #overflow condition otherwise
|
108
|
+
@stream << "\005" # represents an amf3 complex number
|
109
|
+
write_double(number)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def write_amf3_string(string)
|
114
|
+
if index = @stored_strings[string]
|
115
|
+
if string == "" # store this initially so it gets caught by the stored_strings check
|
116
|
+
@stream << "\001" # represents an amf3 empty string
|
117
|
+
else
|
118
|
+
reference = index << 1
|
119
|
+
write_amf3_integer(reference)
|
120
|
+
end
|
121
|
+
else
|
122
|
+
@stored_strings[string] = @current_strings_index
|
123
|
+
@current_strings_index += 1 # increment the index
|
124
|
+
reference = string.length
|
125
|
+
reference = reference << 1
|
126
|
+
reference = reference | 1
|
127
|
+
write_amf3_integer(reference)
|
128
|
+
writen(string)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def write_amf3_object(hash)
|
133
|
+
not_vo_hash = !hash.is_a?(VoHash) # is this not a vohash - then doesnt have an _explicitType parameter
|
134
|
+
@stream << "\n\v" # represents an amf3 object and dynamic object
|
135
|
+
not_vo_hash || !hash._explicitType ? (@stream << "\001") : write_amf3_string(hash._explicitType)
|
136
|
+
hash.each do |attr, value| # Aryk: no need to remove any "_explicitType" or "rmember" key since they werent added as keys
|
137
|
+
if not_vo_hash # then that means that the attr might not be symbols and it hasn't gone through camelizing if thats needed
|
138
|
+
attr = attr.to_s.dup # need this just in case its frozen
|
139
|
+
attr.to_camel! if ClassMappings.translate_case
|
140
|
+
end
|
141
|
+
write_amf3_string(attr)
|
142
|
+
value ? write_amf3(value) : (@stream << "\001") # represents an amf3 null
|
143
|
+
end
|
144
|
+
@stream << "\001" # represents an amf3 empty string #close open object
|
145
|
+
end
|
146
|
+
|
147
|
+
def write_amf3_array(array)
|
148
|
+
num_objects = array.length * 2 + 1
|
149
|
+
if ClassMappings.use_array_collection
|
150
|
+
@stream << "\n\a" # AMF3_OBJECT and AMF3_XML
|
151
|
+
write_amf3_string("flex.messaging.io.ArrayCollection")
|
152
|
+
end
|
153
|
+
@stream << "\t" # represents an amf3 array
|
154
|
+
write_amf3_integer(num_objects)
|
155
|
+
@stream << "\001" # represents an amf3 empty string #write empty for string keyed elements here, as it's never allowed from ruby
|
156
|
+
array.each{|v| write_amf3(v) }
|
157
|
+
end
|
158
|
+
|
159
|
+
def write_amf3_date(datetime) # Aryk: Dates will almost never be the same, so turn off the storing_objects
|
160
|
+
write_amf3_integer(1)
|
161
|
+
seconds = if datetime.is_a?(Time)
|
162
|
+
datetime.utc unless datetime.utc?
|
163
|
+
datetime.to_f
|
164
|
+
elsif datetime.is_a?(Date) # this also handles the case for DateTime
|
165
|
+
datetime.strftime("%s").to_i
|
166
|
+
# datetime = Time.gm( datetime.year, datetime.month, datetime.day )
|
167
|
+
# datetime = Time.gm( datetime.year, datetime.month, datetime.day, datetime.hour, datetime.min, datetime.sec )
|
168
|
+
end
|
169
|
+
write_double( (seconds*1000).to_i ) # used to be total_milliseconds = datetime.to_i * 1000 + ( datetime.usec/1000 )
|
170
|
+
end
|
171
|
+
|
172
|
+
def write_amf3_xml(value)
|
173
|
+
xml = value.to_s
|
174
|
+
a = xml.strip
|
175
|
+
if(a != nil)
|
176
|
+
b = a.gsub!(/\>(\n|\r|\r\n| |\t)*\</,'><') #clean whitespace
|
177
|
+
else
|
178
|
+
b = xml.gsub!(/\>(\n|\r|\r\n| |\t)*\</,'><') #clean whitespace
|
179
|
+
end
|
180
|
+
write_amf3_string(b)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,308 @@
|
|
1
|
+
begin
|
2
|
+
module RubyAMF
|
3
|
+
module IO
|
4
|
+
module Constants
|
5
|
+
AMF3_TYPE = 0x11
|
6
|
+
AMF3_UNDEFINED = 0x00
|
7
|
+
AMF3_NULL = 0x01
|
8
|
+
AMF3_FALSE = 0x02
|
9
|
+
AMF3_TRUE = 0x03
|
10
|
+
AMF3_INTEGER = 0x04
|
11
|
+
AMF3_NUMBER = 0x05
|
12
|
+
AMF3_STRING = 0x06
|
13
|
+
AMF3_XML = 0x07
|
14
|
+
AMF3_DATE = 0x08
|
15
|
+
AMF3_ARRAY = 0x09
|
16
|
+
AMF3_OBJECT = 0x0A
|
17
|
+
AMF3_XML_STRING = 0x0B
|
18
|
+
AMF3_BYTE_ARRAY = 0x0C
|
19
|
+
AMF3_INTEGER_MAX = 268435455
|
20
|
+
AMF3_INTEGER_MIN = -268435456
|
21
|
+
end
|
22
|
+
module BinaryReader
|
23
|
+
|
24
|
+
Native = :Native
|
25
|
+
Big = BigEndian = Network = :BigEndian
|
26
|
+
Little = LittleEndian = :LittleEndian
|
27
|
+
|
28
|
+
#examines the locale byte order on the running machine
|
29
|
+
def byte_order
|
30
|
+
if [0x12345678].pack("L") == "\x12\x34\x56\x78"
|
31
|
+
:BigEndian
|
32
|
+
else
|
33
|
+
:LittleEndian
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def byte_order_little?
|
38
|
+
(byte_order == :LittleEndian) ? true : false;
|
39
|
+
end
|
40
|
+
|
41
|
+
def byte_order_big?
|
42
|
+
(byte_order == :BigEndian) ? true : false;
|
43
|
+
end
|
44
|
+
alias :byte_order_network? :byte_order_big?
|
45
|
+
|
46
|
+
#read N length from stream starting at position
|
47
|
+
def readn(length)
|
48
|
+
self.stream_position ||= 0
|
49
|
+
str = self.stream[self.stream_position, length]
|
50
|
+
self.stream_position += length
|
51
|
+
str
|
52
|
+
end
|
53
|
+
|
54
|
+
#reada a boolean
|
55
|
+
def read_boolean
|
56
|
+
d = self.stream[self.stream_position,1].unpack('c').first
|
57
|
+
self.stream_position += 1
|
58
|
+
(d == 1) ? true : false;
|
59
|
+
end
|
60
|
+
|
61
|
+
#8bits no byte order
|
62
|
+
def read_int8
|
63
|
+
d = self.stream[self.stream_position,1].unpack('c').first
|
64
|
+
self.stream_position += 1
|
65
|
+
d
|
66
|
+
end
|
67
|
+
alias :read_byte :read_int8
|
68
|
+
|
69
|
+
# Aryk: TODO: This needs to be written more cleanly. Using rescue and then regex checks on top of that slows things down
|
70
|
+
def read_word8
|
71
|
+
begin
|
72
|
+
d = self.stream[self.stream_position,1].unpack('C').first
|
73
|
+
self.stream_position += 1
|
74
|
+
d
|
75
|
+
rescue Exception => e
|
76
|
+
#this handles an exception condition when Rails'
|
77
|
+
#ActionPack strips off the last "\000" of the AMF stream
|
78
|
+
self.stream_position += 1
|
79
|
+
return 0
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
#16 bits Unsigned
|
84
|
+
def read_word16_native
|
85
|
+
d = self.stream[self.stream_position,2].unpack('S').first
|
86
|
+
self.stream_position += 2
|
87
|
+
d
|
88
|
+
end
|
89
|
+
|
90
|
+
def read_word16_little
|
91
|
+
d = self.stream[self.stream_position,2].unpack('v').first
|
92
|
+
self.stream_position += 2
|
93
|
+
d
|
94
|
+
end
|
95
|
+
|
96
|
+
def read_word16_network
|
97
|
+
d = self.stream[self.stream_position,2].unpack('n').first
|
98
|
+
self.stream_position += 2
|
99
|
+
d
|
100
|
+
end
|
101
|
+
|
102
|
+
#16 bits Signed
|
103
|
+
def read_int16_native
|
104
|
+
str = self.readn(2).unpack('s').first
|
105
|
+
end
|
106
|
+
|
107
|
+
def read_int16_little
|
108
|
+
str = self.readn(2)
|
109
|
+
str.reverse! if byte_order_network? # swap bytes as native=network (and we want little)
|
110
|
+
str.unpack('s').first
|
111
|
+
end
|
112
|
+
|
113
|
+
def read_int16_network
|
114
|
+
str = self.readn(2)
|
115
|
+
str.reverse! if byte_order_little? # swap bytes as native=little (and we want network)
|
116
|
+
str.unpack('s').first
|
117
|
+
end
|
118
|
+
|
119
|
+
#32 bits unsigned
|
120
|
+
def read_word32_native
|
121
|
+
d = self.stream[self.stream_position,4].unpack('L').first
|
122
|
+
self.stream_position += 4
|
123
|
+
d
|
124
|
+
end
|
125
|
+
|
126
|
+
def read_word32_little
|
127
|
+
d = self.stream[self.stream_position,4].unpack('V').first
|
128
|
+
self.stream_position += 4
|
129
|
+
d
|
130
|
+
end
|
131
|
+
|
132
|
+
def read_word32_network
|
133
|
+
d = self.stream[self.stream_position,4].unpack('N').first
|
134
|
+
self.stream_position += 4
|
135
|
+
d
|
136
|
+
end
|
137
|
+
|
138
|
+
#32 bits signed
|
139
|
+
def read_int32_native
|
140
|
+
d = self.stream[self.stream_position,4].unpack('l').first
|
141
|
+
self.stream_position += 4
|
142
|
+
d
|
143
|
+
end
|
144
|
+
|
145
|
+
def read_int32_little
|
146
|
+
str = readn(4)
|
147
|
+
str.reverse! if byte_order_network? # swap bytes as native=network (and we want little)
|
148
|
+
str.unpack('l').first
|
149
|
+
end
|
150
|
+
|
151
|
+
def read_int32_network
|
152
|
+
str = readn(4)
|
153
|
+
str.reverse! if byte_order_little? # swap bytes as native=little (and we want network)
|
154
|
+
str.unpack('l').first
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
#UTF string
|
159
|
+
def read_utf
|
160
|
+
length = self.read_word16_network
|
161
|
+
readn(length)
|
162
|
+
end
|
163
|
+
|
164
|
+
def read_int32_network
|
165
|
+
str = self.readn(4)
|
166
|
+
str.reverse! if byte_order_little? # swap bytes as native=little (and we want network)
|
167
|
+
str.unpack('l').first
|
168
|
+
end
|
169
|
+
|
170
|
+
def read_double
|
171
|
+
d = self.stream[self.stream_position,8].unpack('G').first
|
172
|
+
self.stream_position += 8
|
173
|
+
d
|
174
|
+
end
|
175
|
+
|
176
|
+
def read_long_utf(length)
|
177
|
+
length = read_word32_network #get the length of the string (1st 4 bytes)
|
178
|
+
self.readn(length) #read length number of bytes
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
module BinaryWriter
|
184
|
+
|
185
|
+
#examines the locale byte order on the running machine
|
186
|
+
def byte_order
|
187
|
+
if [0x12345678].pack("L") == "\x12\x34\x56\x78"
|
188
|
+
:BigEndian
|
189
|
+
else
|
190
|
+
:LittleEndian
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def byte_order_little?
|
195
|
+
(byte_order == :LittleEndian) ? true : false;
|
196
|
+
end
|
197
|
+
|
198
|
+
def byte_order_big?
|
199
|
+
(byte_order == :BigEndian) ? true : false;
|
200
|
+
end
|
201
|
+
alias :byte_order_network? :byte_order_big?
|
202
|
+
|
203
|
+
def writen(val)
|
204
|
+
@stream << val
|
205
|
+
end
|
206
|
+
|
207
|
+
#8 bit no byteorder
|
208
|
+
def write_word8(val)
|
209
|
+
self.stream << [val].pack('C')
|
210
|
+
end
|
211
|
+
|
212
|
+
def write_int8(val)
|
213
|
+
self.stream << [val].pack('c')
|
214
|
+
end
|
215
|
+
|
216
|
+
#16 bit unsigned
|
217
|
+
def write_word16_native(val)
|
218
|
+
self.stream << [val].pack('S')
|
219
|
+
end
|
220
|
+
|
221
|
+
def write_word16_little(val)
|
222
|
+
str = [val].pack('S')
|
223
|
+
str.reverse! if byte_order_network? # swap bytes as native=network (and we want little)
|
224
|
+
self.stream << str
|
225
|
+
end
|
226
|
+
|
227
|
+
def write_word16_network(val)
|
228
|
+
str = [val].pack('S')
|
229
|
+
str.reverse! if byte_order_little? # swap bytes as native=little (and we want network)
|
230
|
+
self.stream << str
|
231
|
+
end
|
232
|
+
|
233
|
+
#16 bits signed
|
234
|
+
def write_int16_native(val)
|
235
|
+
self.stream << [val].pack('s')
|
236
|
+
end
|
237
|
+
|
238
|
+
def write_int16_little(val)
|
239
|
+
self.stream << [val].pack('v')
|
240
|
+
end
|
241
|
+
|
242
|
+
def write_int16_network(val)
|
243
|
+
self.stream << [val].pack('n')
|
244
|
+
end
|
245
|
+
|
246
|
+
#32 bit unsigned
|
247
|
+
def write_word32_native(val)
|
248
|
+
self.stream << [val].pack('L')
|
249
|
+
end
|
250
|
+
|
251
|
+
def write_word32_little(val)
|
252
|
+
str = [val].pack('L')
|
253
|
+
str.reverse! if byte_order_network? # swap bytes as native=network (and we want little)
|
254
|
+
self.stream << str
|
255
|
+
end
|
256
|
+
|
257
|
+
def write_word32_network(val)
|
258
|
+
str = [val].pack('L')
|
259
|
+
str.reverse! if byte_order_little? # swap bytes as native=little (and we want network)
|
260
|
+
self.stream << str
|
261
|
+
end
|
262
|
+
|
263
|
+
#32 signed
|
264
|
+
def write_int32_native(val)
|
265
|
+
self.stream << [val].pack('l')
|
266
|
+
end
|
267
|
+
|
268
|
+
def write_int32_little(val)
|
269
|
+
self.stream << [val].pack('V')
|
270
|
+
end
|
271
|
+
|
272
|
+
def write_int32_network(val)
|
273
|
+
self.stream << [val].pack('N')
|
274
|
+
end
|
275
|
+
|
276
|
+
# write utility methods
|
277
|
+
def write_byte(val)
|
278
|
+
#self.write_int8(val)
|
279
|
+
@stream << [val].pack('c')
|
280
|
+
end
|
281
|
+
|
282
|
+
def write_boolean(val)
|
283
|
+
if val then self.write_byte(1) else self.write_byte(0) end
|
284
|
+
end
|
285
|
+
|
286
|
+
def write_utf(str)
|
287
|
+
self.write_int16_network(str.length)
|
288
|
+
self.stream << str
|
289
|
+
end
|
290
|
+
|
291
|
+
def write_long_utf(str)
|
292
|
+
self.write_int32_network(str.length)
|
293
|
+
self.stream << str
|
294
|
+
end
|
295
|
+
|
296
|
+
def write_double(val)
|
297
|
+
self.stream << ( @floats_cache[val] ||=
|
298
|
+
[val].pack('G')
|
299
|
+
)
|
300
|
+
#puts "WRITE DOUBLE"
|
301
|
+
#puts @floats_cache
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
rescue Exception => e
|
307
|
+
raise RUBYAMFException.new(RUBYAMFException.AMF_ERROR, "The AMF data is incorrect or incomplete.")
|
308
|
+
end
|