Skip to content

Add basic Credentials wrapper + ManagedNative mixin #20

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

Merged
merged 18 commits into from
Oct 12, 2020
Merged
Show file tree
Hide file tree
Changes from 4 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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
strategy:
fail-fast: false
matrix:
ruby: [2.5, 2.6, 2.7, jruby, truffleruby]
ruby: [2.5, 2.6, 2.7, jruby]
runs-on: ubuntu-latest
steps:
- uses: ruby/setup-ruby@v1
Expand Down Expand Up @@ -72,7 +72,7 @@ jobs:
fail-fast: false
matrix:
os: [macos]
ruby: [2.5, 2.6, 2.7, jruby, truffleruby]
ruby: [2.5, 2.6, 2.7, jruby]
runs-on: macos-latest
steps:
- uses: ruby/setup-ruby@v1
Expand Down
28 changes: 9 additions & 19 deletions gems/aws-crt-auth/lib/aws-crt-auth/credentials.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ module Aws
module Crt
module Auth
# Utility class for Credentials.
# @api private
class Credentials
include Aws::Crt::ManagedNative
native_destroy Aws::Crt::Native.method(:credentials_release)
Expand All @@ -14,7 +13,7 @@ class Credentials
# @param [String] access_key_id
# @param [String] secret_access_key
# @param [String] session_token (nil)
# @param [Time|int] expiration (nil) - Either a Time or if an int
# @param [Time|int] expiration (nil) - Either a Time or an int
# seconds since unix epoch
def initialize(access_key_id, secret_access_key,
session_token = nil, expiration = nil)
Expand All @@ -36,40 +35,31 @@ def initialize(access_key_id, secret_access_key,
end
end

# @return [String, nil]
# @return [String]
def access_key_id
Aws::Crt::Native.credentials_get_access_key_id(native)
Aws::Crt::Native.credentials_get_access_key_id(native).to_s
end

# @return [String, nil]
# @return [String]
def secret_access_key
Aws::Crt::Native.credentials_get_secret_access_key(native)
Aws::Crt::Native.credentials_get_secret_access_key(native).to_s
end

# @return [String, nil]
def session_token
Aws::Crt::Native.credentials_get_session_token(native)
Aws::Crt::Native.credentials_get_session_token(native).to_s
end

# @return [Time,nil]
def expiration
exp = Aws::Crt::Native.credentials_get_expiration(native)
exp = Aws::Crt::Native.credentials_get_expiration_timepoint_seconds!(
native
)
return if exp == UINT64_MAX

Time.at(exp)
end

# @return [Credentials]
def credentials
self
end

# @return [Boolean] Returns `true` if the access key id and secret
# access key are both set.
def set?
native_set?
end

# Removing the secret access key from the default inspect string.
# @api private
def inspect
Expand Down
12 changes: 0 additions & 12 deletions gems/aws-crt-auth/spec/credentials_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,6 @@ module Auth #:nodoc:
end
end

describe '#set?' do
it 'returns true when the key and secret are both non nil values' do
expect(Credentials.new('akid', 'secret').set?).to be(true)
end

it 'returns false after the credentials have been released' do
creds = Credentials.new('akid', 'secret')
creds.release
expect(creds.set?).to be(false)
end
end

describe '#inspect' do
let(:creds) { Credentials.new('akid', 'secret', 'token') }

Expand Down
14 changes: 0 additions & 14 deletions gems/aws-crt/lib/aws-crt.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,5 @@ module Aws
module Crt
# Ensure native init() is called when gem loads
Aws::Crt::Native.init

# Invoke native call, and raise exception if it failed
def self.call
res = yield
# functions that return void cannot fail
return unless res

# for functions that return int, non-zero indicates failure
Errors.raise_last_error if res.is_a?(Integer) && res != 0

# for functions that return pointer, NULL indicates failure
Errors.raise_last_error if res.is_a?(FFI::Pointer) && res.null?
res
end
end
end
2 changes: 1 addition & 1 deletion gems/aws-crt/lib/aws-crt/managed_native.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def manage_native(&block)
'set the method used to cleanup the native object this ' \
'class manages.'
end
native = Aws::Crt.call { block.call }
native = block.call
@native = FFI::AutoPointer.new(native, self.class.method(:on_release))
end

Expand Down
70 changes: 58 additions & 12 deletions gems/aws-crt/lib/aws-crt/native.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# frozen_string_literal: true

require 'ffi'

module Aws
module Crt
# FFI Bindings to native CRT functions
Expand All @@ -10,30 +9,77 @@ module Native

ffi_lib [crt_bin_path(local_platform), 'libaws-crt']

# aws_byte_cursor binding
class ByteCursor < FFI::Struct
layout :len, :size_t,
:ptr, :pointer

def to_s
return unless (self[:len]).positive? && !(self[:ptr]).null?

self[:ptr].get_string(0, self[:len])
end
end

# Core API
attach_function :init, :aws_crt_init, [], :void
attach_function :last_error, :aws_crt_last_error, [], :int
attach_function :error_str, :aws_crt_error_str, [:int], :string
attach_function :error_name, :aws_crt_error_name, [:int], :string
attach_function :error_debug_str, :aws_crt_error_debug_str, [:int], :string
attach_function :reset_error, :aws_crt_reset_error, [], :void
attach_function :global_thread_creator_shutdown_wait_for, :aws_crt_global_thread_creator_shutdown_wait_for, [:uint32], :int

# This MUST follow definitions of core error functions since it relies on them
# And error functions should NOT be wrapped.
#
# Overridden for three purposes.
#
# 1. Allows us to only supply the aws_crt C name, and converts it removes
# the aws_crt.
# 2. Wraps the call in an error-raise checker.
# 3. Creates a bang method that does not do automatic error checking.
def self.attach_function(c_name, params, returns, options = {})
ruby_name = c_name.to_s.sub(/aws_crt_/, '').to_sym
bang_name = "#{ruby_name}!"

super(ruby_name, c_name, params, returns, options)
alias_method(bang_name, ruby_name)

define_method(ruby_name) do |*args, &block|
res = public_send(bang_name, *args, &block)
# functions that return void cannot fail
return unless res

# for functions that return int, non-zero indicates failure
Errors.raise_last_error if res.is_a?(Integer) && res != 0

# for functions that return pointer, NULL indicates failure
Errors.raise_last_error if res.is_a?(FFI::Pointer) && res.null?

res
end

module_function ruby_name
module_function bang_name
end

attach_function :aws_crt_global_thread_creator_shutdown_wait_for, [:uint32], :int

# IO API
attach_function :event_loop_group_new, :aws_crt_event_loop_group_new, [:uint16], :pointer
attach_function :event_loop_group_release, :aws_crt_event_loop_group_release, [:pointer], :void
attach_function :aws_crt_event_loop_group_new, [:uint16], :pointer
attach_function :aws_crt_event_loop_group_release, [:pointer], :void

# Auth API
attach_function :credentials_new, :aws_crt_credentials_new, %i[string string string uint64], :pointer
attach_function :credentials_release, :aws_crt_credentials_release, [:pointer], :void
attach_function :credentials_get_access_key_id, :aws_crt_credentials_get_access_key_id, [:pointer], :string
attach_function :credentials_get_secret_access_key, :aws_crt_credentials_get_secret_access_key, [:pointer], :string
attach_function :credentials_get_session_token, :aws_crt_credentials_get_session_token, [:pointer], :string
attach_function :credentials_get_expiration, :aws_crt_credentials_get_expiration_timepoint_seconds, [:pointer], :uint64
attach_function :aws_crt_credentials_new, %i[string string string uint64], :pointer
attach_function :aws_crt_credentials_release, [:pointer], :void
attach_function :aws_crt_credentials_get_access_key_id, [:pointer], ByteCursor.by_value
attach_function :aws_crt_credentials_get_secret_access_key, [:pointer], ByteCursor.by_value
attach_function :aws_crt_credentials_get_session_token, [:pointer], ByteCursor.by_value
attach_function :aws_crt_credentials_get_expiration_timepoint_seconds, [:pointer], :uint64

# Internal testing API
attach_function :test_error, :aws_crt_test_error, [:int], :int
attach_function :test_pointer_error, :aws_crt_test_pointer_error, [], :pointer
attach_function :aws_crt_test_error, [:int], :int
attach_function :aws_crt_test_pointer_error, [], :pointer
end
end
end
6 changes: 3 additions & 3 deletions gems/aws-crt/native/src/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ AWS_CRT_API struct aws_credentials *aws_crt_credentials_new(
const char *session_token,
uint64_t expiration_timepoint_seconds);
AWS_CRT_API void aws_crt_credentials_release(struct aws_credentials *credentials);
AWS_CRT_API const char *aws_crt_credentials_get_access_key_id(const struct aws_credentials *credentials);
AWS_CRT_API const char *aws_crt_credentials_get_secret_access_key(const struct aws_credentials *credentials);
AWS_CRT_API const char *aws_crt_credentials_get_session_token(const struct aws_credentials *credentials);
AWS_CRT_API struct aws_byte_cursor aws_crt_credentials_get_access_key_id(const struct aws_credentials *credentials);
AWS_CRT_API struct aws_byte_cursor aws_crt_credentials_get_secret_access_key(const struct aws_credentials *credentials);
AWS_CRT_API struct aws_byte_cursor aws_crt_credentials_get_session_token(const struct aws_credentials *credentials);
AWS_CRT_API uint64_t aws_crt_credentials_get_expiration_timepoint_seconds(const struct aws_credentials *credentials);

AWS_EXTERN_C_END
Expand Down
12 changes: 6 additions & 6 deletions gems/aws-crt/native/src/credentials.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ struct aws_credentials *aws_crt_credentials_new(
expiration_timepoint_seconds);
}

