rubyamf-ouvrages 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.
@@ -0,0 +1,53 @@
1
+ require 'rubyamf/rails/controller'
2
+ require 'rubyamf/rails/model'
3
+ require 'rubyamf/rails/request_processor'
4
+ require 'rubyamf/rails/routing'
5
+ require 'rubyamf/rails/time'
6
+ require 'action_controller'
7
+
8
+ # Hook up MIME type
9
+ Mime::Type.register RubyAMF::MIME_TYPE, :amf
10
+
11
+ # Hook routing into routes
12
+ ActionDispatch::Routing::Mapper.send(:include, RubyAMF::Rails::Routing)
13
+
14
+ # Add some utility methods to ActionController
15
+ ActionController::Base.send(:include, RubyAMF::Rails::Controller)
16
+
17
+ # Hook up ActiveRecord Model extensions and make sure Relation objects work
18
+ if defined?(ActiveRecord)
19
+ ActiveRecord::Base.send(:include, RubyAMF::Rails::Model)
20
+ class ActiveRecord::Relation
21
+ def encode_amf ser
22
+ ser.serialize ser.version, self.to_a
23
+ end
24
+ end
25
+ end
26
+
27
+ # Hook up rendering
28
+ ActionController::Renderers.add :amf do |amf, options|
29
+ @amf_response = amf
30
+ @mapping_scope = options[:class_mapping_scope] || options[:mapping_scope] || nil
31
+ self.content_type ||= Mime::AMF
32
+ self.response_body = " "
33
+ end
34
+
35
+ # Add custom responder so respond_with works
36
+ class ActionController::Responder
37
+ def to_amf
38
+ display resource
39
+ end
40
+ end
41
+
42
+ class RubyAMF::Railtie < Rails::Railtie #:nodoc:
43
+ config.rubyamf = RubyAMF.configuration
44
+
45
+ initializer "rubyamf.configured" do
46
+ RubyAMF.bootstrap
47
+ end
48
+
49
+ initializer "rubyamf.middleware" do
50
+ config.app_middleware.use RubyAMF::RequestParser
51
+ config.app_middleware.use RubyAMF::Rails::RequestProcessor
52
+ end
53
+ end
@@ -0,0 +1,90 @@
1
+ module RubyAMF::Rails
2
+ # Rack middleware that handles dispatching AMF calls to the appropriate controller
3
+ # and action.
4
+ class RequestProcessor
5
+ def initialize app
6
+ @app = app
7
+ end
8
+
9
+ # Processes the AMF request and forwards the method calls to the corresponding
10
+ # rails controllers. No middleware beyond the request processor will receive
11
+ # anything if the request is a handleable AMF request.
12
+ def call env
13
+ return @app.call(env) unless env['rubyamf.response']
14
+
15
+ # Handle each method call
16
+ req = env['rubyamf.request']
17
+ res = env['rubyamf.response']
18
+ res.each_method_call req do |method, args|
19
+ handle_method method, args, env
20
+ end
21
+ end
22
+
23
+ # Actually dispatch a fake request to the appropriate controller and extract
24
+ # the response for serialization
25
+ def handle_method method, args, env
26
+ # Parse method and load service
27
+ path = method.split('.')
28
+ method_name = path.pop
29
+ controller_name = path.pop
30
+ controller, method_name = get_service controller_name, method_name
31
+
32
+ # Setup request and controller
33
+ new_env = env.dup
34
+ new_env['HTTP_ACCEPT'] = RubyAMF::MIME_TYPE # Force amf response only
35
+ if defined? ActionDispatch::Request then
36
+ # rails 3.1
37
+ req = ActionDispatch::Request.new(new_env)
38
+ else
39
+ # older rails
40
+ req = ActionController::Request.new(new_env)
41
+ end
42
+ con = controller.new
43
+
44
+ # Populate with AMF data
45
+ amf_req = env['rubyamf.request']
46
+ params_hash = amf_req.params_hash(controller.name, method_name, args)
47
+ req.params.merge!(params_hash) if RubyAMF.configuration.populate_params_hash
48
+ con.instance_variable_set("@is_amf", true)
49
+ con.instance_variable_set("@rubyamf_params", params_hash)
50
+ con.instance_variable_set("@credentials", amf_req.credentials)
51
+
52
+ # Dispatch the request to the controller
53
+ rails_version = ::Rails::VERSION::MAJOR
54
+ if rails_version == 3
55
+ res = con.dispatch(method_name, req)
56
+ else # Rails 2
57
+ req.params['controller'] = controller.controller_name
58
+ req.params['action'] = method_name
59
+ con.process(req, ActionController::Response.new)
60
+ end
61
+
62
+ # Copy mapping scope over to response so it can be used when serialized
63
+ env['rubyamf.response'].mapping_scope = con.send(:mapping_scope)
64
+
65
+ return con.send(:amf_response)
66
+ end
67
+
68
+ # Validate the controller and method name and return the controller class
69
+ def get_service controller_name, method_name
70
+ # Check controller and validate against hacking attempts
71
+ begin
72
+ controller_name += "Controller" unless controller_name =~ /^.+Controller$/
73
+ controller = controller_name.constantize
74
+ raise "not controller" unless controller.respond_to?(:controller_name) && controller.respond_to?(:action_methods)
75
+ rescue Exception => e
76
+ raise "Service #{controller_name} does not exist"
77
+ end
78
+
79
+ # Check action both plain and underscored
80
+ actions = controller.action_methods
81
+ if actions.include?(method_name)
82
+ return [controller, method_name]
83
+ elsif actions.include?(method_name.underscore)
84
+ return [controller, method_name.underscore]
85
+ else
86
+ raise "Service #{controller_name} does not respond to #{method_name}"
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,97 @@
1
+ module RubyAMF::Rails
2
+ # The prefered method for parameter mapping in Rails is through the routing
3
+ # file. RubyAMF supports namespacing for controllers and several different
4
+ # syntax styles for better integration into Rails 2 or Rails 3. This module
5
+ # can also be used outside of Rails by including it wherever you want.
6
+ module Routing
7
+ RAILS2_NAMESPACE_OPTIONS = [:path_prefix, :name_prefix, :namespace]
8
+
9
+ # Define a parameter mapping
10
+ #
11
+ # ===Rails 2
12
+ #
13
+ # ActionController::Routing::Routes.draw do |map|
14
+ # map.amf :controller => "controller", :action => "action", :params => [:param1, :param2]
15
+ # map.namespace :admin do |admin|
16
+ # admin.amf "controller#action", [:param1, :param2]
17
+ # end
18
+ # map.amf "controller", "action1" => [:param1, :param2],
19
+ # "action2" => [:param1, :param2],
20
+ # "action3" => [:param1]
21
+ # end
22
+ #
23
+ # ===Rails 3
24
+ #
25
+ # AmfApplication::Application.routes.draw do |map|
26
+ # map_amf "controller#action", [:param1, :param2]
27
+ # namespace :admin do
28
+ # map_amf "controller#action", [:param1, :param2]
29
+ # end
30
+ # map_amf "controller", "action1" => [:param1, :param2],
31
+ # "action2" => [:param1, :param2],
32
+ # "action3" => [:param1]
33
+ # end
34
+ #
35
+ # ===Generic Framework
36
+ #
37
+ # include Routing
38
+ # # Namespace is WillBe::Camelized
39
+ # map_amf "controller#action", [:param1, :param2]
40
+ # map_amf "controller#action", [:param1, :param2], {:namespace => "will_be/camelized"}
41
+ # map_amf :controller => "controller", :action => "action", :params => [:param1, :param2], :namespace => "will_be/camelized"
42
+ def map_amf *args
43
+ # Rails 2 namespace uses ActiveSupport::OptionMerger, which adds namespace
44
+ # options to last hash, or passes it as an additional parameter
45
+ # Rails 3 stores current namespace info in @scope variable
46
+
47
+ # Process args
48
+ if args.length == 2 && args[1].is_a?(Hash) # "controller", "action" => [], "action" => []
49
+ # Extract the rails2_with_options hash and separate it from the actions
50
+ rails2_with_options = {}
51
+ actions = {}
52
+ args[1].each do |k,v|
53
+ if RAILS2_NAMESPACE_OPTIONS.include?(k)
54
+ rails2_with_options[k] = v
55
+ else
56
+ actions[k] = v
57
+ end
58
+ end
59
+
60
+ # Call map_amf for all actions
61
+ actions.each do |k, v|
62
+ map_amf({:controller => args[0].to_s, :action => k.to_s, :params => v}.merge(rails2_with_options))
63
+ end
64
+ return nil
65
+ elsif args[0].is_a?(String) # "controller#action", []
66
+ (controller, action) = args[0].split("#")
67
+ params = args[1]
68
+ rails2_with_options = args[2] || {}
69
+ else # :controller => "con", :action => "act", :params => []
70
+ controller = args[0].delete(:controller)
71
+ action = args[0].delete(:action)
72
+ params = args[0].delete(:params)
73
+ rails2_with_options = args[0]
74
+ end
75
+
76
+ # Convert controller name to actual controller class name
77
+ controller = controller.camelize(:upper)+"Controller" unless controller =~ /Controller$/
78
+
79
+ # Namespace controller name if used
80
+ modules = if @scope && @scope[:module]
81
+ # Rails 3 code path
82
+ @scope[:module].split("/").map {|n| n.camelize(:upper)}
83
+ elsif rails2_with_options[:namespace]
84
+ # Rails 2 code path
85
+ namespaces = rails2_with_options[:namespace].split("/")
86
+ namespaces.map {|n| n.camelize(:upper)}
87
+ else
88
+ []
89
+ end
90
+ modules << controller
91
+ controller = modules.join("::")
92
+
93
+ RubyAMF.configuration.map_params controller, action, params
94
+ end
95
+ alias_method :amf, :map_amf
96
+ end
97
+ end
@@ -0,0 +1,6 @@
1
+ # Make sure ActiveSupport::TimeWithZone serializes correctly
2
+ class ActiveSupport::TimeWithZone
3
+ def encode_amf ser
4
+ ser.serialize ser.version, self.to_datetime
5
+ end
6
+ end
@@ -0,0 +1,99 @@
1
+ module RubyAMF
2
+ # RubyAMF uses a two-stage middleware strategy. RequestParser is the first
3
+ # stage, and is responsible for parsing the stream and setting
4
+ # <tt>env ['rubyamf.request']</tt> and <tt>env ['rubyamf.response']</tt> to
5
+ # an instance of RubyAMF::Envelope. If the response envelope is marked as
6
+ # constructed, it will send back the serialized response. The second stage is
7
+ # RubyAMF::Rails::RequestProcessor.
8
+ class RequestParser
9
+ def initialize app
10
+ @app = app
11
+ end
12
+
13
+ # Determine how to handle the request and pass off to <tt>handle_amf</tt>,
14
+ # <tt>handle_image</tt>, or <tt>handle_html</tt>. If the <tt>show_html_gateway</tt>
15
+ # config is set to false, it will not serve an HTML page for non-amf requests
16
+ # to the gateway.
17
+ def call env
18
+ # Show HTML gateway page if it's enabled for non-amf requests
19
+ if RubyAMF.configuration.show_html_gateway
20
+ if env['PATH_INFO'] == gateway_image_path
21
+ return handle_image
22
+ elsif env['PATH_INFO'] == gateway_path && env['CONTENT_TYPE'] != RubyAMF::MIME_TYPE
23
+ return handle_html
24
+ end
25
+ end
26
+
27
+ # Handle if it's AMF or pass it up the chain
28
+ if env['PATH_INFO'] == gateway_path && env['CONTENT_TYPE'] == RubyAMF::MIME_TYPE
29
+ return handle_amf(env)
30
+ else
31
+ return @app.call(env)
32
+ end
33
+ end
34
+
35
+ # It parses the request, creates a response object, and forwards the call
36
+ # to the next middleware. If the amf response is constructed, then it serializes
37
+ # the response and returns it as the response.
38
+ def handle_amf env
39
+ # Wrap request and response
40
+ env['rack.input'].rewind
41
+ begin
42
+ env['rubyamf.request'] = RubyAMF::Envelope.new.populate_from_stream(env['rack.input'].read)
43
+ rescue Exception => e
44
+ RubyAMF.logger.log_error(e)
45
+ msg = "Invalid AMF request"
46
+ return [400, {"Content-Type" => "text/plain", 'Content-Length' => msg.length.to_s}, [msg]]
47
+ end
48
+ env['rubyamf.response'] = RubyAMF::Envelope.new
49
+
50
+ # Pass up the chain to the request processor, or whatever is layered in between
51
+ result = @app.call(env)
52
+
53
+ # Calculate length and return response
54
+ if env['rubyamf.response'].constructed?
55
+ RubyAMF.logger.info "Sending back AMF"
56
+ response = env['rubyamf.response'].to_s
57
+ return [200, {"Content-Type" => RubyAMF::MIME_TYPE, 'Content-Length' => response.length.to_s}, [response]]
58
+ else
59
+ return result
60
+ end
61
+ end
62
+
63
+ # It returns a simple HTML page confirming that the gateway is properly running
64
+ def handle_html
65
+ info_url = "https://github.com/rubyamf/rubyamf"
66
+ html = <<END_OF_HTML
67
+ <html>
68
+ <head>
69
+ <title>RubyAMF Gateway</title>
70
+ <style>body{margin:0;padding:0;color:#c8c8c8;background-color:#222222;}</style>
71
+ </head>
72
+ <body>
73
+ <table width="100%" height="100%" align="center" valign="middle">
74
+ <tr><td align="center"><a href="#{info_url}"><img border="0" src="#{gateway_image_path}" /></a></td></tr>
75
+ </table>
76
+ </body>
77
+ </html>
78
+ END_OF_HTML
79
+ return [200, {'Content-Type' => 'text/html', 'Content-Length' => html.length.to_s}, [html]]
80
+ end
81
+
82
+ # Serve rubyamf logo for html page
83
+ def handle_image
84
+ path = File.join(File.dirname(__FILE__), 'gateway.png')
85
+ content = File.read(path)
86
+ size = content.respond_to?(:bytesize) ? content.bytesize : content.size
87
+ return [200, {'Content-Type' => 'image/png', 'Content-Length' => size.to_s}, [content]]
88
+ end
89
+
90
+ def gateway_path #:nodoc:
91
+ path = RubyAMF.configuration.gateway_path
92
+ path.end_with?("/") ? path[0...-1] : path
93
+ end
94
+
95
+ def gateway_image_path #:nodoc:
96
+ gateway_path + "/gateway.png"
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,61 @@
1
+ require 'rack/mock'
2
+
3
+ module RubyAMF
4
+ # Contains helpers to make testing AMF controller testing simple. Rails users
5
+ # can simply use <tt>create_call</tt> and <tt>create_flex_call</tt> to create
6
+ # requests and run them using <tt>dispatch_rails</tt>. Users of other rack-based
7
+ # frameworks will need to handle properly dispatching the request to the right
8
+ # middleware. <tt>create_call_type</tt> creates a rack environment similar to
9
+ # what you would get from RubyAMF::RequestParser, so you can just pass it to
10
+ # whatever your processing middleware is.
11
+ #
12
+ # Rails Example:
13
+ #
14
+ # env = RubyAMF::Test.create_call 3, "TestController.get_user", 5
15
+ # res = RubyAMF::Test.dispatch_rails env
16
+ # res.mapping_scope.should == "testing"
17
+ # res.result.class.name.should == "User"
18
+ module Test
19
+ class << self
20
+ # Creates a rack environment hash that can be used to dispatch the given
21
+ # call. The environment that is created can be directly dispatched to
22
+ # RubyAMF::Rails::RequestProcessor or your own middleware. The type can either
23
+ # be <tt>:standard</tt> or <tt>:flex</tt>, with the flex type using the same
24
+ # style as <tt>RemoteObject</tt> does.
25
+ def create_call_type type, amf_version, target, *args
26
+ amf_req = RubyAMF::Envelope.new :amf_version => amf_version
27
+ if type == :standard
28
+ amf_req.call target, *args
29
+ elsif type == :flex
30
+ amf_req.call_flex target, *args
31
+ else
32
+ raise "Invalid call type: #{type}"
33
+ end
34
+
35
+ env = ::Rack::MockRequest.env_for(RubyAMF.configuration.gateway_path, :method => "post", :input => amf_req.to_s, "CONTENT_TYPE" => RubyAMF::MIME_TYPE)
36
+ env["REQUEST_URI"] = env["PATH_INFO"] # Rails 2.3.X needs this
37
+ env['rubyamf.request'] = amf_req
38
+ env['rubyamf.response'] = RubyAMF::Envelope.new
39
+ env
40
+ end
41
+
42
+ # Creates a rack environment for the standard call type
43
+ def create_call amf_version, target, *args
44
+ create_call_type :standard, amf_version, target, *args
45
+ end
46
+
47
+ # Creates a rack environment for the flex call type
48
+ def create_flex_call target, *args
49
+ create_call_type :flex, 3, target, *args
50
+ end
51
+
52
+ # Dispatches the given rack environment to RubyAMF::Rails::RequestProcessor,
53
+ # which calls the specified controllers. Returns the response RubyAMF::Envelope.
54
+ def dispatch_rails env
55
+ middleware = RubyAMF::Rails::RequestProcessor.new nil
56
+ middleware.call env
57
+ env['rubyamf.response']
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ module RubyAMF
2
+ VERSION = "2.0.0"
3
+ end
data/rubyamf.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rubyamf/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rubyamf-ouvrages"
7
+ s.version = RubyAMF::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Stephen Augenstein"]
10
+ s.email = ["perl.programmer@gmail.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{AMF remoting for Ruby and Rails}
13
+ s.description = %q{RubyAMF is an open source flash remoting gateway for Ruby on Rails and other Rack-based web frameworks.}
14
+ s.rubyforge_project = "rubyamf"
15
+
16
+ s.add_dependency('activesupport', '>= 2.3')
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+
23
+ s.has_rdoc = true
24
+ s.extra_rdoc_files = ['README.rdoc']
25
+ s.rdoc_options = ['--line-numbers', '--main', 'README.rdoc']
26
+ end