agile-proxy-jruby 0.1.25-jruby

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.
Files changed (112) hide show
  1. checksums.yaml +7 -0
  2. data/.bowerrc +3 -0
  3. data/.gitignore +10 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +36 -0
  6. data/.travis.yml +10 -0
  7. data/Gemfile +4 -0
  8. data/Guardfile +20 -0
  9. data/LICENSE +22 -0
  10. data/README.md +131 -0
  11. data/Rakefile +15 -0
  12. data/agile-proxy.gemspec +60 -0
  13. data/assets/index.html +39 -0
  14. data/assets/ui/app/AgileProxyApi.js +31 -0
  15. data/assets/ui/app/app.js +1 -0
  16. data/assets/ui/app/controller/Stubs.js +64 -0
  17. data/assets/ui/app/controller/main.js +12 -0
  18. data/assets/ui/app/directive/AppEnhancedFormElement.js +21 -0
  19. data/assets/ui/app/directive/AppFor.js +16 -0
  20. data/assets/ui/app/directive/AppResponseEditor.js +54 -0
  21. data/assets/ui/app/model/RequestSpec.js +6 -0
  22. data/assets/ui/app/routes.js +11 -0
  23. data/assets/ui/app/service/Dialog.js +49 -0
  24. data/assets/ui/app/service/DomId.js +10 -0
  25. data/assets/ui/app/service/Error.js +7 -0
  26. data/assets/ui/app/service/Stub.js +36 -0
  27. data/assets/ui/app/view/404.html +2 -0
  28. data/assets/ui/app/view/dialog/error.html +10 -0
  29. data/assets/ui/app/view/dialog/yesNo.html +8 -0
  30. data/assets/ui/app/view/responses/editForm.html +78 -0
  31. data/assets/ui/app/view/status.html +1 -0
  32. data/assets/ui/app/view/stubs.html +19 -0
  33. data/assets/ui/app/view/stubs/edit.html +58 -0
  34. data/assets/ui/css/main.css +3 -0
  35. data/bin/agile_proxy +4 -0
  36. data/bower.json +27 -0
  37. data/config.yml +6 -0
  38. data/db.yml +10 -0
  39. data/db/migrations/20140818110800_create_users.rb +9 -0
  40. data/db/migrations/20140818134700_create_applications.rb +10 -0
  41. data/db/migrations/20140818135200_create_request_specs.rb +13 -0
  42. data/db/migrations/20140821115300_create_responses.rb +14 -0
  43. data/db/migrations/20140823082900_add_method_to_request_specs.rb +7 -0
  44. data/db/migrations/20140823083900_rename_request_spec_columns.rb +8 -0
  45. data/db/migrations/20141031072100_add_url_type_to_request_specs.rb +8 -0
  46. data/db/migrations/20141105125600_add_conditions_to_request_specs.rb +7 -0
  47. data/db/migrations/20141106083100_add_username_and_password_to_applications.rb +8 -0
  48. data/db/migrations/20141119143800_add_record_to_applications.rb +7 -0
  49. data/db/migrations/20141119174300_create_recordings.rb +18 -0
  50. data/db/migrations/20150221152500_add_record_requests_to_request_specs.rb +7 -0
  51. data/db/schema.rb +78 -0
  52. data/db/seed.rb +26 -0
  53. data/echo_server.rb +19 -0
  54. data/examples/README.md +1 -0
  55. data/examples/facebook_api.html +59 -0
  56. data/examples/tumblr_api.html +22 -0
  57. data/lib/agile_proxy.rb +8 -0
  58. data/lib/agile_proxy/api/applications.rb +77 -0
  59. data/lib/agile_proxy/api/recordings.rb +52 -0
  60. data/lib/agile_proxy/api/request_spec_recordings.rb +52 -0
  61. data/lib/agile_proxy/api/request_specs.rb +86 -0
  62. data/lib/agile_proxy/api/root.rb +45 -0
  63. data/lib/agile_proxy/cli.rb +116 -0
  64. data/lib/agile_proxy/config.rb +66 -0
  65. data/lib/agile_proxy/handlers/handler.rb +43 -0
  66. data/lib/agile_proxy/handlers/proxy_handler.rb +111 -0
  67. data/lib/agile_proxy/handlers/request_handler.rb +75 -0
  68. data/lib/agile_proxy/handlers/stub_handler.rb +146 -0
  69. data/lib/agile_proxy/mitm.crt +22 -0
  70. data/lib/agile_proxy/mitm.key +27 -0
  71. data/lib/agile_proxy/model/application.rb +20 -0
  72. data/lib/agile_proxy/model/recording.rb +17 -0
  73. data/lib/agile_proxy/model/request_spec.rb +48 -0
  74. data/lib/agile_proxy/model/response.rb +51 -0
  75. data/lib/agile_proxy/model/user.rb +17 -0
  76. data/lib/agile_proxy/proxy_connection.rb +112 -0
  77. data/lib/agile_proxy/rack/get_only_cache.rb +30 -0
  78. data/lib/agile_proxy/route.rb +106 -0
  79. data/lib/agile_proxy/router.rb +99 -0
  80. data/lib/agile_proxy/server.rb +119 -0
  81. data/lib/agile_proxy/servers/api.rb +40 -0
  82. data/lib/agile_proxy/servers/request_spec.rb +40 -0
  83. data/lib/agile_proxy/servers/request_spec_direct.rb +35 -0
  84. data/lib/agile_proxy/version.rb +6 -0
  85. data/load_proxy.js +39 -0
  86. data/log/.gitkeep +0 -0
  87. data/spec/common_helper.rb +32 -0
  88. data/spec/fixtures/example_static_file.html +1 -0
  89. data/spec/fixtures/test-server.crt +15 -0
  90. data/spec/fixtures/test-server.key +15 -0
  91. data/spec/integration/helpers/request_spec_helper.rb +84 -0
  92. data/spec/integration/specs/lib/server_spec.rb +474 -0
  93. data/spec/integration_spec_helper.rb +16 -0
  94. data/spec/spec_helper.rb +39 -0
  95. data/spec/support/test_server.rb +105 -0
  96. data/spec/unit/agile_proxy/api/applications_spec.rb +102 -0
  97. data/spec/unit/agile_proxy/api/common_helper.rb +31 -0
  98. data/spec/unit/agile_proxy/api/recordings_spec.rb +115 -0
  99. data/spec/unit/agile_proxy/api/request_spec_recordings_spec.rb +119 -0
  100. data/spec/unit/agile_proxy/api/request_specs_spec.rb +159 -0
  101. data/spec/unit/agile_proxy/handlers/handler_spec.rb +8 -0
  102. data/spec/unit/agile_proxy/handlers/proxy_handler_spec.rb +138 -0
  103. data/spec/unit/agile_proxy/handlers/request_handler_spec.rb +76 -0
  104. data/spec/unit/agile_proxy/handlers/stub_handler_spec.rb +177 -0
  105. data/spec/unit/agile_proxy/model/recording_spec.rb +0 -0
  106. data/spec/unit/agile_proxy/model/request_spec_spec.rb +45 -0
  107. data/spec/unit/agile_proxy/model/response_spec.rb +38 -0
  108. data/spec/unit/agile_proxy/server_spec.rb +91 -0
  109. data/spec/unit/agile_proxy/servers/api_spec.rb +35 -0
  110. data/spec/unit/agile_proxy/servers/request_spec_direct_spec.rb +51 -0
  111. data/spec/unit/agile_proxy/servers/request_spec_spec.rb +35 -0
  112. metadata +736 -0
@@ -0,0 +1,51 @@
1
+ require 'flavour_saver'
2
+ require 'flavour_saver/runtime'
3
+ module AgileProxy
4
+ #
5
+ # = The associated response for the RequestSpec
6
+ #
7
+ # An instance of this class is expected to be stored alongside every RequestSpec.
8
+ #
9
+ # It is responsible for the following :-
10
+ #
11
+ # 1. Retrieving response
12
+ # 2. Persisting responses
13
+ # 3. Providing a 'rack' ouput of the response
14
+ # 4. Convenient setters for code, body and content_type
15
+ # 5. Template parsing
16
+ class Response < ActiveRecord::Base
17
+ PROTECTED_HEADERS = ['Content-Type']
18
+ has_many :request_specs
19
+ serialize :headers, JSON
20
+ # A convenient setter for the content_type within the header
21
+ # @param val [String] The content type
22
+ def content_type=(val)
23
+ write_attribute(:content_type, val)
24
+ headers.merge!('Content-Type' => val)
25
+ val
26
+ end
27
+ # Provides the response as a 'rack' response
28
+ #
29
+ # If the response is a template (by specifying is_template as true), the output will
30
+ # have its template values parsed and replaced with
31
+ # data from the input_params, input_headers and input_body
32
+ # Otherwise, the body of the output is sent as is.
33
+ # @param input_params [Hash] The input parameters as a hash
34
+ # @param _input_headers [Hash] The input headers as a hash
35
+ # @param _input_body [String] The input body
36
+ # @return [Array] A 'rack' response array (status, headers, body)
37
+ def to_rack(input_params, _input_headers, _input_body)
38
+ output_headers = headers.clone
39
+ output_headers.merge! 'Cache-Control' => 'no-store'
40
+ output_content = content
41
+ output_status_code = status_code
42
+ if is_template
43
+ data = OpenStruct.new input_params
44
+ template = Tilt['handlebars'].new { output_content }
45
+ output_content = template.render data
46
+ end
47
+ EventMachine::Synchrony.sleep(delay) if delay > 0
48
+ [output_status_code, output_headers, [output_content]]
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'application'
2
+ require 'active_record'
3
+ module AgileProxy
4
+ #
5
+ # = An API User
6
+ #
7
+ # The API access to the system is multi user in that each user
8
+ # can have many applications and each application can have many stubs etc...
9
+ #
10
+ # This class is responsible for :-
11
+ # 1. Retrieving users from storage
12
+ # 2. Persisting users to storage
13
+ # 3. Providing a list of applications that the user owns
14
+ class User < ActiveRecord::Base
15
+ has_many :applications
16
+ end
17
+ end
@@ -0,0 +1,112 @@
1
+ require 'uri'
2
+ require 'eventmachine'
3
+ require 'stringio'
4
+ require 'rack'
5
+ require 'goliath/request'
6
+ require 'goliath/env'
7
+
8
+ module AgileProxy
9
+ #
10
+ # = The Proxy Connection
11
+ #
12
+ # This class is the event machine connection used by the proxy. Every request creates a new instance of this
13
+ class ProxyConnection < Goliath::Connection
14
+ def logger
15
+ ::AgileProxy.config.logger
16
+ end
17
+ def post_init
18
+ super
19
+ #@proxy_parser = Http::Parser.new(self)
20
+ @proxy_parser = Http::Parser.new
21
+ end
22
+
23
+ def receive_data(data)
24
+ #@proxy_parser << data
25
+ @parser << data
26
+ end
27
+
28
+ def on_message_begin
29
+ @headers = nil
30
+ @body = ''
31
+ end
32
+
33
+ def on_headers_complete(headers)
34
+ @headers = headers
35
+ end
36
+
37
+ def on_body(chunk)
38
+ @body << chunk
39
+ end
40
+
41
+ def on_message_complete
42
+ if @proxy_parser.http_method == 'CONNECT'
43
+ restart_with_ssl(@proxy_parser.request_url)
44
+ else
45
+ if @ssl
46
+ uri = URI.parse(@proxy_parser.request_url)
47
+ @url = "https://#{@ssl}#{[uri.path, uri.query].compact.join('?')}"
48
+ else
49
+ @url = @proxy_parser.request_url
50
+ end
51
+ handle_request
52
+ end
53
+ end
54
+
55
+
56
+ protected
57
+
58
+ def restart_with_ssl(url)
59
+ @ssl = url
60
+ @proxy_parser = Http::Parser.new(self)
61
+ @original_headers = @headers.clone
62
+ send_data("HTTP/1.0 200 Connection established\r\nProxy-agent: Http-Flexible-Proxy/0.0.0\r\n\r\n")
63
+ start_tls(
64
+ private_key_file: File.expand_path('../mitm.key', __FILE__),
65
+ cert_chain_file: File.expand_path('../mitm.crt', __FILE__)
66
+ )
67
+ end
68
+
69
+ def handle_request
70
+ EM.synchrony do
71
+ request = ::Goliath::Request.new(handler, self, env)
72
+ request.set_deferred_status :succeeded
73
+ request.process
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ def env
80
+ return @__env if @__env
81
+ fake_input_buffer = StringIO.new(@body)
82
+ fake_error_buffer = StringIO.new
83
+ url_parsed = URI.parse(@url)
84
+ @__env = ::Goliath::Env.new
85
+ @__env.merge!({
86
+ 'rack.input' => Rack::Lint::InputWrapper.new(fake_input_buffer),
87
+ 'rack.errors' => Rack::Lint::ErrorWrapper.new(fake_error_buffer),
88
+ 'REQUEST_METHOD' => @proxy_parser.http_method,
89
+ 'REQUEST_PATH' => url_parsed.path,
90
+ 'PATH_INFO' => url_parsed.path,
91
+ 'QUERY_STRING' => url_parsed.query || '',
92
+ 'REQUEST_URI' => url_parsed.path + (url_parsed.query || ''),
93
+ 'rack.url_scheme' => url_parsed.scheme,
94
+ 'CONTENT_LENGTH' => @body.length,
95
+ 'SERVER_NAME' => url_parsed.host,
96
+ 'SERVER_PORT' => url_parsed.port,
97
+ 'rack.logger' => logger
98
+
99
+
100
+ })
101
+ @headers.merge(@original_headers || {}).each do |name, value|
102
+ converted_name = "HTTP_#{name.gsub(/-/, '_').upcase}"
103
+ @__env[converted_name] = value
104
+ end
105
+ @__env['CONTENT_TYPE'] = @__env.delete('HTTP_CONTENT_TYPE') if @__env.key?('HTTP_CONTENT_TYPE')
106
+ @__env['CONTENT_LENGTH'] = @__env.delete('HTTP_CONTENT_LENGTH') if @__env.key?('HTTP_CONTENT_LENGTH')
107
+ @__env
108
+ end
109
+
110
+
111
+ end
112
+ end
@@ -0,0 +1,30 @@
1
+ require 'rack-cache'
2
+ require 'action_dispatch/http/request'
3
+ module AgileProxy
4
+ module Rack
5
+ class GetOnlyCache
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+ def call(env)
10
+ force_caching(env)
11
+ request = ::ActionDispatch::Request.new(env)
12
+ if request.request_method_symbol == :get
13
+ cache_app.call(env)
14
+ else
15
+ @app.call(env)
16
+ end
17
+ end
18
+
19
+ private
20
+ def force_caching(env)
21
+ env.delete 'HTTP_PRAGMA' if env['HTTP_PRAGMA'] == 'no-cache'
22
+ env.delete 'HTTP_CACHE_CONTROL' if env['HTTP_CACHE_CONTROL'] == 'no-cache'
23
+ end
24
+ def cache_app
25
+ @cache_app ||= ::Rack::Cache.new(@app)
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,106 @@
1
+ module AgileProxy
2
+ #
3
+ # An instance of this class represents a route within the system.
4
+ #
5
+ class Route
6
+ attr_accessor :request_method, :pattern, :app, :constraints, :name
7
+
8
+ PATH_INFO = 'PATH_INFO'.freeze
9
+ ROUTE_PARAMS = 'rack.route_params'.freeze
10
+ QUERY_STRING = 'QUERY_STRING'.freeze
11
+ FORM_HASH = 'rack.request.form_hash'.freeze
12
+ REQUEST_METHOD = 'REQUEST_METHOD'.freeze
13
+ HEAD = 'HEAD'.freeze
14
+ GET = 'GET'.freeze
15
+ POST = 'POST'.freeze
16
+ PUT = 'PUT'.freeze
17
+ DELETE = 'DELETE'.freeze
18
+
19
+ DEFAULT_WILDCARD_NAME = :paths
20
+ WILDCARD_PATTERN = /\/\*(.*)/.freeze
21
+ NAMED_SEGMENTS_PATTERN = /\/:([^$\/]+)/.freeze
22
+ NAMED_SEGMENTS_REPLACEMENT_PATTERN = /\/:([^$\/]+)/.freeze
23
+ DOT = '.'.freeze
24
+
25
+ def initialize(request_method, pattern, app, options = {})
26
+ fail ArgumentError, 'pattern cannot be blank' if pattern.to_s.strip.empty?
27
+ fail ArgumentError, 'app must be callable' unless app.respond_to?(:call)
28
+ @request_method = request_method
29
+ @pattern = pattern
30
+ @app = app
31
+ @constraints = options && options[:constraints]
32
+ @name = options && options[:as]
33
+ end
34
+
35
+ def regexp
36
+ @regexp ||= compile
37
+ end
38
+
39
+ def compile
40
+ pattern_match = pattern.match(WILDCARD_PATTERN)
41
+ src = if pattern_match
42
+ @wildcard_name = if pattern_match[1].to_s.strip.empty?
43
+ DEFAULT_WILDCARD_NAME
44
+ else
45
+ pattern_match[1].to_sym
46
+ end
47
+ pattern.gsub(WILDCARD_PATTERN, '(?:/(.*)|)')
48
+ else
49
+ pattern_match = pattern.match(NAMED_SEGMENTS_PATTERN)
50
+ p = if pattern_match
51
+ pattern.gsub(NAMED_SEGMENTS_REPLACEMENT_PATTERN, '/(?<\1>[^.$/]+)')
52
+ else
53
+ pattern
54
+ end
55
+ p + '(?:\.(?<format>.*))?'
56
+ end
57
+ Regexp.new("\\A#{src}\\Z")
58
+ end
59
+
60
+ def match(env)
61
+ request_method = env[REQUEST_METHOD]
62
+ request_method = GET if request_method == HEAD
63
+ path = env[PATH_INFO]
64
+ qs = env[QUERY_STRING]
65
+ return nil unless request_method == self.request_method
66
+ fail ArgumentError, 'path is required' if path.to_s.strip.empty?
67
+ path_match = path.match(regexp)
68
+ return unless path_match
69
+ params = if @wildcard_name
70
+ { @wildcard_name => path_match[1].to_s.split('/') }
71
+ else
72
+ Hash[path_match.names.map(&:to_sym).zip(path_match.captures)]
73
+ end
74
+ params.merge!(::Rack::Utils.parse_nested_query(qs).symbolize_keys) unless qs.nil? || qs.empty?
75
+ params.merge! env[FORM_HASH] if env.key? FORM_HASH
76
+ params.delete(:format) if params.key?(:format) && params[:format].nil?
77
+
78
+ params if meets_constraints(params)
79
+ end
80
+
81
+ def meets_constraints(params)
82
+ if constraints
83
+ constraints.each do |param, constraint|
84
+ unless params.symbolize_keys[param.to_sym].to_s.match(constraint)
85
+ return false
86
+ end
87
+ end
88
+ end
89
+ true
90
+ end
91
+
92
+ def eql?(other)
93
+ other.is_a?(self.class) &&
94
+ other.request_method == request_method &&
95
+ other.pattern == pattern &&
96
+ other.app == app &&
97
+ other.constraints == constraints
98
+ end
99
+
100
+ alias_method :==, :eql?
101
+
102
+ def hash
103
+ request_method.hash ^ pattern.hash ^ app.hash ^ constraints.hash
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,99 @@
1
+ require 'agile_proxy/route'
2
+
3
+ module AgileProxy
4
+ #
5
+ # A rack router used for selecting a 'request spec' from a shortlist
6
+ #
7
+ class Router
8
+ VERSION = '0.4.0'
9
+
10
+ HEAD = 'HEAD'.freeze
11
+ GET = 'GET'.freeze
12
+ POST = 'POST'.freeze
13
+ PUT = 'PUT'.freeze
14
+ DELETE = 'DELETE'.freeze
15
+ REQUEST_METHOD = 'REQUEST_METHOD'.freeze
16
+ PATH_INFO = 'PATH_INFO'.freeze
17
+ ROUTE_PARAMS = 'rack.route_params'.freeze
18
+ QUERY_STRING = 'QUERY_STRING'.freeze
19
+ FORM_HASH = 'rack.request.form_hash'.freeze
20
+
21
+ def initialize(&block)
22
+ @named_routes = {}
23
+ routes(&block)
24
+ end
25
+
26
+ def [](route_name)
27
+ @named_routes[route_name]
28
+ end
29
+
30
+ def routes(&block)
31
+ instance_eval(&block) if block
32
+ @routes
33
+ end
34
+
35
+ def get(route_spec)
36
+ route(GET, route_spec)
37
+ end
38
+
39
+ def post(route_spec)
40
+ route(POST, route_spec)
41
+ end
42
+
43
+ def put(route_spec)
44
+ route(PUT, route_spec)
45
+ end
46
+
47
+ def delete(route_spec)
48
+ route(DELETE, route_spec)
49
+ end
50
+
51
+ def route(method, route_spec)
52
+ route = Route.new(
53
+ method,
54
+ route_spec.first.first,
55
+ route_spec.first.last,
56
+ route_spec.reject { |k, _| k == route_spec.first.first }
57
+ )
58
+ @routes ||= []
59
+ @routes << route
60
+ if route_spec && route_spec[:as]
61
+ # Using ||= so the first route with that name will be returned
62
+ @named_routes[route_spec[:as].to_sym] ||= route_spec.first.first
63
+ end
64
+ route
65
+ end
66
+
67
+ def call(env)
68
+ app = match(env)
69
+ if app
70
+ app.call(env)
71
+ else
72
+ not_found(env)
73
+ end
74
+ end
75
+
76
+ def match(env)
77
+ routes.each do |route|
78
+ params = route.match(env)
79
+ if params
80
+ env[ROUTE_PARAMS] = params
81
+ return route.app
82
+ end
83
+ end
84
+ nil
85
+ end
86
+
87
+ def not_found(env)
88
+ body = "<h1>Not Found</h1><p>No route matches #{env[REQUEST_METHOD]} #{env[PATH_INFO]}</p>"
89
+ [
90
+ 404,
91
+ {
92
+ 'Content-Type' => 'text/html',
93
+ 'Content-Length' => body.length.to_s
94
+ },
95
+ [body]
96
+ ]
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,119 @@
1
+ require 'active_record'
2
+ require 'yaml'
3
+ require 'cgi'
4
+ require 'uri'
5
+ require 'eventmachine'
6
+ require 'grape'
7
+ require 'agile_proxy/api/root'
8
+ require 'agile_proxy/servers/api'
9
+ require 'agile_proxy/servers/request_spec'
10
+ require 'agile_proxy/servers/request_spec_direct'
11
+ require 'forwardable'
12
+
13
+ require 'goliath/api'
14
+ require 'goliath/runner'
15
+
16
+ # Example demonstrating how to use a custom Goliath runner
17
+ #
18
+
19
+ class Custom < Goliath::API
20
+ def response(env)
21
+ [200, {}, "hello!"]
22
+ end
23
+ end
24
+
25
+
26
+
27
+ module AgileProxy
28
+ #
29
+ # This class is responsible for controlling the underlying proxy and web servers
30
+ #
31
+ class Server
32
+ ROOT = File.expand_path '../../', File.dirname(__FILE__)
33
+ extend Forwardable
34
+ attr_reader :request_handler
35
+
36
+ def_delegators :request_handler, :reset_cache, :restore_cache, :handle_request
37
+
38
+ def initialize
39
+ environment = AgileProxy.config.environment
40
+ dbconfig = YAML.load(File.read(AgileProxy.config.database_config_file)).with_indifferent_access
41
+ ActiveRecord::Base.configurations = dbconfig
42
+ ActiveRecord::Base.establish_connection dbconfig[environment.to_s]
43
+ end
44
+
45
+ # Starts the proxy and web servers
46
+ def start
47
+ main_loop
48
+ end
49
+
50
+ # The url that the proxy server is running on
51
+ # @return [String] The URL
52
+ def url
53
+ "http://#{host}:#{port}"
54
+ end
55
+
56
+ # The url that the web server can be accessed from
57
+ # @return [String] The URL
58
+ def webserver_url
59
+ "http://#{webserver_host}:#{webserver_port}"
60
+ end
61
+
62
+ # The url that the direct web server can be accessed from
63
+ # @return [String] The URL
64
+ def server_url
65
+ "http://#{server_host}:#{server_port}"
66
+ end
67
+
68
+ # The host that the proxy server is running on
69
+ # @return [String] The host
70
+ def host
71
+ 'localhost'
72
+ end
73
+
74
+ # The port that the proxy server is running on
75
+ # @return [String] The port
76
+ def port
77
+ @request_spec_server.port
78
+ end
79
+
80
+ # The host that the webserver is running on
81
+ # @return [String] The host
82
+ def webserver_host
83
+ AgileProxy.config.webserver_host
84
+ end
85
+
86
+ # The port that the webserver is running on
87
+ # @return [String] The port
88
+ def webserver_port
89
+ AgileProxy.config.webserver_port
90
+ end
91
+
92
+ # The host that the direct server is running on
93
+ # @return [String] The host
94
+ def server_host
95
+ AgileProxy.config.server_host
96
+ end
97
+
98
+ # The port that the direct server is running on
99
+ # @return [String] The port
100
+ def server_port
101
+ AgileProxy.config.server_port
102
+ end
103
+
104
+ protected
105
+
106
+ def main_loop
107
+ EM.run do
108
+ EM.error_handler do |e|
109
+ puts e.class.name, e
110
+ puts e.backtrace.join("\n")
111
+ end
112
+ AgileProxy::Servers::Api.start(webserver_host, webserver_port)
113
+ AgileProxy::Servers::RequestSpecDirect.start(server_host, server_port)
114
+ @request_spec_server = AgileProxy::Servers::RequestSpec.start enable_cache: AgileProxy.config.enable_cache
115
+ AgileProxy.log(:info, "agile-proxy: Proxy listening on #{url}, API webserver listening on #{webserver_url} and Direct webserver listening on #{server_url}")
116
+ end
117
+ end
118
+ end
119
+ end