Class: OpenReceive::Server::RackApp
- Inherits:
-
Object
- Object
- OpenReceive::Server::RackApp
- Defined in:
- lib/openreceive/server/rack_app.rb
Constant Summary collapse
- KNOWN_PATHS =
Route paths (method-independent), used to answer a known path called with the wrong method with 405 instead of 404 — mirrors the JS router.
[ "/checkouts/prepare", "/checkouts", "/payments/check", "/swaps/quote", "/swaps", "/swaps/status", "/swaps/refunds", "/rates" ].freeze
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#initialize(service:, authorize:, resolve_checkout:, on_checkout_created:, on_paid:, rate_limit: nil, client_ip: nil, prefix: "/openreceive") ⇒ RackApp
constructor
A new instance of RackApp.
Constructor Details
#initialize(service:, authorize:, resolve_checkout:, on_checkout_created:, on_paid:, rate_limit: nil, client_ip: nil, prefix: "/openreceive") ⇒ RackApp
Returns a new instance of RackApp.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/openreceive/server/rack_app.rb', line 17 def initialize(service:, authorize:, resolve_checkout:, on_checkout_created:, on_paid:, rate_limit: nil, client_ip: nil, prefix: "/openreceive") @prefix = prefix.to_s.chomp("/") raw_client_ip = client_ip || ->(request) { request.is_a?(Hash) ? request["REMOTE_ADDR"] : nil } @handler = RequestHandler.new( service: service, authorize: , resolve_checkout: resolve_checkout, on_checkout_created: on_checkout_created, on_paid: on_paid, rate_limit: rate_limit, # Stamped IPs are normalized into the same bucket the limiter counts # with (IPv6 /64, v4-mapped collapsed) — mirrors the JS handler. client_ip: ->(request) { ClientIp.attributed(raw_client_ip.call(request)) } ) end |
Instance Method Details
#call(env) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/openreceive/server/rack_app.rb', line 34 def call(env) # Always server-generated (matches JS): a client-supplied X-Request-Id # is unvalidated content and must not be reflected into headers/logs. request_id = "req_#{SecureRandom.uuid}" path = env["PATH_INFO"].to_s return response(@handler.error_response(NotFoundError.new("No OpenReceive route matched this method and path."), request_id)) unless path.start_with?(@prefix) relative = path.delete_prefix(@prefix).sub(%r{/\z}, "") # The body is read only after a route matches (an unknown path stays a # 404 no matter how large the body is), mirroring the JS dispatch order. triple = case [env["REQUEST_METHOD"], relative] when ["POST", "/checkouts/prepare"] then @handler.prepare_checkout(raw_body: read_body(env), request: env, request_id: request_id) when ["POST", "/checkouts"] then @handler.create_checkout(raw_body: read_body(env), request: env, request_id: request_id) when ["POST", "/payments/check"] then @handler.check_payment(raw_body: read_body(env), request: env, request_id: request_id) when ["POST", "/swaps/quote"] then @handler.quote_swap(raw_body: read_body(env), request: env, request_id: request_id) when ["POST", "/swaps"] then @handler.create_swap(raw_body: read_body(env), request: env, request_id: request_id) when ["POST", "/swaps/status"] then @handler.get_swap(raw_body: read_body(env), request: env, request_id: request_id) when ["POST", "/swaps/refunds"] then @handler.refund_swap(raw_body: read_body(env), request: env, request_id: request_id) when ["GET", "/rates"] then @handler.read_rates(query_string: env["QUERY_STRING"], request: env, request_id: request_id) else @handler.error_response(unmatched_route_error(relative), request_id) end response(triple) rescue StandardError => e response(@handler.error_response(e, request_id)) end |