mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 03:51:07 +08:00
FEATURE: Support backup uploads/downloads directly to/from S3.
This reverts commit 3c59106bac4d79f39981bda3ff9db7786c1a78a0.
This commit is contained in:
95
lib/backup_restore/s3_backup_store.rb
Normal file
95
lib/backup_restore/s3_backup_store.rb
Normal file
@ -0,0 +1,95 @@
|
||||
require_dependency "backup_restore/backup_store"
|
||||
require_dependency "s3_helper"
|
||||
|
||||
module BackupRestore
|
||||
class S3BackupStore < BackupStore
|
||||
DOWNLOAD_URL_EXPIRES_AFTER_SECONDS ||= 15
|
||||
UPLOAD_URL_EXPIRES_AFTER_SECONDS ||= 21_600 # 6 hours
|
||||
|
||||
def initialize(opts = {})
|
||||
s3_options = S3Helper.s3_options(SiteSetting)
|
||||
s3_options.merge!(opts[:s3_options]) if opts[:s3_options]
|
||||
@s3_helper = S3Helper.new(SiteSetting.s3_backup_bucket, '', s3_options)
|
||||
end
|
||||
|
||||
def remote?
|
||||
true
|
||||
end
|
||||
|
||||
def file(filename, include_download_source: false)
|
||||
obj = @s3_helper.object(filename)
|
||||
create_file_from_object(obj, include_download_source) if obj.exists?
|
||||
end
|
||||
|
||||
def delete_file(filename)
|
||||
obj = @s3_helper.object(filename)
|
||||
obj.delete if obj.exists?
|
||||
end
|
||||
|
||||
def download_file(filename, destination_path, failure_message = nil)
|
||||
unless @s3_helper.object(filename).download_file(destination_path)
|
||||
raise failure_message&.to_s || "Failed to download file"
|
||||
end
|
||||
end
|
||||
|
||||
def upload_file(filename, source_path, content_type)
|
||||
obj = @s3_helper.object(filename)
|
||||
raise BackupFileExists.new if obj.exists?
|
||||
|
||||
obj.upload_file(source_path, content_type: content_type)
|
||||
end
|
||||
|
||||
def generate_upload_url(filename)
|
||||
obj = @s3_helper.object(filename)
|
||||
raise BackupFileExists.new if obj.exists?
|
||||
|
||||
presigned_url(obj, :put, UPLOAD_URL_EXPIRES_AFTER_SECONDS)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def unsorted_files
|
||||
objects = []
|
||||
|
||||
@s3_helper.list.each do |obj|
|
||||
if obj.key.match?(/\.t?gz$/i)
|
||||
objects << create_file_from_object(obj)
|
||||
end
|
||||
end
|
||||
|
||||
objects
|
||||
rescue Aws::Errors::ServiceError => e
|
||||
Rails.logger.warn("Failed to list backups from S3: #{e.message.presence || e.class.name}")
|
||||
raise StorageError
|
||||
end
|
||||
|
||||
def create_file_from_object(obj, include_download_source = false)
|
||||
BackupFile.new(
|
||||
filename: File.basename(obj.key),
|
||||
size: obj.size,
|
||||
last_modified: obj.last_modified,
|
||||
source: include_download_source ? presigned_url(obj, :get, DOWNLOAD_URL_EXPIRES_AFTER_SECONDS) : nil
|
||||
)
|
||||
end
|
||||
|
||||
def presigned_url(obj, method, expires_in_seconds)
|
||||
ensure_cors!
|
||||
obj.presigned_url(method, expires_in: expires_in_seconds)
|
||||
end
|
||||
|
||||
def ensure_cors!
|
||||
rule = {
|
||||
allowed_headers: ["*"],
|
||||
allowed_methods: ["PUT"],
|
||||
allowed_origins: [Discourse.base_url_no_prefix],
|
||||
max_age_seconds: 3000
|
||||
}
|
||||
|
||||
@s3_helper.ensure_cors!([rule])
|
||||
end
|
||||
|
||||
def cleanup_allowed?
|
||||
!SiteSetting.s3_disable_cleanup
|
||||
end
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user