//! \~\file pifiletransfer.h
//! \~\ingroup IO-Utils
//! \~\brief
//! \~english Class for sending and receiving files and directories via \a PIBaseTransfer
//! \~russian Класс для отправки и приема файлов и папок с помощью \a PIBaseTransfer
//! \~\details
//! \~english PIFileTransfer provides functionality for transferring files and directories over a network using PIBaseTransfer protocol
//! \~russian PIFileTransfer предоставляет функциональность для передачи файлов и папок по сети с использованием протокола PIBaseTransfer
/*
PIP - Platform Independent Primitives
Class for send and receive files and directories via PIBaseTransfer
Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
#ifndef PIFILETRANSFER_H
#define PIFILETRANSFER_H
#include "pibasetransfer.h"
#include "pidir.h"
#define __PIFILETRANSFER_VERSION 2
//! \~\ingroup IO-Utils
//! \~\brief
//! \~english Class for sending and receiving files and directories via \a PIBaseTransfer
//! \~russian Класс для отправки и приема файлов и папок с помощью \a PIBaseTransfer
class PIP_EXPORT PIFileTransfer: public PIBaseTransfer {
PIOBJECT_SUBCLASS(PIFileTransfer, PIBaseTransfer);
public:
//! \~english Constructs empty file transfer
//! \~russian Создает пустой transfer файлов
PIFileTransfer();
//! \~english Destructor
//! \~russian Деструктор
~PIFileTransfer();
//! \~english Stage of the file-transfer protocol.
//! \~russian Этап протокола передачи файлов.
enum StepType {
pft_None /** \~english No active stage \~russian Активный этап отсутствует */,
pft_Description /** \~english Exchange file list and metadata \~russian Обмен списком файлов и метаданными */,
pft_Data /** \~english Exchange file data blocks \~russian Обмен блоками данных файлов */
};
//! \~english File-system entry description extended with destination relative path.
//! \~russian Описание элемента файловой системы, расширенное относительным путем назначения.
struct PIP_EXPORT PFTFileInfo: public PIFile::FileInfo {
//! \~english Constructs transferable file info from base \a PIFile::FileInfo.
//! \~russian Создает передаваемое описание файла из базового \a PIFile::FileInfo.
PFTFileInfo(const PIFile::FileInfo & fi = PIFile::FileInfo()): PIFile::FileInfo(fi) {}
//! \~english Relative destination path on the receiver side.
//! \~russian Относительный путь назначения на стороне приемника.
PIString dest_path;
};
#pragma pack(push, 1)
//! \~english Custom packet header used by the file-transfer protocol.
//! \~russian Пользовательский заголовок пакета, используемый протоколом передачи файлов.
struct PIP_EXPORT PFTHeader {
union {
struct {
//! \~english Three-byte protocol signature "PFT".
//! \~russian Трехбайтовая сигнатура протокола "PFT".
char sig[3]; // PFT
//! \~english Protocol version stored in the packet.
//! \~russian Версия протокола, сохраненная в пакете.
uchar version;
};
//! \~english Raw 32-bit representation of signature and version.
//! \~russian Сырое 32-битное представление сигнатуры и версии.
uint raw_sig;
};
//! \~english Current transfer step from \a StepType.
//! \~russian Текущий этап передачи из \a StepType.
int step;
//! \~english File-transfer session identifier.
//! \~russian Идентификатор сессии передачи файлов.
int session_id;
//! \~english Check if signature is valid
//! \~russian Проверка валидности сигнатуры
bool check_sig() {
if (sig[0] != sign[0] || sig[1] != sign[1] || sig[2] != sign[2] || version != __PIFILETRANSFER_VERSION) return false;
return true;
}
};
#pragma pack(pop)
//! \~english Sends one file-system entry identified by "file".
//! \~russian Отправляет один элемент файловой системы, заданный "file".
bool send(const PIFile & file);
//! \~english Sends one file or directory by path.
//! \~russian Отправляет один файл или каталог по пути.
bool send(const PIString & file);
//! \~english Sends all files or directories listed in "files".
//! \~russian Отправляет все файлы или каталоги из списка "files".
bool send(const PIStringList & files);
//! \~english Sends one file-system entry described by "entry".
//! \~russian Отправляет один элемент файловой системы, описанный "entry".
bool send(PIFile::FileInfo entry) { return send(PIVector() << entry); }
//! \~english Sends file entries from "entries", recursively expanding directories.
//! \~russian Отправляет элементы файловой системы из "entries", рекурсивно раскрывая каталоги.
bool send(PIVector entries);
//! \~english Sets destination directory used for received files.
//! \~russian Устанавливает каталог назначения для принимаемых файлов.
void setDirectory(const PIDir & d) { dir = d; }
//! \~english Sets destination directory used for received files by path.
//! \~russian Устанавливает каталог назначения для принимаемых файлов по пути.
//! \~russian Установить директорию по пути
void setDirectory(const PIString & path) { dir.setDir(path); }
//! \~english Returns destination directory used for received files.
//! \~russian Возвращает каталог назначения для принимаемых файлов.
PIDir directory() const { return dir; }
//! \~english Returns whether the overall file transfer workflow is active.
//! \~russian Возвращает, активен ли общий процесс передачи файлов.
bool isStarted() const { return started_; }
//! \~english Returns current file path or scanning status string.
//! \~russian Возвращает путь текущего файла или строку состояния сканирования.
PIString curFile() const;
//! \~english Returns total size of the current file being processed.
//! \~russian Возвращает общий размер текущего обрабатываемого файла.
llong bytesFileAll() const { return bytes_file_all; }
//! \~english Returns processed size of the current file being processed.
//! \~russian Возвращает уже обработанный объем текущего файла.
llong bytesFileCur() const { return bytes_file_cur; }
//! \~english Get pointer to current file name
//! \~russian Получить указатель на имя текущего файла
const PIString * curFile_ptr() const { return &cur_file_string; }
//! \~english Get pointer to total bytes of current file
//! \~russian Получить указатель на общее количество байт текущего файла
const llong * bytesFileAll_ptr() const { return &bytes_file_all; }
//! \~english Get pointer to current bytes of current file
//! \~russian Получить указатель на текущие байты текущего файла
const llong * bytesFileCur_ptr() const { return &bytes_file_cur; }
//! \events
//! \{
//! \~\fn void receiveFilesStarted()
//! \~english Emitted when a new incoming file-transfer workflow starts.
//! \~russian Генерируется при запуске нового входящего процесса передачи файлов.
EVENT(receiveFilesStarted);
//! \~\fn void receiveFilesFinished(bool ok)
//! \~english Emitted when receiving files finishes with result "ok".
//! \~russian Генерируется, когда прием файлов завершается с результатом "ok".
EVENT1(receiveFilesFinished, bool, ok);
//! \~\fn void sendFilesStarted()
//! \~english Emitted when preparing and sending files starts.
//! \~russian Генерируется при начале подготовки и отправки файлов.
EVENT(sendFilesStarted);
//! \~\fn void sendFilesFinished(bool ok)
//! \~english Emitted when sending files finishes with result "ok".
//! \~russian Генерируется, когда отправка файлов завершается с результатом "ok".
EVENT1(sendFilesFinished, bool, ok);
//! \~\fn void receiveFilesRequest(PIStringList files, llong total_bytes, bool * ok)
//! \~english Emitted after the description phase so user code can accept or reject the incoming file set.
//! \~russian Генерируется после фазы описания, чтобы пользовательский код мог принять или отклонить входящий набор файлов.
EVENT3(receiveFilesRequest, PIStringList, files, llong, total_bytes, bool *, ok);
//! \}
private:
static const char sign[];
PIVector files_;
PIString cur_file_string;
llong bytes_file_all, bytes_file_cur;
PFTHeader pftheader;
PIDir dir;
PIFile work_file;
PIByteArray desc;
PIDir scan_dir;
bool started_, scanning;
PIMutex step_mutex;
bool sendFiles(const PIVector & files);
void processFile(int id, ullong start, PIByteArray & data);
void receivePart(Part fi, PIByteArray ba, PIByteArray pheader) override;
PIByteArray buildPacket(Part fi) override;
PIByteArray customHeader() override;
void beginReceive() override;
EVENT_HANDLER1(void, send_finished, bool, ok);
EVENT_HANDLER1(void, receive_finished, bool, ok);
};
//! \~english Binary stream write operator for PFTHeader
//! \~russian Оператор записи в бинарный поток для PFTHeader
BINARY_STREAM_WRITE(PIFileTransfer::PFTHeader) {
s << v.raw_sig << v.step << v.session_id;
return s;
}
//! \~english Binary stream read operator for PFTHeader
//! \~russian Оператор чтения из бинарного потока для PFTHeader
BINARY_STREAM_READ(PIFileTransfer::PFTHeader) {
s >> v.raw_sig >> v.step >> v.session_id;
return s;
}
//! \~english Binary stream write operator for PFTFileInfo
//! \~russian Оператор записи в бинарный поток для PFTFileInfo
BINARY_STREAM_WRITE(PIFileTransfer::PFTFileInfo) {
s << v.dest_path << v.size << v.time_access << v.time_modification << v.flags << v.id_user << v.id_group << v.perm_user.raw
<< v.perm_group.raw << v.perm_other.raw;
return s;
}
//! \~english Binary stream read operator for PFTFileInfo
//! \~russian Оператор чтения из бинарного потока для PFTFileInfo
BINARY_STREAM_READ(PIFileTransfer::PFTFileInfo) {
s >> v.dest_path >> v.size >> v.time_access >> v.time_modification >> v.flags >> v.id_user >> v.id_group >> v.perm_user.raw >>
v.perm_group.raw >> v.perm_other.raw;
return s;
}
//! \~\relatesalso PICout
//! \~english Output \a PICout operator for PFTFileInfo
//! \~russian Оператор вывода в \a PICout для PFTFileInfo
inline PICout operator<<(PICout s, const PIFileTransfer::PFTFileInfo & v) {
s.saveAndSetControls(0);
s << "FileInfo(\"" << v.dest_path << "\", " << PIString::readableSize(v.size) << ", " << v.perm_user.toString() << " "
<< v.perm_group.toString() << " " << v.perm_other.toString() << ", " << v.time_access.toString() << ", "
<< v.time_modification.toString() << ", 0x" << PICoutManipulators::Hex << v.flags << ")";
s.restoreControls();
return s;
}
#endif // PIFILETRANSFER_H