Files
pip/utils/udp_file_transfer/main.cpp
peri4 1c7fc39b6c version 4.0.0_alpha
in almost all methods removed timeouts in milliseconds, replaced to PISystemTime
PITimer rewrite, remove internal impl, now only thread implementation, API similar to PIThread
PITimer API no longer pass void*
PIPeer, PIConnection improved stability on reinit and exit
PISystemTime new methods
pisd now exit without hanging
2024-07-30 14:18:02 +03:00

248 lines
7.5 KiB
C++

/*
PIP - Platform Independent Primitives
UDP file transfer (send /receive files) utility
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/>.
*/
#include "picli.h"
#include "pidatatransfer.h"
#include "piethernet.h"
#include "pifiletransfer.h"
#include "piliterals_time.h"
#include "piscreen.h"
#include "piscreentiles.h"
TileSimple pmt;
using namespace PICoutManipulators;
class UDPFileTransfer: public PITimer {
PIOBJECT_SUBCLASS(UDPFileTransfer, PITimer)
public:
UDPFileTransfer(const PIString & src_ip_port, const PIString & dst_ip_port, bool test = false) {
quet_ = false;
test_ = test;
eth.setReadAddress(src_ip_port);
eth.setSendAddress(dst_ip_port);
if (test_) {
testt.setCRCEnabled(false);
testt.setName("TEST");
CONNECT1(void, PIByteArray &, &testt, sendRequest, this, ftsend);
} else {
ft.setPacketSize(65000);
ft.setName("PIFT");
CONNECT1(void, PIByteArray &, &ft, sendRequest, this, ftsend);
CONNECTU(&ft, sendFilesStarted, this, ftevent);
CONNECTU(&ft, receiveFilesStarted, this, ftevent);
CONNECTU(&ft, sendFilesFinished, this, ftevent);
CONNECTU(&ft, receiveFilesFinished, this, ftevent);
}
CONNECT2(void, const uchar *, ssize_t, &eth, threadedReadEvent, this, received);
start(20_Hz);
eth.setParameter(PIEthernet::SeparateSockets);
eth.startThreadedRead();
}
void setQuet(bool quet) { quet_ = quet; }
void startSend(const PIStringList & file) { ft.send(file); }
void startTest() {
PIByteArray ba(1024 * 1024 * 8);
testt.send(ba);
}
PIFileTransfer ft;
PIDataTransfer testt;
bool test_;
private:
PIEthernet eth;
bool quet_;
void tick(int) override {
if (ft.isStarted()) {
ftevent();
updatePMT();
if (PIKbdListener::exiting) {
ft.stopSend();
ft.stopReceive();
}
}
if (testt.isSending() || testt.isReceiving()) {
ftevent();
updatePMT();
}
}
EVENT_HANDLER(void, ftevent) {
if (test_) {
#ifdef WINDOWS
piCout
#else
PICout(AddSpaces) << ClearLine
#endif
<< testt.stateString() << testt.diagnostic().receiveSpeed() << testt.diagnostic().sendSpeed() << "("
<< PIString::readableSize(testt.bytesCur()) << "/" << PIString::readableSize(testt.bytesAll()) << ")"
#ifndef WINDOWS
<< Flush
#endif
;
return;
}
if (quet_) return;
#ifdef WINDOWS
piCout
#else
PICout(AddSpaces)
<< ClearLine
#endif
<< ft.stateString() << ft.curFile() << ft.diagnostic().receiveSpeed() << ft.diagnostic().sendSpeed() << "("
<< PIString::readableSize(ft.bytesFileCur()) << "/" << PIString::readableSize(ft.bytesFileAll()) << ", "
<< PIString::readableSize(ft.bytesCur()) << "/" << PIString::readableSize(ft.bytesAll()) << ")"
<< "ETA"
<< (ft.diagnostic().state().received_bytes_per_sec > 0
? PIString::fromNumber(
PISystemTime::fromSeconds((ft.bytesAll() - ft.bytesCur()) / ft.diagnostic().state().received_bytes_per_sec)
.toSeconds())
: PIString("unknown"))
#ifndef WINDOWS
<< Flush
#endif
;
}
EVENT_HANDLER1(void, ftsend, PIByteArray &, data) { eth.send(data); }
EVENT_HANDLER2(void, received, const uchar *, readed, ssize_t, size) {
PIByteArray ba(readed, size);
if (test_) {
testt.received(ba);
return;
}
ft.received(ba);
}
void updatePMT() {
PIString pm;
if (test_)
pm = testt.packetMap();
else
pm = ft.packetMap();
int wd = 110;
pmt.content.resize(pm.size() / wd + 1);
for (int i = 0; i < pmt.content.size_s(); i++) {
pmt.content[i].first = pm.mid(wd * i, piMini(pm.size() - i * wd, wd));
}
}
};
void usage() {
piCout << Bold << "PIP UDP file transfer";
piCout << Cyan << "Version" << Bold << PIPVersion() << NewLine;
piCout << Green << Bold << "Usage:" << Default
<< "\"pift [-hqf] -r <receive_ip> -s <send_ip> [-d <work_dir>] [-p <port>] [<path1>] [<path2>] [<path3>] [...]\"" << NewLine;
piCout << Green << Bold << "Details:";
piCout << "-f --fullpath " << Green << "- full path in <receive_ip> and <send_ip>";
piCout << "-h --help " << Green << "- display this message and exit";
piCout << "-q --quet " << Green << "- quiet, no debug output to console";
piCout << "-r --receive <receive_ip> " << Green << "- set receive ip address, must be ip address of this computer";
piCout << "-s --send <send_ip> " << Green << "- set send ip address, address of computer which communicate with you";
piCout << "-p --port <port> " << Green << "- UDP port for transfer, by default 50005";
piCout << "-d --dir <work_dir> " << Green << "- directory, where place received files";
piCout << "<path> " << Green << "- add path to send, if no path, then \"pift\" working in receive mode";
piCout << "-t --test " << Green << "- test mode";
}
int main(int argc, char * argv[]) {
PICLI cli(argc, argv);
cli.setOptionalArgumentsCount(-1);
cli.addArgument("send", true);
cli.addArgument("receive", true);
cli.addArgument("dir", true);
cli.addArgument("port", true);
cli.addArgument("help");
cli.addArgument("quet");
cli.addArgument("fullpath");
cli.addArgument("test", true);
if (cli.hasArgument("test")) {
PIString src;
PIString dst;
bool send_ = false;
if (cli.argumentValue("test") == "1") {
src = "127.0.0.1:50005";
dst = "127.0.0.1:50006";
send_ = true;
} else {
src = "127.0.0.1:50006";
dst = "127.0.0.1:50005";
}
if (cli.hasArgument("send") && cli.hasArgument("receive") && cli.hasArgument("fullpath")) {
src = cli.argumentValue("receive");
dst = cli.argumentValue("send");
}
PIScreen screen(false);
screen.enableExitCapture();
screen.rootTile()->addTile(new TilePICout());
screen.rootTile()->addTile(&pmt);
UDPFileTransfer tuf(src, dst, true);
screen.start();
if (send_) tuf.startTest();
screen.waitForFinish();
return 0;
}
if ((!cli.hasArgument("send") || !cli.hasArgument("receive")) || cli.hasArgument("help")) {
usage();
return 0;
}
PIString src = cli.argumentValue("receive");
PIString dst = cli.argumentValue("send");
int port = -1;
if (cli.hasArgument("port")) port = cli.argumentValue("port").toInt();
if (port <= 0) port = 50005;
if (!cli.hasArgument("fullpath")) {
src += ":" + PIString::fromNumber(port);
dst += ":" + PIString::fromNumber(port);
}
PIScreen screen(false);
screen.enableExitCapture();
screen.rootTile()->addTile(new TilePICout());
screen.rootTile()->addTile(&pmt);
screen.start();
UDPFileTransfer f(src, dst);
if (cli.hasArgument("dir")) f.ft.setDirectory(cli.argumentValue("dir"));
if (cli.hasArgument("quet")) f.setQuet(true);
piCout << "work directory" << f.ft.directory().absolutePath() << ", listen on" << src << ", send to" << dst;
PIStringList fls = cli.optionalArguments();
if (fls.size() > 0) {
piCout << "send files" << fls;
f.startSend(fls);
PICout(PICoutManipulators::AddNone) << "\n";
return 0;
} else {
piCout << "wait for receiving";
}
PICout(PICoutManipulators::AddNone) << "\n";
screen.waitForFinish();
return 0;
}