Files
pip/libs/main/io_utils/pifiletransfer.h
2026-03-12 14:46:57 +03:00

266 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \~\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