Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ruby client #89

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,31 @@ jobs:
working-directory: clients/js
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-ruby-client:
runs-on: ubuntu-latest
needs: create-release
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Set up Ruby 2.6
uses: ruby/setup-ruby@477b21f02be01bcb8030d50f37cfec92bfa615b6
with:
ruby-version: 2.6
- run: bundle install
working-directory: clients/ruby
- name: Publish to RubyGems
run: |
mkdir -p $HOME/.gem
touch $HOME/.gem/credentials
chmod 0600 $HOME/.gem/credentials
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
gem build *.gemspec
gem push *.gem
env:
GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davalpargal Typo here. Secret name is RUBYGEMS_TOKEN

working-directory: clients/ruby
publish-server:
runs-on: ubuntu-latest
needs: create-release
Expand Down
21 changes: 21 additions & 0 deletions .github/workflows/ruby-client-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Test stencil RUBY client
on:
push:
paths:
- "clients/ruby/**"
branches:
- master
pull_request:
paths:
- "clients/ruby/**"
branches:
- master
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-ruby@v1
with:
ruby-version: '2.5'
- run: cd clients/ruby; bin/setup; rspec -fd
1 change: 1 addition & 0 deletions clients/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ Stencil clients abstracts handling of descriptorset file on client side. Current
- [Java](java)
- [Go](go)
- [Javascript](js)
- [Ruby](ruby)
16 changes: 16 additions & 0 deletions clients/ruby/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.mine
*.gem
.config
.rvmrc
.yardoc
InstalledFiles
_yardoc

.bundle
.ruby-version
doc
coverage
pkg
spec/examples.txt
tmp
Gemfile.lock
5 changes: 5 additions & 0 deletions clients/ruby/.rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
--backtrace
--color
--format=documentation
--order random
--require spec_helper
19 changes: 19 additions & 0 deletions clients/ruby/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

source "https://rubygems.org"

# Specify your gem's dependencies in stencil.gemspec
gemspec

gem "rake", "~> 13.0"
gem "http", "4.4.1"
gem 'concurrent-ruby', require: 'concurrent'
gem 'protobuf'

group :test do
gem "simplecov", ">= 0.9"
gem "rspec", "~> 3.0"
gem "rubocop", "~> 1.7"
gem "pry"
gem "google-protobuf"
end
26 changes: 26 additions & 0 deletions clients/ruby/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Stencil

Stencil ruby gem provides a store to lookup protobuf descriptors and options to keep the protobuf descriptors upto date.

## Installation

```ruby
gem 'stencil'
```

And then execute:

$ bundle install

Or install it yourself as:

$ gem install stencil

## Usage


## Development

After checking out the repo, run `bin/setup` to install dependencies. 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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
8 changes: 8 additions & 0 deletions clients/ruby/Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

require "bundler/gem_tasks"
require "rubocop/rake_task"

RuboCop::RakeTask.new

task default: :rubocop
15 changes: 15 additions & 0 deletions clients/ruby/bin/console
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require "bundler/setup"
require "stencil"

# 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__)
9 changes: 9 additions & 0 deletions clients/ruby/bin/setup
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

gem install bundler:1.17.3
bundle install

# Do any other automated setup that you need to do here
18 changes: 18 additions & 0 deletions clients/ruby/lib/stencil.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
require_relative "stencil/version"
require_relative "stencil/configuration"
require_relative "stencil/constants"
require_relative "stencil/client"
require_relative "stencil/store"

require "http"
require "concurrent/timer_task"
require "concurrent/mutable_struct"
require "protobuf"

module Stencil
class Error < StandardError; end
class InvalidConfiguration < Error; end
class InvalidProtoClass < Error; end
class HTTPClientError < Error; end
class HTTPServerError < Error; end
end
65 changes: 65 additions & 0 deletions clients/ruby/lib/stencil/client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
module Stencil
class Client
attr_reader :root
def initialize
begin
@config = Stencil.configuration
validate_configuration(@config)

