peerplays-fc/include/fc/ssh/client.hpp
2013-03-01 18:56:06 -05:00

163 lines
5.4 KiB
C++

#pragma once
#include <fc/ssh/process.hpp>
#include <functional>
#include <fc/filesystem.hpp>
namespace fc {
class path;
class logger;
namespace ssh {
namespace detail {
class client_impl;
class process_impl;
};
enum sftp_file_type {
named_pipe = 0010000,
directory = 0040000,
regular = 0100000,
symlink = 0120000
};
enum sftp_file_mode {
owner_mask = 0000700, /* RWX mask for owner */
owner_read = 0000400, /* R for owner */
owner_write = 0000200, /* W for owner */
owner_exec = 0000100, /* X for owner */
group_mask = 0000070, /* RWX mask for group */
group_read = 0000040, /* R for group */
group_write = 0000020, /* W for group */
group_exec = 0000010, /* X for group */
other_mask = 0000007, /* RWX mask for other */
other_read = 0000004, /* R for other */
other_write = 0000002, /* W for other */
other_exec = 0000001 /* X for other */
};
struct file_attrib {
file_attrib();
uint64_t size;
uint32_t uid;
uint32_t gid;
uint32_t permissions;
uint32_t atime;
uint32_t mtime;
bool exists();
bool is_file();
bool is_directory();
};
/**
* @brief Enables communication over ssh using libssh2.
*
* Because the client creates other resources that depend upon
* it, it can only be created as a std::shared_ptr<client> (aka client::ptr)
* via client::create();
*
*/
class client {
public:
enum trace_level {
TRACE_NONE = 0,
TRACE_TRANS = (1<<1),
TRACE_KEX = (1<<2),
TRACE_AUTH = (1<<3),
TRACE_CONN = (1<<4),
TRACE_SCP = (1<<5),
TRACE_SFTP = (1<<6),
TRACE_ERROR = (1<<7),
TRACE_PUBLICKEY = (1<<8),
TRACE_SOCKET = (1<<9)
};
/**
* Everything but TRACE_ERROR will be logged at fc::log_level::debug, while
* TRACE_ERROR will be logged at fc::log_level::error
*
* @param bitmask comprised of values from trace_level
**/
void set_trace_level( int bitmask );
int get_trace_level()const;
/**
* Override the default logger used by fc::ssh::client
*/
void set_logger( const logger& lgr );
const logger& get_logger()const;
void connect( const fc::string& user, const fc::string& host, uint16_t port = 22);
/**
* Connect via password or keyboard-interactive
*/
void connect( const fc::string& user, const fc::string& pass, const fc::string& host, uint16_t port = 22);
/**
* @brief execute command on remote machine
* @param pty_type - whether or not to request a PTY when executing this process, this is necessary
* for interactive (non-buffered) IO with the remote process, if left empty no pty will be
* requested
*
* @note Processes launched in this manner will fully buffer stdin and stdout regardless of whether
* the process calls flush(). If you need unbuffered (streaming, realtime) access to standard
* out then you must launch the process via a shell.
*/
ssh::process exec( const fc::string& cmd, const fc::string& pty_type = "" );
/**
* @brief upload a file to remote host
* @param progress a callback to report / cancel upload.
* The callback takes two parameters, bytes sent and file size. To continue the
* transfer, the callback should return true. To cancel the callback should return false.
*/
void scp_send( const fc::path& local_path, const fc::path& remote_path,
std::function<bool(size_t,size_t)> progress = [](size_t,size_t){return true;} );
/**
* @brief recursively sends the contents of local_dir to the remote_path
*
* If remote_path ends in '/' then a new directory at <code>remote_path/local_dir.filename()</code> will
* be created, otherwise <code>local_dir / *</code> will be copied to <code>remote_path / *</code>
*
* Progress will be reported as total bytes transferred for all files.
*/
void scp_send_dir( const fc::path& local_dir, const fc::path& remote_path,
std::function<bool(size_t,size_t)> progress = [](size_t,size_t){return true;} );
/**
* @pre remote_path is not a directory
* @post remote file is removed from the remote filesystem
*/
void rm( const fc::path& remote_path );
file_attrib stat( const fc::path& remote_path );
/**
* @pre all parent directories already exist.
* @pre remote_dir is not exist or is already a directory
* @post remote_dir exists.
*/
void mkdir( const fc::path& remote_dir, int mode = owner_read|owner_write|owner_exec );
/**
* Create all parent directories for remote_dir if they do not exist.
*
* @post remote_dir exists.
*/
void create_directories( const fc::path& remote_dir, int mode = owner_read|owner_write|owner_exec );
void close();
client();
~client();
private:
friend class process;
friend class detail::process_impl;
fc::shared_ptr<detail::client_impl> my;
};
} } // namespace fc::ssh