Skip to content

Commit

Permalink
🎉Sprout initial compensated-proxy gem (#67)
Browse files Browse the repository at this point in the history
* 🎉Sprout initial compensated-proxy gem

See #49

Initializes gem folder structure and hooks the specs into CI

* ✨Forward requests to the downstream endpoint

We're relying on the built in Net::HTTP class, because that keeps
our dependency graph down to zero.

* ♻️It felt odd to have a `Compensated::Proxy::Service`

* ♻️ Inline Forwarder class as it is no longer useful

It was useful when thinking about the problem, but
just adds clutter now that we have decent tests.

* Don't use hardcoded strings because they don't play nice with timezones

* 🎨 💡 Document the classes and apply linting

I'm not sold on rubocop, especially since rubyfmt is so close to  a production release.

However, I am not going to worry too much about it for now.

* 🚧✨ CLI app for forwarding formatted events (#69)

This is still pretty rough, but the general bones are there.

You can now use the executable compensated-proxy in place of
writing your own forwarder in Ruby.

This should make it a bit easier for folks who _do not_ want
to write their entire application in Ruby to do use compensated for
reformatting payment, invoice and subscription related events across payment providers.
  • Loading branch information
zspencer authored May 18, 2020
1 parent 7b56ffc commit 6d5cee2
Show file tree
Hide file tree
Showing 26 changed files with 415 additions and 1 deletion.
2 changes: 2 additions & 0 deletions bin/setup
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ set -vx
if [ -z ${CI+x} ]; then
echo "A local build, dispatch the compensated-ruby module's setup script"
(cd compensated-ruby && bin/setup)
(cd compensated-proxy && bin/setup)
else
echo "A CI build, dispatch the compensated-ruby module's setup script"
(cd compensated-ruby && bin/setup)
(cd compensated-proxy && bin/setup)
fi
1 change: 1 addition & 0 deletions bin/setup-matrix
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ IFS=$'\n\t'
set -vx

(cd compensated-ruby && bin/setup-matrix)
(cd compensated-proxy && bin/setup-matrix)
2 changes: 2 additions & 0 deletions bin/test
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ set -vx
if [ ! -z ${CI+x} ]; then
echo "Testing on CI, dispatch the compensated-ruby module's full test suite"
(cd compensated-ruby && bin/test)
(cd compensated-proxy && bin/test)
else
echo "Testing locally, dispatch the compensated-ruby module's full test suite"
(cd compensated-ruby && bin/test)
(cd compensated-proxy && bin/test)
fi
1 change: 1 addition & 0 deletions bin/test-matrix
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ IFS=$'\n\t'
set -vx

(cd compensated-ruby && bin/test-matrix)
(cd compensated-proxy && bin/test-matrix)
11 changes: 11 additions & 0 deletions compensated-proxy/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/.bundle/
/.yardoc
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/

# rspec failure tracking
.rspec_status
3 changes: 3 additions & 0 deletions compensated-proxy/.rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
--format documentation
--color
--require spec_helper
6 changes: 6 additions & 0 deletions compensated-proxy/.travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
language: ruby
cache: bundler
rvm:
- 2.6.5
before_install: gem install bundler -v 2.1.4
7 changes: 7 additions & 0 deletions compensated-proxy/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
source "https://rubygems.org"

# Specify your gem's dependencies in compensated-proxy.gemspec
gemspec

gem "rake", "~> 12.0"
gem "rspec", "~> 3.0"
36 changes: 36 additions & 0 deletions compensated-proxy/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
PATH
remote: .
specs:
compensated-proxy (0.1.0)
compensated

GEM
remote: https://rubygems.org/
specs:
compensated (0.1.0.pre13)
diff-lcs (1.3)
rake (12.3.3)
rspec (3.9.0)
rspec-core (~> 3.9.0)
rspec-expectations (~> 3.9.0)
rspec-mocks (~> 3.9.0)
rspec-core (3.9.2)
rspec-support (~> 3.9.3)
rspec-expectations (3.9.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.9.0)
rspec-mocks (3.9.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.9.0)
rspec-support (3.9.3)

PLATFORMS
ruby

DEPENDENCIES
compensated-proxy!
rake (~> 12.0)
rspec (~> 3.0)

BUNDLED WITH
2.1.4
50 changes: 50 additions & 0 deletions compensated-proxy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Compensated::Proxy

A forwarding proxy for the [Compensated] payment adapter library, so you can use it
without needing to switch your project to Ruby!

[Compensated]: https://www.zinc.coop/compensated

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'compensated-proxy'
```

And then execute:

$ bundle install

Or install it yourself as:

$ gem install compensated-proxy

## Usage
The Compensated::Proxy is primarily used as a command line program that
verifies the signature of inbound payment processor events, reformats the
events into the standardized Compensated event format, signs them, and
forwards them on to your event listener endpoint.

`$ compensated-proxy --forward-to=https://example.com/your-event-listener --payment-processors=stripe,apple_iap,gumroad`

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/zinc-collective/compensated. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct].

For more information, see the [Contributing Guide].

[Contributing Guide]:../CONTRIBUTING.md

## Code of Conduct

Everyone interacting in the Compensated::Proxy project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct].

[code of conduct]: https://www.zinc.coop/code-of-conduct
6 changes: 6 additions & 0 deletions compensated-proxy/Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require "bundler/gem_tasks"
require "rspec/core/rake_task"

RSpec::Core::RakeTask.new(:spec)

task :default => :spec
14 changes: 14 additions & 0 deletions compensated-proxy/bin/console
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env ruby

require "bundler/setup"
require "compensated/proxy"

# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.

