rubyamf-ouvrages 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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