From 30a1f204e976ad290242a589eccf2264a2159693 Mon Sep 17 00:00:00 2001 From: evazion Date: Fri, 5 May 2017 21:45:14 -0500 Subject: [PATCH 1/3] backups: add stub backup service. --- app/logical/backup_service.rb | 5 +++++ app/logical/null_backup_service.rb | 5 +++++ app/models/post.rb | 19 +++++++++++++++++++ config/danbooru_default_config.rb | 5 +++++ 4 files changed, 34 insertions(+) create mode 100644 app/logical/backup_service.rb create mode 100644 app/logical/null_backup_service.rb diff --git a/app/logical/backup_service.rb b/app/logical/backup_service.rb new file mode 100644 index 000000000..b3fac3b64 --- /dev/null +++ b/app/logical/backup_service.rb @@ -0,0 +1,5 @@ +class BackupService + def backup(file_path, options = {}) + raise NotImplementedError.new("#{self.class}.backup not implemented") + end +end diff --git a/app/logical/null_backup_service.rb b/app/logical/null_backup_service.rb new file mode 100644 index 000000000..48f60bdd4 --- /dev/null +++ b/app/logical/null_backup_service.rb @@ -0,0 +1,5 @@ +class NullBackupService + def backup(file_path, options = {}) + # do nothing + end +end diff --git a/app/models/post.rb b/app/models/post.rb index 9906baff8..bfc1428cc 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -23,6 +23,7 @@ class Post < ActiveRecord::Base before_save :set_tag_counts before_save :set_pool_category_pseudo_tags before_create :autoban + after_save :queue_backup, if: :md5_changed? after_save :create_version after_save :update_parent_on_save after_save :apply_post_metatags @@ -229,6 +230,23 @@ class Post < ActiveRecord::Base end end + module BackupMethods + extend ActiveSupport::Concern + + def queue_backup + Post.delay(queue: "default", priority: -1).backup_file(file_path, id: id, type: :original) + Post.delay(queue: "default", priority: -1).backup_file(large_file_path, id: id, type: :large) if has_large? + Post.delay(queue: "default", priority: -1).backup_file(preview_file_path, id: id, type: :preview) if has_preview? + end + + module ClassMethods + def backup_file(file_path, options = {}) + backup_service = Danbooru.config.backup_service + backup_service.backup(file_path, options) + end + end + end + module ImageMethods def device_scale if large_image_width > 320 @@ -1701,6 +1719,7 @@ class Post < ActiveRecord::Base end include FileMethods + include BackupMethods include ImageMethods include ApprovalMethods include PresenterMethods diff --git a/config/danbooru_default_config.rb b/config/danbooru_default_config.rb index 3a1a6faa8..775ceb9a0 100644 --- a/config/danbooru_default_config.rb +++ b/config/danbooru_default_config.rb @@ -90,6 +90,10 @@ module Danbooru true end + def backup_service + NullBackupService.new + end + # What method to use to store images. # local_flat: Store every image in one directory. # local_hierarchy: Store every image in a hierarchical directory, based on the post's MD5 hash. On some file systems this may be faster. @@ -477,6 +481,7 @@ module Danbooru false end + # Used for backing up images to S3. Must be changed to your own S3 bucket. def aws_s3_bucket_name "danbooru" end From 7db40fe69f8052663424d1e843e525c8850a6343 Mon Sep 17 00:00:00 2001 From: evazion Date: Fri, 5 May 2017 21:51:05 -0500 Subject: [PATCH 2/3] backups: add amazon s3 backup service. --- app/logical/s3_backup_service.rb | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 app/logical/s3_backup_service.rb diff --git a/app/logical/s3_backup_service.rb b/app/logical/s3_backup_service.rb new file mode 100644 index 000000000..2dfd1926c --- /dev/null +++ b/app/logical/s3_backup_service.rb @@ -0,0 +1,35 @@ +class S3BackupService < BackupService + attr_reader :client, :bucket + + def initialize(client: nil, bucket: Danbooru.config.aws_s3_bucket_name) + @credentials = Aws::Credentials.new(Danbooru.config.aws_access_key_id, Danbooru.config.aws_secret_access_key) + @client = client || Aws::S3::Client.new(credentials: @credentials, region: "us-east-1", logger: Logger.new(STDOUT)) + @bucket = bucket + end + + def backup(file_path, type: nil, **options) + key = s3_key(file_path, type) + upload_to_s3(key, file_path) + end + +protected + def s3_key(file_path, type) + case type + when :original + "#{File.basename(file_path)}" + when :preview + "preview/#{File.basename(file_path)}" + when :large + "large/#{File.basename(file_path)}" + else + raise ArgumentError.new("Unknown type: #{type}") + end + end + + def upload_to_s3(key, file_path) + File.open(file_path, "rb") do |body| + base64_md5 = Digest::MD5.base64digest(File.read(file_path)) + client.put_object(bucket: bucket, key: key, body: body, content_md5: base64_md5) + end + end +end From fb7e6c7e8e14eab7b8383d551172b0ba0da1e7f5 Mon Sep 17 00:00:00 2001 From: evazion Date: Fri, 5 May 2017 22:00:05 -0500 Subject: [PATCH 3/3] backups: default to s3 backup for production. --- config/danbooru_default_config.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/config/danbooru_default_config.rb b/config/danbooru_default_config.rb index 775ceb9a0..904152d77 100644 --- a/config/danbooru_default_config.rb +++ b/config/danbooru_default_config.rb @@ -90,8 +90,18 @@ module Danbooru true end + # What method to use to backup images. + # + # NullBackupService: Don't backup images at all. + # + # S3BackupService: Backup to Amazon S3. Must configure aws_access_key_id, + # aws_secret_access_key, and aws_s3_bucket_name. Bucket must exist and be writable. def backup_service - NullBackupService.new + if Rails.env.production? + S3BackupService.new + else + NullBackupService.new + end end # What method to use to store images.