2020-06-08 04:49:55 +02:00
|
|
|
require "ipc"
|
2020-06-06 20:43:14 +02:00
|
|
|
|
2023-02-09 23:28:10 +01:00
|
|
|
class FileStorage::Client < IPC
|
2020-06-08 04:49:55 +02:00
|
|
|
property auth_token : String
|
2020-06-06 20:43:14 +02:00
|
|
|
|
2020-06-08 04:49:55 +02:00
|
|
|
def initialize(@auth_token, service_name = "filestorage")
|
2023-02-09 23:28:10 +01:00
|
|
|
super
|
|
|
|
@server_fd = self.connect service_name
|
2020-06-08 04:49:55 +02:00
|
|
|
end
|
2020-06-06 20:43:14 +02:00
|
|
|
|
2020-10-21 03:27:51 +02:00
|
|
|
# TODO: parse_message should raise exception if response not anticipated
|
|
|
|
def parse_message(expected_messages, message)
|
|
|
|
em = Array(IPC::JSON.class).new
|
|
|
|
expected_messages.each do |e|
|
|
|
|
em << e
|
2020-06-06 20:43:14 +02:00
|
|
|
end
|
2020-10-21 03:27:51 +02:00
|
|
|
em << FileStorage::Errors::GenericError
|
|
|
|
em << FileStorage::Errors::Authorization
|
|
|
|
em << FileStorage::Errors::ChunkAlreadyUploaded
|
|
|
|
em << FileStorage::Errors::ChunkUploadDenied
|
|
|
|
em << FileStorage::Errors::FileExists
|
|
|
|
em << FileStorage::Errors::FileDoesNotExist
|
|
|
|
em << FileStorage::Errors::FileFullyUploaded
|
2020-10-22 01:21:44 +02:00
|
|
|
em << FileStorage::Errors::FileTooBig
|
2020-10-21 03:27:51 +02:00
|
|
|
em.parse_ipc_json message
|
|
|
|
end
|
|
|
|
end
|
2020-06-06 20:43:14 +02:00
|
|
|
|
2023-02-09 23:28:10 +01:00
|
|
|
class FileStorage::Client < IPC
|
2020-10-21 03:27:51 +02:00
|
|
|
def login
|
|
|
|
request = FileStorage::Request::Login.new @auth_token
|
2023-02-09 23:28:10 +01:00
|
|
|
write @server_fd.not_nil!, request
|
2020-10-21 03:27:51 +02:00
|
|
|
parse_message [ FileStorage::Response::Login ], read
|
2020-06-06 20:43:14 +02:00
|
|
|
end
|
|
|
|
|
2020-10-21 03:27:51 +02:00
|
|
|
# Helper function.
|
2020-06-08 04:49:55 +02:00
|
|
|
def get_file_info(file_path : String)
|
|
|
|
file_info : FileStorage::FileInfo
|
|
|
|
file = File.open(file_path)
|
|
|
|
file_info = FileStorage::FileInfo.new file
|
|
|
|
file.close
|
|
|
|
file_info.not_nil!
|
|
|
|
end
|
2020-06-06 20:43:14 +02:00
|
|
|
|
2020-06-08 04:49:55 +02:00
|
|
|
def transfer(file_path : String)
|
|
|
|
file_info = get_file_info file_path
|
|
|
|
|
|
|
|
File.open(file_path) do |file|
|
|
|
|
buffer_size = FileStorage.message_buffer_size
|
|
|
|
|
|
|
|
buffer = Bytes.new buffer_size
|
|
|
|
counter = 0
|
|
|
|
size = 0
|
|
|
|
|
|
|
|
while (size = file.read(buffer)) > 0
|
|
|
|
# transfer message = file_info, chunk count, data (will be base64'd)
|
|
|
|
transfer_message = FileStorage::Request::PutChunk.new file_info,
|
|
|
|
counter,
|
|
|
|
buffer[0 ... size]
|
|
|
|
|
2023-02-09 23:28:10 +01:00
|
|
|
write @server_fd.not_nil!, transfer_message
|
2020-06-08 04:49:55 +02:00
|
|
|
counter += 1
|
|
|
|
|
|
|
|
buffer = Bytes.new buffer_size
|
|
|
|
|
|
|
|
# Check for the response
|
2020-10-21 03:27:51 +02:00
|
|
|
response = parse_message [ FileStorage::Response::PutChunk ], read
|
2020-06-08 04:49:55 +02:00
|
|
|
|
|
|
|
if response.responds_to? :mid
|
|
|
|
if response.mid != transfer_message.mid
|
|
|
|
raise "request and response mid !=: #{response.mid} != #{transfer_message.mid}"
|
|
|
|
else
|
|
|
|
pp! response
|
|
|
|
end
|
|
|
|
else
|
|
|
|
raise "response doesn't have mid"
|
|
|
|
end
|
|
|
|
end
|
2020-06-06 20:43:14 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def download(filedigest = nil, name = nil, tags = nil)
|
|
|
|
request = FileStorage::Request::Download.new filedigest, name, tags
|
2023-02-09 23:28:10 +01:00
|
|
|
write @server_fd.not_nil!, request
|
2020-10-21 03:27:51 +02:00
|
|
|
parse_message [ FileStorage::Response::Download ], read
|
2020-06-06 20:43:14 +02:00
|
|
|
end
|
|
|
|
|
2020-10-21 19:59:57 +02:00
|
|
|
def get_chunks(dl_response : FileStorage::Response::Download, path : String = ".")
|
|
|
|
file_path = "#{path}/#{dl_response.file_info.name}"
|
|
|
|
|
|
|
|
digest = dl_response.file_info.digest
|
|
|
|
buffer_size = FileStorage.message_buffer_size
|
|
|
|
|
|
|
|
counter = 0
|
|
|
|
size = 0
|
|
|
|
|
|
|
|
while counter < dl_response.file_info.nb_chunks
|
2020-10-21 23:24:53 +02:00
|
|
|
Baguette::Log.debug "getting #{file_path}: chunk #{counter+1}/#{dl_response.file_info.nb_chunks}"
|
2020-10-21 19:59:57 +02:00
|
|
|
get_chunk_message = FileStorage::Request::GetChunk.new digest, counter
|
2023-02-09 23:28:10 +01:00
|
|
|
write @server_fd.not_nil!, get_chunk_message
|
2020-10-21 19:59:57 +02:00
|
|
|
response = parse_message [ FileStorage::Response::GetChunk ], read
|
|
|
|
|
|
|
|
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
|
|
|
|
)
|
|
|
|
|
2020-10-21 23:24:53 +02:00
|
|
|
# pp! file_path, chunk_size, offset, data.size
|
|
|
|
Baguette::Log.debug "writing on #{file_path}"
|
2020-10-21 19:59:57 +02:00
|
|
|
|
|
|
|
# Create the file if non existant.
|
|
|
|
File.open(file_path, "a+") do |file|
|
|
|
|
file.seek (offset * chunk_size)
|
|
|
|
file.write data
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2020-06-08 04:49:55 +02:00
|
|
|
def upload(file : String)
|
|
|
|
file_info : FileStorage::FileInfo
|
|
|
|
File.open(file) do |f|
|
|
|
|
file_info = FileStorage::FileInfo.new f
|
|
|
|
request = FileStorage::Request::Upload.new file_info
|
2023-02-09 23:28:10 +01:00
|
|
|
write @server_fd.not_nil!, request
|
2020-06-06 20:43:14 +02:00
|
|
|
end
|
|
|
|
|
2020-10-21 03:27:51 +02:00
|
|
|
parse_message [ FileStorage::Response::Upload ], read
|
2020-06-06 20:43:14 +02:00
|
|
|
end
|
|
|
|
end
|