require 'digest' require 'singleton' require 'colored2' require 'timeout' require 'sym/extensions/with_retry' require 'sym/extensions/with_timeout' require 'sym/configuration' require 'sym/app/password/providers' module Sym module App module Password # +Provider+ is the primary implementation of the underlying cache. # It should support the following API: # # def initialize(*args, **opts, &block) # end # # def read(key) # end # # def write(key, value, expire_timeout_seconds) # end # # it must be intantiatable via #new class Cache include Singleton include Sym::Extensions::WithRetry include Sym::Extensions::WithTimeout attr_accessor :provider, :enabled, :timeout, :verbose def configure(**opts) self.enabled = opts[:enabled] self.verbose = opts[:verbose] self.timeout = opts[:timeout] || ::Sym::Configuration.config.password_cache_timeout self.provider = Providers.provider(opts[:provider], opts[:provider_opts] || {}) self.enabled = false unless self.provider self end def [](key) cache = self operation { cache.provider.read(cache.md5(key)) } end def []=(key, value) cache = self operation { cache.provider.write(cache.md5(key), value, cache.timeout) } end def md5(string) Digest::MD5.base64digest(string) end private def operation return nil unless self.enabled with_timeout(1) do with_retry do yield if block_given? end end rescue Timeout::Error => e error(nil, 'Password cache server timed out...') rescue StandardError => e error(e, 'Error connecting to password caching server...') end def error(exception = nil, message = nil) if self.verbose print 'WARNING: ' print message ? message.yellow : '' print exception ? exception.message.red : '' puts end self.enabled = false nil end end end end end