Class: RocketAMF::Envelope

Inherits:
Object
  • Object
show all
Includes:
RocketAMF::Ext::Envelope, Pure::Envelope
Defined in:
lib/rocketamf/ext.rb,
lib/rocketamf/pure.rb,
lib/rocketamf/remoting.rb

Overview

Container for the AMF request/response.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Pure::WriteIOHelpers

#byte_order, #byte_order_little?, #pack_double, #pack_int16_network, #pack_int8, #pack_integer, #pack_word32_network

Methods included from Pure::ReadIOHelpers

#byte_order, #byte_order_little?, #read_double, #read_int16_network, #read_int8, #read_word16_network, #read_word32_network, #read_word8

Constructor Details

#initialize(props = {}) ⇒ Envelope

Returns a new instance of Envelope.



6
7
8
9
10
# File 'lib/rocketamf/remoting.rb', line 6

def initialize props={}
  @amf_version = props[:amf_version] || 0
  @headers = props[:headers] || {}
  @messages = props[:messages] || []
end

Instance Attribute Details

#amf_versionObject (readonly)

Returns the value of attribute amf_version.



4
5
6
# File 'lib/rocketamf/remoting.rb', line 4

def amf_version
  @amf_version
end

#headersObject (readonly)

Returns the value of attribute headers.



4
5
6
# File 'lib/rocketamf/remoting.rb', line 4

def headers
  @headers
end

#messagesObject (readonly)

Returns the value of attribute messages.



4
5
6
# File 'lib/rocketamf/remoting.rb', line 4

def messages
  @messages
end

Instance Method Details

#call(target, *args) ⇒ Object

Creates the appropriate message and adds it to messages to call the given target using the standard (old) remoting APIs. You can call multiple targets in the same request, unlike with the flex remotings APIs.

Example:

req = RocketAMF::Envelope.new
req.call 'test', "arg_1", ["args", "args"]
req.call 'Controller.action'


33
34
35
36
37
38
39
# File 'lib/rocketamf/remoting.rb', line 33

def call target, *args
  raise "Cannot use different call types" unless @call_type.nil? || @call_type == :simple
  @call_type = :simple

  msg_num = messages.length+1
  @messages << RocketAMF::Message.new(target, "/#{msg_num}", args)
end

#call_flex(target, *args) ⇒ Object

Creates the appropriate message and adds it to messages using the new flex (RemoteObject) remoting APIs. You can only make one flex remoting call per envelope, and the AMF version must be set to 3.

Example:

req = RocketAMF::Envelope.new :amf_version => 3
req.call_flex 'Controller.action', "arg_1", ["args", "args"]


49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/rocketamf/remoting.rb', line 49

def call_flex target, *args
  raise "Can only call one flex target per request" if @call_type == :flex
  raise "Cannot use different call types" if @call_type == :simple
  raise "Cannot use flex remoting calls with AMF0" if @amf_version != 3
  @call_type = :flex

  flex_msg = RocketAMF::Values::RemotingMessage.new
  target_parts = target.split(".")
  flex_msg.operation = target_parts.pop # Use pop so that a missing source is possible without issues
  flex_msg.source = target_parts.pop
  flex_msg.body = args
  @messages << RocketAMF::Message.new('null', '/2', flex_msg) # /2 because it always sends a command message before
end

#constructed?Boolean

Whether or not the response has been constructed. Can be used to prevent serialization when no processing has taken place.

Returns:

  • (Boolean)


156
157
158
# File 'lib/rocketamf/remoting.rb', line 156

def constructed?
  @constructed
end

#dispatch_call(p) ⇒ Object

:nodoc:



165
166
167
168
169
170
171
172
# File 'lib/rocketamf/remoting.rb', line 165

def dispatch_call p #:nodoc:
  begin
    p[:block].call(p[:method], p[:args])
  rescue Exception => e
    # Create ErrorMessage object using the source message as the base
    Values::ErrorMessage.new(p[:source], e)
  end
end

#each_method_call(request, &block) ⇒ Object

