diff --git a/.env b/.env new file mode 100644 index 000000000..45d5b9539 --- /dev/null +++ b/.env @@ -0,0 +1,79 @@ +# The settings here, if defined, override the settings in config/database.yml, +# config/unicorn/unicorn.rb, config/danbooru_local_config.rb, and +# ~/.danbooru/{secret_token,session_secret_key}. +# +# `.env.$RAILS_ENV` takes precedence over .env, and .env.local takes +# precedence over .env and `.env.$RAILS_ENV`. +# +# In other words: put your shared config in .env.local, and your put +# environment-specific config in .env.development / .env.production / .env.test. + +# +# Unicorn +# + +# These settings only take effect when running with `bundle exec unicorn -c config/unicorn/unicorn.rb`. + +# export UNICORN_ROOT="$(pwd)" +# export UNICORN_LISTEN=127.0.0.1:9000 +# export UNICORN_PROCESSES=1 +# export UNICORN_TIMEOUT=90 +# export UNICORN_LOG="log/unicorn-${UNICORN_LISTEN}.log" +# export UNICORN_PIDFILE="$UNICORN_ROOT/tmp/pids/unicorn-${UNICORN_LISTEN}.pid" + +# These only take effect if you're running unicorn as root in order to bind to +# port 80 and need to drop privileges. Reverse proxying behind nginx is a better idea. +# export UNICORN_USER=danbooru +# export UNICORN_GROUP=danbooru + +# +# Database +# + +# DATABASE_URL takes precedence over config/database.yml if defined. + +# Put these in .env.production or .env.development to define your dev/prod +# databases. Do not define it in .env or .env.local! It will be taken as your +# test database too, and rails will wipe it if you run the test suite. +# export DATABASE_URL="postgresql://localhost/danbooru2" +# export ARCHIVE_DATABASE_URL="postgresql://localhost/archive_development" +# export RO_DATABASE_URL="$DATABASE_URL" + +# Put these in .env.test to define your test database. +# export DATABASE_URL="postgresql://localhost/danbooru2_test" +# export RO_DATABASE_URL="postgresql://localhost/danbooru2_test" +# export ARCHIVE_DATABASE_URL="postgresql://localhost/danbooru2_archive_test" + +# +# Rails +# + +# These take precedence over ~/.danbooru/{secret_token,session_secret_key}. +# export SECRET_TOKEN= +# export SESSION_SECRET_KEY= + +# Override the normal Gemfile with another file. +# export BUNDLE_GEMFILE= + +# Logs a stacktrace for each SQL query. +# export QUERY_TRACE= + +# +# Danbooru +# + +# These take precedence over config/danbooru_local_config.rb. Any setting in +# danbooru_default_config.rb can be defined here by prefixing it with `DANBOORU_`. + +# export DANBOORU_APP_NAME= +# export DANBOORU_VERSION= +# export DANBOORU_HOSTNAME= +# export DANBOORU_PIXIV_LOGIN= +# export DANBOORU_PIXIV_PASSWORD= +# export DANBOORU_TWITTER_API_KEY= +# export DANBOORU_TWITTER_API_SECRET= +# export DANBOORU_AWS_ACCESS_KEY_ID= +# export DANBOORU_AWS_SECRET_ACCESS_KEY= +# export DANBOORU_AWS_SQS_REGION= +# export DANBOORU_IQDBS_AUTH_KEY= +# export DANBOORU_IQDBS_SERVER= diff --git a/.gitignore b/.gitignore index ca9a5714d..6b05cc066 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.env.* .bundle config/database.yml config/danbooru_local_config.rb diff --git a/Gemfile b/Gemfile index cd8e257f0..dfa7d4cd0 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,7 @@ source 'https://rubygems.org/' +gem 'dotenv-rails', :require => "dotenv/rails-now" + group :test do gem "shoulda" gem "factory_girl" diff --git a/Gemfile.lock b/Gemfile.lock index 0c9f63164..48dd65240 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -127,6 +127,10 @@ GEM docile (1.1.5) domain_name (0.5.24) unf (>= 0.0.5, < 1.0.0) + dotenv (2.1.2) + dotenv-rails (2.1.2) + dotenv (= 2.1.2) + railties (>= 3.2, < 5.1) equalizer (0.0.11) erubis (2.7.0) execjs (2.6.0) @@ -434,6 +438,7 @@ DEPENDENCIES delayed_job delayed_job_active_record diff-lcs! + dotenv-rails dtext_rb! factory_girl fakeweb diff --git a/Procfile b/Procfile new file mode 100644 index 000000000..0fe2ce1c7 --- /dev/null +++ b/Procfile @@ -0,0 +1,2 @@ +unicorn: bundle exec unicorn -c config/unicorn/unicorn.rb +jobs: bundle exec script/delayed_job run diff --git a/app/models/pool_archive.rb b/app/models/pool_archive.rb index 062fc047b..ff38de4f9 100644 --- a/app/models/pool_archive.rb +++ b/app/models/pool_archive.rb @@ -6,7 +6,7 @@ class PoolArchive < ActiveRecord::Base Danbooru.config.aws_sqs_archives_url.present? end - establish_connection "archive_#{Rails.env}".to_sym if enabled? + establish_connection (ENV["ARCHIVE_DATABASE_URL"] || "archive_#{Rails.env}".to_sym) if enabled? self.table_name = "pool_versions" module SearchMethods diff --git a/app/models/post_archive.rb b/app/models/post_archive.rb index bb1315670..711e51ff1 100644 --- a/app/models/post_archive.rb +++ b/app/models/post_archive.rb @@ -3,7 +3,7 @@ class PostArchive < ActiveRecord::Base Danbooru.config.aws_sqs_archives_url.present? end - establish_connection "archive_#{Rails.env}".to_sym if enabled? + establish_connection (ENV["ARCHIVE_DATABASE_URL"] || "archive_#{Rails.env}".to_sym) if enabled? self.table_name = "post_versions" def self.calculate_version(post_id, updated_at, version_id) diff --git a/app/models/post_read_only.rb b/app/models/post_read_only.rb index 3307e8472..96d0a1f3d 100644 --- a/app/models/post_read_only.rb +++ b/app/models/post_read_only.rb @@ -1,5 +1,5 @@ class PostReadOnly < Post - establish_connection "ro_#{Rails.env}".to_sym + establish_connection (ENV["RO_DATABASE_URL"] || "ro_#{Rails.env}".to_sym) attr_readonly *column_names def with_timeout(n, default_value = nil) diff --git a/config/danbooru_default_config.rb b/config/danbooru_default_config.rb index 1b623381a..f6093284c 100644 --- a/config/danbooru_default_config.rb +++ b/config/danbooru_default_config.rb @@ -502,4 +502,16 @@ module Danbooru def aws_sqs_archives_url end end + + class EnvironmentConfiguration + def method_missing(method, *args) + var = ENV["DANBOORU_#{method.to_s.upcase}"] + + if var.present? + var + else + CustomConfiguration.new.send(method, *args) + end + end + end end diff --git a/config/initializers/danbooru_config.rb b/config/initializers/danbooru_config.rb index b4a0ff385..78a505bae 100644 --- a/config/initializers/danbooru_config.rb +++ b/config/initializers/danbooru_config.rb @@ -3,7 +3,7 @@ require "#{Rails.root}/config/danbooru_local_config" module Danbooru def config - @configuration ||= CustomConfiguration.new + @configuration ||= EnvironmentConfiguration.new end module_function :config diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb index e44bc013b..2a5a73b82 100644 --- a/config/initializers/secret_token.rb +++ b/config/initializers/secret_token.rb @@ -1,9 +1,9 @@ require File.expand_path('../../state_checker', __FILE__) -StateChecker.new.check! +StateChecker.check! Rails.application.config.action_dispatch.session = { :key => '_danbooru2_session', - :secret => File.read(File.expand_path("~/.danbooru/session_secret_key")) + :secret => StateChecker.session_secret_key } -Rails.application.config.secret_token = File.read(File.expand_path("~/.danbooru/secret_token")) +Rails.application.config.secret_token = StateChecker.secret_token diff --git a/config/state_checker.rb b/config/state_checker.rb index 8a1be76f8..a3286a143 100644 --- a/config/state_checker.rb +++ b/config/state_checker.rb @@ -1,7 +1,17 @@ -class StateChecker +module StateChecker + module_function + def check! - check_secret_token - check_session_secret_key + ENV["SECRET_TOKEN"].present? || check_secret_token + ENV["SESSION_SECRET_KEY"].present? || check_session_secret_key + end + + def secret_token + ENV["SECRET_TOKEN"] || File.read(secret_token_path) + end + + def session_secret_key + ENV["SESSION_SECRET_KEY"] || File.read(session_secret_key_path) end private diff --git a/config/unicorn/unicorn.rb b/config/unicorn/unicorn.rb new file mode 100644 index 000000000..755b80484 --- /dev/null +++ b/config/unicorn/unicorn.rb @@ -0,0 +1,41 @@ +require "dotenv" + +rails_env = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development' +Dotenv.load(".env.local", ".env.#{rails_env}", ".env") + +addr = ENV["UNICORN_LISTEN"] || "127.0.0.1:9000" +app_path = ENV["UNICORN_ROOT"] || Dir.pwd +instance = "unicorn-#{addr}" + +listen addr +worker_processes ENV["UNICORN_PROCESSES"].to_i || 1 +timeout ENV["UNICORN_TIMEOUT"].to_i || 90 + +user = ENV["UNICORN_USER"] || "danbooru" +group = ENV["UNICORN_GROUP"] || "danbooru" + +stderr_path ENV["UNICORN_LOG"] || "log/#{instance}.log" +stdout_path ENV["UNICORN_LOG"] || "log/#{instance}.log" + +working_directory app_path +pid ENV["UNICORN_PIDFILE"] || "#{app_path}/tmp/pids/#{instance}.pid" + +if rails_env == "production" + preload_app true + + before_fork do |server, worker| + ActiveRecord::Base.connection.disconnect! if defined?(ActiveRecord::Base) + + # Throttle the master from forking too quickly by sleeping. Due + # to the implementation of standard Unix signal handlers, this + # helps (but does not completely) prevent identical, repeated signals + # from being lost when the receiving process is busy. + sleep 1 + end + + after_fork do |server, worker| + ActiveRecord::Base.establish_connection if defined?(ActiveRecord::Base) + end +else + preload_app false +end diff --git a/script/install/database.yml.templ b/script/install/database.yml.templ index 91e7e4312..5caf077ef 100755 --- a/script/install/database.yml.templ +++ b/script/install/database.yml.templ @@ -5,6 +5,7 @@ development: database: danbooru2 pool: 5 timeout: 5000 + url: <%= ENV['DATABASE_URL'] %> # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". @@ -14,42 +15,52 @@ test: database: danbooru2_test pool: 5 timeout: 5000 + url: <%= ENV['DATABASE_URL'] %> production: adapter: postgresql database: danbooru2 pool: 5 timeout: 5000 + url: <%= ENV['DATABASE_URL'] %> # read only databases, just point to local copies if you have no need ro_development: adapter: postgresql database: danbooru2 + url: <%= ENV['RO_DATABASE_URL'] %> ro_test: adapter: postgresql database: danbooru2_test + url: <%= ENV['RO_DATABASE_URL'] %> ro_production: adapter: postgresql database: danbooru2 + url: <%= ENV['RO_DATABASE_URL'] %> ro_staging: adapter: postgresql database: danbooru2 + url: <%= ENV['RO_DATABASE_URL'] %> archive_development: adapter: postgresql database: archive_development + url: <%= ENV['ARCHIVE_DATABASE_URL'] %> archive_test: adapter: postgresql database: archive_test + url: <%= ENV['ARCHIVE_DATABASE_URL'] %> archive_production: adapter: postgresql database: archive_development + url: <%= ENV['ARCHIVE_DATABASE_URL'] %> archive_staging: adapter: postgresql - database: archive_development \ No newline at end of file + database: archive_development + url: <%= ENV['ARCHIVE_DATABASE_URL'] %>