# (If you use this, don't forget to add pry to your Gemfile!)
# require "pry"
# Pry.start

require "irb"
IRB.start(__FILE__)
29 changes: 29 additions & 0 deletions compensated-proxy/bin/rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

#
# This file was generated by Bundler.
#
# The application 'rake' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)

bundle_binstub = File.expand_path("../bundle", __FILE__)

if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end

require "rubygems"
require "bundler/setup"

load Gem.bin_path("rake", "rake")
29 changes: 29 additions & 0 deletions compensated-proxy/bin/rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

#
# This file was generated by Bundler.
#
# The application 'rspec' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)

bundle_binstub = File.expand_path("../bundle", __FILE__)

if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end

require "rubygems"
require "bundler/setup"

load Gem.bin_path("rspec-core", "rspec")
8 changes: 8 additions & 0 deletions compensated-proxy/bin/setup
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx

bundle install

# Do any other automated setup that you need to do here
9 changes: 9 additions & 0 deletions compensated-proxy/bin/setup-matrix
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx

supported_versions=(2.4.9 2.5.7 2.6.5 2.7.0)
for version in "${supported_versions[@]}" ; do
RBENV_VERSION=$version bin/setup
done
12 changes: 12 additions & 0 deletions compensated-proxy/bin/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash


# Configure the script to be verbose and fail early
# See: https://ss64.com/bash/set.html
# See: https://bash.cyberciti.biz/guide/$IFS
set -euo pipefail
IFS=$'\n\t'
set -vx

# Run RSpec
bin/rspec
14 changes: 14 additions & 0 deletions compensated-proxy/bin/test-matrix
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
# Dispatches compensated-ruby's full test suite in each supported Ruby versions

# Configure the script to be verbose and fail early
# See: https://ss64.com/bash/set.html
# See: https://bash.cyberciti.biz/guide/$IFS
set -euo pipefail
IFS=$'\n\t'
set -vx

supported_versions=(2.4.9 2.5.7 2.6.5 2.7.0)
for version in "${supported_versions[@]}" ; do
RBENV_VERSION=$version bin/test
done
29 changes: 29 additions & 0 deletions compensated-proxy/compensated-proxy.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require_relative 'lib/compensated/proxy/version'

Gem::Specification.new do |spec|
spec.name = "compensated-proxy"
spec.version = Compensated::Proxy::VERSION
spec.authors = ["Zinc Collective LLC"]
spec.email = ["[email protected]"]

spec.summary = %q{Provide value. Get paid.}
spec.description = %q{Forward standardized payment events from Stripe, Apple Pay, etc to your service}
spec.homepage = "https://www.zinc.coop/compensated/"
spec.license = "Prosperity Public License 3.0.0"
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")


spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = "https://github.com/zinc-collective/compensated/tree/0.X/compensated-proxy"
spec.metadata["changelog_uri"] = "https://github.com/zinc-collective/compensated/tree/0.X/compensated-proxy/CHANGELOG.md"

# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
spec.add_dependency 'compensated'
end
32 changes: 32 additions & 0 deletions compensated-proxy/exe/compensated-proxy
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env ruby

require 'optparse'

options = {}
OptionParser.new do |opts|
opts.banner = "Usage: compensated-proxy --forward-to=https://example.com/payment-event-handler --payment-processors=stripe"

opts.on("-fhttps://your.example.com/event-handler", "--forward-to=https://your.example.com/event-handler", "URL to forward reformatted payment events") do |forward_to|
options[:forward_to] = forward_to
end
opts.on("-pstripe,gumroad,apple_iap", "--payment-processors=stripe,gumroad,apple_iap", "The payment processors you want to format and forward") do |processors|
options[:payment_processors] = processors.split(',')
end

opts.on("-h", "--help", "Prints this help") do
puts opts
exit
end
end.parse!


port = ENV['PORT'] || 9292
require 'rack'
require_relative '../lib/compensated/proxy'
options[:payment_processors].each do |payment_processor|
require "compensated/#{payment_processor}"
end

Rack::Server.start(
app: Rack::ShowExceptions.new(Rack::Lint.new(Compensated::Proxy.new(forward_to: options[:forward_to]))), Port: port
)
44 changes: 44 additions & 0 deletions compensated-proxy/lib/compensated/proxy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# frozen_string_literal: true

require_relative 'proxy/version'

require 'net/http'

require 'compensated'

module Compensated
class Proxy
# Parent class for Proxy errors.
class Error < StandardError; end

attr_accessor :forward_to, :http_client

# @param [String, URI] forward_to Downstream event handler that accepts formatted payment events
# @param [#post] http_client Object HTTP transport. Defaults to the `Net::HTTP` constant.
def initialize(forward_to:, http_client: Net::HTTP)
self.http_client = http_client
self.forward_to = URI(forward_to)
end

def call(env)
request = Rack::Request.new(env)
handle(request)
res = Rack::Response.new
res.finish
end

# Accepts an HTTP request and forwards it to the downstream event handler
# @param [Rack::Request] request Inbound HTTP request with a Payment Gateways'
# event payload
def handle(request)
handler = Compensated::PaymentProcessorEventRequestHandler.new(request)
data = handler.normalized_event_data
data.delete(:raw_body)
forward(JSON.dump(data))
end

private def forward(data)
http_client.post(forward_to, data, 'Content-Type' => 'application/json')
end
end
end
7 changes: 7 additions & 0 deletions compensated-proxy/lib/compensated/proxy/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

module Compensated
class Proxy
VERSION = '0.1.0'
end
end
Loading

0 comments on commit 6d5cee2

Please sign in to comment.