storage manager: refactor base_dir option.
Fix it so the `base_dir` option is only required by subclasses that actually use it. The StorageManager::Mirror class doesn't use it.
This commit is contained in:
@@ -3,22 +3,25 @@
|
|||||||
# are handled by a StorageManager.
|
# are handled by a StorageManager.
|
||||||
#
|
#
|
||||||
# A StorageManager has methods for saving, deleting, and opening files, and for
|
# A StorageManager has methods for saving, deleting, and opening files, and for
|
||||||
# generates URLs for images.
|
# generating URLs for files.
|
||||||
#
|
#
|
||||||
# @abstract
|
# @abstract
|
||||||
# @see StorageManager::Local
|
# @see StorageManager::Local
|
||||||
|
# @see StorageManager::Mirror
|
||||||
|
# @see StorageManager::Rclone
|
||||||
# @see StorageManager::SFTP
|
# @see StorageManager::SFTP
|
||||||
class StorageManager
|
class StorageManager
|
||||||
class Error < StandardError; end
|
class Error < StandardError; end
|
||||||
|
|
||||||
attr_reader :base_url, :base_dir
|
attr_reader :base_url
|
||||||
|
|
||||||
# Initialize a storage manager object.
|
# Initialize a storage manager object.
|
||||||
# @param base_url [String] the base URL where images are stored (ex: "https://cdn.donmai.us/")
|
#
|
||||||
# @param base_dir [String] the base directory where images are stored (ex: "/var/www/danbooru/public/images")
|
# @param base_url [String, nil] the base URL where files are served from (ex:
|
||||||
def initialize(base_url: nil, base_dir: nil)
|
# "https://cdn.donmai.us"), or nil if the files don't have an URL (they're
|
||||||
@base_url = base_url.to_s.chomp("/")
|
# stored in a publicly inaccessible location).
|
||||||
@base_dir = base_dir.to_s
|
def initialize(base_url: nil)
|
||||||
|
@base_url = base_url
|
||||||
end
|
end
|
||||||
|
|
||||||
# Store the given file at the given path. If a file already exists at that
|
# Store the given file at the given path. If a file already exists at that
|
||||||
@@ -41,16 +44,16 @@ class StorageManager
|
|||||||
|
|
||||||
# Return a readonly copy of the file located at the given path.
|
# Return a readonly copy of the file located at the given path.
|
||||||
# @param path [String] the remote path of the file to open
|
# @param path [String] the remote path of the file to open
|
||||||
# @return [MediaFile] the image file
|
# @return [File] the file
|
||||||
def open(path)
|
def open(path)
|
||||||
raise NotImplementedError, "open not implemented"
|
raise NotImplementedError, "open not implemented"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Return the full URL of the file at the given path, or nil if the file
|
||||||
|
# doesn't have an URL.
|
||||||
|
# @return [String, nil] the file URL
|
||||||
def file_url(path)
|
def file_url(path)
|
||||||
|
return nil if base_dir.nil?
|
||||||
File.join(base_url, path)
|
File.join(base_url, path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def full_path(path)
|
|
||||||
File.join(base_dir, path)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,6 +2,14 @@
|
|||||||
class StorageManager::Local < StorageManager
|
class StorageManager::Local < StorageManager
|
||||||
DEFAULT_PERMISSIONS = 0o644
|
DEFAULT_PERMISSIONS = 0o644
|
||||||
|
|
||||||
|
attr_reader :base_dir
|
||||||
|
|
||||||
|
# @param base_url [String] the base directory where files are stored (ex: "/home/danbooru/public/data")
|
||||||
|
def initialize(base_dir: nil, **options)
|
||||||
|
@base_dir = base_dir.to_s
|
||||||
|
super(**options)
|
||||||
|
end
|
||||||
|
|
||||||
def store(io, dest_path)
|
def store(io, dest_path)
|
||||||
temp_path = full_path(dest_path) + "-" + SecureRandom.uuid + ".tmp"
|
temp_path = full_path(dest_path) + "-" + SecureRandom.uuid + ".tmp"
|
||||||
|
|
||||||
@@ -24,4 +32,10 @@ class StorageManager::Local < StorageManager
|
|||||||
def open(path)
|
def open(path)
|
||||||
File.open(full_path(path), "r", binmode: true)
|
File.open(full_path(path), "r", binmode: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def full_path(path)
|
||||||
|
File.join(base_dir, path)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# A null StorageManager that doesn't store files at all. Used for testing or
|
# A null StorageManager that doesn't store files at all. Used for testing or
|
||||||
# disabling backups.
|
# disabling backups.
|
||||||
class StorageManager::Null < StorageManager
|
class StorageManager::Null < StorageManager
|
||||||
def initialize(base_url: "/", base_dir: "/")
|
def initialize
|
||||||
super
|
super(base_url: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
def store(io, path)
|
def store(io, path)
|
||||||
|
|||||||
@@ -5,11 +5,12 @@
|
|||||||
# @see https://rclone.org/
|
# @see https://rclone.org/
|
||||||
class StorageManager::Rclone < StorageManager
|
class StorageManager::Rclone < StorageManager
|
||||||
class Error < StandardError; end
|
class Error < StandardError; end
|
||||||
attr_reader :remote, :bucket, :rclone_path, :rclone_options
|
attr_reader :remote, :bucket, :rclone_path, :rclone_options, :base_dir
|
||||||
|
|
||||||
def initialize(remote:, bucket:, rclone_path: "rclone", rclone_options: {}, **options)
|
def initialize(remote:, bucket:, base_dir: nil, rclone_path: "rclone", rclone_options: {}, **options)
|
||||||
@remote = remote
|
@remote = remote
|
||||||
@bucket = bucket
|
@bucket = bucket
|
||||||
|
@base_dir = base_dir.to_s
|
||||||
@rclone_path = rclone_path
|
@rclone_path = rclone_path
|
||||||
@rclone_options = rclone_options
|
@rclone_options = rclone_options
|
||||||
super(**options)
|
super(**options)
|
||||||
@@ -37,4 +38,8 @@ class StorageManager::Rclone < StorageManager
|
|||||||
def key(path)
|
def key(path)
|
||||||
":#{remote}:#{bucket}#{full_path(path)}"
|
":#{remote}:#{bucket}#{full_path(path)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def full_path(path)
|
||||||
|
File.join(base_dir, path)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ class StorageManager::SFTP < StorageManager
|
|||||||
non_interactive: true
|
non_interactive: true
|
||||||
}
|
}
|
||||||
|
|
||||||
attr_reader :hosts, :ssh_options
|
attr_reader :hosts, :ssh_options, :base_dir
|
||||||
|
|
||||||
def initialize(*hosts, ssh_options: {}, **options)
|
def initialize(*hosts, base_dir: nil, ssh_options: {}, **options)
|
||||||
@hosts = hosts
|
@hosts = hosts
|
||||||
|
@base_dir = base_dir.to_s
|
||||||
@ssh_options = DEFAULT_SSH_OPTIONS.merge(ssh_options)
|
@ssh_options = DEFAULT_SSH_OPTIONS.merge(ssh_options)
|
||||||
super(**options)
|
super(**options)
|
||||||
end
|
end
|
||||||
@@ -73,4 +74,8 @@ class StorageManager::SFTP < StorageManager
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def full_path(path)
|
||||||
|
File.join(base_dir, path)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class ActiveSupport::TestCase
|
|||||||
@temp_dir = Dir.mktmpdir("danbooru-temp-")
|
@temp_dir = Dir.mktmpdir("danbooru-temp-")
|
||||||
storage_manager = StorageManager::Local.new(base_url: "https://www.example.com/data", base_dir: @temp_dir)
|
storage_manager = StorageManager::Local.new(base_url: "https://www.example.com/data", base_dir: @temp_dir)
|
||||||
Danbooru.config.stubs(:storage_manager).returns(storage_manager)
|
Danbooru.config.stubs(:storage_manager).returns(storage_manager)
|
||||||
Danbooru.config.stubs(:backup_storage_manager).returns(StorageManager::Null.new(base_url: "/", base_dir: "/"))
|
Danbooru.config.stubs(:backup_storage_manager).returns(StorageManager::Null.new)
|
||||||
end
|
end
|
||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
|
|||||||
Reference in New Issue
Block a user