Commit 1896c345 authored by louiz’'s avatar louiz’

Implement the request of a file by the client, and the sending of that file by the server.

TODO: the reception of that file by the client.
parent 7e593994
......@@ -46,10 +46,17 @@ void Game::authenticate(const std::string& login, const std::string& password)
this->client.request_answer("AUTH", std::string(login + '*' + password).data(), boost::bind(&Game::on_authenticate, this, _1));
}
void Game::request_file(const std::string& filename)
{
this->client.request_answer("TRANSFER", filename.data());
}
void Game::on_authenticate(const std::string& result)
{
int res = atoi(result.data());
log_debug("on_authenticate :" << res << "." << ((res > 4) ? "Unknown error" : auth_messages[res]));
if (res == 0)
this->request_file("file.txt");
// TODO some UI stuf, etc.
}
......
......@@ -17,6 +17,12 @@ public:
void on_connection_success(const std::string&, const std::string&);
void authenticate(const std::string&, const std::string&);
void on_authenticate(const std::string&);
/**
* Sends a request for a file transfer.
* @param filename The file that we want to receive.
*/
void request_file(const std::string&);
void run();
private:
......
......@@ -9,14 +9,13 @@
* @class Logger
*/
#include <config/config.hpp>
#include <iostream>
#ifndef __LOGGING_HPP__
# define __LOGGING_HPP__
#include <config/config.hpp>
#define debug_lvl 0
#define info_lvl 1
#define warning_lvl 2
......
......@@ -128,23 +128,29 @@ void CommandHandler::request_answer(const char* command, const char* data,
ssize << strlen(data);
msg += std::string(".") + std::string(ssize.str()) + std::string(":") + std::string(data);
this->install_callback_once(command, on_answer);
// We may want to send a command that do not require an answer.
if (on_answer)
this->install_callback_once(command, on_answer);
this->send(msg.data());
}
void CommandHandler::send(const char* msg)
void CommandHandler::send(const char* msg, boost::function< void(void) > on_sent)
{
async_write(*this->socket,
boost::asio::buffer(msg, strlen(msg)),
boost::bind(&CommandHandler::send_handler, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
boost::asio::placeholders::bytes_transferred,
on_sent));
log_debug("Sending [" << msg << "]");
}
void CommandHandler::send_handler(const boost::system::error_code& error,
std::size_t bytes_transferred)
std::size_t bytes_transferred,
boost::function< void(void) > on_sent)
{
// TODO check for error
log_debug(bytes_transferred << " bytes sent");
if (on_sent)
on_sent();
}
......@@ -19,10 +19,12 @@
#ifndef __COMMAND_HANDLER_HPP__
# define __COMMAND_HANDLER_HPP__
#include <network/transfer_sender.hpp>
using boost::asio::ip::tcp;
class CommandHandler
{
friend void TransferSender::send_next_chunk();
public:
CommandHandler();
~CommandHandler() {}
......@@ -40,10 +42,10 @@ public:
*/
void binary_read_handler(const boost::system::error_code&, std::size_t, boost::function<void(std::string)>);
/**
* Sends a commad, and use install_callback_once to wait for the answer
* Sends a command, and use install_callback_once to wait for the answer
* and call that callback to handle it.
*/
void request_answer(const char*, const char*, boost::function< void(const std::string&) >);
void request_answer(const char*, const char*, boost::function< void(const std::string&) > on_answer = 0);
protected:
/**
......@@ -67,11 +69,11 @@ protected:
/**
* Send the given data on the socket.
*/
void send(const char*);
void send(const char*, boost::function< void(void) > on_send = 0);
/**
* @todo Check if the data was correctly sent on the socket
*/
void send_handler(const boost::system::error_code&, std::size_t);
void send_handler(const boost::system::error_code&, std::size_t, boost::function< void(void) > on_sent);
/**
* A buffer keeping the data that is read on the socket.
*/
......@@ -79,6 +81,7 @@ protected:
* What happens when a read error occurs.
*/
virtual void on_connection_closed() = 0;
boost::asio::streambuf data;
tcp::socket* socket;
......
......@@ -35,12 +35,13 @@ User* RemoteClient::get_user()
void RemoteClient::install_callbacks()
{
this->install_callback("AUTH", boost::bind(&RemoteClient::auth_callback, this, _1));
this->install_callback("TRANSFER", boost::bind(&RemoteClient::transfer_callback, this, _1));
}
void RemoteClient::auth_callback(const std::string& arg)
{
std::string res("AUTH.");
bool success = false;
log_debug("auth_callback: " << arg);
size_t pos = arg.find('*');
if (pos == std::string::npos)
......@@ -74,9 +75,22 @@ void RemoteClient::auth_callback(const std::string& arg)
log_info("Authentication: succes for user " << login);
res += "1:0";
this->user = static_cast<User*>(user);
success = true;
}
}
this->send(res.data());
if (success)
this->on_auth_success();
}
void RemoteClient::transfer_callback(const std::string& filename)
{
this->send_file(filename);
}
void RemoteClient::on_auth_success()
{
log_debug("on_auth_success");
}
void RemoteClient::start()
......@@ -86,7 +100,29 @@ void RemoteClient::start()
this->install_callbacks();
}
void RemoteClient::send_file(const std::string& filename)
{
TransferSender* sender = new TransferSender(this, filename);
if (sender->start() == true)
{
this->senders.push_back(sender);
sender->send_next_chunk();
}
else
delete sender;
}
void RemoteClient::on_connection_closed()
{
this->server->remove_client(this);
}
void RemoteClient::on_transfer_ended(TransferSender* transfer)
{
log_debug("on_transfer_ended");
std::vector<TransferSender*>::iterator it;
for (it = this->senders.begin(); it < this->senders.end(); ++it)
if (*it == transfer)
this->senders.erase(it);
delete transfer;
}
......@@ -19,7 +19,7 @@
#include <database/user.hpp>
#include <network/command_handler.hpp>
#include <network/transfer_sender.hpp>
class Server;
......@@ -45,7 +45,26 @@ public:
static unsigned long int clients_number;
virtual void on_connection_closed();
/**
* Sends a file to the remote client.
* @param filename The file to send.
*/
void send_file(const std::string&);
/**
* To be called whenever a file transfer ends.
* Removes the TransferSender from the list.
* @param transfer The TransferSender to remove from the list.
*/
void on_transfer_ended(TransferSender*);
/**
* Called when the client is successfully authenticated.
* For example, checks if there are news to send, or offline messages, etc
*/
void on_auth_success();
User* get_user();
private:
/**
* Creates the default callbacks associated with a network command.
......@@ -55,6 +74,7 @@ private:
void install_callbacks();
void install_read_handler(void);
void auth_callback(const std::string&);
void transfer_callback(const std::string&);
const unsigned long int number;
/**
* A pointer to the server, to call its method when the RemoteClient
......@@ -62,6 +82,10 @@ private:
*/
Server* server;
User* user;
/**
* A list of all the current file transfers with tha client.
*/
std::vector<TransferSender*> senders;
};
#endif
......
#include <network/transfer_sender.hpp>
#include <network/remote_client.hpp>
unsigned long int TransferSender::current_id = 0;
TransferSender::TransferSender(RemoteClient* client, const std::string& filename):
client(client),
filename(filename),
file(filename.data()),
id(TransferSender::current_id++)
{
}
TransferSender::~TransferSender()
{
log_debug("Deleting file transfer of " << this->filename << ": " << this->id);
this->file.close();
}
bool TransferSender::start()
{
log_debug("Starting file transfer " << this->id);
if (this->file.good())
{
// get length of file:
this->file.seekg(0, std::ios::end);
this->length = this->file.tellg();
this->file.seekg(0, std::ios::beg);
std::ostringstream sid;
sid << this->id;
std::ostringstream slength;
slength << this->length;
std::string transfer_description(sid.str());
transfer_description += "|" + this->filename + "|" + slength.str();
this->client->request_answer("TRANSFER", transfer_description.data());
return true;
}
log_warning("Could not open file to send: " << this->filename);
return false;
}
void TransferSender::send_next_chunk()
{
char data[4096+1];
this->file.read(data, 4096);
std::streamsize read_size = this->file.gcount();
log_debug("Read from file: " << read_size);
data[read_size] = 0;
std::ostringstream sid;
sid << this->id;
std::ostringstream ssize;
ssize << read_size;
std::string msg = "TRANSFER_" + std::string(sid.str());
msg += std::string(".") + std::string(ssize.str()) + std::string(":") + std::string(data);
if (read_size)
// this was not the last chunk, so we'll send an other one when this one is
// successfully sent.
this->client->send(msg.data(), boost::bind(&TransferSender::send_next_chunk, this));
else
this->client->send(msg.data(), boost::bind(&RemoteClient::on_transfer_ended, this->client, this));
}
/** @addtogroup Network
* @{
*/
#include <iostream>
#include <fstream>
#include <string>
#ifndef __TRANSFER_SENDER_HPP__
# define __TRANSFER_SENDER_HPP__
#include <logging/logging.hpp>
class RemoteClient;
class TransferSender
{
public:
static unsigned long int current_id;
TransferSender(RemoteClient*, const std::string&);
~TransferSender();
/**
* Try to start the file transfer, returns true if there was
* no error opening the file and reading, false otherwise (in
* that case this object should immediately be deleted by the RemoteClient
* object.
*/
bool start();
void send_next_chunk();
private:
TransferSender(const TransferSender&);
TransferSender& operator=(const TransferSender&);
const std::string filename;
RemoteClient* client;
std::ifstream file;
int length;
unsigned long int id;
};
#endif // __TRANSFER_SENDER_HPP__
/**@}*/
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment