Skip to content

Commit

Permalink
Refactor remote support
Browse files Browse the repository at this point in the history
This moves the logic into a separate file and also implements proper
caching.
  • Loading branch information
vimpostor committed Mar 25, 2024
1 parent 4c6630c commit dea22dd
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 89 deletions.
77 changes: 0 additions & 77 deletions src/Util/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
#include <unistd.h>

#ifdef Q_OS_UNIX
#include <netdb.h>
#include <pwd.h>
#include <unistd.h>
#endif

namespace Util {
Expand All @@ -34,79 +32,4 @@ std::string pwd() {
}
return result;
}

bool get_local_domain(std::string &result) {
static std::string cached_result;
if (!cached_result.empty()) {
result = cached_result;
return true;
}

#ifndef Q_OS_UNIX
return false;
#else
char host[HOST_NAME_MAX];
if (gethostname(host, HOST_NAME_MAX)) {
std::cerr << "gethostname failed" << std::endl;
return false;
}

// got the host, try to get the FQDN
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_CANONNAME;

int err = getaddrinfo(host, "http", &hints, &res);
if (err) {
std::cerr << "getaddrinfo failed: " << gai_strerror(err) << std::endl;
return false;
}

const auto fqdn = res->ai_canonname;
bool success = true;

if (!strncmp(fqdn, host, HOST_NAME_MAX)) {
std::cerr << "failed to retreive a proper FQDN for " << host << std::endl;
success = false;
} else {
result = fqdn;

// remove possible leading dot
if (result.starts_with('.')) {
result = result.substr(1);
}

cached_result = result;
}

freeaddrinfo(res);
return success;
#endif
}

std::string get_username() {
#ifdef Q_OS_UNIX
return getlogin();
#else
return {};
#endif
}

int get_port() {
const auto env = std::getenv("SSH_CONNECTION");
if (env) {
std::string ssh_connection {env};
const auto n = ssh_connection.rfind(' ');
if (n != std::string::npos) {
try {
return std::stoi(ssh_connection.substr(n + 1));
} catch (std::invalid_argument const &) {
std::cerr << "Failed to parse port number " << ssh_connection << std::endl;
}
}
}
return -1;
}
}
3 changes: 0 additions & 3 deletions src/Util/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,4 @@ namespace Util {

const char *home_dir();
std::string pwd();
bool get_local_domain(std::string &result);
std::string get_username();
int get_port();
}
11 changes: 2 additions & 9 deletions src/path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "Util/util.hpp"
#include "mimedb.hpp"
#include "remote.hpp"
#include "settings.hpp"

Path::Path(const std::string &p)
Expand All @@ -30,15 +31,7 @@ QUrl Path::get_url() const {
auto res = QUrl::fromLocalFile(QString::fromStdString(path.string()));

if (Settings::get()->remote) {
std::string host;
if (Util::get_local_domain(host)) {
res.setScheme("sftp");
res.setUserName(QString::fromStdString(Util::get_username()));
res.setHost(QString::fromStdString(host));
res.setPort(Util::get_port());
} else {
std::cerr << "Failed deducing remote prefix" << std::endl;
}
std::ignore = Remote::get()->rewire_url(res);
}

return res;
Expand Down
111 changes: 111 additions & 0 deletions src/remote.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#include "remote.hpp"

#include <iostream>

#ifdef Q_OS_UNIX
#include <netdb.h>
#include <unistd.h>
#endif

bool Remote::rewire_url(QUrl &url) {
if (!init_done) {
init();
}
if (!ok) {
return false;
}

url.setScheme("sftp");
url.setUserName(username);
url.setHost(host);
url.setPort(port);

return true;
}

void Remote::init() {
init_done = true;

username = get_username();
if (username.isEmpty()) {
std::cerr << "Could not read username" << std::endl;
return;
}

host = get_local_domain();
if (host.isEmpty()) {
std::cerr << "Could not read host" << std::endl;
return;
}

// not a big deal if this fails, usually it still works without an explicit port
port = get_port();

ok = true;
}

QString Remote::get_local_domain() {
#ifndef Q_OS_UNIX
return {};
#else
char host[HOST_NAME_MAX];
if (gethostname(host, HOST_NAME_MAX)) {
std::cerr << "gethostname failed" << std::endl;
return {};
}

// got the host, try to get the FQDN
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_CANONNAME;

int err = getaddrinfo(host, "http", &hints, &res);
if (err) {
std::cerr << "getaddrinfo failed: " << gai_strerror(err) << std::endl;
return {};
}

const auto fqdn = res->ai_canonname;
std::string result;

if (!strncmp(fqdn, host, HOST_NAME_MAX)) {
std::cerr << "failed to retreive a proper FQDN for " << host << std::endl;
} else {
result = fqdn;

// remove possible leading dot
if (result.starts_with('.')) {
result = result.substr(1);
}
}

freeaddrinfo(res);
return QString::fromStdString(result);
#endif
}

QString Remote::get_username() {
#ifdef Q_OS_UNIX
return getlogin();
#else
return {};
#endif
}

int Remote::get_port() {
const auto env = std::getenv("SSH_CONNECTION");
if (env) {
std::string ssh_connection {env};
const auto n = ssh_connection.rfind(' ');
if (n != std::string::npos) {
try {
return std::stoi(ssh_connection.substr(n + 1));
} catch (std::invalid_argument const &) {
std::cerr << "Failed to parse port number " << ssh_connection << std::endl;
}
}
}
return -1;
}
23 changes: 23 additions & 0 deletions src/remote.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include <QUrl>

#include "Util/util.hpp"

class Remote {
public:
SINGLETON(Remote)
bool rewire_url(QUrl &url);
private:
void init();
QString get_local_domain();
QString get_username();
int get_port();

bool init_done = false;
bool ok = false;

QString username;
QString host;
int port = -1;
};

0 comments on commit dea22dd

Please sign in to comment.