266 lines
13 KiB
C++
266 lines
13 KiB
C++
//! \~\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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#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<PIFile::FileInfo>() << entry); }
|
|
|
|
//! \~english Sends file entries from "entries", recursively expanding directories.
|
|
//! \~russian Отправляет элементы файловой системы из "entries", рекурсивно раскрывая каталоги.
|
|
bool send(PIVector<PIFile::FileInfo> 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<PFTFileInfo> 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<PFTFileInfo> & 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
|