From c4fe6e0ec7fca4e1c050cc476e06bf69b566228a Mon Sep 17 00:00:00 2001
From: Philippe PITTOLI
Date: Sat, 4 Jan 2020 15:07:04 +0100
Subject: [PATCH] FileStorage::Message is now a class that messages inherit
from.
---
src/client/main.cr | 14 ++--
src/common/filestorage.cr | 158 +++++++++++++++++++-------------------
src/server/context.cr | 7 +-
src/server/handlers.cr | 56 +++++++++-----
src/server/main-loop.cr | 34 +++++---
5 files changed, 149 insertions(+), 120 deletions(-)
diff --git a/src/client/main.cr b/src/client/main.cr
index 5b51023..e975128 100644
--- a/src/client/main.cr
+++ b/src/client/main.cr
@@ -6,8 +6,6 @@ require "base64"
require "../common/filestorage.cr"
-alias FM = FileStorage::Message
-
# TODO
# For now, this example only upload files.
# In a near future, we should be able to download files, too.
@@ -17,7 +15,7 @@ service_name = "filestorage"
files_and_directories_to_transfer = Array(String).new
# This is the requests we will send to the server
-upload_requests = Array(FM::UploadRequest).new
+upload_requests = Array(FileStorage::UploadRequest).new
OptionParser.parse do |parser|
@@ -68,7 +66,7 @@ files_and_directories_to_transfer.each do |f|
end
files_info.values.each do |file_info|
- upload_requests << FM::UploadRequest.new file_info
+ upload_requests << FileStorage::UploadRequest.new file_info
end
# pp! upload_requests
@@ -84,7 +82,7 @@ client = IPC::Client.new service_name
#
token = FileStorage::Token.new 1002, "karchnu"
-authentication_message = FM::Authentication.new token, upload_requests
+authentication_message = FileStorage::Authentication.new token, upload_requests
pp! authentication_message
client.send FileStorage::MessageType::Authentication.to_u8, authentication_message.to_json
@@ -96,7 +94,7 @@ m = client.read
# puts "message received: #{m.to_s}"
# puts "message received payload: #{String.new m.payload}"
-response = FM::Response.from_json(String.new m.payload)
+response = FileStorage::Response.from_json(String.new m.payload)
if response.mid == authentication_message.mid
puts "This is a response for the authentication message"
@@ -118,7 +116,7 @@ def file_transfer(client : IPC::Client, file : File, file_info : FileStorage::Fi
while (size = file.read(buffer)) > 0
# transfer message = file_info, chunk count, data (will be base64'd)
- transfer_message = FM::Transfer.new file_info, counter, buffer[0 ... size]
+ transfer_message = FileStorage::Transfer.new file_info, counter, buffer[0 ... size]
client.send FileStorage::MessageType::Transfer.to_u8, transfer_message.to_json
counter += 1
@@ -134,7 +132,7 @@ def file_transfer(client : IPC::Client, file : File, file_info : FileStorage::Fi
raise "Message received was not expected: #{mtype}"
end
- response = FM::Response.from_json(String.new m.payload)
+ response = FileStorage::Response.from_json(String.new m.payload)
if response.mid != transfer_message.mid
raise "Message received has a wrong mid: #{response.mid} != #{transfer_message.mid}"
diff --git a/src/common/filestorage.cr b/src/common/filestorage.cr
index 8f0bf84..e442a5c 100644
--- a/src/common/filestorage.cr
+++ b/src/common/filestorage.cr
@@ -90,108 +90,108 @@ module FileStorage
end
class Message
+ end
- alias Request = UploadRequest | DownloadRequest
+ alias Request = UploadRequest | DownloadRequest
- class UploadRequest
- JSON.mapping({
- # autogenerated
- mid: String,
- file: FileInfo
- })
+ class UploadRequest < Message
+ JSON.mapping({
+ # autogenerated
+ mid: String,
+ file: FileInfo
+ })
- def initialize(@file)
- @mid = UUID.random.to_s
- end
+ def initialize(@file)
+ @mid = UUID.random.to_s
end
+ end
- # WIP
- class DownloadRequest
- JSON.mapping({
- # autogenerated
- mid: String,
- # SHA256 digest of the file, used as ID
- uuid: String?,
- name: String?,
- tags: Array(String)?
- })
+ # WIP
+ class DownloadRequest < Message
+ JSON.mapping({
+ # autogenerated
+ mid: String,
+ # SHA256 digest of the file, used as ID
+ uuid: String?,
+ name: String?,
+ tags: Array(String)?
+ })
- def initialize(@uuid = nil, @name = nil, @tags = nil)
- @mid = UUID.random.to_s
- end
+ def initialize(@uuid = nil, @name = nil, @tags = nil)
+ @mid = UUID.random.to_s
end
+ end
- class Authentication
- JSON.mapping({
- # autogenerated
- mid: String,
- token: Token,
- uploads: Array(UploadRequest),
- downloads: Array(DownloadRequest)
- })
+ class Authentication < Message
+ JSON.mapping({
+ # autogenerated
+ mid: String,
+ token: Token,
+ uploads: Array(UploadRequest),
+ downloads: Array(DownloadRequest)
+ })
- def initialize(@token, @uploads = Array(UploadRequest).new, @downloads = Array(DownloadRequest).new)
- @mid = UUID.random.to_s
- end
+ def initialize(@token, @uploads = Array(UploadRequest).new, @downloads = Array(DownloadRequest).new)
+ @mid = UUID.random.to_s
end
+ end
- class Response
- JSON.mapping({
- mid: String,
- response: String,
- reason: String?
- })
+ class Response < Message
+ JSON.mapping({
+ mid: String,
+ response: String,
+ reason: String?
+ })
- def initialize(@mid, @response, @reason = nil)
- end
+ def initialize(@mid, @response, @reason = nil)
end
+ end
- class Error
- JSON.mapping({
- mid: String,
- # a response for each request
- response: String,
- reason: String?
- })
+ class Error < Message
+ JSON.mapping({
+ mid: String,
+ # a response for each request
+ response: String,
+ reason: String?
+ })
- def initialize(@mid, @response, @reason = nil)
- end
+ def initialize(@mid, @response, @reason = nil)
end
+ end
- class Responses
- JSON.mapping({
- mid: String,
- # a response for each request
- responses: Array(Response),
- response: String,
- reason: String?
- })
+ class Responses < Message
+ JSON.mapping({
+ mid: String,
+ # a response for each request
+ responses: Array(Response),
+ response: String,
+ reason: String?
+ })
- def initialize(@mid, @response, @responses, @reason = nil)
- end
+ def initialize(@mid, @response, @responses, @reason = nil)
end
+ end
- class Transfer
- JSON.mapping({
- # autogenerated
- mid: String,
- # SHA256 digest of the entire file
- filedigest: String,
- # For now, just the counter in a string
- chunk: Chunk,
- # base64 slice
- data: String,
- })
+ class Transfer < Message
+ JSON.mapping({
+ # autogenerated
+ mid: String,
+ # SHA256 digest of the entire file
+ filedigest: String,
+ # For now, just the counter in a string
+ chunk: Chunk,
+ # base64 slice
+ data: String,
+ })
- def initialize(file_info : FileInfo, count, bindata)
- # count: chunk number
+ def initialize(file_info : FileInfo, count, bindata)
+ # count: chunk number
- @filedigest = file_info.digest
- @data = Base64.encode bindata
- @chunk = FileStorage::Chunk.new count, file_info.nb_chunks, @data
- @mid = UUID.random.to_s
- end
+ @filedigest = file_info.digest
+ @data = Base64.encode bindata
+ @chunk = FileStorage::Chunk.new count, file_info.nb_chunks, @data
+ @mid = UUID.random.to_s
end
end
diff --git a/src/server/context.cr b/src/server/context.cr
index 111a060..50c6b28 100644
--- a/src/server/context.cr
+++ b/src/server/context.cr
@@ -4,9 +4,12 @@
class User
property uid : Int32
property token : FileStorage::Token
- property requests : Array(FileStorage::Message::Request)?
+ property uploads : Array(FileStorage::UploadRequest)
+ property downloads : Array(FileStorage::DownloadRequest)
- def initialize(@token, @requests = nil)
+ def initialize(@token,
+ @uploads = Array(FileStorage::UploadRequest).new,
+ @downloads = Array(FileStorage::DownloadRequest).new)
@uid = token.uid
end
end
diff --git a/src/server/handlers.cr b/src/server/handlers.cr
index 41dbe01..62cb455 100644
--- a/src/server/handlers.cr
+++ b/src/server/handlers.cr
@@ -3,63 +3,76 @@ require "dodb"
require "base64"
# reception of a file chunk
-def hdl_transfer(message : FileStorage::Message::Transfer,
+def hdl_transfer(message : FileStorage::Transfer,
user : User,
- event : IPC::Event::Message) : FileStorage::Message::Response
+ event : IPC::Event::Message) : FileStorage::Response
puts "receiving a file"
- transfer_message = FileStorage::Message::Transfer.from_json(
- String.new event.message.payload
- )
+ mid = message.mid
+ mid ||= "no message id"
- pp! transfer_message
+ # pp! transfer_message
+
+ file_info = user.uploads.select do |v|
+ v.file.digest == message.filedigest
+ end.first.file
+
+ pp! file_info
+
+ # TODO: verify the digest
+ # TODO: store the file
+ # TODO: register the file, with its tags
# puts "chunk: #{transfer_message.chunk}"
# puts "data: #{Base64.decode transfer_message.data}"
- FileStorage::Message::Response.new message.mid, "Ok"
+ FileStorage::Response.new mid, "Ok"
+
+rescue e
+ puts "Error handling transfer: #{e.message}"
+ FileStorage::Response.new mid.not_nil!, "Not Ok", "Unexpected error: #{e.message}"
end
# TODO
# the client sent an upload request
-def hdl_upload(request : FileStorage::Message::UploadRequest,
+def hdl_upload(request : FileStorage::UploadRequest,
user : User,
- event : IPC::Event::Message) : FileStorage::Message::Response
+ event : IPC::Event::Message) : FileStorage::Response
puts "hdl upload: mid=#{request.mid}"
pp! request
- FileStorage::Message::Response.new request.mid, "Upload OK"
+ FileStorage::Response.new request.mid, "Upload OK"
end
# TODO
# the client sent a download request
-def hdl_download(request : FileStorage::Message::DownloadRequest,
+def hdl_download(request : FileStorage::DownloadRequest,
user : User,
- event : IPC::Event::Message) : FileStorage::Message::Response
+ event : IPC::Event::Message) : FileStorage::Response
puts "hdl download: mid=#{request.mid}"
pp! request
- FileStorage::Message::Response.new request.mid, "Download OK"
+ FileStorage::Response.new request.mid, "Download OK"
end
# Entry point for request management
# Each request should have a response.
# Then, responses are sent in a single message.
-def hdl_requests(requests : Array(FileStorage::Message::Request),
+def hdl_requests(requests : Array(FileStorage::Request),
user : User,
- event : IPC::Event::Message) : Array(FileStorage::Message::Response)
+ event : IPC::Event::Message) : Array(FileStorage::Response)
puts "hdl request"
- responses = Array(FileStorage::Message::Response).new
+ responses = Array(FileStorage::Response).new
requests.each do |request|
case request
- when FileStorage::Message::DownloadRequest
+ when FileStorage::DownloadRequest
responses << hdl_download request, user, event
- when FileStorage::Message::UploadRequest
+ when FileStorage::UploadRequest
responses << hdl_upload request, user, event
else
raise "request not understood"
@@ -78,7 +91,7 @@ end
def hdl_authentication(event : IPC::Event::Message)
authentication_message =
- FileStorage::Message::Authentication.from_json(
+ FileStorage::Authentication.from_json(
String.new event.message.payload
)
@@ -98,7 +111,8 @@ def hdl_authentication(event : IPC::Event::Message)
# AuthenticationMessage includes requests.
new_user =
User.new authentication_message.token,
- [ authentication_message.uploads, authentication_message.downloads ].flatten
+ authentication_message.uploads,
+ authentication_message.downloads
Context.connected_users[event.connection.fd] = userid
@@ -127,7 +141,7 @@ def hdl_authentication(event : IPC::Event::Message)
# Sending a response, containing a response for each request.
# The response is "Ok" when the message is well received and authorized.
- response = FileStorage::Message::Responses.new authentication_message.mid, "Ok", responses
+ response = FileStorage::Responses.new authentication_message.mid, "Ok", responses
event.connection.send FileStorage::MessageType::Responses.to_u8, response.to_json
pp! FileStorage::MessageType::Responses.to_u8
pp! response
diff --git a/src/server/main-loop.cr b/src/server/main-loop.cr
index 4b7aedd..645a5ff 100644
--- a/src/server/main-loop.cr
+++ b/src/server/main-loop.cr
@@ -42,8 +42,8 @@ Context.service.not_nil!.loop do |event|
if ! userid && mtype != FileStorage::MessageType::Authentication
# TODO: replace this with an Error message?
mid = "no message id"
- response = FileStorage::Message::Response.new mid, "Not OK", "Action on non connected user"
- event.connection.send FileStorage::MessageType::Response.to_u8, response.to_json
+ response = FileStorage::Response.new mid, "Not OK", "Action on non connected user"
+ do_response event, response
end
case mtype
@@ -59,22 +59,20 @@ Context.service.not_nil!.loop do |event|
end
when .upload_request?
puts "Upload request"
- request = FileStorage::Message::UploadRequest.from_json(
+ request = FileStorage::UploadRequest.from_json(
String.new event.message.payload
)
response = hdl_upload request, Context.users_status[userid], event
- event.connection.send FileStorage::MessageType::Response.to_u8, response.to_json
- raise "not implemented yet"
+ do_response event, response
when .download_request?
puts "Download request"
- request = FileStorage::Message::DownloadRequest.from_json(
+ request = FileStorage::DownloadRequest.from_json(
String.new event.message.payload
)
response = hdl_download request, Context.users_status[userid], event
- event.connection.send FileStorage::MessageType::Response.to_u8, response.to_json
- raise "not implemented yet"
+ do_response event, response
when .response?
puts "Response message"
raise "not implemented yet"
@@ -90,12 +88,12 @@ Context.service.not_nil!.loop do |event|
raise "The user isn't recorded in the users_status structure"
end
- transfer = FileStorage::Message::Transfer.from_json(
+ transfer = FileStorage::Transfer.from_json(
String.new event.message.payload
)
response = hdl_transfer transfer, Context.users_status[userid], event
- event.connection.send FileStorage::MessageType::Response.to_u8, response.to_json
+ do_response event, response
end
else
raise "Event type not supported."
@@ -103,3 +101,19 @@ Context.service.not_nil!.loop do |event|
rescue e
puts "A problem occured : #{e.message}"
end
+
+def do_response(event : IPC::Event::Message,
+ response : FileStorage::Message)
+
+ case response
+ when FileStorage::Response
+ event.connection.send FileStorage::MessageType::Response.to_u8, response.to_json
+ when FileStorage::Responses
+ event.connection.send FileStorage::MessageType::Responses.to_u8, response.to_json
+ when FileStorage::Error
+ event.connection.send FileStorage::MessageType::Error.to_u8, response.to_json
+ else
+ puts "response should not happen: #{response}"
+ pp! response
+ end
+end