neerfri-ramf 0.1.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.
- data/LICENSE +166 -0
- data/README +3 -0
- data/Rakefile +17 -0
- data/lib/ramf/amf_header.rb +9 -0
- data/lib/ramf/amf_message.rb +26 -0
- data/lib/ramf/amf_object.rb +54 -0
- data/lib/ramf/configuration.rb +8 -0
- data/lib/ramf/default_operation_processor.rb +20 -0
- data/lib/ramf/deserializer/amf0_reader.rb +61 -0
- data/lib/ramf/deserializer/amf3_reader.rb +242 -0
- data/lib/ramf/deserializer/base.rb +76 -0
- data/lib/ramf/deserializer.rb +9 -0
- data/lib/ramf/extensions/class.rb +139 -0
- data/lib/ramf/extensions/exception.rb +3 -0
- data/lib/ramf/extensions/hash.rb +8 -0
- data/lib/ramf/extensions/object.rb +44 -0
- data/lib/ramf/flex_class_traits.rb +98 -0
- data/lib/ramf/flex_objects/acknowledge_message.rb +31 -0
- data/lib/ramf/flex_objects/byte_array.rb +9 -0
- data/lib/ramf/flex_objects/command_message.rb +86 -0
- data/lib/ramf/flex_objects/error_message.rb +14 -0
- data/lib/ramf/flex_objects/flex_anonymous_object.rb +37 -0
- data/lib/ramf/flex_objects/flex_object.rb +13 -0
- data/lib/ramf/flex_objects/remoting_message.rb +26 -0
- data/lib/ramf/io/common_read_write.rb +73 -0
- data/lib/ramf/io/constants.rb +79 -0
- data/lib/ramf/io/flex_class_signature.rb +16 -0
- data/lib/ramf/io/place_holder.rb +8 -0
- data/lib/ramf/io/reference_table.rb +74 -0
- data/lib/ramf/operation_processors_manager.rb +30 -0
- data/lib/ramf/operation_request.rb +51 -0
- data/lib/ramf/serializer/amf0_writer.rb +89 -0
- data/lib/ramf/serializer/amf3_writer.rb +193 -0
- data/lib/ramf/serializer/base.rb +57 -0
- data/lib/ramf/serializer.rb +9 -0
- data/lib/ramf/util.rb +34 -0
- data/lib/ramf.rb +62 -0
- data/spec/amf_object_spec.rb +85 -0
- data/spec/deserializer_spec.rb +22 -0
- data/spec/examples/examples_helper.rb +75 -0
- data/spec/examples/remoting_login_spec.rb +53 -0
- data/spec/examples/simple_amf_spec.rb +55 -0
- data/spec/examples/simple_remoting_spec.rb +60 -0
- data/spec/extensions/class_extensions_spec.rb +62 -0
- data/spec/fixtures/catalog.yml +5 -0
- data/spec/fixtures/deserializer1.bin +0 -0
- data/spec/fixtures/deserializer1.rb +31 -0
- data/spec/fixtures/deserializer2.bin +0 -0
- data/spec/fixtures/deserializer2.rb +40 -0
- data/spec/fixtures/deserializer3.bin +0 -0
- data/spec/fixtures/ping_command_message.amf +0 -0
- data/spec/fixtures/remoting_login_operation.amf +0 -0
- data/spec/fixtures/simple_remoting_message.amf +0 -0
- data/spec/flex_class_traits_spec.rb +52 -0
- data/spec/inherited_class_traits_spec.rb +58 -0
- data/spec/io/reference_table_spec.rb +38 -0
- data/spec/operation_processors_manager_spec.rb +61 -0
- data/spec/serializer/amf3_writer_spec.rb +565 -0
- data/spec/serializer/base_spec.rb +92 -0
- data/spec/serializer/full_spec.rb +172 -0
- data/spec/spec_helper.rb +28 -0
- metadata +153 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
class Class
|
|
2
|
+
|
|
3
|
+
#returns the FlexClassTraits object of the class,
|
|
4
|
+
#if it doesn't exist, it will create one.
|
|
5
|
+
#
|
|
6
|
+
# class Car
|
|
7
|
+
# @@my_flex_remoting = flex_remoting
|
|
8
|
+
# #Why would you be doing that ???
|
|
9
|
+
# end
|
|
10
|
+
def flex_remoting
|
|
11
|
+
@flex_remoting ||= RAMF::FlexClassTraits.new(self, true, :transient=>[:flex_remoting])
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
#This method defines members that are transient, which means
|
|
15
|
+
#they will not be sent by amf, and will be ignored if received from amf.
|
|
16
|
+
#For Exmple:
|
|
17
|
+
# class User
|
|
18
|
+
# flex_remoting_transient :encrypted_password, :encription_salt
|
|
19
|
+
# end
|
|
20
|
+
#this will define <tt>:encrypted_password, :encription_salt</tt> not
|
|
21
|
+
#to be sent over amf.
|
|
22
|
+
#Make sure they are not important to represent the object when it comes from amf.
|
|
23
|
+
def flex_remoting_transient(*args)
|
|
24
|
+
flex_remoting.transient_members += args.map {|v| v.to_sym}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
#defines members for a specific scope.
|
|
28
|
+
#For exmple:
|
|
29
|
+
# class User
|
|
30
|
+
# flex_remoting_scope :limited, :except=>[:phone,:email]
|
|
31
|
+
# flex_remoting_scope :private, :only=>[:fullname, :nickname]
|
|
32
|
+
# end
|
|
33
|
+
#this will set :phone and :email attributes not to be sent
|
|
34
|
+
#when using <tt> render :amf=>@user, :scope=>:limited </tt>.
|
|
35
|
+
#
|
|
36
|
+
#it will also set only :fullname and :nickname to be sent when
|
|
37
|
+
#using <tt> render :amf=>@user_list, :scope=>:private </tt>
|
|
38
|
+
#
|
|
39
|
+
#Each scope can only be set with either :except or :only, not both.
|
|
40
|
+
def flex_remoting_scope(scope, options)
|
|
41
|
+
raise "only & except" if options[:only] && options[:except]
|
|
42
|
+
flex_remoting.amf_scope_options[scope] = options
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
#define the action script name of the class (or what they set
|
|
46
|
+
#in RemoteAlias('') )
|
|
47
|
+
# class SomeRubyClass
|
|
48
|
+
# flex_alias_name :SomeActionScriptClass
|
|
49
|
+
# end
|
|
50
|
+
#this will make the client side(flex) receive a class
|
|
51
|
+
#named SomeActionScriptClass
|
|
52
|
+
def flex_alias(class_name)
|
|
53
|
+
flex_remoting.name = class_name.to_s
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
#This method defines members that are fixed with the object, which means
|
|
57
|
+
#they will use to define the class's signature during serialization.
|
|
58
|
+
#For Exmple:
|
|
59
|
+
# class User
|
|
60
|
+
# flex_remoting_members :great_attribute, :important_attribute
|
|
61
|
+
# end
|
|
62
|
+
#this will define <tt>:great_attribute, :important_attribute</tt> to
|
|
63
|
+
#always be sent over amf.
|
|
64
|
+
#
|
|
65
|
+
#Note that some classes can use other mechanisms to find sealed members,
|
|
66
|
+
#this is the most simple way to do so.
|
|
67
|
+
|
|
68
|
+
def flex_remoting_members(*members)
|
|
69
|
+
flex_remoting.defined_members = members
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
#Defines dynamic members finder block.
|
|
73
|
+
#The block should return an array of symbols or nil(for empty array)
|
|
74
|
+
#each symbol in the array will represent a dynamic member to be serialized
|
|
75
|
+
#For example:
|
|
76
|
+
# class User
|
|
77
|
+
# flex_dynamic_members_finder do |instance, scope|
|
|
78
|
+
# instance.instance_variable_get("@dynamic") ? [:dynamic] : []
|
|
79
|
+
# end
|
|
80
|
+
# end
|
|
81
|
+
#this will add :dynamic to the list of dynamic members if an instance variable named @dynamic exists.
|
|
82
|
+
def flex_dynamic_members_finder(&block)
|
|
83
|
+
flex_remoting.dynamic_members_finders.push(block)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
#defines a callback to set the value of the object's members.
|
|
87
|
+
#For example:
|
|
88
|
+
# class User
|
|
89
|
+
# attr_accessor :my_other_data #this is a hash...
|
|
90
|
+
# flex_members_reader do |obj, member, value|
|
|
91
|
+
# obj.my_other_data.has_key?(member) ? obj.my_other_data[member]=value : obj.send(member.to_s+"=",value)
|
|
92
|
+
# end
|
|
93
|
+
# end
|
|
94
|
+
#if the hash <tt>my_other_data</tt> has key <tt>member</tt> insert the value to the hash,
|
|
95
|
+
#otherwise use a setter method
|
|
96
|
+
def flex_members_writer(&block)
|
|
97
|
+
flex_remoting.members_writer = block
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
#defines a callback to set the value of the object's dynamic members.
|
|
101
|
+
#For example:
|
|
102
|
+
# class User
|
|
103
|
+
# attr_accessor :my_dynamic_members #this is a hash...
|
|
104
|
+
# flex_dynamic_members_reader do |obj, member, value|
|
|
105
|
+
# obj.my_dynamic_members[member] = value
|
|
106
|
+
# end
|
|
107
|
+
# end
|
|
108
|
+
#this will set all dynamic members to the hash <tt>my_dynamic_members</tt>
|
|
109
|
+
def flex_dynamic_members_writer(&block)
|
|
110
|
+
flex_remoting.dynamic_members_writer = block
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
#defines a callback to get the value of the object's members.
|
|
114
|
+
#For example:
|
|
115
|
+
# class User
|
|
116
|
+
# attr_accessor :my_other_data #this is a hash...
|
|
117
|
+
# flex_members_reader do |obj, member|
|
|
118
|
+
# obj.my_other_data.has_key?(member) ? obj.my_other_data[member] : obj.send(member)
|
|
119
|
+
# end
|
|
120
|
+
# end
|
|
121
|
+
#if the hash <tt>my_other_data</tt> has key <tt>member</tt> get it from the hash,
|
|
122
|
+
#otherwise get it from calling the appropriate method
|
|
123
|
+
def flex_members_reader(&block)
|
|
124
|
+
flex_remoting.members_reader = block
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
#defines a callback to get the value of the object's dynamic members.
|
|
128
|
+
#For example:
|
|
129
|
+
# class User
|
|
130
|
+
# attr_accessor :my_dynamic_members #this is a hash...
|
|
131
|
+
# flex_dynamic_members_reader do |obj, member|
|
|
132
|
+
# obj.my_dynamic_members[member]
|
|
133
|
+
# end
|
|
134
|
+
# end
|
|
135
|
+
#this will get all dynamic members from the hash <tt>my_dynamic_members</tt>
|
|
136
|
+
def flex_dynamic_members_reader(&block)
|
|
137
|
+
flex_remoting.dynamic_members_reader = block
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
class Object
|
|
2
|
+
|
|
3
|
+
flex_dynamic_members_finder do |instance, scope|
|
|
4
|
+
instance.instance_variables.map{|v| v[1..-1].to_sym}
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
flex_members_reader do |instance, member|
|
|
8
|
+
instance.send(member)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
flex_members_writer do |obj, key, value|
|
|
12
|
+
obj.respond_to?("#{key}=") ? obj.send("#{key}=",value) : obj.instance_variable_set("@#{key}",value)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
flex_dynamic_members_reader do |instance, member|
|
|
16
|
+
case
|
|
17
|
+
when instance.respond_to?(member)
|
|
18
|
+
instance.send(member)
|
|
19
|
+
when instance.instance_variable_defined?("@#{member}")
|
|
20
|
+
instance.instance_variable_get("@#{member}")
|
|
21
|
+
when instance.respond_to?(:[])
|
|
22
|
+
instance[member]
|
|
23
|
+
else
|
|
24
|
+
begin
|
|
25
|
+
instance.send(member)
|
|
26
|
+
rescue NoMethodError=>e
|
|
27
|
+
warn("***Warning: Couldn't find value from dynamic member #{member} in object #{instance.class.name}!")
|
|
28
|
+
nil
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
flex_dynamic_members_writer do |instance, member, value|
|
|
34
|
+
instance.send("#{member}=", value)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
unless defined?(returning)
|
|
38
|
+
def returning(value)
|
|
39
|
+
yield(value)
|
|
40
|
+
value
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
module RAMF
|
|
3
|
+
#The term 'traits' is used to describe the defining characteristics of a class. (amf3 spec document section 3.12)
|
|
4
|
+
class FlexClassTraits
|
|
5
|
+
|
|
6
|
+
KNOWN_CLASSES = {}
|
|
7
|
+
|
|
8
|
+
def self.find_ruby_class(name)
|
|
9
|
+
# RAILS_DEFAULT_LOGGER.info "name: #{name.to_s.inspect}"
|
|
10
|
+
# RAILS_DEFAULT_LOGGER.info "KNOWN_CLASSES[name]:#{KNOWN_CLASSES[name.to_s].inspect}"
|
|
11
|
+
# RAILS_DEFAULT_LOGGER.info "KNOWN_CLASSES:\n#{KNOWN_CLASSES.inspect}"
|
|
12
|
+
Object.module_eval(KNOWN_CLASSES[name.to_s]) rescue nil
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
attr_reader :klass, :members, :name
|
|
16
|
+
attr_accessor :transient_members, :amf_scope_options, :is_dynamic
|
|
17
|
+
attr_accessor :dynamic_members_writer, :members_writer
|
|
18
|
+
attr_accessor :dynamic_members_reader, :members_reader
|
|
19
|
+
|
|
20
|
+
def initialize(klass,is_dynamic, options = {})
|
|
21
|
+
@klass = klass
|
|
22
|
+
@amf_scope_options = get_duplicate_from_super({}, :amf_scope_options)
|
|
23
|
+
@members = {}
|
|
24
|
+
self.name= klass.name
|
|
25
|
+
@is_dynamic = is_dynamic
|
|
26
|
+
@defined_members = []
|
|
27
|
+
@transient_members = options[:transient] || []
|
|
28
|
+
[:dynamic_members_writer, :members_writer, :dynamic_members_reader, :members_reader].each do |a|
|
|
29
|
+
default = Proc.new{raise "No #{a} defined for #{klass}"}
|
|
30
|
+
instance_variable_set("@#{a}", get_attribute_from_super(default, a))
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def name=(new_name)
|
|
35
|
+
new_name = new_name.to_s
|
|
36
|
+
if KNOWN_CLASSES[new_name] && KNOWN_CLASSES[new_name]!=klass.name
|
|
37
|
+
raise("An ActionScript class named '#{new_name}' already exists.")
|
|
38
|
+
end
|
|
39
|
+
KNOWN_CLASSES.delete(@name)
|
|
40
|
+
@name = new_name
|
|
41
|
+
KNOWN_CLASSES[new_name] = klass.name
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def transient_members
|
|
45
|
+
(@transient_members + get_attribute_from_super([], :transient_members)).uniq
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def members(scope = RAMF::Configuration::DEFAULT_SCOPE)
|
|
49
|
+
@members[scope] ||= find_members(scope)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def defined_members=(members)
|
|
53
|
+
@defined_members = members.flatten.map {|v| v.to_sym}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def dynamic_members_finders
|
|
57
|
+
@dynamic_members_finders ||= get_duplicate_from_super([], :dynamic_members_finders)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def dynamic_members(instance, scope = RAMF::Configuration::DEFAULT_SCOPE)
|
|
61
|
+
members = dynamic_members_finders.map{|b| b.call(instance, scope)}.flatten.uniq
|
|
62
|
+
members -= members(scope)
|
|
63
|
+
members -= transient_members
|
|
64
|
+
scope_opt = amf_scope_options[scope]
|
|
65
|
+
except = scope_opt && scope_opt[:except] ? scope_opt[:except] : []
|
|
66
|
+
members -= except
|
|
67
|
+
members.inject({}) do |hash,member|
|
|
68
|
+
hash[member] = dynamic_members_reader.call(instance,member)
|
|
69
|
+
hash
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
##############################################################
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def find_members(scope)
|
|
77
|
+
if (amf_scope_options[scope] && amf_scope_options[scope][:only])
|
|
78
|
+
members = amf_scope_options[scope][:only]
|
|
79
|
+
else
|
|
80
|
+
members = get_duplicate_from_super([], :members, scope) + @defined_members
|
|
81
|
+
members += klass.flex_members if klass.respond_to?(:flex_members)
|
|
82
|
+
members -= transient_members
|
|
83
|
+
members -= amf_scope_options[scope][:except] if amf_scope_options[scope]
|
|
84
|
+
end
|
|
85
|
+
members
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def get_duplicate_from_super(default, attribute, *args)
|
|
89
|
+
get_attribute_from_super(default, attribute, *args).dup
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_attribute_from_super(default, attribute, *args)
|
|
94
|
+
klass.superclass ? klass.superclass.flex_remoting.send(attribute,*args) : default
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module RAMF
|
|
2
|
+
module FlexObjects
|
|
3
|
+
class AcknowledgeMessage
|
|
4
|
+
flex_alias 'flex.messaging.messages.AcknowledgeMessage'
|
|
5
|
+
MEMBERS = [:messageId, :clientId, :destination, :body, :timeToLive, :timestamp, :headers, :correlationId]
|
|
6
|
+
|
|
7
|
+
flex_remoting_members MEMBERS
|
|
8
|
+
attr_accessor *MEMBERS
|
|
9
|
+
|
|
10
|
+
def initialize(options={})
|
|
11
|
+
@messageId = rand_uuid
|
|
12
|
+
@clientId = options[:clientId] ||rand_uuid
|
|
13
|
+
@destination = nil
|
|
14
|
+
@body = options[:body] || nil
|
|
15
|
+
@timeToLive = 0
|
|
16
|
+
@timestamp = Time.now.to_i * 100
|
|
17
|
+
@headers = {}
|
|
18
|
+
@correlationId = options[:correlationId]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def rand_uuid
|
|
22
|
+
[8,4,4,4,12].map {|n| rand_hex_3(n)}.join('-').to_s
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def rand_hex_3(l)
|
|
26
|
+
"%0#{l}x" % rand(1 << l*4)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
class RAMF::FlexObjects::CommandMessage
|
|
2
|
+
flex_alias "flex.messaging.messages.CommandMessage"
|
|
3
|
+
flex_remoting_members :operation, :correlationId, :clientId,
|
|
4
|
+
:messageId, :body, :timestamp, :timeToLive,
|
|
5
|
+
:destination, :headers
|
|
6
|
+
|
|
7
|
+
attr_accessor :operation, :correlationId, :clientId,
|
|
8
|
+
:messageId, :body, :timestamp, :timeToLive,
|
|
9
|
+
:destination, :headers
|
|
10
|
+
|
|
11
|
+
######################################OPERATION TYPES###############################3
|
|
12
|
+
#holdes the operations names for easier debugging and exception reporting
|
|
13
|
+
OPERATION_NAMES = {}
|
|
14
|
+
|
|
15
|
+
#This operation is used to subscribe to a remote destination.
|
|
16
|
+
SUBSCRIBE_OPERATION = 0; OPERATION_NAMES[0] = "SUBSCRIBE_OPERATION"
|
|
17
|
+
|
|
18
|
+
#This operation is used to unsubscribe from a remote destination.
|
|
19
|
+
UNSUBSCRIBE_OPERATION = 1; OPERATION_NAMES[1] = "UNSUBSCRIBE_OPERATION"
|
|
20
|
+
|
|
21
|
+
#This operation is used to poll a remote destination for pending, undelivered messages.
|
|
22
|
+
POLL_OPERATION = 2; OPERATION_NAMES[2] = "POLL_OPERATION"
|
|
23
|
+
|
|
24
|
+
#This operation is used by a remote destination to sync missed or cached messages
|
|
25
|
+
#back to a client as a result of a client issued poll command.
|
|
26
|
+
CLIENT_SYNC_OPERATION = 4; OPERATION_NAMES[4] = "CLIENT_SYNC_OPERATION"
|
|
27
|
+
|
|
28
|
+
#This operation is used to test connectivity over the current channel to
|
|
29
|
+
#the remote endpoint.
|
|
30
|
+
CLIENT_PING_OPERATION = 5; OPERATION_NAMES[5] = "CLIENT_PING_OPERATION"
|
|
31
|
+
|
|
32
|
+
#This operation is used to request a list of failover endpoint URIs
|
|
33
|
+
#for the remote destination based on cluster membership.
|
|
34
|
+
CLUSTER_REQUEST_OPERATION = 7; OPERATION_NAMES[7] = "CLUSTER_REQUEST_OPERATION"
|
|
35
|
+
|
|
36
|
+
#This operation is used to send credentials to the endpoint so that
|
|
37
|
+
#the user can be logged in over the current channel.
|
|
38
|
+
#The credentials need to be Base64 encoded and stored in the <code>body</code>
|
|
39
|
+
#of the message.
|
|
40
|
+
LOGIN_OPERATION = 8; OPERATION_NAMES[8] = "LOGIN_OPERATION"
|
|
41
|
+
|
|
42
|
+
#This operation is used to log the user out of the current channel, and
|
|
43
|
+
#will invalidate the server session if the channel is HTTP based.
|
|
44
|
+
LOGOUT_OPERATION = 9; OPERATION_NAMES[9] = "LOGOUT_OPERATION"
|
|
45
|
+
|
|
46
|
+
#This operation is used to indicate that the client's subscription with a
|
|
47
|
+
#remote destination has timed out.
|
|
48
|
+
SUBSCRIPTION_INVALIDATE_OPERATION = 10; OPERATION_NAMES[10] = "SUBSCRIPTION_INVALIDATE_OPERATION"
|
|
49
|
+
|
|
50
|
+
#Used by the MultiTopicConsumer to subscribe/unsubscribe for more
|
|
51
|
+
#than one topic in the same message.
|
|
52
|
+
MULTI_SUBSCRIBE_OPERATION = 11; OPERATION_NAMES[11] = "MULTI_SUBSCRIBE_OPERATION"
|
|
53
|
+
|
|
54
|
+
#This operation is used to indicate that a channel has disconnected.
|
|
55
|
+
DISCONNECT_OPERATION = 12; OPERATION_NAMES[12] = "DISCONNECT_OPERATION"
|
|
56
|
+
|
|
57
|
+
#This is the default operation for new CommandMessage instances.
|
|
58
|
+
UNKNOWN_OPERATION = 10000; OPERATION_NAMES[10000] = "UNKNOWN_OPERATION"
|
|
59
|
+
|
|
60
|
+
######################################HEADER VALUES###############################
|
|
61
|
+
|
|
62
|
+
#Endpoints can imply what features they support by reporting the
|
|
63
|
+
#latest version of messaging they are capable of during the handshake of
|
|
64
|
+
#the initial ping CommandMessage.
|
|
65
|
+
MESSAGING_VERSION = "DSMessagingVersion"
|
|
66
|
+
|
|
67
|
+
def credentials_for_login_operation
|
|
68
|
+
RAMF::Util.extract_credentials(body.to_s) || {:userid => nil, :password => nil}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
#construct an Operation object from the command message <tt>message</tt>
|
|
72
|
+
def to_operation
|
|
73
|
+
case operation
|
|
74
|
+
when CLIENT_PING_OPERATION
|
|
75
|
+
RAMF::OperationRequest.new :operation => operation,
|
|
76
|
+
:messageId=>messageId
|
|
77
|
+
when LOGIN_OPERATION
|
|
78
|
+
RAMF::OperationRequest.new :operation => operation,
|
|
79
|
+
:credentials => credentials_for_login_operation,
|
|
80
|
+
:messageId=>messageId
|
|
81
|
+
else
|
|
82
|
+
raise "Unimplemented Operation: #{operation} - #{OPERATION_NAMES[operation]}"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class RAMF::FlexObjects::ErrorMessage < RAMF::FlexObjects::AcknowledgeMessage
|
|
2
|
+
flex_alias "flex.messaging.messages.ErrorMessage"
|
|
3
|
+
flex_remoting_members :extendedData, :faultCode, :faultDetail, :faultString, :rootCause
|
|
4
|
+
|
|
5
|
+
attr_accessor :extendedData, :faultCode, :faultDetail, :faultString, :rootCause
|
|
6
|
+
|
|
7
|
+
def initialize(options = {})
|
|
8
|
+
super(options)
|
|
9
|
+
self.extendedData = options[:exception]
|
|
10
|
+
self.faultDetail = options[:exception].message if options[:exception]
|
|
11
|
+
self.faultString = options[:exception].message if options[:exception]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module RAMF
|
|
2
|
+
module FlexObjects
|
|
3
|
+
|
|
4
|
+
#This class is used to create objects that are anonymous flex objects.
|
|
5
|
+
#these objects are very much like a ruby hash but their attributes can be accessed
|
|
6
|
+
#via methods as well.
|
|
7
|
+
#
|
|
8
|
+
# some_object = RAMF::FlexObjects::FlexAnonymousObject.new
|
|
9
|
+
# => {}
|
|
10
|
+
# some_object.my_attribute = "Wow !"
|
|
11
|
+
# => "Wow !"
|
|
12
|
+
# some_object
|
|
13
|
+
# => {:my_attribute=>"Wow !"}
|
|
14
|
+
# some_object.my_attribute == some_object[:my_attribute]
|
|
15
|
+
# => true
|
|
16
|
+
#
|
|
17
|
+
class FlexAnonymousObject < Hash
|
|
18
|
+
|
|
19
|
+
flex_alias ""
|
|
20
|
+
|
|
21
|
+
def method_missing(method_name,*args,&block)
|
|
22
|
+
method_name = method_name.to_s
|
|
23
|
+
if method_name[method_name.length-1,1] == "="
|
|
24
|
+
self["#{method_name[0,method_name.length-1]}".to_sym] = args.first
|
|
25
|
+
else
|
|
26
|
+
self["#{method_name}".to_sym]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# def flex_dynamic_members(scope = :default)
|
|
32
|
+
# self.keys.inject({}) {|mem, key| mem[key.to_s] = self[key]; mem}
|
|
33
|
+
# end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'base64'
|
|
2
|
+
|
|
3
|
+
class RAMF::FlexObjects::RemotingMessage
|
|
4
|
+
flex_alias 'flex.messaging.messages.RemotingMessage'
|
|
5
|
+
flex_remoting_members :operation, :source, :correlationId, :clientId,
|
|
6
|
+
:messageId, :body, :timestamp, :timeToLive,
|
|
7
|
+
:destination, :headers
|
|
8
|
+
|
|
9
|
+
attr_accessor :operation, :source, :correlationId, :clientId,
|
|
10
|
+
:messageId, :body, :timestamp, :timeToLive,
|
|
11
|
+
:destination, :headers
|
|
12
|
+
|
|
13
|
+
def credentials_header
|
|
14
|
+
RAMF::Util.extract_credentials(headers[:DSRemoteCredentials].to_s) || {:userid => nil, :password => nil}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
#construct an Operation object from the remoting message <tt>message</tt>
|
|
18
|
+
def to_operation
|
|
19
|
+
RAMF::OperationRequest.new :service => RAMF::Util.service_name(destination.to_s),
|
|
20
|
+
:method => RAMF::Util.method_name(operation.to_s),
|
|
21
|
+
:args => body,
|
|
22
|
+
:credentials => credentials_header,
|
|
23
|
+
:messageId=>messageId
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
module RAMF
|
|
2
|
+
module IO
|
|
3
|
+
module CommonReadWrite
|
|
4
|
+
BigEndian = :BigEndian
|
|
5
|
+
LittleEndian = :LittleEndian
|
|
6
|
+
@@BYTE_ORDER = nil
|
|
7
|
+
|
|
8
|
+
#examines the locale byte order on the running machine
|
|
9
|
+
def byte_order
|
|
10
|
+
if @@BYTE_ORDER.nil?
|
|
11
|
+
@@BYTE_ORDER = ([0x12345678].pack("L") == "\x12\x34\x56\x78") ? :BigEndian : :LittleEndian
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def byte_order_little?
|
|
16
|
+
(byte_order == :LittleEndian)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def byte_order_big?
|
|
20
|
+
(byte_order == :BigEndian)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def readU8(stream)
|
|
24
|
+
stream.read(1).unpack('C').first
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def readU16(stream)
|
|
28
|
+
stream.read(2).unpack('n').first
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def readU32(stream)
|
|
32
|
+
stream.read(4).unpack('N').first
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def read_double(stream)
|
|
36
|
+
stream.read(8).unpack('G').first
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def readUTF8(stream)
|
|
40
|
+
length = readU16(stream)
|
|
41
|
+
stream.read(length)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def writeU8(val, stream)
|
|
45
|
+
stream.write [val].pack('C')
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def writeU16(val,stream)
|
|
49
|
+
stream.write [val].pack('n')
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
#write an unsigned 32-bit integer in network (big-endian) byte order
|
|
53
|
+
def writeU32(val,stream)
|
|
54
|
+
stream.write [val].pack('N')
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def writeUTF8(string,stream)
|
|
58
|
+
writeU16(string.length,stream)
|
|
59
|
+
stream.write string
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def writeUTF8Long(string,stream)
|
|
63
|
+
writeU32(string.length, stream)
|
|
64
|
+
stream.write string
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def write_double(val,stream)
|
|
68
|
+
stream.write( @double_mappings[val] ||= [val].pack('G'))
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
module RAMF
|
|
2
|
+
module IO
|
|
3
|
+
module Constants
|
|
4
|
+
#AMF0
|
|
5
|
+
AMF0_NUMBER = 0x00
|
|
6
|
+
AMF0_BOOLEAN = 0x01
|
|
7
|
+
AMF0_STRING = 0x02
|
|
8
|
+
AMF0_OBJECT = 0x03
|
|
9
|
+
AMF0_MOVIE_CLIP = 0x04
|
|
10
|
+
AMF0_NULL = 0x05
|
|
11
|
+
AMF0_UNDEFINED = 0x06
|
|
12
|
+
AMF0_REFERENCE = 0x07
|
|
13
|
+
AMF0_MIXED_ARRAY = 0x08
|
|
14
|
+
AMF0_EOO = 0x09
|
|
15
|
+
AMF0_ARRAY = 0x0A
|
|
16
|
+
AMF0_DATE = 0x0B
|
|
17
|
+
AMF0_LONG_STRING = 0x0C
|
|
18
|
+
AMF0_UNSUPPORTED = 0x0D
|
|
19
|
+
AMF0_RECORDSET = 0x0E
|
|
20
|
+
AMF0_XML = 0x0F
|
|
21
|
+
AMF0_TYPED_OBJECT = 0x10
|
|
22
|
+
|
|
23
|
+
#AMF0 MARKERS
|
|
24
|
+
AMF0_NUMBER_MARKER = "\000"
|
|
25
|
+
AMF0_BOOLEAN_MARKER = "\001"
|
|
26
|
+
AMF0_STRING_MARKER = "\002"
|
|
27
|
+
AMF0_OBJECT_MARKER = "\003"
|
|
28
|
+
AMF0_MOVIE_CLIP_MARKER = "\004"
|
|
29
|
+
AMF0_NULL_MARKER = "\005"
|
|
30
|
+
AMF0_UNDEFINED_MARKER = "\006"
|
|
31
|
+
AMF0_REFERENCE_MARKER = "\007"
|
|
32
|
+
AMF0_ECMA_ARRAY_MARKER = "\010"
|
|
33
|
+
AMF0_OBJECT_END_MARKER = "\011"
|
|
34
|
+
AMF0_ARRAY_MARKER = "\012"
|
|
35
|
+
AMF0_DATE_MARKER = "\013"
|
|
36
|
+
AMF0_LONG_STRING_MARKER = "\014"
|
|
37
|
+
AMF0_UNSUPPORTED_MARKER = "\015"
|
|
38
|
+
AMF0_RECORDSET_MARKER = "\016"
|
|
39
|
+
AMF0_XML_MARKER = "\017"
|
|
40
|
+
AMF0_TYPED_OBJECT_MARKER = "\020"
|
|
41
|
+
|
|
42
|
+
#AMF3
|
|
43
|
+
AMF3_TYPE = 0x11
|
|
44
|
+
AMF3_UNDEFINED = 0x00
|
|
45
|
+
AMF3_NULL = 0x01
|
|
46
|
+
AMF3_FALSE = 0x02
|
|
47
|
+
AMF3_TRUE = 0x03
|
|
48
|
+
AMF3_INTEGER = 0x04
|
|
49
|
+
AMF3_DOUBLE = 0x05
|
|
50
|
+
AMF3_STRING = 0x06
|
|
51
|
+
AMF3_XML_DOC = 0x07
|
|
52
|
+
AMF3_DATE = 0x08
|
|
53
|
+
AMF3_ARRAY = 0x09
|
|
54
|
+
AMF3_OBJECT = 0x0A
|
|
55
|
+
AMF3_XML = 0x0B
|
|
56
|
+
AMF3_BYTE_ARRAY = 0x0C
|
|
57
|
+
AMF3_INTEGER_MAX = 268435455
|
|
58
|
+
AMF3_INTEGER_MIN = -268435456
|
|
59
|
+
|
|
60
|
+
#AMF3 Markers
|
|
61
|
+
AMF3_TYPE_MARKER = "\021"
|
|
62
|
+
AMF3_UNDEFINED_MARKER = "\000"
|
|
63
|
+
AMF3_NULL_MARKER = "\001"
|
|
64
|
+
AMF3_FALSE_MARKER = "\002"
|
|
65
|
+
AMF3_TRUE_MARKER = "\003"
|
|
66
|
+
AMF3_INTEGER_MARKER = "\004"
|
|
67
|
+
AMF3_DOUBLE_MARKER = "\005"
|
|
68
|
+
AMF3_STRING_MARKER = "\006"
|
|
69
|
+
AMF3_XML_DOC_MARKER = "\007"
|
|
70
|
+
AMF3_DATE_MARKER = "\010"
|
|
71
|
+
AMF3_ARRAY_MARKER = "\011"
|
|
72
|
+
AMF3_OBJECT_MARKER = "\012"
|
|
73
|
+
AMF3_XML_STRING_MARKER = "\013"
|
|
74
|
+
AMF3_BYTE_ARRAY_MARKER = "\014"
|
|
75
|
+
|
|
76
|
+
AMF3_EMPTY_STRING = "\001"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|