Upload and download OK, on both server and client.
This commit is contained in:
parent
3491a394a9
commit
bfa43f2667
@ -83,6 +83,53 @@ class FileStorage::Client < IPC::Client
|
|||||||
parse_message [ FileStorage::Response::Download ], read
|
parse_message [ FileStorage::Response::Download ], read
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_chunks(dl_response : FileStorage::Response::Download, path : String = ".")
|
||||||
|
file_path = "#{path}/#{dl_response.file_info.name}"
|
||||||
|
Baguette::Log.debug "Getting #{file_path}"
|
||||||
|
|
||||||
|
digest = dl_response.file_info.digest
|
||||||
|
buffer_size = FileStorage.message_buffer_size
|
||||||
|
|
||||||
|
counter = 0
|
||||||
|
size = 0
|
||||||
|
|
||||||
|
while counter < dl_response.file_info.nb_chunks
|
||||||
|
Baguette::Log.debug "Getting #{file_path}: chunk #{counter+1}/#{dl_response.file_info.nb_chunks}"
|
||||||
|
get_chunk_message = FileStorage::Request::GetChunk.new digest, counter
|
||||||
|
send_now @server_fd.not_nil!, get_chunk_message
|
||||||
|
response = parse_message [ FileStorage::Response::GetChunk ], read
|
||||||
|
# TODO: write the file
|
||||||
|
pp! response
|
||||||
|
|
||||||
|
case response
|
||||||
|
when FileStorage::Response::GetChunk
|
||||||
|
b64_decoded_data = Base64.decode response.data
|
||||||
|
write_chunk file_path, buffer_size, response.chunk.n, b64_decoded_data
|
||||||
|
else
|
||||||
|
Baguette::Log.error "#{response}"
|
||||||
|
raise "wrong response: #{response}"
|
||||||
|
end
|
||||||
|
counter += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Reception of a file chunk.
|
||||||
|
def write_chunk(file_path : String,
|
||||||
|
chunk_size : Int32,
|
||||||
|
offset : Int32,
|
||||||
|
data : Bytes
|
||||||
|
)
|
||||||
|
|
||||||
|
pp! file_path, chunk_size, offset, data.size
|
||||||
|
|
||||||
|
# Create the file if non existant.
|
||||||
|
File.open(file_path, "a+") do |file|
|
||||||
|
file.seek (offset * chunk_size)
|
||||||
|
file.write data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
def upload(file : String)
|
def upload(file : String)
|
||||||
file_info : FileStorage::FileInfo
|
file_info : FileStorage::FileInfo
|
||||||
File.open(file) do |f|
|
File.open(file) do |f|
|
||||||
|
@ -21,7 +21,9 @@ class Context
|
|||||||
class_property authd_login : String = "test"
|
class_property authd_login : String = "test"
|
||||||
class_property authd_pass : String = "test"
|
class_property authd_pass : String = "test"
|
||||||
|
|
||||||
class_property to_transfer = Array(String).new
|
class_property path : String = "."
|
||||||
|
|
||||||
|
class_property args = Array(String).new
|
||||||
|
|
||||||
class_property service_name = "filestorage"
|
class_property service_name = "filestorage"
|
||||||
class_property command = "unknown"
|
class_property command = "unknown"
|
||||||
@ -29,7 +31,7 @@ end
|
|||||||
|
|
||||||
opt_unknown_args = ->(parser : OptionParser) {
|
opt_unknown_args = ->(parser : OptionParser) {
|
||||||
parser.unknown_args do |arg|
|
parser.unknown_args do |arg|
|
||||||
Context.to_transfer = arg
|
Context.args = arg
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +66,13 @@ OptionParser.parse do |parser|
|
|||||||
Context.authd_pass = pass
|
Context.authd_pass = pass
|
||||||
end
|
end
|
||||||
|
|
||||||
|
parser.on "-d directory",
|
||||||
|
"--directory path",
|
||||||
|
"Path where to put downloaded files." do |path|
|
||||||
|
Context.path = path
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
parser.on "-v verbosity",
|
parser.on "-v verbosity",
|
||||||
"--verbosity level",
|
"--verbosity level",
|
||||||
"Verbosity. From 0 to 4." do |v|
|
"Verbosity. From 0 to 4." do |v|
|
||||||
@ -85,8 +94,7 @@ def put(client : FileStorage::Client)
|
|||||||
|
|
||||||
files = [] of String
|
files = [] of String
|
||||||
|
|
||||||
Baguette::Log.debug "files and directories to transfer"
|
Context.args.each do |f|
|
||||||
Context.to_transfer.each do |f|
|
|
||||||
if File.directory? f
|
if File.directory? f
|
||||||
# TODO
|
# TODO
|
||||||
Baguette::Log.warning "Directories not supported, for now"
|
Baguette::Log.warning "Directories not supported, for now"
|
||||||
@ -104,15 +112,34 @@ def put(client : FileStorage::Client)
|
|||||||
end
|
end
|
||||||
|
|
||||||
files.each do |file|
|
files.each do |file|
|
||||||
Baguette::Log.info "upload: #{file}"
|
response = client.upload file
|
||||||
pp! client.upload file
|
if response.is_a?(FileStorage::Errors::FileFullyUploaded)
|
||||||
Baguette::Log.debug "transfer"
|
file_info = File.open(file) do |f|
|
||||||
|
FileStorage::FileInfo.new f
|
||||||
|
end
|
||||||
|
Baguette::Log.warning "file #{file} already uploaded, digest: #{file_info.digest}"
|
||||||
|
next
|
||||||
|
end
|
||||||
|
Baguette::Log.info "transfering: #{file}"
|
||||||
client.transfer file
|
client.transfer file
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def get(client : FileStorage::Client)
|
def get(client : FileStorage::Client)
|
||||||
Baguette::Log.error "get command not available, yet"
|
Baguette::Log.warning "get command not complete, yet"
|
||||||
|
|
||||||
|
files = Context.args
|
||||||
|
files.each do |filedigest|
|
||||||
|
response = client.download filedigest
|
||||||
|
case response
|
||||||
|
when FileStorage::Response::Download
|
||||||
|
Baguette::Log.info "downloading file #{filedigest} with #{response.file_info.nb_chunks} chunks"
|
||||||
|
client.get_chunks response, Context.path
|
||||||
|
else
|
||||||
|
Baguette::Log.error ">> #{response.class.name}"
|
||||||
|
next
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,8 +28,8 @@ end
|
|||||||
class FileStorage::Response
|
class FileStorage::Response
|
||||||
IPC::JSON.message Download, 30 do
|
IPC::JSON.message Download, 30 do
|
||||||
property mid : String
|
property mid : String
|
||||||
property nb_chunks : Int32
|
property file_info : FileInfo
|
||||||
def initialize(@mid, @nb_chunks)
|
def initialize(@mid, @file_info)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -64,9 +64,9 @@ class FileStorage::Service < IPC::Server
|
|||||||
@auth : AuthD::Client
|
@auth : AuthD::Client
|
||||||
@auth_key : String
|
@auth_key : String
|
||||||
|
|
||||||
def initialize(storage_directory, @auth_key)
|
def initialize(storage_directory, @auth_key, reindex : Bool)
|
||||||
# Data and metadata storage directory.
|
# Data and metadata storage directory.
|
||||||
@storage = FileStorage::Storage.new storage_directory
|
@storage = FileStorage::Storage.new storage_directory, reindex
|
||||||
|
|
||||||
@logged_users = Hash(Int32, AuthD::User::Public).new
|
@logged_users = Hash(Int32, AuthD::User::Public).new
|
||||||
@all_connections = Array(Int32).new
|
@all_connections = Array(Int32).new
|
||||||
@ -204,6 +204,8 @@ class FileStorage::Service < IPC::Server
|
|||||||
key = "nico-nico-nii" # Default authd key, as per the specs. :eyes:
|
key = "nico-nico-nii" # Default authd key, as per the specs. :eyes:
|
||||||
timer = 30_000 # Default timer: 30 seconds.
|
timer = 30_000 # Default timer: 30 seconds.
|
||||||
|
|
||||||
|
reindex = false
|
||||||
|
|
||||||
OptionParser.parse do |parser|
|
OptionParser.parse do |parser|
|
||||||
parser.banner = "usage: filestoraged [options]"
|
parser.banner = "usage: filestoraged [options]"
|
||||||
|
|
||||||
@ -225,6 +227,11 @@ class FileStorage::Service < IPC::Server
|
|||||||
Baguette::Context.verbosity = v.to_i
|
Baguette::Context.verbosity = v.to_i
|
||||||
end
|
end
|
||||||
|
|
||||||
|
parser.on "-I",
|
||||||
|
"--re-index",
|
||||||
|
"Reindex the database." do
|
||||||
|
reindex = true
|
||||||
|
end
|
||||||
|
|
||||||
parser.on "-h",
|
parser.on "-h",
|
||||||
"--help",
|
"--help",
|
||||||
@ -241,7 +248,7 @@ class FileStorage::Service < IPC::Server
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
service = ::FileStorage::Service.new storage_directory, key
|
service = ::FileStorage::Service.new storage_directory, key, reindex
|
||||||
service.base_timer = timer
|
service.base_timer = timer
|
||||||
service.timer = timer
|
service.timer = timer
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ class FileStorage::Storage
|
|||||||
# - meta/ : DODB TransferInfo
|
# - meta/ : DODB TransferInfo
|
||||||
# - users/ : DODB UserData (for later use: quotas, rights)
|
# - users/ : DODB UserData (for later use: quotas, rights)
|
||||||
|
|
||||||
def initialize(@root)
|
def initialize(@root, reindex : Bool = false)
|
||||||
@db = DODB::DataBase(TransferInfo).new "#{@root}/meta"
|
@db = DODB::DataBase(TransferInfo).new "#{@root}/meta"
|
||||||
|
|
||||||
# Where to store uploaded files.
|
# Where to store uploaded files.
|
||||||
@ -58,6 +58,11 @@ class FileStorage::Storage
|
|||||||
|
|
||||||
@user_data = DODB::DataBase(UserData).new "#{@root}/users"
|
@user_data = DODB::DataBase(UserData).new "#{@root}/users"
|
||||||
@user_data_per_user = @user_data.new_index "uid", &.uid.to_s
|
@user_data_per_user = @user_data.new_index "uid", &.uid.to_s
|
||||||
|
|
||||||
|
if reindex
|
||||||
|
@db.reindex_everything!
|
||||||
|
@user_data.reindex_everything!
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Path part of the URL.
|
# Path part of the URL.
|
||||||
@ -127,9 +132,6 @@ class FileStorage::Storage
|
|||||||
|
|
||||||
digest = transfer_info.file_info.digest
|
digest = transfer_info.file_info.digest
|
||||||
FileStorage::Response::PutChunk.new mid, digest, chunk_number
|
FileStorage::Response::PutChunk.new mid, digest, chunk_number
|
||||||
rescue e
|
|
||||||
Baguette::Log.error "Error handling write_chunk: #{e.message}"
|
|
||||||
FileStorage::Errors::GenericError.new mid.not_nil!, "Unexpected error: #{e.message}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Provide a file chunk to the client.
|
# Provide a file chunk to the client.
|
||||||
@ -166,9 +168,6 @@ class FileStorage::Storage
|
|||||||
chunk = Chunk.new chunk_number, transfer_info.file_info.nb_chunks, b64_encoded_data
|
chunk = Chunk.new chunk_number, transfer_info.file_info.nb_chunks, b64_encoded_data
|
||||||
|
|
||||||
FileStorage::Response::GetChunk.new mid, digest, chunk, b64_encoded_data
|
FileStorage::Response::GetChunk.new mid, digest, chunk, b64_encoded_data
|
||||||
rescue e
|
|
||||||
Baguette::Log.error "Error handling read_chunk: #{e.message}"
|
|
||||||
FileStorage::Errors::GenericError.new mid.not_nil!, "Unexpected error: #{e.message}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# the client sent an upload request
|
# the client sent an upload request
|
||||||
@ -216,9 +215,6 @@ class FileStorage::Storage
|
|||||||
# TODO: store upload request in UserData?
|
# TODO: store upload request in UserData?
|
||||||
|
|
||||||
FileStorage::Response::Upload.new request.mid, path
|
FileStorage::Response::Upload.new request.mid, path
|
||||||
rescue e
|
|
||||||
Baguette::Log.error "Error handling upload request: #{e.message}"
|
|
||||||
FileStorage::Errors::GenericError.new mid.not_nil!, "Unexpected error in upload request: #{e.message}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# The client sent a download request.
|
# The client sent a download request.
|
||||||
@ -235,7 +231,7 @@ class FileStorage::Storage
|
|||||||
|
|
||||||
# This is acceptation.
|
# This is acceptation.
|
||||||
# Return some useful values: number of chunks.
|
# Return some useful values: number of chunks.
|
||||||
return FileStorage::Response::Download.new mid, file_transfer.file_info.nb_chunks
|
return FileStorage::Response::Download.new mid, file_transfer.file_info
|
||||||
else
|
else
|
||||||
return FileStorage::Errors::GenericError.new mid, "Unknown file digest: #{file_digest}"
|
return FileStorage::Errors::GenericError.new mid, "Unknown file digest: #{file_digest}"
|
||||||
end
|
end
|
||||||
@ -247,9 +243,6 @@ class FileStorage::Storage
|
|||||||
|
|
||||||
# Should have returned by now: file wasn't found.
|
# Should have returned by now: file wasn't found.
|
||||||
FileStorage::Errors::GenericError.new mid, "File not found with provided parameters."
|
FileStorage::Errors::GenericError.new mid, "File not found with provided parameters."
|
||||||
rescue e
|
|
||||||
Baguette::Log.error "Error handling download request: #{e.message}"
|
|
||||||
FileStorage::Errors::GenericError.new mid.not_nil!, "Unexpected error in download request: #{e.message}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Entry point for request management
|
# Entry point for request management
|
||||||
@ -283,8 +276,9 @@ class FileStorage::Storage
|
|||||||
|
|
||||||
path = get_fs_path file_digest
|
path = get_fs_path file_digest
|
||||||
real_size = 0
|
real_size = 0
|
||||||
File.open(path, "rb").read_at offset, chunk_size do |buffer|
|
File.open(path, "rb") do |file|
|
||||||
real_size = buffer.read buffer_data
|
file.seek offset
|
||||||
|
real_size = file.read buffer_data
|
||||||
end
|
end
|
||||||
|
|
||||||
buffer_data[0..real_size-1]
|
buffer_data[0..real_size-1]
|
||||||
|
Loading…
Reference in New Issue
Block a user