IPC::JSON structure
This commit is contained in:
parent
2f649b6b15
commit
86495365d6
@ -10,7 +10,7 @@
|
|||||||
# Quotas are not defined yet.
|
# Quotas are not defined yet.
|
||||||
|
|
||||||
#class FileStorage::Request
|
#class FileStorage::Request
|
||||||
# JSONIPC.request Authentication, 10 do
|
# IPC::JSON.message Authentication, 10 do
|
||||||
# property mid : String # autogenerated
|
# property mid : String # autogenerated
|
||||||
# property token : Token
|
# property token : Token
|
||||||
# property uploads : Array(UploadRequest)?
|
# property uploads : Array(UploadRequest)?
|
||||||
@ -70,7 +70,7 @@
|
|||||||
#end
|
#end
|
||||||
#
|
#
|
||||||
#class FileStorage::Response
|
#class FileStorage::Response
|
||||||
# JSONIPC.request AuthenticationSuccess, 10 do
|
# IPC::JSON.message AuthenticationSuccess, 10 do
|
||||||
# property mid : String
|
# property mid : String
|
||||||
# property responses : Array(FileStorage::Response)
|
# property responses : Array(FileStorage::Response)
|
||||||
# def initialize(@mid, @responses)
|
# def initialize(@mid, @responses)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
class FileStorage::Request
|
class FileStorage::Request
|
||||||
|
|
||||||
JSONIPC.request Download, 30 do
|
IPC::JSON.message Download, 30 do
|
||||||
property mid : String # autogenerated
|
property mid : String # autogenerated
|
||||||
property filedigest : String? # SHA256 digest of the file, used as ID
|
property filedigest : String? # SHA256 digest of the file, used as ID
|
||||||
property name : String?
|
property name : String?
|
||||||
@ -28,7 +28,7 @@ class FileStorage::Request
|
|||||||
end
|
end
|
||||||
|
|
||||||
class FileStorage::Response
|
class FileStorage::Response
|
||||||
JSONIPC.request Download, 30 do
|
IPC::JSON.message Download, 30 do
|
||||||
property mid : String
|
property mid : String
|
||||||
property nb_chunks : Int32
|
property nb_chunks : Int32
|
||||||
def initialize(@mid, @nb_chunks)
|
def initialize(@mid, @nb_chunks)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
class FileStorage::Errors
|
class FileStorage::Errors
|
||||||
JSONIPC.request GenericError, 200 do
|
IPC::JSON.message GenericError, 200 do
|
||||||
property mid : String
|
property mid : String
|
||||||
property reason : String
|
property reason : String
|
||||||
def initialize(@mid, @reason)
|
def initialize(@mid, @reason)
|
||||||
@ -7,7 +7,7 @@ class FileStorage::Errors
|
|||||||
end
|
end
|
||||||
FileStorage.errors << GenericError
|
FileStorage.errors << GenericError
|
||||||
|
|
||||||
JSONIPC.request Authorization, 201 do
|
IPC::JSON.message Authorization, 201 do
|
||||||
property mid : String
|
property mid : String
|
||||||
property reason : String
|
property reason : String
|
||||||
def initialize(@mid, @reason = "authorization")
|
def initialize(@mid, @reason = "authorization")
|
||||||
@ -16,7 +16,7 @@ class FileStorage::Errors
|
|||||||
FileStorage.errors << Authorization
|
FileStorage.errors << Authorization
|
||||||
|
|
||||||
# When uploading a chunk already present in the DB.
|
# When uploading a chunk already present in the DB.
|
||||||
JSONIPC.request ChunkAlreadyUploaded, 202 do
|
IPC::JSON.message ChunkAlreadyUploaded, 202 do
|
||||||
property mid : String
|
property mid : String
|
||||||
property reason = "Chunk already present"
|
property reason = "Chunk already present"
|
||||||
property filedigest : String
|
property filedigest : String
|
||||||
@ -28,7 +28,7 @@ class FileStorage::Errors
|
|||||||
FileStorage.errors << ChunkAlreadyUploaded
|
FileStorage.errors << ChunkAlreadyUploaded
|
||||||
|
|
||||||
# You upload a chunk, but you are not the owner of the file.
|
# You upload a chunk, but you are not the owner of the file.
|
||||||
JSONIPC.request ChunkUploadDenied, 203 do
|
IPC::JSON.message ChunkUploadDenied, 203 do
|
||||||
property mid : String
|
property mid : String
|
||||||
property reason = "This file is not yours"
|
property reason = "This file is not yours"
|
||||||
property filedigest : String
|
property filedigest : String
|
||||||
@ -39,7 +39,7 @@ class FileStorage::Errors
|
|||||||
FileStorage.errors << ChunkUploadDenied
|
FileStorage.errors << ChunkUploadDenied
|
||||||
|
|
||||||
# When uploading a file already present in the DB.
|
# When uploading a file already present in the DB.
|
||||||
JSONIPC.request FileExists, 204 do
|
IPC::JSON.message FileExists, 204 do
|
||||||
property mid : String
|
property mid : String
|
||||||
property reason = "file already present"
|
property reason = "file already present"
|
||||||
property path : String
|
property path : String
|
||||||
@ -51,7 +51,7 @@ class FileStorage::Errors
|
|||||||
FileStorage.errors << FileExists
|
FileStorage.errors << FileExists
|
||||||
|
|
||||||
# When transfering a chunk for an inexistent file.
|
# When transfering a chunk for an inexistent file.
|
||||||
JSONIPC.request FileDoesNotExist, 205 do
|
IPC::JSON.message FileDoesNotExist, 205 do
|
||||||
property mid : String
|
property mid : String
|
||||||
property reason = "file does not exist"
|
property reason = "file does not exist"
|
||||||
property filedigest : String
|
property filedigest : String
|
||||||
@ -62,7 +62,7 @@ class FileStorage::Errors
|
|||||||
FileStorage.errors << FileDoesNotExist
|
FileStorage.errors << FileDoesNotExist
|
||||||
|
|
||||||
# When a file was already fully uploaded.
|
# When a file was already fully uploaded.
|
||||||
JSONIPC.request FileFullyUploaded, 206 do
|
IPC::JSON.message FileFullyUploaded, 206 do
|
||||||
property mid : String
|
property mid : String
|
||||||
property reason = "file already uploaded fully"
|
property reason = "file already uploaded fully"
|
||||||
property path : String
|
property path : String
|
||||||
|
@ -4,7 +4,7 @@ require "json"
|
|||||||
require "base64"
|
require "base64"
|
||||||
|
|
||||||
class FileStorage::Request
|
class FileStorage::Request
|
||||||
JSONIPC.request Login, 0 do
|
IPC::JSON.message Login, 0 do
|
||||||
property mid : String = ""
|
property mid : String = ""
|
||||||
|
|
||||||
property token : String
|
property token : String
|
||||||
@ -34,7 +34,7 @@ class FileStorage::Request
|
|||||||
end
|
end
|
||||||
|
|
||||||
class FileStorage::Response
|
class FileStorage::Response
|
||||||
JSONIPC.request Login, 5 do
|
IPC::JSON.message Login, 5 do
|
||||||
property mid : String
|
property mid : String
|
||||||
def initialize(@mid)
|
def initialize(@mid)
|
||||||
end
|
end
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
class FileStorage::Request
|
class FileStorage::Request
|
||||||
JSONIPC.request PutChunk, 40 do
|
IPC::JSON.message PutChunk, 40 do
|
||||||
property mid : String # autogenerated
|
property mid : String # autogenerated
|
||||||
property filedigest : String # SHA256 digest of the entire file
|
property filedigest : String # SHA256 digest of the entire file
|
||||||
# Chunk:
|
# Chunk:
|
||||||
@ -36,7 +36,7 @@ class FileStorage::Request
|
|||||||
end
|
end
|
||||||
FileStorage.requests << PutChunk
|
FileStorage.requests << PutChunk
|
||||||
|
|
||||||
JSONIPC.request GetChunk, 41 do
|
IPC::JSON.message GetChunk, 41 do
|
||||||
property mid : String # autogenerated
|
property mid : String # autogenerated
|
||||||
property filedigest : String # SHA256 digest of the entire file
|
property filedigest : String # SHA256 digest of the entire file
|
||||||
property n : Int32 # chunk number
|
property n : Int32 # chunk number
|
||||||
@ -64,7 +64,7 @@ class FileStorage::Request
|
|||||||
end
|
end
|
||||||
|
|
||||||
class FileStorage::Response
|
class FileStorage::Response
|
||||||
JSONIPC.request PutChunk, 40 do
|
IPC::JSON.message PutChunk, 40 do
|
||||||
property mid : String
|
property mid : String
|
||||||
property file_digest : String
|
property file_digest : String
|
||||||
property n : Int32 # chunk number
|
property n : Int32 # chunk number
|
||||||
@ -72,7 +72,7 @@ class FileStorage::Response
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
JSONIPC.request GetChunk, 41 do
|
IPC::JSON.message GetChunk, 41 do
|
||||||
property mid : String
|
property mid : String
|
||||||
property file_digest : String
|
property file_digest : String
|
||||||
# Chunk:
|
# Chunk:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
class FileStorage::Request
|
class FileStorage::Request
|
||||||
JSONIPC.request Upload, 20 do
|
IPC::JSON.message Upload, 20 do
|
||||||
property mid : String # autogenerated
|
property mid : String # autogenerated
|
||||||
property file : FileInfo
|
property file : FileInfo
|
||||||
def initialize(@file : FileInfo)
|
def initialize(@file : FileInfo)
|
||||||
@ -26,7 +26,7 @@ class FileStorage::Request
|
|||||||
end
|
end
|
||||||
|
|
||||||
class FileStorage::Response
|
class FileStorage::Response
|
||||||
JSONIPC.request Upload, 20 do
|
IPC::JSON.message Upload, 20 do
|
||||||
property mid : String
|
property mid : String
|
||||||
property path : String
|
property path : String
|
||||||
def initialize(@mid, @path)
|
def initialize(@mid, @path)
|
||||||
@ -34,7 +34,7 @@ class FileStorage::Response
|
|||||||
end
|
end
|
||||||
FileStorage.responses << Upload
|
FileStorage.responses << Upload
|
||||||
|
|
||||||
# JSONIPC.request Responses, 100 do
|
# IPC::JSON.message Responses, 100 do
|
||||||
# property mid : String
|
# property mid : String
|
||||||
# property responses : Array(Response | Errors) # a response for each request
|
# property responses : Array(Response | Errors) # a response for each request
|
||||||
# property response : String
|
# property response : String
|
||||||
|
@ -29,6 +29,23 @@ require "./network.cr"
|
|||||||
|
|
||||||
require "dodb"
|
require "dodb"
|
||||||
|
|
||||||
|
class IPC::JSON
|
||||||
|
def handle(filestoraged : FileStorage::Service, event : IPC::Event::Events)
|
||||||
|
raise "unknown request"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module FileStorage
|
||||||
|
class Exception < ::Exception
|
||||||
|
end
|
||||||
|
class AuthorizationException < ::Exception
|
||||||
|
end
|
||||||
|
class NotLoggedException < ::Exception
|
||||||
|
end
|
||||||
|
class AdminAuthorizationException < ::Exception
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
class FileStorage::Service < IPC::Server
|
class FileStorage::Service < IPC::Server
|
||||||
# List of connected users (fd => uid).
|
# List of connected users (fd => uid).
|
||||||
@ -85,11 +102,49 @@ class FileStorage::Service < IPC::Server
|
|||||||
@storage.user_data_per_user.update_or_create user_data.uid.to_s, user_data
|
@storage.user_data_per_user.update_or_create user_data.uid.to_s, user_data
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: could be useful to send notifications.
|
def handle_request(event : IPC::Event::MessageReceived)
|
||||||
#def send_notifications(fd : Int32, value : Int32)
|
|
||||||
# @all_connections.select(&.!=(fd)).each do |fd| ... end
|
request = FileStorage.requests.parse_ipc_json event.message
|
||||||
# IPC::Connection.new(fd).send Response::Something.new ...
|
if request.nil?
|
||||||
#end
|
raise "unknown request type"
|
||||||
|
end
|
||||||
|
|
||||||
|
request_name = request.class.name.sub /^FileStorage::Request::/, ""
|
||||||
|
Baguette::Log.info "<< #{request_name}"
|
||||||
|
|
||||||
|
response = FileStorage::Errors::GenericError.new "#{request.id}", "generic error"
|
||||||
|
|
||||||
|
request_id = "#{request.id}"
|
||||||
|
|
||||||
|
begin
|
||||||
|
response = request.handle self, event
|
||||||
|
rescue e : AuthorizationException
|
||||||
|
Baguette::Log.error "#{request_name} authorization error"
|
||||||
|
response = FileStorage::Errors::GenericError.new request_id, "authorization error"
|
||||||
|
rescue e : AdminAuthorizationException
|
||||||
|
Baguette::Log.error "#{request_name} no admin authorization"
|
||||||
|
response = FileStorage::Errors::GenericError.new request_id, "admin authorization error"
|
||||||
|
rescue e : NotLoggedException
|
||||||
|
Baguette::Log.error "#{request_name} user not logged"
|
||||||
|
response = FileStorage::Errors::GenericError.new request_id, "user not logged"
|
||||||
|
# Do not handle generic exception case: do not provide a response.
|
||||||
|
# rescue e # Generic case
|
||||||
|
# Baguette::Log.error "#{request_name} generic error #{e}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# If clients sent requests with an “id” field, it is copied
|
||||||
|
# in the responses. Allows identifying responses easily.
|
||||||
|
response.id = request.id
|
||||||
|
|
||||||
|
send event.fd, response
|
||||||
|
|
||||||
|
response_name = response.class.name.sub /^FileStorage::(Response|Errors)::/, ""
|
||||||
|
if response.responds_to?(:reason)
|
||||||
|
Baguette::Log.warning ">> #{response_name} (#{response.reason})"
|
||||||
|
else
|
||||||
|
Baguette::Log.info ">> #{response_name}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
Baguette::Log.title "Starting filestoraged"
|
Baguette::Log.title "Starting filestoraged"
|
||||||
@ -128,102 +183,10 @@ class FileStorage::Service < IPC::Server
|
|||||||
Baguette::Log.debug "IPC::Event::Message: #{event.fd}"
|
Baguette::Log.debug "IPC::Event::Message: #{event.fd}"
|
||||||
|
|
||||||
request_start = Time.utc
|
request_start = Time.utc
|
||||||
|
handle_request event
|
||||||
request = parse_message FileStorage.requests, event.message
|
|
||||||
|
|
||||||
if request.nil?
|
|
||||||
raise "unknown request type"
|
|
||||||
end
|
|
||||||
|
|
||||||
Baguette::Log.info "<< #{request.class.name.sub /^FileStorage::Request::/, ""}"
|
|
||||||
|
|
||||||
response = request.handle self, event
|
|
||||||
response_type = response.class.name
|
|
||||||
|
|
||||||
if response.responds_to?(:reason)
|
|
||||||
Baguette::Log.warning ">> #{response_type.sub /^FileStorage::Errors::/, ""} (#{response.reason})"
|
|
||||||
else
|
|
||||||
Baguette::Log.info ">> #{response_type.sub /^FileStorage::Response::/, ""}"
|
|
||||||
end
|
|
||||||
|
|
||||||
#################################################################
|
|
||||||
# THERE START
|
|
||||||
#################################################################
|
|
||||||
|
|
||||||
# # The first message sent to the server has to be the AuthenticationMessage.
|
|
||||||
# # Users sent their token (JWT) to authenticate themselves.
|
|
||||||
# # The token contains the user id, its login and a few other parameters.
|
|
||||||
# # (see the authd documentation).
|
|
||||||
# # TODO: for now, the token is replaced by a hardcoded one, for debugging
|
|
||||||
#
|
|
||||||
# mtype = FileStorage::MessageType.new event.message.utype.to_i32
|
|
||||||
#
|
|
||||||
# # First, the user has to be authenticated unless we are receiving its first message.
|
|
||||||
# userid = Context.connected_users[event.fd]?
|
|
||||||
#
|
|
||||||
# # If the user is not yet connected but does not try to perform authentication.
|
|
||||||
# if ! userid && mtype != FileStorage::MessageType::Authentication
|
|
||||||
# # TODO: replace this with an Error message.
|
|
||||||
# mid = "no message id"
|
|
||||||
# response = FileStorage::Response.new mid, "Not OK", "Action on non connected user"
|
|
||||||
# do_response event, response
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# case mtype
|
|
||||||
# when .authentication?
|
|
||||||
# Baguette::Log.debug "Receiving an authentication message"
|
|
||||||
# # Test if the client is already authenticated.
|
|
||||||
# if userid
|
|
||||||
# user = Context.users_status[userid]
|
|
||||||
# raise "Authentication message while the user was already connected: this should not happen"
|
|
||||||
# else
|
|
||||||
# Baguette::Log.debug "User is not currently connected"
|
|
||||||
# hdl_authentication event
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# when .upload_request?
|
|
||||||
# Baguette::Log.debug "Upload request"
|
|
||||||
# request = FileStorage::UploadRequest.from_json(
|
|
||||||
# String.new event.message.payload
|
|
||||||
# )
|
|
||||||
# response = hdl_upload request, Context.users_status[userid]
|
|
||||||
# do_response event, response
|
|
||||||
#
|
|
||||||
# when .download_request?
|
|
||||||
# Baguette::Log.debug "Download request"
|
|
||||||
# request = FileStorage::DownloadRequest.from_json(
|
|
||||||
# String.new event.message.payload
|
|
||||||
# )
|
|
||||||
# response = hdl_download request, Context.users_status[userid]
|
|
||||||
# do_response event, response
|
|
||||||
#
|
|
||||||
# when .transfer?
|
|
||||||
# # throw an error if the user isn't recorded
|
|
||||||
# unless user = Context.users_status[userid]?
|
|
||||||
# raise "The user isn't recorded in the users_status structure"
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# transfer = FileStorage::PutChunk.from_json(
|
|
||||||
# String.new event.message.payload
|
|
||||||
# )
|
|
||||||
# response = hdl_transfer transfer, Context.users_status[userid]
|
|
||||||
#
|
|
||||||
# do_response event, response
|
|
||||||
# end
|
|
||||||
|
|
||||||
#################################################################
|
|
||||||
# FINISH
|
|
||||||
#################################################################
|
|
||||||
|
|
||||||
|
|
||||||
# If clients sent requests with an “id” field, it is copied
|
|
||||||
# in the responses. Allows identifying responses easily.
|
|
||||||
response.id = request.id
|
|
||||||
|
|
||||||
send event.fd, response
|
|
||||||
|
|
||||||
duration = Time.utc - request_start
|
duration = Time.utc - request_start
|
||||||
Baguette::Log.debug "request took: #{duration}"
|
Baguette::Log.debug "request took: #{duration}"
|
||||||
|
|
||||||
when IPC::Event::MessageSent
|
when IPC::Event::MessageSent
|
||||||
Baguette::Log.debug "IPC::Event::MessageSent: #{event.fd}"
|
Baguette::Log.debug "IPC::Event::MessageSent: #{event.fd}"
|
||||||
else
|
else
|
||||||
|
@ -1,42 +1,16 @@
|
|||||||
require "ipc"
|
require "ipc"
|
||||||
require "json"
|
require "json"
|
||||||
|
|
||||||
class JSONIPC
|
|
||||||
include JSON::Serializable
|
|
||||||
|
|
||||||
getter type = -1
|
|
||||||
class_getter type = -1
|
|
||||||
|
|
||||||
property id : JSON::Any?
|
|
||||||
|
|
||||||
def handle(service : IPC::Server, event : IPC::Event::Events)
|
|
||||||
raise "unimplemented"
|
|
||||||
end
|
|
||||||
|
|
||||||
macro request(id, type, &block)
|
|
||||||
class {{id}} < ::JSONIPC
|
|
||||||
include JSON::Serializable
|
|
||||||
|
|
||||||
@@type = {{type}}
|
|
||||||
def type
|
|
||||||
@@type
|
|
||||||
end
|
|
||||||
|
|
||||||
{{yield}}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class IPC::Context
|
class IPC::Context
|
||||||
def send(fd : Int32, request : JSONIPC)
|
def send(fd : Int32, request : IPC::JSON)
|
||||||
send fd, request.type.to_u8, request.to_json
|
send fd, request.type.to_u8, request.to_json
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class FileStorage
|
module FileStorage
|
||||||
class_getter requests = [] of JSONIPC.class
|
class_getter requests = [] of IPC::JSON.class
|
||||||
class_getter responses = [] of JSONIPC.class
|
class_getter responses = [] of IPC::JSON.class
|
||||||
class_getter errors = [] of JSONIPC.class
|
class_getter errors = [] of IPC::JSON.class
|
||||||
end
|
end
|
||||||
|
|
||||||
class FileStorage::Client < IPC::Client
|
class FileStorage::Client < IPC::Client
|
||||||
@ -45,19 +19,6 @@ class FileStorage::Client < IPC::Client
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_message(requests : Array(JSONIPC.class), message : IPC::Message) : JSONIPC?
|
|
||||||
request_type = requests.find &.type.==(message.utype)
|
|
||||||
|
|
||||||
payload = String.new message.payload
|
|
||||||
|
|
||||||
if request_type.nil?
|
|
||||||
raise "invalid request type (#{message.utype})"
|
|
||||||
end
|
|
||||||
|
|
||||||
request_type.from_json payload
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
require "../common/requests/client.cr"
|
require "../common/requests/client.cr"
|
||||||
require "../common/requests/login.cr"
|
require "../common/requests/login.cr"
|
||||||
require "../common/requests/transfer.cr"
|
require "../common/requests/transfer.cr"
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
# })
|
# })
|
||||||
#end
|
#end
|
||||||
|
|
||||||
class FileStorage
|
module FileStorage
|
||||||
|
|
||||||
# 1 MB read buffer, on-disk
|
# 1 MB read buffer, on-disk
|
||||||
def self.file_reading_buffer_size
|
def self.file_reading_buffer_size
|
||||||
@ -45,10 +45,6 @@ class FileStorage
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
class FileStorage::Exception < ::Exception
|
|
||||||
end
|
|
||||||
|
|
||||||
class FileStorage::Chunk
|
class FileStorage::Chunk
|
||||||
include JSON::Serializable
|
include JSON::Serializable
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
class FileStorage
|
module FileStorage
|
||||||
def self.message_buffer_size
|
def self.message_buffer_size
|
||||||
def self.file_reading_buffer_size
|
def self.file_reading_buffer_size
|
||||||
def self.data_digest(data : Bytes)
|
def self.data_digest(data : Bytes)
|
||||||
|
Loading…
Reference in New Issue
Block a user