record users, handling user status, new message format
parent
5a25cfcd25
commit
d6aa9f35fb
|
@ -4,13 +4,22 @@ require "json"
|
|||
|
||||
require "./common.cr"
|
||||
|
||||
# TODO
|
||||
# For now, this example only upload files.
|
||||
# In a near future, we should be able to download files, too.
|
||||
|
||||
service_name = "filestorage"
|
||||
|
||||
files_and_directories_to_transfer = Array(String).new
|
||||
|
||||
# This is the requests we will send to the server
|
||||
requets = Array(Requets).new
|
||||
|
||||
|
||||
OptionParser.parse do |parser|
|
||||
parser.on "-s service-name", "--service-name service-name", "Service name." do |name|
|
||||
parser.on "-s service-name",
|
||||
"--service-name service-name",
|
||||
"Service name." do |name|
|
||||
service_name = name
|
||||
end
|
||||
|
||||
|
@ -24,19 +33,16 @@ OptionParser.parse do |parser|
|
|||
end
|
||||
end
|
||||
|
||||
client = IPC::Client.new service_name
|
||||
|
||||
|
||||
#
|
||||
# Get informations about files to transfer
|
||||
# For now, we only want to upload files, so we create an UploadRequest
|
||||
#
|
||||
|
||||
files_info = Array(FileInfo).new
|
||||
|
||||
puts "files and directories to transfer"
|
||||
files_and_directories_to_transfer.each do |f|
|
||||
puts "- #{f}"
|
||||
|
||||
if File.directory? f
|
||||
# TODO
|
||||
puts "Directories not supported, for now"
|
||||
|
@ -45,11 +51,11 @@ files_and_directories_to_transfer.each do |f|
|
|||
files_info << FileInfo.new file
|
||||
end
|
||||
else
|
||||
if File.exists? f
|
||||
if ! File.exists? f
|
||||
puts "#{f} does not exist"
|
||||
elsif File.file? f
|
||||
elsif ! File.file? f
|
||||
puts "#{f} is neither a directory or a file"
|
||||
elsif File.readable? f
|
||||
elsif ! File.readable? f
|
||||
puts "#{f} is not readable"
|
||||
end
|
||||
end
|
||||
|
@ -57,10 +63,16 @@ end
|
|||
|
||||
pp! files_info
|
||||
|
||||
exit 0
|
||||
requests << UploadRequest.new files_info
|
||||
|
||||
#
|
||||
# Create the authentication message, including files info
|
||||
# Connection to the service
|
||||
#
|
||||
|
||||
client = IPC::Client.new service_name
|
||||
|
||||
#
|
||||
# Sending the authentication message, including files info
|
||||
#
|
||||
|
||||
token = Token.new 1002, "karchnu"
|
||||
|
@ -69,6 +81,10 @@ authentication_message = AuthenticationMessage.new token, files_info
|
|||
|
||||
client.send(1.to_u8, authentication_message.to_json)
|
||||
|
||||
#
|
||||
# Receiving a response
|
||||
#
|
||||
|
||||
m = client.read
|
||||
# puts "message received: #{m.to_s}"
|
||||
# puts "message received payload: #{String.new m.payload}"
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
require "uuid"
|
||||
|
||||
enum MessageType
|
||||
Error
|
||||
AuthenticationMessage
|
||||
Response
|
||||
Transfer
|
||||
end
|
||||
|
||||
# For now, upload and download are sequentials.
|
||||
# In a future version, we will be able to send
|
||||
# arbitrary parts of each file.
|
||||
|
||||
class Token
|
||||
JSON.mapping({
|
||||
uid: Int32,
|
||||
|
@ -10,28 +21,62 @@ class Token
|
|||
end
|
||||
end
|
||||
|
||||
# Who knows, maybe someday we will be on UDP, too.
|
||||
#class SHA256
|
||||
# JSON.mapping({
|
||||
# chunk: Slice(UInt8)
|
||||
# })
|
||||
#end
|
||||
|
||||
|
||||
# A file has a name, a size and tags.
|
||||
class FileInfo
|
||||
JSON.mapping({
|
||||
name: String,
|
||||
size: UInt32,
|
||||
size: UInt64,
|
||||
# list of SHA256, if we are on UDP
|
||||
# chunks: Array(SHA256),
|
||||
tags: Array(String)?
|
||||
})
|
||||
|
||||
# debugging constructor
|
||||
def initialize(@name, @size, @tags = nil)
|
||||
# If on UDP
|
||||
# @chunks = Array(SHA256).new
|
||||
# arbitrary values here
|
||||
end
|
||||
|
||||
def initialize(file : File, @tags = nil)
|
||||
@name = file.basename
|
||||
@name = File.basename file.path
|
||||
@size = file.size
|
||||
end
|
||||
end
|
||||
|
||||
class Request
|
||||
end
|
||||
|
||||
class UploadRequest < Request
|
||||
property files_to_upload : Array(FileInfo)
|
||||
|
||||
def initialize(@files_to_upload)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# WIP
|
||||
class DownloadRequest < Request
|
||||
property names : Array(String)?,
|
||||
property tags : Array(String)?
|
||||
|
||||
def initialize(@names = nil, @tags = nil)
|
||||
end
|
||||
end
|
||||
|
||||
class AuthenticationMessage
|
||||
JSON.mapping({
|
||||
mid: String,
|
||||
token: Token,
|
||||
files: Array(FileInfo),
|
||||
tags: Array(String)?
|
||||
requests: Array(Requests)
|
||||
})
|
||||
|
||||
def initialize(@token, @files, @tags = nil)
|
||||
|
@ -50,7 +95,7 @@ class Response
|
|||
end
|
||||
end
|
||||
|
||||
class Transfer
|
||||
class TransferMessage
|
||||
JSON.mapping({
|
||||
mid: String,
|
||||
chunk: String,
|
||||
|
|
|
@ -2,13 +2,16 @@ require "json"
|
|||
|
||||
require "./common.cr"
|
||||
|
||||
files_info = Array(FileInfo).new
|
||||
files_info << FileInfo.new "file.txt", 4123.to_u64, %w(important truc machin)
|
||||
|
||||
token = Token.new 1002, "karchnu"
|
||||
authentication_message = AuthenticationMessage.new token
|
||||
authentication_message = AuthenticationMessage.new token, files_info
|
||||
|
||||
# TODO, TEST, DEBUG, XXX, FIXME
|
||||
pp! authentication_message.to_json
|
||||
|
||||
|
||||
am_from_json = AuthenticationMessage.from_json authentication_message.to_json
|
||||
|
||||
pp! am_from_json
|
||||
|
|
85
src/main.cr
85
src/main.cr
|
@ -30,33 +30,50 @@ OptionParser.parse do |parser|
|
|||
end
|
||||
|
||||
|
||||
# keep track of connected users
|
||||
# keep track of connected users and their requests
|
||||
# TODO: requests should be handled concurrently
|
||||
class User
|
||||
property uid : Int32
|
||||
property token : Token
|
||||
property requests : Array(Request)
|
||||
|
||||
def initialize(@token)
|
||||
@uid = token.uid
|
||||
end
|
||||
end
|
||||
|
||||
# list of connected users
|
||||
# fd => User
|
||||
connected_users = Hash(Int32, User).new
|
||||
# fd => uid
|
||||
connected_users = Hash(Int32, Int32).new
|
||||
users_status = Hash(Int32, User).new
|
||||
|
||||
service = IPC::SwitchingService.new service_name
|
||||
|
||||
def receiving_files(user : User, event : IPC::Event::Message)
|
||||
end
|
||||
|
||||
# Could be the reception of a file or a file request
|
||||
def request_handling(user : User, event : IPC::Event::Message)
|
||||
puts "request handling"
|
||||
|
||||
#
|
||||
# Here we get requests from the message received
|
||||
#
|
||||
|
||||
end
|
||||
|
||||
service.loop do |event|
|
||||
case event
|
||||
when IPC::Event::Timer
|
||||
puts "#{CORANGE}IPC::Event::Timer#{CRESET}"
|
||||
|
||||
# puts "Disconnected client is: #{client_name}"
|
||||
|
||||
when IPC::Event::Connection
|
||||
puts "#{CBLUE}IPC::Event::Connection: #{event.connection.fd}#{CRESET}"
|
||||
|
||||
when IPC::Event::Disconnection
|
||||
puts "#{CBLUE}IPC::Event::Disconnection: #{event.connection.fd}#{CRESET}"
|
||||
|
||||
connected_users.select! do |fd, user|
|
||||
connected_users.select! do |fd, uid|
|
||||
fd != event.connection.fd
|
||||
end
|
||||
|
||||
|
@ -72,31 +89,57 @@ service.loop do |event|
|
|||
puts "#{CBLUE}IPC::Event::Message#{CRESET}: #{event.connection.fd}"
|
||||
|
||||
# 1. test if the client is already authenticated
|
||||
if user = connected_users[event.connection.fd]?
|
||||
if userid = connected_users[event.connection.fd]?
|
||||
puts "User is connected: #{user.token.login}"
|
||||
request_handling users_status[userid], event
|
||||
else
|
||||
puts "User is not currently connected"
|
||||
|
||||
authentication_message = AuthenticationMessage.from_json(String.new event.message.payload)
|
||||
# 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).
|
||||
authentication_message =
|
||||
AuthenticationMessage.from_json(
|
||||
String.new event.message.payload
|
||||
)
|
||||
|
||||
authentication_message.files.each do |file|
|
||||
puts "uploading #{file.name} - #{file.size} bytes"
|
||||
# Is the user already recorded in users_status?
|
||||
if users_status[authentication_message.token.uid]?
|
||||
puts "We already knew the user #{authentication_message.token.uid}"
|
||||
pp! users_status[authentication_message.token.uid]
|
||||
else
|
||||
# AuthenticationMessage includes requests.
|
||||
new_user =
|
||||
User.new authentication_message.token,
|
||||
authentication_message.requests
|
||||
|
||||
connected_users[event.connection.fd] = new_user.uid
|
||||
|
||||
# record the new user in users_status
|
||||
users_status[new_user.uid] = new_user
|
||||
|
||||
puts "New user is: #{new_user.token.login}"
|
||||
end
|
||||
|
||||
new_user = User.new authentication_message.token
|
||||
connected_users[event.connection.fd] = new_user
|
||||
puts "New user is: #{new_user.token.login}"
|
||||
# The user is now connected.
|
||||
user = users_status[authentication_message.token.uid]
|
||||
|
||||
# We verify the user's rights to upload files.
|
||||
# TODO RIGHTS
|
||||
# if user wants to upload but not allowed to: Response
|
||||
# if user wants to get a file but not allowed to: Response
|
||||
|
||||
# The user is authorized to upload files.
|
||||
|
||||
# TODO: quotas
|
||||
# Quotas are not defined yet.
|
||||
|
||||
# Sending a response.
|
||||
# The response is "Ok" when the message is well received and authorized.
|
||||
response = Response.new authentication_message.mid, "Ok"
|
||||
event.connection.send 2.to_u8, response.to_json
|
||||
event.connection.send MessageType::Response.to_u8, response.to_json
|
||||
end
|
||||
|
||||
|
||||
# puts "New connected client is: #{client_name}"
|
||||
|
||||
# The first message is the connection.
|
||||
# Users sent their token (JWT) to authenticate.
|
||||
# From the token, we get the user id, its login and a few other parameters (see the authd documentation).
|
||||
else
|
||||
raise "Event type not supported."
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue