- Time-constrained blocking, and non blocking operation modes. - Multithreaded file transfers, using worker threads. - IPv6 connections and NATs, as specified in RFC 2428. - Ftp over TLS/SSL (FTPS), as specified in RFC 2228. - Feature negotiation mechanism as specifien in RFC 2389. - Parsing of UNIX and DOS style directory listings. - Extending the existing functionality of Ftp class. - Transfer restart/resume mechanism, as specified in RFC 3959. - UTF-8 encoded path names.
- FtpGet: Demonstrates a basic FTP file download in blocking mode. - FtpGetNB: Demonstrates a basic FTP file download in non-blocking mode. - FtpGetMT: Demonstrates a basic Ftp file download, using worker threads. - FtpMultiGetMT: Demonstrates FTP dir listing and concurrent file transfers, using worker threads. - FtpGUI: Demonstrates a basic FTP browser with GUI (with upload, download, mkdir, rename, delete commands). - FtpOverTLS: Demonstrates the secure connection capability of FTP package in blocking mode. - FtpQueryFeatures: Demonstrates the feature query mechanism, as defined in RFC 2389 - FtpRawCommand: Demonstrates FTP raw command execution in blocking mode.
int FtpGet(const String& path, Stream& out, const String& host, int port = 21, const String& user = Null, const String& pass = Null, Gate2<int64, int64> progress = false, Callback whenwait = CNULL, int type = Ftp::BINARY, int mode = Ftp::PASSIVE); int FtpPut(Stream& in, const String& path, const String& host, int port = 21, const String& user = Null, const String& pass = Null, Gate2<int64, int64> progress = false, Callback whenwait = CNULL, int type = Ftp::BINARY, int mode = Ftp::PASSIVE);
int FtpAsyncGet(const String& remote_file, const String& local_file, const String& host, int port = 21, const String& user = Null, const String& pass = Null, Event<int, int, String, int64, int64> progress = CNULL, bool active = false, bool ssl = false, bool ascii = false); int FtpAsyncPut(const String& local_file, const String& remote_file, const String& host, int port = 21, const String& user = Null, const String& pass = Null, Event<int, int, String, int64, int64> progress = CNULL, bool active = false, bool ssl = false, bool ascii = false);
ftp.uni-erlangen.de, User: Anonymous, Password: Anonymous. test.rebex.net, User: demo, Password: password. Allows FTPS demo.wftpserver.com, User: demo-user, Password: demo-user. Allows FTPS and temporary uploads.
int FtpAsyncGet(const String& remote_file, const String& local_file, const String& host, int port = 21, const String& user = Null, const String& pass = Null, Event<int, int, String, int64, int64> progress = CNULL, bool active = false, bool ssl = false, bool ascii = false);
FtpAsyncGet("remote.txt", "local.txt", "locaclhost, 21, Null, Null, CNull, false, false, true);
int FtpAsyncGet(const FtpAssyncRequestConfig& config); FtpAsyncGet(FtpAssyncRequestConfig("remote.txt", "local.txt", "locaclhost.txt").EnableAscii()); class FtpAssyncRequestConfig final { public: FtpAssyncRequestConfig(const String& remote_file, const String& local_file, const String& host) : // initialization ... {} // Get, Set, Enable interface... private: // private members };
You could replace NAMESPACE_UPP with namespace Upp { and END_NAMESPACE_UPP with }. The NAMESPACE_UPP approach was deprecated since last release.
The next problem I see in the code is the ordering problem - you should put public class interface at the top then private things (Ftp and DirEntry classes). This is the general rule mentioned in following documentation topic.
We can replace following code with the object approach
FtpGet(Ftp::Request(local_file, remote_file, localhost).SSL().Passive(), progress, whenwait) FtpAsyncGet(Ftp::Request(local_file, remote_file, localhost).SSL().Active(), progress)
Ftp:: Result { public: int GetErrorCode() const; String GetErrorDesc() const; int64 GetTotal() const; int64 GetDone() const; // Async only. int GetId() const; bool IsSuccess() const; bool IsFailed() const; // Async only. bool InProgress() const; Result() {} private: // members... }; // // If we return Ftp::Result from FtpGet() if(FtpGet(...).IsSuccess()) //.... else //.... // OR Event<Ftp::Result> r; FtpAsyncGet(..., r, ...); // In somewhere else, probably in the main thread: void Foo::TransferProgress(Ftp::Result r) { // First take care of UI thread synchronization, using whatever necessary, e.g PostCallback. // then simply... if(r.InProgress()) some_ctrl.Text(r.GetTotal(), r.GetDone()); else if(r.IsSuccess()) some_ctrl.Text("Done."); else some_ctrl.Text("Failed".); }
Does it work for HTTP(S) file gets?
I need to implement a large file downloader with pause and resume...
// Single-threaded. Ftp::Result FtpGet(const Ftp::Request& request, Gate<int64, int64> progress = false, Event<> whenwait = CNULL); Ftp::Result FtpPut(const Ftp::Request& request, Gate<int64, int64> progress = false, Event<> whenwait = CNULL); // Multi-threaded. int FtpAsyncGet(Ftp::Request& request, Event<Ftp::Result> progress = CNULL); int FtpAsyncPut(Ftp::Request& request, Event<Ftp::Result> progress = CNULL);
DirEntry& User(const String& u) { vm(USER) = u; return *this; }
enum Style { UNIX, DOS }; enum class Type { UNIX, DOS }; // You could consider chaining the name to Type // The user can refere: DirEntry::Type::UNIX instead of: DirEntry::UNIX
ValueMap vm; Bits owner, group, other; friend bool ParseFtpDirEntry(const String& in, Vector<Ftp::DirEntry>& out);
const ValueMap& GetVm(); // Read only access - i believe ParseFtpDirEntry doesn't set anything?
class Ftp : private NoCopy { public: // Just remove extra empty line. class Request; class Result; // Do we need forward declarations in class? I believe when we remove friendship we will not ;) class DirEntry final : Moveable<Ftp::DirEntry> {
class Result // Interface - all methods are abstract { public: // The same as previous virtual bool IsAsync() = 0; // Mt methods are presented without #ifdef guard }; class RegularResult : public Result // The name could be different { public: bool IsAsync() override { return false; } // Mt methods returning falses, -1 etc. }; class AsyncResult : public Result { public: bool IsAsync() override { return true; } // Return correct values for MT }; One<Result> result(new AsyncResult());
Hello,
In my opinion handling multi-threading API using #ifdef in header is not good for the end user. Because, he/seh is obligated to use #ifdef in theire code. Personally, i would hide it inside the interface and use One container (Movable will not work for this class).
class Result // Interface - all methods are abstract
{
public:
// The same as previous
virtual bool IsAsync() = 0;
// Mt methods are presented without #ifdef guard
};
class RegularResult : public Result // The name could be different
{
public:
bool IsAsync() override { return false; }
// Mt methods returning falses, -1 etc.
};
class AsyncResult : public Result
{
public:
bool IsAsync() override { return true; }
// Return correct values for MT
};
One<Result> result(new AsyncResult());
What do you think?
Sincerely,
Klugier
static inline bool IsMultithreaded() { #ifdef flagMT return true; #else return false; #endif }
Ftp::Result FtpAsyncIO(Ftp::Request request, Event<Ftp::Result> progress, bool put) { // Check if U++ MT is enabled. Ftp::Result r; try { if(!IsMultithreaded()) throw Exc("Multithreading is not enabled."); // ... } catch(Exc& e) { // Couldn'r create or run the worker thread. r.info("state") = "failed"; r.info("rc") = -1; r.info("msg") = e; LLOG("-- FTP worker failed. Reason: " << e); } return r;
multithreaded functions are further improved. - Available worker slots are limited to 256 ftp worker thread per process. - It is now possible to pre-set the thread priority of each worker. - It is now possible to pass a user data (a U++ Value), using Request::UserData() and Result::GetUserData(); - Worker abort mechanism is both simplified and improved. Vector is ditched in favor of a static Bits instance. This reduces both memory consumption and mutex lock/unlock times. Since, previously we needed to iterate over the vector to check if a worker was registered to be aborted. This was time consuming. Now we simply set a bit on or off. Since the worker counter resets at 65536 and max. worker slots are limeted to 256, it should be pretty safe. See the FtpAsyncIO(), Ftp::AbortWorker() and Ftp::IsWorkerAborted() for details. (I'm open to suggestions, if you have better ideas.) - Made room for NetworkProxy support. I will add NetworkProxy support (HTTP/SOCKS4/SOCKS5) via a preprocessor directive (USEPROXY flag), since NetworkProxy package is currently not in bazaar.
- It is now possible to multiselect the files to be downloaded or uploaded. - FtpBrowser no longer asks for download location for each download. A default download location can be selected. And it can be changed via environment settings. - FtpBrowser gained file editing support. While it is still a barebone example with ability to edit only one file at a time, it will change in the near future. (Mirek had suggested this when we were discussing SSH package last year on "Developer's Corner", which is on it's way, by the way.) Of course this is far from what he suggested, but it is operational in it's current state anyway. :)
class DirEntry { // ... enum Style { UNIX, DOS }; // In my opinion "Type" world is a better alternative in this situation... enum class Type { UNIX, DOS };
if (dirType == DirEntry::Type::UNIX) { // .. do something }
if (dirType == DirEntry::UNIX) { // ... }
For me it is a great news that somebody published video related to U++. You could consider posting URL to our site in the movie description Wink
Backing to FTP - did you consider moving to enum class (c++11 feature) instead of old-c like enum. I think the whole API will gained on this change. For example:
// In my opinion "Type" world is a better alternative in this situation...
Let me ask you one question - do you have GitHub repository for that project?
MAJOR RELEASE: Ftp package, version 2.0.0 Necessary API breakage. Ftp is redesigned, using an effective, and simple queue-model similar to the SSH package's. Old multithreading code completely ditched in favor of the new AsyncWork based ftp workers. This resulted in noticable performance gain, and simplicity. Non-blocking mode is finally implemented. Ftp class can do non-blocking calls easily. FTPS mode improved. It is now possible to inspect the SSL information after handshake. Support for user-defined consumer functions (for incoming data) is added. A simple ftp URL scheme is implemented. This scheme replaces (partially) the old Ftp::Request class. UTF-8 path name encoding support is added. Optional Connect/Login() methods pair added. It is now possible to execute commands before login. Ftp::DirEntry now uses pcre to parse listing strings. Logging is improved. Reference examples are added to the package.
- FtpGet: Demonstrates a basic FTP file download in blocking mode. - FtpGetNB: Demonstrates a basic FTP file download in non-blocking mode. - FtpGetMT: Demonstrates a basic Ftp file download, using worker threads. - FtpMultiGetMT: Demonstrates FTP dir listing and concurrent file transfers, using worker threads. - FtpGUI: Demonstrates a basic FTP browser with GUI (with upload, download, mkdir, rename, delete commands). - FtpOverTLS: Demonstrates the secure connection capability of FTP package in blocking mode. - FtpQueryFeatures: Demonstrates the feature query mechanism, as defined in RFC 2389 - FtpRawCommand: Demonstrates FTP raw command execution in blocking mode.