require "aws-sdk-dynamodb" require 'fileutils' require 'erb' require 'yaml' module Dynomite::DbConfig def self.included(base) base.extend(ClassMethods) end def db self.class.db end # NOTE: Class including Dynomite::DbConfig is required to have table_name method defined def namespaced_table_name [self.class.table_namespace, table_name].reject {|s| s.nil? || s.empty?}.join('-') end module ClassMethods @@db = nil def db return @@db if @@db config = db_config endpoint = ENV['DYNAMODB_ENDPOINT'] || config['endpoint'] check_dynamodb_local!(endpoint) # Normally, do not set the endpoint to use the current configured region. # Probably want to stay in the same region anyway for db connections. # # List of regional endpoints: https://docs.aws.amazon.com/general/latest/gr/rande.html#ddb_region # Example: # endpoint: https://dynamodb.us-east-1.amazonaws.com options = endpoint ? { endpoint: endpoint } : {} @@db ||= Aws::DynamoDB::Client.new(options) end # When endoint has been configured to point at dynamodb local: localhost:8000 # check if port 8000 is listening and timeout quickly. Or else it takes a # for DynamoDB local to time out, about 10 seconds... # This wastes less of the users time. def check_dynamodb_local!(endpoint) return unless endpoint && endpoint.include?("8000") open = port_open?("127.0.0.1", 8000, 0.2) unless open raise "You have configured your app to use DynamoDB local, but it is not running. Please start DynamoDB local. Example: brew cask install dynamodb-local && dynamodb-local" end end # Thanks: https://gist.github.com/ashrithr/5305786 def port_open?(ip, port, seconds=1) # => checks if a port is open or not Timeout::timeout(seconds) do begin TCPSocket.new(ip, port).close true rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError false end end rescue Timeout::Error false end # useful for specs def db=(db) @@db = db end def db_config return @db_config if @db_config if defined?(Jets) config_path = "#{Jets.root}config/dynamodb.yml" env = Jets.env else config_path = ENV['DYNOMITE_CONFIG'] || "./config/dynamodb.yml" env = ENV['DYNOMITE_ENV'] || "development" end config = YAML.load(Dynomite::Erb.result(config_path)) @db_config ||= config[env] || {} end def table_namespace(*args) case args.size when 0 get_table_namespace when 1 set_table_namespace(args[0]) end end def get_table_namespace return @table_namespace if defined?(@table_namespace) config = db_config @table_namespace = config['table_namespace'] end def set_table_namespace(value) @table_namespace = value end end end