require 'active_support/core_ext/hash' require 'active_support/ordered_options' require 'neo4j/core/cypher_session/adaptors/http' require 'neo4j/core/cypher_session/adaptors/bolt' require 'neo4j/core/cypher_session/adaptors/embedded' module Neo4j class SessionManager class << self def setup!(cfg = nil) cfg ||= ActiveSupport::OrderedOptions.new setup_default_session(cfg) cfg.sessions.each do |session_opts| open_neo4j_session(session_opts, cfg.wait_for_connection) end Neo4j::Config.configuration.merge!(cfg.to_h) end # TODO: Remove ability for multiple sessions? # Ability to overwrite default session per-model like ActiveRecord? def setup_default_session(cfg) setup_config_defaults!(cfg) return if !cfg.sessions.empty? cfg.sessions << {type: cfg.session_type, path: cfg.session_path, options: cfg.session_options.merge(default: true)} end # TODO: Support `session_url` config for server mode def setup_config_defaults!(cfg) cfg.session_type ||= default_session_type cfg.session_path ||= default_session_path cfg.session_options ||= {} cfg.sessions ||= [] end def open_neo4j_session(options, wait_for_connection = false) session_type, path, url = options.values_at(:type, :path, :url) enable_unlimited_strength_crypto! if java_platform? && session_type_is_embedded?(session_type) adaptor = wait_for_value(wait_for_connection) do cypher_session_adaptor(session_type, url || path, (options[:options] || {}).merge(wrap_level: :proc)) end Neo4j::ActiveBase.current_adaptor = adaptor end protected def session_type_is_embedded?(session_type) [:embedded_db, :embedded].include?(session_type) end def enable_unlimited_strength_crypto! # See https://github.com/jruby/jruby/wiki/UnlimitedStrengthCrypto security_class = java.lang.Class.for_name('javax.crypto.JceSecurity') restricted_field = security_class.get_declared_field('isRestricted') restricted_field.accessible = true restricted_field.set nil, false end def config_data @config_data ||= if yaml_path HashWithIndifferentAccess.new(YAML.load(ERB.new(yaml_path.read).result)[Rails.env]) else {} end end def yaml_path return unless defined?(Rails) @yaml_path ||= %w(config/neo4j.yml config/neo4j.yaml).map do |path| Rails.root.join(path) end.detect(&:exist?) end # TODO: Deprecate embedded_db and http in favor of embedded and http # def cypher_session_adaptor(type, path_or_url, options = {}) case type when :embedded_db, :embedded Neo4j::Core::CypherSession::Adaptors::Embedded.new(path_or_url, options) when :http Neo4j::Core::CypherSession::Adaptors::HTTP.new(path_or_url, options) when :bolt Neo4j::Core::CypherSession::Adaptors::Bolt.new(path_or_url, options) else extra = ' (`server_db` has been replaced by `http` or `bolt`)' fail ArgumentError, "Invalid session type: #{type.inspect}#{extra if type.to_sym == :server_db}" end end def default_session_type if ENV['NEO4J_URL'] URI(ENV['NEO4J_URL']).scheme.tap do |scheme| fail "Invalid scheme for NEO4J_URL: #{scheme}" if !%w(http bolt).include?(scheme) end else ENV['NEO4J_TYPE'] || config_data[:type] || :http end.to_sym end def default_session_path ENV['NEO4J_URL'] || ENV['NEO4J_PATH'] || config_data[:url] || config_data[:path] || 'http://localhost:7474' end def java_platform? RUBY_PLATFORM =~ /java/ end def wait_for_value(wait) session = nil Timeout.timeout(60) do until session begin if session = yield puts return session end rescue Neo4j::Core::CypherSession::ConnectionFailedError raise e if !wait putc '.' sleep(1) end end end end end end end