setup_http_client

@store = Store.new
load_descriptors
setup_store_update_job
end
end

def get_type(proto_name)
file_descriptor_set = @store.read(@config.registry_url)
file_descriptor_set.file.each do |file_desc|
file_desc.message_type.each do |message|
if proto_name == "#{file_desc.options.java_package}.#{message.name}"
return message
end
end
end
raise InvalidProtoClass.new
end

def close
@task.shutdown
end

private

def validate_configuration(configuration)
raise Stencil::InvalidConfiguration.new() if configuration.registry_url.nil? || configuration.bearer_token.nil? || configuration.bearer_token == "Bearer "
end

def setup_http_client
@http_client = HTTP.auth(@config.bearer_token).timeout(@config.http_timeout)
end

def load_descriptors
begin
response = @http_client.get(@config.registry_url)
if response.code != 200
raise HTTPServerError.new("Error while fetching descriptor file: Got #{response.code} from stencil server")
end
rescue StandardError => e
raise HTTPClientError.new(e.message)
end

file_descriptor_set = Google::Protobuf::FileDescriptorSet.decode(response.body)
@store.write(@config.registry_url, file_descriptor_set)
end

def setup_store_update_job
begin
@task = Concurrent::TimerTask.new(execution_interval: @config.refresh_ttl_in_secs) do
load_descriptors
end
end
end
end
end
55 changes: 55 additions & 0 deletions clients/ruby/lib/stencil/configuration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module Stencil
class Configuration
def initialize
@config = ::OpenStruct.new
end

def registry_url
@config.registry_url
end

def registry_url=(registry_url)
@config.registry_url = registry_url
end

def http_timeout
@config.http_timeout || DEFAULT_TIMEOUT_IN_MS
end

def http_timeout=(timeout)
@config.http_timeout = timeout
end

def refresh_enabled
@config.refresh_enabled.nil? ? true : @config.refresh_enabled
end

def refresh_enabled=(refresh_enabled = true)
@config.refresh_enabled = refresh_enabled
end

def refresh_ttl_in_secs
@config.refresh_ttl_in_secs || DEFAULT_REFRESH_INTERVAL_IN_SECONDS
end

def refresh_ttl_in_secs=(refresh_ttl_in_secs)
@config.refresh_ttl_in_secs = refresh_ttl_in_secs
end

def bearer_token=(token)
@config.bearer_token = "Bearer " + token
end

def bearer_token
@config.bearer_token
end
end

def self.configuration
@config ||= Configuration.new
end

def self.configure
yield(configuration)
end
end
4 changes: 4 additions & 0 deletions clients/ruby/lib/stencil/constants.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Stencil
DEFAULT_TIMEOUT_IN_MS = 10000
DEFAULT_REFRESH_INTERVAL_IN_SECONDS = 43200
end
18 changes: 18 additions & 0 deletions clients/ruby/lib/stencil/store.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module Stencil
class Store
def initialize
@lock = Concurrent::ReadWriteLock.new
@data = Hash.new
end

def write(key, value)
@lock.with_write_lock do
@data.store(key, value)
end
end

def read(key)
@data[key]
end
end
end
5 changes: 5 additions & 0 deletions clients/ruby/lib/stencil/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

module Stencil
VERSION = "0.1.0"
end
Binary file added clients/ruby/spec/data/desc-proto-bin
Binary file not shown.
28 changes: 28 additions & 0 deletions clients/ruby/spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require 'simplecov'

SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
[
SimpleCov::Formatter::HTMLFormatter,
]
)

SimpleCov.start do
add_filter "/spec/"
minimum_coverage 80
end

require 'bundler/setup'
Bundler.setup

require 'pry'
require 'stencil'
require 'webmock/rspec'

RSpec.configure do |config|
config.filter_run_when_matching focus: true
config.disable_monkey_patching!
config.profile_examples = 10
config.order = :random
end

WebMock.disable_net_connect!(allow_localhost: true)
Loading