add support for github repos

This commit is contained in:
Chee Yee
2025-02-28 15:44:17 -08:00
parent 467a459665
commit 8602a5353e
7 changed files with 283 additions and 2 deletions
+2 -1
View File
@@ -28,6 +28,7 @@ add_executable(ezremote_client
source/clients/archiveorg.cpp
source/clients/ftpclient.cpp
source/clients/gdrive.cpp
source/clients/github.cpp
source/clients/myrient.cpp
source/clients/iis.cpp
source/clients/nginx.cpp
@@ -69,7 +70,7 @@ add_executable(ezremote_client
add_self(ezremote_client)
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.34" 32 0)
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.35" 32 0)
target_link_libraries(ezremote_client
c
+3
View File
@@ -12,6 +12,7 @@
#include "clients/webdav.h"
#include "clients/apache.h"
#include "clients/archiveorg.h"
#include "clients/github.h"
#include "clients/myrient.h"
#include "clients/nginx.h"
#include "clients/npxserve.h"
@@ -1314,6 +1315,8 @@ namespace Actions
remoteclient = new ArchiveOrgClient();
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_MYRIENT) == 0)
remoteclient = new MyrientClient();
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_GITHUB) == 0)
remoteclient = new GithubClient();
}
else if (strncmp(remote_settings->server, "webdavs://", 10) == 0 || strncmp(remote_settings->server, "webdav://", 9) == 0)
{
+228
View File
@@ -0,0 +1,228 @@
#include <json-c/json.h>
#include <fstream>
#include <algorithm>
#include "common.h"
#include "clients/remote_client.h"
#include "clients/github.h"
#include "lang.h"
#include "util.h"
#include "windows.h"
using httplib::Client;
using httplib::Headers;
using httplib::Result;
int GithubClient::Connect(const std::string &url, const std::string &username, const std::string &password)
{
if (url.find("https://github.com") == std::string::npos)
return 0;
this->host_url = "https://api.github.com";
this->base_path = "/repos" + url.substr(18);
Util::Rtrim(this->base_path, "/");
this->base_path += "/releases";
client = new httplib::Client(this->host_url);
if (username.length() > 0)
client->set_basic_auth(username, password);
client->set_follow_location(true);
client->set_connection_timeout(10);
client->set_read_timeout(30);
client->enable_server_certificate_verification(false);
m_client.Connect("https://github.com", username, password);
if (Ping())
this->connected = true;
return 1;
}
std::vector<DirEntry> GithubClient::ListDir(const std::string &path)
{
std::vector<DirEntry> out;
DirEntry entry;
Util::SetupPreviousFolder(path, &entry);
out.push_back(entry);
if (!releases_parsed)
{
if (auto res = client->Get(this->base_path + "?per_page=100&page=1"))
{
if (HTTP_SUCCESS(res->status))
{
json_object *jobj = json_tokener_parse(res->body.c_str());
struct array_list *areleases = json_object_get_array(jobj);
for (size_t release_idx = 0; release_idx < areleases->length; ++release_idx)
{
GitRelease release_entry;
json_object *release = (json_object *)array_list_get_idx(areleases, release_idx);
release_entry.name = std::string(json_object_get_string(json_object_object_get(release, "tag_name")));
std::string date_time = std::string(json_object_get_string(json_object_object_get(release, "published_at")));
auto date_time_array = Util::Split(date_time, "T");
auto date_array = Util::Split(date_time_array[0], "-");
auto time_array = Util::Split(date_time_array[1], ":");
release_entry.modified.year = std::atoi(date_array[0].c_str());
release_entry.modified.month = std::atoi(date_array[1].c_str());
release_entry.modified.day = std::atoi(date_array[2].c_str());
release_entry.modified.hours = std::atoi(time_array[0].c_str());
release_entry.modified.minutes = std::atoi(time_array[1].c_str());
release_entry.modified.seconds = std::atoi(time_array[2].substr(0,2).c_str());
json_object *obj_assets = json_object_object_get(release, "assets");
if (json_object_get_type(obj_assets) == json_type_array)
{
struct array_list *aassets = json_object_get_array(obj_assets);
std::map<std::string, GitAsset> assets;
for (size_t asset_idx = 0; asset_idx < aassets->length; ++asset_idx)
{
GitAsset asset_entry;
json_object *asset = (json_object *)array_list_get_idx(aassets, asset_idx);
asset_entry.name = std::string(json_object_get_string(json_object_object_get(asset, "name")));
asset_entry.size = json_object_get_uint64(json_object_object_get(asset, "size"));
std::string date_time = std::string(json_object_get_string(json_object_object_get(asset, "updated_at")));
asset_entry.url = std::string(json_object_get_string(json_object_object_get(asset, "browser_download_url")));
Util::ReplaceAll(asset_entry.url, "https://github.com", "");
auto date_time_array = Util::Split(date_time, "T");
auto date_array = Util::Split(date_time_array[0], "-");
auto time_array = Util::Split(date_time_array[1], ":");
asset_entry.modified.year = std::atoi(date_array[0].c_str());
asset_entry.modified.month = std::atoi(date_array[1].c_str());
asset_entry.modified.day = std::atoi(date_array[2].c_str());
asset_entry.modified.hours = std::atoi(time_array[0].c_str());
asset_entry.modified.minutes = std::atoi(time_array[1].c_str());
asset_entry.modified.seconds = std::atoi(time_array[2].substr(0,2).c_str());
assets.insert(std::make_pair(asset_entry.name, asset_entry));
}
m_assets.insert(std::make_pair(release_entry.name, assets));
}
m_releases.push_back(release_entry);
}
}
}
releases_parsed = true;
}
if (path.compare("/") == 0) // return releases as folders
{
for (std::vector<GitRelease>::iterator release = m_releases.begin(); release != m_releases.end();)
{
DirEntry entry;
entry.isDir = true;
entry.selectable = true;
entry.file_size = 0;
snprintf(entry.directory, 512, "%s", "/");
snprintf(entry.name, 256, "%s", release->name.c_str());
snprintf(entry.path, 768, "/%s", release->name.c_str());
snprintf(entry.display_size, 48, "%s", lang_strings[STR_FOLDER]);
entry.modified = release->modified;
out.push_back(entry);
release++;
}
}
else // return assets in the releases matching the path
{
std::string tag_name = path.substr(1);
std::map<std::string, GitAsset> assets = m_assets[tag_name];
for (std::map<std::string, GitAsset>::iterator asset = assets.begin(); asset != assets.end();)
{
DirEntry entry;
memset(&entry, 0, sizeof(DirEntry));
entry.isDir = false;
entry.selectable = true;
snprintf(entry.directory, 512, "%s", path.c_str());
snprintf(entry.name, 256, "%s", asset->second.name.c_str());
snprintf(entry.path, 768, "%s/%s", path.c_str(), asset->second.name.c_str());
entry.file_size = asset->second.size;
entry.modified = asset->second.modified;
DirEntry::SetDisplaySize(&entry);
out.push_back(entry);
asset++;
}
}
return out;
}
int GithubClient::Size(const std::string &path, int64_t *size)
{
std::vector<std::string> path_parts = Util::Split(path, "/");
if (path_parts.size() != 2)
{
return 0;
}
*size = m_assets[path_parts[0]][path_parts[1]].size;
return 1;
}
int GithubClient::Head(const std::string &path, void *buffer, uint64_t len)
{
std::vector<std::string> path_parts = Util::Split(path, "/");
if (path_parts.size() != 2)
{
return 0;
}
return m_client.Head(m_assets[path_parts[0]][path_parts[1]].url, buffer, len);
}
int GithubClient::Get(const std::string &outputfile, const std::string &path, uint64_t offset)
{
std::vector<std::string> path_parts = Util::Split(path, "/");
if (path_parts.size() != 2)
{
return 0;
}
return m_client.Get(outputfile, m_assets[path_parts[0]][path_parts[1]].url, offset);
}
int GithubClient::Get(SplitFile *split_file, const std::string &path, uint64_t offset)
{
std::vector<std::string> path_parts = Util::Split(path, "/");
if (path_parts.size() != 2)
{
return 0;
}
return m_client.Get(split_file, m_assets[path_parts[0]][path_parts[1]].url, offset);
}
int GithubClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset)
{
std::vector<std::string> path_parts = Util::Split(path, "/");
if (path_parts.size() != 2)
{
return 0;
}
return m_client.GetRange(m_assets[path_parts[0]][path_parts[1]].url, buffer, size, offset);
}
int GithubClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset)
{
std::vector<std::string> path_parts = Util::Split(path, "/");
if (path_parts.size() != 2)
{
return 0;
}
return m_client.GetRange(m_assets[path_parts[0]][path_parts[1]].url, sink, size, offset);
}
+44
View File
@@ -0,0 +1,44 @@
#ifndef EZ_GITHUB_H
#define EZ_GITHUB_H
#include <string>
#include <vector>
#include "http/httplib.h"
#include "clients/remote_client.h"
#include "clients/baseclient.h"
#include "common.h"
class GithubClient : public BaseClient
{
public:
int Connect(const std::string &url, const std::string &username, const std::string &password);
std::vector<DirEntry> ListDir(const std::string &path);
int Size(const std::string &path, int64_t *size);
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
int Get(SplitFile *split_file, const std::string &path, uint64_t offset=0);
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
int Head(const std::string &path, void *buffer, uint64_t len);
private:
struct GitAsset
{
std::string name;
std::string url;
DateTime modified;
uint64_t size;
};
struct GitRelease
{
std::string name;
DateTime modified;
};
std::vector<GitRelease> m_releases;
std::map<std::string, std::map<std::string, GitAsset>> m_assets;
bool releases_parsed = false;
BaseClient m_client;
};
#endif
+1 -1
View File
@@ -162,7 +162,7 @@ namespace CONFIG
"Hungarian", "Indonesian", "Italiano", "Japanese", "Korean", "Norwegian", "Polish", "Portuguese_BR", "Russian",
"Romanian", "Ryukyuan", "Spanish", "Turkish", "Simplified Chinese", "Traditional Chinese", "Thai", "Ukrainian", "Vietnamese"};
http_servers = {HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE, HTTP_SERVER_RCLONE, HTTP_SERVER_ARCHIVEORG, HTTP_SERVER_MYRIENT};
http_servers = {HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE, HTTP_SERVER_RCLONE, HTTP_SERVER_ARCHIVEORG, HTTP_SERVER_MYRIENT, HTTP_SERVER_GITHUB};
text_file_extensions = { ".txt", ".ini", ".log", ".json", ".xml", ".html", ".xhtml", ".conf", ".config" };
image_file_extensions = { ".bmp", ".jpg", ".jpeg", ".png", ".webp" };
+1
View File
@@ -84,6 +84,7 @@
#define HTTP_SERVER_RCLONE "RClone"
#define HTTP_SERVER_ARCHIVEORG "Archive.org"
#define HTTP_SERVER_MYRIENT "Myrient"
#define HTTP_SERVER_GITHUB "Github"
#define MAX_EDIT_FILE_SIZE 32768
+4
View File
@@ -2647,6 +2647,10 @@ namespace Windows
{
sprintf(remote_settings->http_server_type, "%s", HTTP_SERVER_MYRIENT);
}
else if (strncasecmp(remote_settings->server, "https://github.com/", 19) == 0)
{
snprintf(remote_settings->http_server_type, 24, "%s", HTTP_SERVER_GITHUB);
}
}
}