Builds response from the request, iterating over each method call and using the return value as the method call’s return value. Marks as envelope as constructed after running. – Iterate over all the sent messages. If they’re somthing we can handle, like a command message, then simply add the response message ourselves. If it’s a method call, then call the block with the method and args, catching errors for handling. Then create the appropriate response message using the return value of the block as the return value for the method call.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/rocketamf/remoting.rb', line 80

def each_method_call request, &block
  raise 'Response already constructed' if @constructed

  # Set version from response
  # Can't just copy version because FMS sends version as 1
  @amf_version = request.amf_version == 3 ? 3 : 0 

  request.messages.each do |m|
    # What's the request body?
    case m.data
    when Values::CommandMessage
      # Pings should be responded to with an AcknowledgeMessage built using the ping
      # Everything else is unsupported
      command_msg = m.data
      if command_msg.operation == Values::CommandMessage::CLIENT_PING_OPERATION
        response_value = Values::AcknowledgeMessage.new(command_msg)
      else
        e = Exception.new("CommandMessage #{command_msg.operation} not implemented")
        e.set_backtrace ["RocketAMF::Envelope each_method_call"]
        response_value = Values::ErrorMessage.new(command_msg, e)
      end
    when Values::RemotingMessage
      # Using RemoteObject style message calls
      remoting_msg = m.data
      acknowledge_msg = Values::AcknowledgeMessage.new(remoting_msg)
      method_base = remoting_msg.source.to_s.empty? ? '' : remoting_msg.source+'.'
      body = dispatch_call :method => method_base+remoting_msg.operation, :args => remoting_msg.body, :source => remoting_msg, :block => block

      # Response should be the bare ErrorMessage if there was an error
      if body.is_a?(Values::ErrorMessage)
        response_value = body
      else
        acknowledge_msg.body = body
        response_value = acknowledge_msg
      end
    else
      # Standard response message
      response_value = dispatch_call :method => m.target_uri, :args => m.data, :source => m, :block => block
    end

    target_uri = m.response_uri
    target_uri += response_value.is_a?(Values::ErrorMessage) ? '/onStatus' : '/onResult'
    @messages << ::RocketAMF::Message.new(target_uri, '', response_value)
  end

  @constructed = true
end

#populate_from_stream(stream, class_mapper = nil) ⇒ Object

Populates the envelope from the given stream or string using the given class mapper, or creates a new one. Returns self for easy chaining.

Example:

req = RocketAMF::Envelope.new.populate_from_stream(env['rack.input'].read)

– Implemented in pure/remoting.rb RocketAMF::Pure::Envelope

Raises:



20
21
22
# File 'lib/rocketamf/remoting.rb', line 20

def populate_from_stream stream, class_mapper=nil
  raise AMFError, 'Must load "rocketamf/pure"'
end

#resultObject

Returns the result of a response envelope, or an array of results if there are multiple action call messages. It automatically unwraps flex-style RemoteObject response messages, where the response result is inside a RocketAMF::Values::AcknowledgeMessage.

Example:

req = RocketAMF::Envelope.new
req.call('TestController.test', 'first_arg', 'second_arg')
res = RocketAMF::Envelope.new
res.each_method_call req do |method, args|
  ['a', 'b']
end
res.result     #=> ['a', 'b']


142
143
144
145
146
147
148
149
150
151
152
# File 'lib/rocketamf/remoting.rb', line 142

def result
  results = []
  messages.each do |msg|
    if msg.data.is_a?(Values::AcknowledgeMessage)
      results << msg.data.body
    else
      results << msg.data
    end
  end
  results.length > 1 ? results : results[0]
end

#serialize(class_mapper = nil) ⇒ Object

Serializes the envelope to a string using the given class mapper, or creates a new one, and returns the result – Implemented in pure/remoting.rb RocketAMF::Pure::Envelope

Raises:



67
68
69
# File 'lib/rocketamf/remoting.rb', line 67

def serialize class_mapper=nil
  raise AMFError, 'Must load "rocketamf/pure"'
end

#to_sObject

Return the serialized envelope as a string



161
162
163
# File 'lib/rocketamf/remoting.rb', line 161

def to_s
  serialize
end