1c7fc39b6c
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
248 lines
7.5 KiB
C++
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, ð, 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;
|
|
}
|