const char *aws_crt_credentials_get_access_key_id(const struct aws_credentials *credentials) {
return (char *)aws_credentials_get_access_key_id(credentials).ptr;
struct aws_byte_cursor aws_crt_credentials_get_access_key_id(const struct aws_credentials *credentials) {
return aws_credentials_get_access_key_id(credentials);
}

const char *aws_crt_credentials_get_secret_access_key(const struct aws_credentials *credentials) {
return (char *)aws_credentials_get_secret_access_key(credentials).ptr;
struct aws_byte_cursor aws_crt_credentials_get_secret_access_key(const struct aws_credentials *credentials) {
return aws_credentials_get_secret_access_key(credentials);
}

const char *aws_crt_credentials_get_session_token(const struct aws_credentials *credentials) {
return (char *)aws_credentials_get_session_token(credentials).ptr;
struct aws_byte_cursor aws_crt_credentials_get_session_token(const struct aws_credentials *credentials) {
return aws_credentials_get_session_token(credentials);
}

uint64_t aws_crt_credentials_get_expiration_timepoint_seconds(const struct aws_credentials *credentials) {
Expand Down
19 changes: 0 additions & 19 deletions gems/aws-crt/spec/crt_spec.rb

This file was deleted.

6 changes: 3 additions & 3 deletions gems/aws-crt/spec/errors_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@
describe Aws::Crt::Errors do
describe '.raise_last_error' do
it 'translates and raises the last error' do
Aws::Crt::Native.test_error(3) # generate an error
Aws::Crt::Native.test_error!(3) # generate an error
expect do
Aws::Crt::Errors.raise_last_error
end.to raise_error(Aws::Crt::Error)
end

it 'does not raise when no error' do
Aws::Crt::Native.test_error(0) # success
Aws::Crt::Native.test_error!(0) # success
expect do
Aws::Crt::Errors.raise_last_error
end.not_to raise_error
end

it 'resets the error after raising it' do
Aws::Crt::Native.test_error(3) # raise error
Aws::Crt::Native.test_error!(3) # raise error
expect do
Aws::Crt::Errors.raise_last_error
end.to raise_error(Aws::Crt::Error)
Expand Down
34 changes: 34 additions & 0 deletions gems/aws-crt/spec/native_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

require_relative 'spec_helper'

describe Aws::Crt::Native do
describe '.attach_function' do
it 'removes the aws_crt_ prefix from C functions' do
expect(Aws::Crt::Native).to respond_to(:test_error)
expect(Aws::Crt::Native).not_to respond_to(:aws_crt_test_error)
end

it 'creates a ! version of the function' do
expect(Aws::Crt::Native).to respond_to(:test_error!)
end

it 'raises an error when called on a function that returns an int' do
expect do
Aws::Crt::Native.test_error(3)
end.to raise_error(Aws::Crt::Error)
end

it 'raises an error when called on a function that returns a pointer' do
expect do
Aws::Crt::Native.test_pointer_error
end.to raise_error(NoMemoryError)
end

it 'the ! function does not raise an error' do
expect do
Aws::Crt::Native.test_error!(3)
end.not_to raise_error
end
end
end
2 changes: 1 addition & 1 deletion gems/aws-crt/spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ def garbage_collect_is_immediate?
def check_for_clean_shutdown
ObjectSpace.garbage_collect

Aws::Crt.call { Aws::Crt::Native.global_thread_creator_shutdown_wait_for(10) }
Aws::Crt::Native.global_thread_creator_shutdown_wait_for(10)
end