Compare commits
16 Commits
1.37
...
poc_bg_install
| Author | SHA1 | Date | |
|---|---|---|---|
| 28c046d5a5 | |||
| 99099a6b82 | |||
| c30a8ab70e | |||
| 046083ccf6 | |||
| 6d36073413 | |||
| b831dd7db4 | |||
| 3ba286a016 | |||
| 7395056a75 | |||
| 81a5143f2f | |||
| 432c0020be | |||
| fd1b9e5d96 | |||
| a3741a0a6c | |||
| ce71f5af9a | |||
| cd42afcb6b | |||
| b6eaef82fd | |||
| 9d0790fccc |
@@ -11,3 +11,4 @@ CTestTestfile.cmake
|
||||
_deps
|
||||
.vscode
|
||||
build
|
||||
data/daemon
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[submodule "ps4-ezremote-server"]
|
||||
path = ps4-ezremote-server
|
||||
url = git@github.com:cy33hc/ps4-ezremote-server.git
|
||||
+12
-5
@@ -68,11 +68,8 @@ add_executable(ezremote_client
|
||||
source/mem_file.cpp
|
||||
)
|
||||
|
||||
add_self(ezremote_client)
|
||||
|
||||
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.37" 32 0)
|
||||
|
||||
target_link_libraries(ezremote_client
|
||||
dbglogger
|
||||
c
|
||||
c++
|
||||
png
|
||||
@@ -110,9 +107,19 @@ target_link_libraries(ezremote_client
|
||||
SceUserService
|
||||
ScePad
|
||||
SceAudioOut
|
||||
SceSysUtil
|
||||
SceImeDialog
|
||||
SceNet
|
||||
SceBgft
|
||||
SceAppInstUtil
|
||||
SceLncUtil
|
||||
)
|
||||
|
||||
add_self(ezremote_client)
|
||||
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "02.00" 32 0)
|
||||
|
||||
add_custom_target(package
|
||||
COMMAND mkdir -p ${PROJECT_SOURCE_DIR}/data/daemon
|
||||
COMMAND cp ${PROJECT_SOURCE_DIR}/ps4-ezremote-server/data/eboot.bin ${PROJECT_SOURCE_DIR}/data/daemon/daemon.self
|
||||
COMMAND cp ${PROJECT_SOURCE_DIR}/ps4-ezremote-server/data/eboot.md5 ${PROJECT_SOURCE_DIR}/data/daemon/daemon.md5
|
||||
COMMAND cp ${PROJECT_SOURCE_DIR}/ps4-ezremote-server/data/sce_sys/param.sfo ${PROJECT_SOURCE_DIR}/data/daemon/param
|
||||
)
|
||||
@@ -2,6 +2,24 @@
|
||||
|
||||
ezRemote Client is an application that allows you to connect the PS4 to remote FTP/SFTP, SMB(Windows Share), NFS, WebDAV, HTTP servers and Google Drive to transfer files. The interface is inspired by Filezilla client which provides a commander like GUI.
|
||||
|
||||
**NEW: As of version 2.00, You can download large file in the background.**
|
||||
- You can enable/disable background download in the Global settings
|
||||
- You can set the minimum file size where background download will use. Default is 1GB
|
||||
- In Global Settings, you can show the background download progress of all requested downloads
|
||||
- Does not support rest mode. Background downloads will stop in rest mode, but will be resumed when ezRemote Server is restarted.
|
||||
- If PS4 is restarted, background downloads will resume when ezRemote Server is restarted.
|
||||
- Updated the Web UI, so you can download files of File shares like mediafire, google shared link, pixeldrain, real-debrid and all-debrid or any direct links
|
||||
|
||||
**NEW: As of version 2.00, PS4 pkgs can be installed in the background. Use ezRemote client to connect to remote server and select pkg to install. You can then close ezRemote Client app and the package will continue installing in background. This is archieved with a new payload called [ezRemote Server](https://github.com/cy33hc/ps4-ezremote-server) that is packaged together with exRemote Client. ezRemote Server runs in the background and acts as a proxy to the remote server. ezRemote Server must be started to enable backgroud installs.**
|
||||
- support background install from all remote servers that ezremote client supports
|
||||
- support background install from file host like mediafire, google shared link, pixeldrain, real-debrid and all-debrid
|
||||
- does not support background install using the options "Disk Cache" or PKGs inside zip files
|
||||
- You can pause and resume installs
|
||||
- After restarting PS4, you can resume installs by first reloading ezRemote Server
|
||||
- From testing, background install continues even in rest mode (This isn't granteed). You may need to restart ezRemote Server payload before you can resume install
|
||||
- ezRemote Server payload can be stop/restarted from ezRemote Client settngs dialog.
|
||||
- Do not submit to many background installs, it can crash ezRemote Server.
|
||||
|
||||
**New: As of version 1.19**
|
||||
- Install PKG inside Zip files from both local hdd and remote servers.
|
||||
- Extact zip files directly from remote servers.
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
installUrl: '/__local__/install',
|
||||
uploadResumeSizeUrl: '__local__/uploadResumeSize',
|
||||
installUrlUrl: '/__local__/install_url',
|
||||
downloadUrlUrl: '/__local__/download_url',
|
||||
multipleDownloadFileName: 'ezremote-client.zip',
|
||||
isExtractableFilePattern: /\.(7z|rar|zip)$/i,
|
||||
pickCallback: function (item) {
|
||||
@@ -63,4 +64,4 @@
|
||||
<angular-filemanager></angular-filemanager>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Submodule
+1
Submodule ps4-ezremote-server added at 7644256a3c
+115
-39
@@ -490,6 +490,43 @@ namespace Actions
|
||||
}
|
||||
}
|
||||
|
||||
int BackgroundDownload(const char *src, const char *dest, uint64_t file_size)
|
||||
{
|
||||
uint64_t id = Util::GetTick();
|
||||
json_object *params = json_object_new_object();
|
||||
json_object_object_add(params, "type", json_object_new_int(remote_settings->type));
|
||||
json_object_object_add(params, "url", json_object_new_string(remote_settings->server));
|
||||
json_object_object_add(params, "username", json_object_new_string(remote_settings->username));
|
||||
json_object_object_add(params, "password", json_object_new_string(remote_settings->password));
|
||||
json_object_object_add(params, "src_path", json_object_new_string(src));
|
||||
json_object_object_add(params, "dest_path", json_object_new_string(dest));
|
||||
json_object_object_add(params, "size", json_object_new_uint64(file_size));
|
||||
json_object_object_add(params, "id", json_object_new_uint64(id));
|
||||
if (remote_settings->type == CLIENT_TYPE_HTTP_SERVER)
|
||||
{
|
||||
json_object_object_add(params, "http_server_type", json_object_new_string(remote_settings->http_server_type));
|
||||
}
|
||||
|
||||
const char *params_str = json_object_to_json_string(params);
|
||||
|
||||
httplib::Client tmp_client = httplib::Client("http://127.0.0.1:" + std::to_string(http_int_server_port));
|
||||
if (auto res = tmp_client.Post("/download_url", params_str, strlen(params_str), "application/json"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
Util::Notify("%s queued for download", src);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Util::Notify("Failed to queue %s for download in background", src);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DownloadFile(const char *src, const char *dest)
|
||||
{
|
||||
bytes_transfered = 0;
|
||||
@@ -526,6 +563,10 @@ namespace Actions
|
||||
if (confirm_state == CONFIRM_YES)
|
||||
{
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
if (enable_background_download && bytes_to_download > minimum_backgrond_file_size)
|
||||
{
|
||||
return BackgroundDownload(src, dest, bytes_to_download);
|
||||
}
|
||||
return remoteclient->Get(dest, src);
|
||||
}
|
||||
|
||||
@@ -654,39 +695,6 @@ namespace Actions
|
||||
else
|
||||
files.push_back(selected_remote_file);
|
||||
|
||||
bool download_and_install = false;
|
||||
if (remote_settings->enable_rpi)
|
||||
{
|
||||
std::string url = INSTALLER::getRemoteUrl(files.begin()->path);
|
||||
sprintf(activity_message, "%s", lang_strings[STR_CHECKING_REMOTE_SERVER_MSG]);
|
||||
file_transfering = false;
|
||||
if (!INSTALLER::canInstallRemotePkg(url))
|
||||
{
|
||||
confirm_state = CONFIRM_WAIT;
|
||||
action_to_take = selected_action;
|
||||
activity_inprogess = false;
|
||||
while (confirm_state == CONFIRM_WAIT)
|
||||
{
|
||||
sceKernelUsleep(100000);
|
||||
}
|
||||
activity_inprogess = true;
|
||||
selected_action = action_to_take;
|
||||
|
||||
if (confirm_state == CONFIRM_YES)
|
||||
{
|
||||
download_and_install = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
download_and_install = true;
|
||||
}
|
||||
|
||||
for (std::vector<DirEntry>::iterator it = files.begin(); it != files.end(); ++it)
|
||||
{
|
||||
if (stop_activity)
|
||||
@@ -708,7 +716,7 @@ namespace Actions
|
||||
{
|
||||
if (BE32(header.pkg_magic) == PKG_MAGIC)
|
||||
{
|
||||
if (download_and_install)
|
||||
if (!remote_settings->enable_rpi)
|
||||
{
|
||||
if (DownloadAndInstallPkg(it->path, &header) == 0)
|
||||
failed++;
|
||||
@@ -728,11 +736,11 @@ namespace Actions
|
||||
SplitFile *sp = new SplitFile(install_pkg_path, INSTALL_ARCHIVE_PKG_SPLIT_SIZE/2);
|
||||
|
||||
install_data->split_file = sp;
|
||||
install_data->remote_client = remoteclient;
|
||||
install_data->remote_client = INSTALLER::GetRemoteClient(remote_settings);
|
||||
install_data->path = it->path;
|
||||
remoteclient->Size(it->path, &install_data->size);
|
||||
install_data->stop_write_thread = false;
|
||||
install_data->delete_client = false;
|
||||
install_data->delete_client = true;
|
||||
|
||||
int ret = pthread_create(&install_data->thread, NULL, DownloadSplitPkg, install_data);
|
||||
|
||||
@@ -745,10 +753,15 @@ namespace Actions
|
||||
{
|
||||
std::string url = INSTALLER::getRemoteUrl(it->path, true);
|
||||
std::string title = INSTALLER::GetRemotePkgTitle(remoteclient, it->path, &header);
|
||||
if (INSTALLER::InstallRemotePkg(url, &header, title, true) == 0)
|
||||
if (INSTALLER::InstallRemotePkg(url, &header, title) == 0)
|
||||
failed++;
|
||||
else
|
||||
success++;
|
||||
|
||||
if (it != files.end())
|
||||
{
|
||||
sleep(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -764,6 +777,8 @@ namespace Actions
|
||||
{
|
||||
while (entry != nullptr)
|
||||
{
|
||||
snprintf(activity_message, 1023, "%s %s", lang_strings[STR_INSTALLING], entry->filename.c_str());
|
||||
|
||||
ArchivePkgInstallData *install_data = (ArchivePkgInstallData*) malloc(sizeof(ArchivePkgInstallData));
|
||||
memset(install_data, 0, sizeof(ArchivePkgInstallData));
|
||||
|
||||
@@ -1470,6 +1485,16 @@ namespace Actions
|
||||
if (src.isDir)
|
||||
{
|
||||
int err;
|
||||
if (!isCopy && !FS::FolderExists(dest))
|
||||
{
|
||||
errno = 0;
|
||||
int ret = rename(src.path, dest);
|
||||
if (ret != 0 && errno != EXDEV && errno != EEXIST)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DirEntry> entries = FS::ListDir(src.path, &err);
|
||||
FS::MkDirs(dest);
|
||||
for (int i = 0; i < entries.size(); i++)
|
||||
@@ -1484,9 +1509,11 @@ namespace Actions
|
||||
if (entries[i].isDir)
|
||||
{
|
||||
if (strcmp(entries[i].name, "..") == 0)
|
||||
{
|
||||
free(new_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
FS::MkDirs(new_path);
|
||||
ret = CopyOrMove(entries[i], new_path, isCopy);
|
||||
if (ret <= 0)
|
||||
{
|
||||
@@ -1510,6 +1537,11 @@ namespace Actions
|
||||
}
|
||||
free(new_path);
|
||||
}
|
||||
|
||||
if (!isCopy && FS::FolderExists(src.path))
|
||||
{
|
||||
FS::RmDir(src.path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1551,7 +1583,6 @@ namespace Actions
|
||||
char new_dir[512];
|
||||
sprintf(new_dir, "%s%s%s", local_directory, FS::hasEndSlash(local_directory) ? "" : "/", it->name);
|
||||
CopyOrMove(*it, new_dir, false);
|
||||
FS::RmRecursive(it->path);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1895,4 +1926,49 @@ namespace Actions
|
||||
sprintf(remote_file_to_select, "%s", temp_file.c_str());
|
||||
}
|
||||
|
||||
void RestartServer()
|
||||
{
|
||||
INSTALLER::StopEzRemoteServer();
|
||||
sleep(2);
|
||||
INSTALLER::StartEzRemoteServer();
|
||||
sleep(2);
|
||||
}
|
||||
|
||||
void GetBackgroundDownloadProgress()
|
||||
{
|
||||
httplib::Client client = httplib::Client("http://127.0.0.1:" + std::to_string(http_int_server_port));
|
||||
|
||||
if (auto res = client.Get("/get_download_state"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
bg_download_progress.clear();
|
||||
|
||||
json_object *jobj = json_tokener_parse(res->body.c_str());
|
||||
if (jobj != nullptr)
|
||||
{
|
||||
struct array_list *progress_list = json_object_get_array(jobj);
|
||||
|
||||
for (size_t idx = 0; idx < progress_list->length; ++idx)
|
||||
{
|
||||
DownloadProgress progress;
|
||||
|
||||
json_object *progress_obj = (json_object *)array_list_get_idx(progress_list, idx);
|
||||
progress.path = json_object_get_string(json_object_object_get(progress_obj, "path"));
|
||||
progress.bytes_transfered = json_object_get_uint64(json_object_object_get(progress_obj, "bytes_transfered"));
|
||||
progress.file_size = json_object_get_uint64(json_object_object_get(progress_obj, "file_size"));
|
||||
progress.state = state_strings[json_object_get_int(json_object_object_get(progress_obj, "state"))];
|
||||
progress.timestamp = json_object_get_uint64(json_object_object_get(progress_obj, "timestamp"));
|
||||
|
||||
bg_download_progress.push_back(progress);
|
||||
}
|
||||
json_object_put(jobj);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(status_message, 1024, "Failed to get the download progress from ezRemote Server");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -122,6 +122,8 @@ namespace Actions
|
||||
void CreateRemoteFile(char *filename);
|
||||
void *ExtractArchivePkg(void *argp);
|
||||
void *DownloadSplitPkg(void *argp);
|
||||
void RestartServer();
|
||||
void GetBackgroundDownloadProgress();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -39,7 +39,7 @@ std::string ArchiveOrgClient::GenerateRandomId(const int len)
|
||||
return tmp_s;
|
||||
}
|
||||
|
||||
int ArchiveOrgClient::Connect(const std::string &url, const std::string &username, const std::string &password)
|
||||
int ArchiveOrgClient::Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping)
|
||||
{
|
||||
this->host_url = url;
|
||||
size_t scheme_pos = url.find("://");
|
||||
@@ -64,6 +64,8 @@ int ArchiveOrgClient::Connect(const std::string &url, const std::string &usernam
|
||||
|
||||
if (username.length() > 0)
|
||||
return Login(username, password);
|
||||
else if (!send_ping)
|
||||
this->connected = true;
|
||||
else if (Ping())
|
||||
this->connected = true;
|
||||
return 1;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
class ArchiveOrgClient : public BaseClient
|
||||
{
|
||||
public:
|
||||
int Connect(const std::string &url, const std::string &username, const std::string &password);
|
||||
int Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping=false);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
|
||||
private:
|
||||
|
||||
@@ -40,7 +40,7 @@ int BaseClient::SetCookies(Headers &headers)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BaseClient::Connect(const std::string &url, const std::string &username, const std::string &password)
|
||||
int BaseClient::Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping)
|
||||
{
|
||||
this->host_url = url;
|
||||
size_t scheme_pos = url.find("://");
|
||||
@@ -58,8 +58,12 @@ int BaseClient::Connect(const std::string &url, const std::string &username, con
|
||||
client->set_connection_timeout(30);
|
||||
client->set_read_timeout(30);
|
||||
client->enable_server_certificate_verification(false);
|
||||
if (Ping())
|
||||
|
||||
if (!send_ping)
|
||||
this->connected = true;
|
||||
else if (Ping())
|
||||
this->connected = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ class BaseClient : public RemoteClient
|
||||
public:
|
||||
BaseClient();
|
||||
~BaseClient();
|
||||
int Connect(const std::string &url, const std::string &username, const std::string &password);
|
||||
int Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping=false);
|
||||
int Connect(const std::string &url, const std::string &api_key);
|
||||
int Mkdir(const std::string &path);
|
||||
int Rmdir(const std::string &path, bool recursive);
|
||||
@@ -59,4 +59,4 @@ protected:
|
||||
std::map<std::string, std::string> cookies;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -46,7 +46,7 @@ FtpClient::~FtpClient()
|
||||
free(mp_ftphandle);
|
||||
}
|
||||
|
||||
int FtpClient::Connect(const std::string &url, const std::string &user, const std::string &pass)
|
||||
int FtpClient::Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping)
|
||||
{
|
||||
int port = 21;
|
||||
std::string host = url.substr(6);
|
||||
@@ -897,7 +897,8 @@ int FtpClient::FtpXfer(SplitFile *split_file, const std::string &path, ftphandle
|
||||
dbuf = static_cast<char *>(malloc(FTP_CLIENT_BUFSIZ));
|
||||
while ((l = FtpRead(dbuf, FTP_CLIENT_BUFSIZ, nData)) > 0)
|
||||
{
|
||||
split_file->Write(dbuf, l);
|
||||
if (split_file->Write(dbuf, l) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
free(dbuf);
|
||||
@@ -1499,9 +1500,16 @@ int FtpClient::ParseDirEntry(char *line, DirEntry *dirEntry)
|
||||
dirEntry->modified.minutes = (uint8_t)strtoul(token + 3, NULL, 10);
|
||||
|
||||
// The PM period covers the 12 hours from noon to midnight
|
||||
// Correct 12-hour clock: 12:xx AM = 00:xx, 12:xx PM = 12:xx
|
||||
if (strstr(token, "PM") != NULL)
|
||||
{
|
||||
dirEntry->modified.hours += 12;
|
||||
if (dirEntry->modified.hours != 12)
|
||||
dirEntry->modified.hours += 12;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dirEntry->modified.hours == 12)
|
||||
dirEntry->modified.hours = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1525,7 +1533,7 @@ int FtpClient::ParseDirEntry(char *line, DirEntry *dirEntry)
|
||||
else
|
||||
{
|
||||
// Save the size of the file
|
||||
dirEntry->file_size = strtoul(token, NULL, 10);
|
||||
dirEntry->file_size = strtoull(token, NULL, 10);
|
||||
}
|
||||
|
||||
// Read filename field
|
||||
@@ -1547,8 +1555,8 @@ int FtpClient::ParseDirEntry(char *line, DirEntry *dirEntry)
|
||||
// Unix listing format?
|
||||
else
|
||||
{
|
||||
// Check file permissions
|
||||
if (strchr(token, 'd') != NULL)
|
||||
// Check file permissions — 'd' must be at position 0 of the permissions field
|
||||
if (token[0] == 'd')
|
||||
{
|
||||
dirEntry->isDir = true;
|
||||
}
|
||||
@@ -1578,7 +1586,7 @@ int FtpClient::ParseDirEntry(char *line, DirEntry *dirEntry)
|
||||
return -1;
|
||||
|
||||
// Save the size of the file
|
||||
dirEntry->file_size = strtoul(token, NULL, 10);
|
||||
dirEntry->file_size = strtoull(token, NULL, 10);
|
||||
|
||||
// Read modification time (month)
|
||||
token = strtok_r(NULL, " ", &p);
|
||||
@@ -1619,12 +1627,13 @@ int FtpClient::ParseDirEntry(char *line, DirEntry *dirEntry)
|
||||
// The format of the year is yyyy
|
||||
dirEntry->modified.year = (uint16_t)strtoul(token, NULL, 10);
|
||||
}
|
||||
else if (strlen(token) == 5)
|
||||
else if (strchr(token, ':') != NULL)
|
||||
{
|
||||
// The format of the time hh:mm
|
||||
token[2] = '\0';
|
||||
// The format of the time is hh:mm or h:mm
|
||||
char *colon = strchr(token, ':');
|
||||
*colon = '\0';
|
||||
dirEntry->modified.hours = (uint8_t)strtoul(token, NULL, 10);
|
||||
dirEntry->modified.minutes = (uint8_t)strtoul(token + 3, NULL, 10);
|
||||
dirEntry->modified.minutes = (uint8_t)strtoul(colon + 1, NULL, 10);
|
||||
dirEntry->modified.year = cur_time.tm_year + 1900;
|
||||
}
|
||||
else
|
||||
@@ -1639,6 +1648,11 @@ int FtpClient::ParseDirEntry(char *line, DirEntry *dirEntry)
|
||||
if (token == NULL)
|
||||
return -1;
|
||||
|
||||
// For symlinks, strip the " -> target" suffix (e.g. "linkname -> /some/target")
|
||||
char *arrow = strstr(token, " -> ");
|
||||
if (arrow != NULL)
|
||||
*arrow = '\0';
|
||||
|
||||
// Retrieve the length of the filename
|
||||
n = strlen(token);
|
||||
// Limit the number of characters to copy
|
||||
@@ -1650,6 +1664,10 @@ int FtpClient::ParseDirEntry(char *line, DirEntry *dirEntry)
|
||||
dirEntry->name[n] = '\0';
|
||||
}
|
||||
|
||||
// Exclude hidden files and folders (names starting with '.')
|
||||
if (!show_hidden_files && dirEntry->name[0] == '.')
|
||||
return -1;
|
||||
|
||||
// The directory entry is valid
|
||||
return 1;
|
||||
}
|
||||
@@ -1660,37 +1678,48 @@ int FtpClient::ParseMLSDDirEntry(char *line, DirEntry *dirEntry)
|
||||
char *token;
|
||||
char *facts;
|
||||
char *keypair;
|
||||
char *factsSave;
|
||||
char key[128];
|
||||
char value[128];
|
||||
|
||||
// Spilt string by space
|
||||
// Split string by first space: facts portion and name portion
|
||||
facts = strtok_r(line, " ", &p);
|
||||
|
||||
// path is the rest of the line after space
|
||||
// path is the rest of the line after the space, strip trailing CR/LF
|
||||
token = strtok_r(p, "\r\n", &p);
|
||||
snprintf(dirEntry->name, 256, "%s", token);
|
||||
|
||||
// split properties by semi-colon and get the key value pair
|
||||
while ((keypair = strtok_r(facts, ";", &facts)))
|
||||
// Split facts by semicolon and parse each key=value pair
|
||||
factsSave = NULL;
|
||||
keypair = strtok_r(facts, ";", &factsSave);
|
||||
while (keypair != NULL)
|
||||
{
|
||||
sscanf(keypair, "%[^=]=%s", key, value);
|
||||
if (strcasecmp(key, "type") == 0)
|
||||
key[0] = '\0';
|
||||
value[0] = '\0';
|
||||
if (sscanf(keypair, "%127[^=]=%127s", key, value) == 2)
|
||||
{
|
||||
dirEntry->isDir = false;
|
||||
if (strcasecmp(value, "dir") == 0)
|
||||
if (strcasecmp(key, "type") == 0)
|
||||
{
|
||||
dirEntry->isDir = true;
|
||||
dirEntry->isDir = false;
|
||||
// dir, cdir (current dir), and pdir (parent dir) are all directory types
|
||||
if (strcasecmp(value, "dir") == 0 ||
|
||||
strcasecmp(value, "cdir") == 0 ||
|
||||
strcasecmp(value, "pdir") == 0)
|
||||
{
|
||||
dirEntry->isDir = true;
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(key, "size") == 0)
|
||||
{
|
||||
dirEntry->file_size = atoll(value);
|
||||
}
|
||||
else if (strcasecmp(key, "modify") == 0)
|
||||
{
|
||||
sscanf(value, "%4d%2d%2d%2d%2d%2d", &dirEntry->modified.year, &dirEntry->modified.month, &dirEntry->modified.day,
|
||||
&dirEntry->modified.hours, &dirEntry->modified.minutes, &dirEntry->modified.seconds);
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(key, "size") == 0)
|
||||
{
|
||||
dirEntry->file_size = atoll(value);
|
||||
}
|
||||
else if (strcasecmp(key, "modify") == 0)
|
||||
{
|
||||
sscanf(value, "%4d%2d%2d%2d%2d%2d", &dirEntry->modified.year, &dirEntry->modified.month, &dirEntry->modified.day,
|
||||
&dirEntry->modified.hours, &dirEntry->modified.minutes, &dirEntry->modified.seconds);
|
||||
}
|
||||
keypair = strtok_r(NULL, ";", &factsSave);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
|
||||
FtpClient();
|
||||
~FtpClient();
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass);
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping=false);
|
||||
void SetConnmode(connmode mode);
|
||||
int Site(const std::string &cmd);
|
||||
int Raw(const std::string &cmd);
|
||||
@@ -137,4 +137,4 @@ private:
|
||||
int ParseMLSDDirEntry(char *line, DirEntry *dirEntry);
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -159,7 +159,7 @@ GDriveClient::GDriveClient()
|
||||
path_id_map.insert(std::make_pair("/" + shared_with_me, shared_with_me));
|
||||
}
|
||||
|
||||
int GDriveClient::Connect(const std::string &url, const std::string &user, const std::string &pass)
|
||||
int GDriveClient::Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping)
|
||||
{
|
||||
if (strlen(remote_settings->gg_account.refresh_token) > 0)
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ class GDriveClient : public BaseClient
|
||||
{
|
||||
public:
|
||||
GDriveClient();
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass);
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping=false);
|
||||
int Rename(const std::string &src, const std::string &dst);
|
||||
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);
|
||||
@@ -51,4 +51,4 @@ private:
|
||||
std::map<std::string, std::string> shared_drive_map;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,7 @@ using httplib::Client;
|
||||
using httplib::Headers;
|
||||
using httplib::Result;
|
||||
|
||||
int GithubClient::Connect(const std::string &url, const std::string &username, const std::string &password)
|
||||
int GithubClient::Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping)
|
||||
{
|
||||
if (url.find("https://github.com") == std::string::npos)
|
||||
return 0;
|
||||
@@ -21,6 +21,7 @@ int GithubClient::Connect(const std::string &url, const std::string &username, c
|
||||
this->base_path = "/repos" + url.substr(18);
|
||||
Util::Rtrim(this->base_path, "/");
|
||||
this->base_path += "/releases";
|
||||
this->m_download_url = "https://github.com";
|
||||
|
||||
client = new httplib::Client(this->host_url);
|
||||
if (username.length() > 0)
|
||||
@@ -31,8 +32,11 @@ int GithubClient::Connect(const std::string &url, const std::string &username, c
|
||||
client->enable_server_certificate_verification(false);
|
||||
m_client.Connect("https://github.com", username, password);
|
||||
|
||||
if (Ping())
|
||||
if (!send_ping)
|
||||
this->connected = true;
|
||||
else if (Ping())
|
||||
this->connected = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -254,4 +258,19 @@ bool GithubClient::ParseReleases()
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
std::string GithubClient::GetDownloadUrl(const std::string &path)
|
||||
{
|
||||
if (!ParseReleases())
|
||||
return "";
|
||||
|
||||
std::vector<std::string> path_parts = Util::Split(path, "/");
|
||||
|
||||
if (path_parts.size() != 2)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return this->m_download_url + Escape(m_assets[path_parts[0]][path_parts[1]].url);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
class GithubClient : public BaseClient
|
||||
{
|
||||
public:
|
||||
int Connect(const std::string &url, const std::string &username, const std::string &password);
|
||||
int Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping=false);
|
||||
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);
|
||||
@@ -19,6 +19,7 @@ public:
|
||||
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);
|
||||
std::string GetDownloadUrl(const std::string &path);
|
||||
|
||||
private:
|
||||
struct GitAsset
|
||||
@@ -38,9 +39,10 @@ private:
|
||||
std::vector<GitRelease> m_releases;
|
||||
std::map<std::string, std::map<std::string, GitAsset>> m_assets;
|
||||
bool releases_parsed = false;
|
||||
std::string m_download_url;
|
||||
BaseClient m_client;
|
||||
|
||||
bool ParseReleases();
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -223,7 +223,10 @@ std::vector<DirEntry> MyrientClient::ListDir(const std::string &path)
|
||||
}
|
||||
|
||||
lxb_dom_collection_destroy(td_collection, true);
|
||||
out.push_back(entry);
|
||||
if (strcmp(entry.name, "..") != 0 && strcmp(entry.name, ".") != 0)
|
||||
{
|
||||
out.push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
|
||||
@@ -27,7 +27,7 @@ NfsClient::~NfsClient()
|
||||
{
|
||||
}
|
||||
|
||||
int NfsClient::Connect(const std::string &url, const std::string &user, const std::string &pass)
|
||||
int NfsClient::Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping)
|
||||
{
|
||||
nfs = nfs_init_context();
|
||||
if (nfs == nullptr)
|
||||
@@ -247,7 +247,7 @@ int NfsClient::Get(SplitFile *split_file, const std::string &ppath, uint64_t off
|
||||
|
||||
void *buff = malloc(BUF_SIZE);
|
||||
int count = 0;
|
||||
while ((count = nfs_read(nfs, nfsfh, BUF_SIZE, buff)) > 0)
|
||||
while ((count = nfs_read(nfs, nfsfh, BUF_SIZE, buff)) != 0)
|
||||
{
|
||||
if (count < 0)
|
||||
{
|
||||
@@ -256,7 +256,13 @@ int NfsClient::Get(SplitFile *split_file, const std::string &ppath, uint64_t off
|
||||
free((void *)buff);
|
||||
return 0;
|
||||
}
|
||||
split_file->Write((char *)buff, count);
|
||||
ret = split_file->Write((char *)buff, count);
|
||||
if (ret < 0)
|
||||
{
|
||||
nfs_close(nfs, nfsfh);
|
||||
free((void *)buff);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
nfs_close(nfs, nfsfh);
|
||||
free((void *)buff);
|
||||
@@ -343,10 +349,28 @@ int NfsClient::GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count = nfs_read(nfs, nfsfh, size, buffer);
|
||||
if (count != size)
|
||||
return 0;
|
||||
size_t bytes_remaining = size;
|
||||
char *buff = (char*)buffer;
|
||||
int total = 0;
|
||||
int count = 0;
|
||||
do
|
||||
{
|
||||
count = nfs_read(nfs, nfsfh, bytes_remaining, buff);
|
||||
if (count > 0)
|
||||
{
|
||||
bytes_remaining -= count;
|
||||
buff += count;
|
||||
total += count;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
if (total != size)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -411,14 +435,14 @@ int NfsClient::Put(const std::string &inputfile, const std::string &ppath, uint6
|
||||
}
|
||||
|
||||
void *buff = malloc(BUF_SIZE);
|
||||
uint64_t count = 0;
|
||||
int count = 0;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
while ((count = FS::Read(in, buff, BUF_SIZE)) > 0)
|
||||
while ((count = FS::Read(in, buff, BUF_SIZE)) != 0)
|
||||
{
|
||||
if (count < 0)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
snprintf(response, sizeof(response), "%s", lang_strings[STR_FAILED]);
|
||||
FS::Close(in);
|
||||
nfs_close(nfs, nfsfh);
|
||||
free(buff);
|
||||
|
||||
@@ -18,7 +18,7 @@ class NfsClient : public RemoteClient
|
||||
public:
|
||||
NfsClient();
|
||||
~NfsClient();
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass);
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping=false);
|
||||
int Mkdir(const std::string &path);
|
||||
int Rmdir(const std::string &path, bool recursive);
|
||||
int Size(const std::string &path, int64_t *size);
|
||||
@@ -53,4 +53,4 @@ private:
|
||||
bool connected = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -35,6 +35,7 @@ enum ClientType
|
||||
CLIENT_TYPE_HTTP_SERVER,
|
||||
CLIENT_TYPE_GOOGLE,
|
||||
CLIENT_TYPE_NFS,
|
||||
CLIENT_TYPE_FILEHOST,
|
||||
CLINET_TYPE_UNKNOWN
|
||||
};
|
||||
|
||||
@@ -45,7 +46,7 @@ class RemoteClient
|
||||
public:
|
||||
RemoteClient(){};
|
||||
virtual ~RemoteClient(){};
|
||||
virtual int Connect(const std::string &url, const std::string &username, const std::string &password) = 0;
|
||||
virtual int Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping=false) = 0;
|
||||
virtual int Mkdir(const std::string &path) = 0;
|
||||
virtual int Rmdir(const std::string &path, bool recursive) = 0;
|
||||
virtual int Size(const std::string &path, int64_t *size) = 0;
|
||||
@@ -74,4 +75,4 @@ public:
|
||||
virtual uint32_t SupportedActions() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -23,7 +23,7 @@ SFTPClient::SFTPClient()
|
||||
|
||||
SFTPClient::~SFTPClient(){};
|
||||
|
||||
int SFTPClient::Connect(const std::string &url, const std::string &username, const std::string &password)
|
||||
int SFTPClient::Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping)
|
||||
{
|
||||
int port = 22;
|
||||
std::string host = url.substr(7);
|
||||
@@ -711,4 +711,4 @@ ClientType SFTPClient::clientType()
|
||||
uint32_t SFTPClient::SupportedActions()
|
||||
{
|
||||
return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class SFTPClient : public RemoteClient
|
||||
public:
|
||||
SFTPClient();
|
||||
~SFTPClient();
|
||||
int Connect(const std::string &url, const std::string &username, const std::string &password);
|
||||
int Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping=false);
|
||||
int Mkdir(const std::string &path);
|
||||
int Rmdir(const std::string &path, bool recursive);
|
||||
int Rmdir(const std::string &path);
|
||||
@@ -51,4 +51,4 @@ protected:
|
||||
bool connected = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -24,34 +24,43 @@ SmbClient::~SmbClient()
|
||||
{
|
||||
}
|
||||
|
||||
int SmbClient::Connect(const std::string &url, const std::string &user, const std::string &pass)
|
||||
int SmbClient::Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping)
|
||||
{
|
||||
struct smb2_url *smb_url;
|
||||
|
||||
smb2 = smb2_init_context();
|
||||
if (smb2 == NULL)
|
||||
{
|
||||
sprintf(response, "Failed to init SMB context");
|
||||
snprintf(response, sizeof(response), "Failed to init SMB context");
|
||||
return 0;
|
||||
}
|
||||
|
||||
smb_url = smb2_parse_url(smb2, url.c_str());
|
||||
if (smb_url == NULL || smb_url->share == NULL || strlen(smb_url->share) == 0)
|
||||
{
|
||||
sprintf(response, "Invalid SMB Url");
|
||||
if (smb_url != NULL)
|
||||
smb2_destroy_url(smb_url);
|
||||
smb2_destroy_context(smb2);
|
||||
smb2 = NULL;
|
||||
snprintf(response, sizeof(response), "Invalid SMB Url");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pass.length() > 0)
|
||||
smb2_set_password(smb2, pass.c_str());
|
||||
smb2_set_security_mode(smb2, SMB2_NEGOTIATE_SIGNING_ENABLED);
|
||||
smb2_set_version(smb2, SMB2_VERSION_ANY);
|
||||
smb2_set_timeout(smb2, 30);
|
||||
|
||||
if (smb2_connect_share(smb2, smb_url->server, smb_url->share, user.c_str()) < 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
smb2_destroy_url(smb_url);
|
||||
smb2_destroy_context(smb2);
|
||||
smb2 = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
smb2_destroy_url(smb_url);
|
||||
max_read_size = smb2_get_max_read_size(smb2);
|
||||
max_write_size = smb2_get_max_write_size(smb2);
|
||||
@@ -109,7 +118,7 @@ int SmbClient::Mkdir(const std::string &ppath)
|
||||
path = Util::Trim(path, "/");
|
||||
if (smb2_mkdir(smb2, path.c_str()) != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -126,7 +135,7 @@ int SmbClient::_Rmdir(const std::string &ppath)
|
||||
path = Util::Trim(path, "/");
|
||||
if (smb2_rmdir(smb2, path.c_str()) != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -193,37 +202,45 @@ int SmbClient::Get(const std::string &outputfile, const std::string &ppath, uint
|
||||
path = Util::Trim(path, "/");
|
||||
if (!Size(path.c_str(), &bytes_to_download))
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct smb2fh *in = smb2_open(smb2, path.c_str(), O_RDONLY);
|
||||
struct smb2fh* in = smb2_open(smb2, path.c_str(), O_RDONLY);
|
||||
if (in == NULL)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE *out = FS::Create(outputfile);
|
||||
FILE* out = FS::Create(outputfile);
|
||||
if (out == NULL)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
snprintf(response, sizeof(response), "%s", lang_strings[STR_FAILED]);
|
||||
smb2_close(smb2, in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *buff = (uint8_t *)malloc(max_read_size);
|
||||
uint8_t *buff = (uint8_t*)malloc(max_read_size);
|
||||
if (buff == NULL)
|
||||
{
|
||||
snprintf(response, sizeof(response), "%s", lang_strings[STR_FAILED]);
|
||||
FS::Close(out);
|
||||
smb2_close(smb2, in);
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
while ((count = smb2_read(smb2, in, buff, max_read_size)) > 0)
|
||||
while ((count = smb2_read(smb2, in, buff, max_read_size)) != 0)
|
||||
{
|
||||
if (count < 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
FS::Close(out);
|
||||
smb2_close(smb2, in);
|
||||
free((void *)buff);
|
||||
free((void*)buff);
|
||||
return 0;
|
||||
}
|
||||
FS::Write(out, buff, count);
|
||||
@@ -231,7 +248,7 @@ int SmbClient::Get(const std::string &outputfile, const std::string &ppath, uint
|
||||
}
|
||||
FS::Close(out);
|
||||
smb2_close(smb2, in);
|
||||
free((void *)buff);
|
||||
free((void*)buff);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -243,23 +260,33 @@ int SmbClient::Get(SplitFile *split_file, const std::string &ppath, uint64_t off
|
||||
struct smb2fh *in = smb2_open(smb2, path.c_str(), O_RDONLY);
|
||||
if (in == NULL)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *buff = (uint8_t *)malloc(max_read_size);
|
||||
if (buff == NULL)
|
||||
{
|
||||
smb2_close(smb2, in);
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
|
||||
while ((count = smb2_read(smb2, in, buff, max_read_size)) > 0)
|
||||
while ((count = smb2_read(smb2, in, buff, max_read_size)) != 0)
|
||||
{
|
||||
if (count < 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
smb2_close(smb2, in);
|
||||
free((void *)buff);
|
||||
return 0;
|
||||
}
|
||||
if (split_file->Write((char*)buff, count) < 0)
|
||||
{
|
||||
smb2_close(smb2, in);
|
||||
free((void *)buff);
|
||||
return 0;
|
||||
}
|
||||
split_file->Write((char*)buff, count);
|
||||
}
|
||||
|
||||
smb2_close(smb2, in);
|
||||
@@ -345,24 +372,27 @@ int SmbClient::GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset)
|
||||
|
||||
smb2_lseek(smb2, in, offset, SEEK_SET, NULL);
|
||||
|
||||
uint8_t *buff = (uint8_t *)buffer;
|
||||
int count = 0;
|
||||
size_t bytes_remaining = size;
|
||||
uint8_t *buff = (uint8_t*)buffer;
|
||||
int count = 0;
|
||||
uint64_t total = 0;
|
||||
do
|
||||
{
|
||||
size_t bytes_to_read = std::min<size_t>(max_read_size, bytes_remaining);
|
||||
count = smb2_read(smb2, in, buff, bytes_to_read);
|
||||
count = smb2_read(smb2, in, buff, bytes_remaining);
|
||||
if (count > 0)
|
||||
{
|
||||
bytes_remaining -= count;
|
||||
buff += count;
|
||||
total += count;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
|
||||
if (total != size)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -425,7 +455,7 @@ bool SmbClient::FileExists(const std::string &ppath)
|
||||
int ret = smb2_stat(smb2, path.c_str(), &st);
|
||||
if (ret != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -449,21 +479,29 @@ int SmbClient::Put(const std::string &inputfile, const std::string &ppath, uint6
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE *in = FS::OpenRead(inputfile);
|
||||
FILE* in = FS::OpenRead(inputfile);
|
||||
if (in == NULL)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
snprintf(response, sizeof(response), "%s", lang_strings[STR_FAILED]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct smb2fh *out = smb2_open(smb2, path.c_str(), O_WRONLY | O_CREAT | O_TRUNC);
|
||||
|
||||
struct smb2fh* out = smb2_open(smb2, path.c_str(), O_WRONLY | O_CREAT | O_TRUNC);
|
||||
if (out == NULL)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
FS::Close(in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *buff = (uint8_t *)malloc(max_write_size);
|
||||
uint8_t* buff = (uint8_t*)malloc(max_write_size);
|
||||
if (buff == NULL)
|
||||
{
|
||||
snprintf(response, sizeof(response), "%s", lang_strings[STR_FAILED]);
|
||||
FS::Close(in);
|
||||
smb2_close(smb2, out);
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
@@ -472,13 +510,20 @@ int SmbClient::Put(const std::string &inputfile, const std::string &ppath, uint6
|
||||
{
|
||||
if (count < 0)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
snprintf(response, sizeof(response), "%s", lang_strings[STR_FAILED]);
|
||||
FS::Close(in);
|
||||
smb2_close(smb2, out);
|
||||
free(buff);
|
||||
return 0;
|
||||
}
|
||||
if (smb2_write(smb2, out, buff, count) < 0)
|
||||
{
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
FS::Close(in);
|
||||
smb2_close(smb2, out);
|
||||
free(buff);
|
||||
return 0;
|
||||
}
|
||||
smb2_write(smb2, out, buff, count);
|
||||
bytes_transfered += count;
|
||||
}
|
||||
FS::Close(in);
|
||||
@@ -496,7 +541,7 @@ int SmbClient::Rename(const std::string &src, const std::string &dst)
|
||||
path2 = Util::Trim(path2, "/");
|
||||
if (smb2_rename(smb2, path1.c_str(), path2.c_str()) != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -509,7 +554,7 @@ int SmbClient::Delete(const std::string &ppath)
|
||||
path = Util::Trim(path, "/");
|
||||
if (smb2_unlink(smb2, path.c_str()) != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -523,7 +568,7 @@ int SmbClient::Size(const std::string &ppath, int64_t *size)
|
||||
smb2_stat_64 st;
|
||||
if (smb2_stat(smb2, path.c_str(), &st) != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
*size = st.smb2_size;
|
||||
@@ -592,7 +637,8 @@ std::vector<DirEntry> SmbClient::ListDir(const std::string &path)
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
break;
|
||||
}
|
||||
if (strcmp(entry.name, "..") != 0 && strcmp(entry.name, ".") != 0)
|
||||
if (strcmp(entry.name, "..") != 0 && strcmp(entry.name, ".") != 0 &&
|
||||
(show_hidden_files || entry.name[0] != '.'))
|
||||
out.push_back(entry);
|
||||
}
|
||||
smb2_closedir(smb2, dir);
|
||||
@@ -619,15 +665,15 @@ int SmbClient::Head(const std::string &ppath, void *buffer, uint64_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct smb2fh *in = smb2_open(smb2, path.c_str(), O_RDONLY);
|
||||
struct smb2fh* in = smb2_open(smb2, path.c_str(), O_RDONLY);
|
||||
if (in == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count = smb2_read(smb2, in, (uint8_t *)buffer, len);
|
||||
uint64_t count = smb2_read(smb2, in, (uint8_t*)buffer, len);
|
||||
smb2_close(smb2, in);
|
||||
if (count != len)
|
||||
if (count < 0 || count != len)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -19,7 +19,7 @@ class SmbClient : public RemoteClient
|
||||
public:
|
||||
SmbClient();
|
||||
~SmbClient();
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass);
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping=false);
|
||||
int Mkdir(const std::string &path);
|
||||
int Rmdir(const std::string &path, bool recursive);
|
||||
int Size(const std::string &path, int64_t *size);
|
||||
@@ -57,4 +57,4 @@ private:
|
||||
uint32_t max_write_size = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -24,10 +24,10 @@ std::string WebDAVClient::GetHttpUrl(std::string url)
|
||||
return http_url;
|
||||
}
|
||||
|
||||
int WebDAVClient::Connect(const std::string &host, const std::string &user, const std::string &pass)
|
||||
int WebDAVClient::Connect(const std::string &host, const std::string &user, const std::string &pass, bool send_ping)
|
||||
{
|
||||
std::string url = GetHttpUrl(host);
|
||||
return BaseClient::Connect(url, user, pass);
|
||||
return BaseClient::Connect(url, user, pass, send_ping);
|
||||
}
|
||||
|
||||
Result WebDAVClient::PropFind(const std::string &path, int depth)
|
||||
@@ -321,4 +321,4 @@ ClientType WebDAVClient::clientType()
|
||||
uint32_t WebDAVClient::SupportedActions()
|
||||
{
|
||||
return REMOTE_ACTION_ALL ^ REMOTE_ACTION_RAW_READ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
class WebDAVClient : public BaseClient
|
||||
{
|
||||
public:
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass);
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping=false);
|
||||
int Mkdir(const std::string &path);
|
||||
int Rmdir(const std::string &path, bool recursive);
|
||||
int Rename(const std::string &src, const std::string &dst);
|
||||
@@ -29,4 +29,4 @@ private:
|
||||
Result PropFind(const std::string &path, int depth);
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+14
-1
@@ -11,6 +11,10 @@
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
|
||||
enum DownloadState { STATE_PENDING, STATE_DOWNLOADING, STATE_RESUMED, STATE_FAILED, STATE_SUCCESS };
|
||||
|
||||
static const char* state_strings[] = {"Pending", "Downloading", "Resumed", "Failed", "Success"};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t year;
|
||||
@@ -88,6 +92,15 @@ struct DirEntry
|
||||
}
|
||||
};
|
||||
|
||||
struct DownloadProgress
|
||||
{
|
||||
std::string path;
|
||||
std::string state;
|
||||
uint64_t bytes_transfered;
|
||||
uint64_t file_size;
|
||||
time_t timestamp;
|
||||
};
|
||||
|
||||
static lxb_dom_node_t *NextChildElement(lxb_dom_element_t *element)
|
||||
{
|
||||
lxb_dom_node_t *node = element->node.first_child;
|
||||
@@ -128,4 +141,4 @@ static lxb_dom_node_t *NextTextNode(lxb_dom_node_t *node)
|
||||
return next;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -41,6 +41,9 @@ bool show_hidden_files;
|
||||
char alldebrid_api_key[64];
|
||||
char realdebrid_api_key[64];
|
||||
char temp_folder[256];
|
||||
std::string ezremote_server_version;
|
||||
bool enable_background_download;
|
||||
uint64_t minimum_backgrond_file_size;
|
||||
|
||||
unsigned char cipher_key[32] = {'s', '5', 'v', '8', 'y', '/', 'B', '?', 'E', '(', 'H', '+', 'M', 'b', 'Q', 'e', 'T', 'h', 'W', 'm', 'Z', 'q', '4', 't', '7', 'w', '9', 'z', '$', 'C', '&', 'F'};
|
||||
unsigned char cipher_iv[16] = {'Y', 'p', '3', 's', '6', 'v', '9', 'y', '$', 'B', '&', 'E', ')', 'H', '@', 'M'};
|
||||
@@ -196,6 +199,12 @@ namespace CONFIG
|
||||
sprintf(temp_folder, ReadString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, TMP_FOLDER_PATH));
|
||||
WriteString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, temp_folder);
|
||||
|
||||
enable_background_download = ReadBool(CONFIG_GLOBAL, CONFIG_ENABLE_BG_DOWNLOAD, true);
|
||||
WriteBool(CONFIG_GLOBAL, CONFIG_ENABLE_BG_DOWNLOAD, enable_background_download);
|
||||
|
||||
minimum_backgrond_file_size = ReadLong(CONFIG_GLOBAL, CONFIG_BG_DOWNLOAD_SIZE, 1024*1024*1024);
|
||||
WriteLong(CONFIG_GLOBAL, CONFIG_BG_DOWNLOAD_SIZE, minimum_backgrond_file_size);
|
||||
|
||||
if (!FS::FolderExists(temp_folder))
|
||||
{
|
||||
FS::MkDirs(temp_folder);
|
||||
@@ -434,6 +443,8 @@ namespace CONFIG
|
||||
WriteInt(CONFIG_HTTP_SERVER, CONFIG_HTTP_SERVER_PORT, http_server_port);
|
||||
WriteString(CONFIG_HTTP_SERVER, CONFIG_HTTP_SERVER_COMPRESSED_FILE_PATH, compressed_file_path);
|
||||
WriteBool(CONFIG_HTTP_SERVER, CONFIG_HTTP_SERVER_ENABLED, web_server_enabled);
|
||||
WriteBool(CONFIG_GLOBAL, CONFIG_ENABLE_BG_DOWNLOAD, enable_background_download);
|
||||
WriteLong(CONFIG_GLOBAL, CONFIG_BG_DOWNLOAD_SIZE, minimum_backgrond_file_size);
|
||||
|
||||
WriteIniFile(CONFIG_INI_FILE);
|
||||
CloseIniFile();
|
||||
|
||||
@@ -77,6 +77,9 @@
|
||||
|
||||
#define CONFIG_LANGUAGE "language"
|
||||
|
||||
#define CONFIG_ENABLE_BG_DOWNLOAD "enable_background_download"
|
||||
#define CONFIG_BG_DOWNLOAD_SIZE "minimum_backgrond_file_size"
|
||||
|
||||
#define HTTP_SERVER_APACHE "Apache"
|
||||
#define HTTP_SERVER_MS_IIS "Microsoft IIS"
|
||||
#define HTTP_SERVER_NGINX "Nginx"
|
||||
@@ -86,6 +89,8 @@
|
||||
#define HTTP_SERVER_MYRIENT "Myrient"
|
||||
#define HTTP_SERVER_GITHUB "Github"
|
||||
|
||||
#define EZREMOTE_SERVER_REQUIRED_VERSION "1.00"
|
||||
|
||||
#define MAX_EDIT_FILE_SIZE 32768
|
||||
|
||||
struct GoogleAccountInfo
|
||||
@@ -153,6 +158,9 @@ extern bool show_hidden_files;
|
||||
extern char alldebrid_api_key[64];
|
||||
extern char realdebrid_api_key[64];
|
||||
extern char temp_folder[256];
|
||||
extern std::string ezremote_server_version;
|
||||
extern bool enable_background_download;
|
||||
extern uint64_t minimum_backgrond_file_size;
|
||||
|
||||
namespace CONFIG
|
||||
{
|
||||
|
||||
+14
-6
@@ -50,7 +50,7 @@ namespace FS
|
||||
|
||||
void RmDir(const std::string &path)
|
||||
{
|
||||
remove(path.c_str());
|
||||
rmdir(path.c_str());
|
||||
}
|
||||
|
||||
int64_t GetSize(const std::string &path)
|
||||
@@ -85,6 +85,7 @@ namespace FS
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Rename(const std::string &from, const std::string &to)
|
||||
{
|
||||
int res = rename(from.c_str(), to.c_str());
|
||||
@@ -269,6 +270,7 @@ namespace FS
|
||||
if (dirent == NULL)
|
||||
{
|
||||
closedir(fd);
|
||||
fd = NULL;
|
||||
return out;
|
||||
}
|
||||
else
|
||||
@@ -344,6 +346,7 @@ namespace FS
|
||||
}
|
||||
}
|
||||
closedir(fd);
|
||||
fd = NULL;
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -549,11 +552,16 @@ namespace FS
|
||||
if (from.compare(to) == 0)
|
||||
return true;
|
||||
|
||||
bool res = Copy(from, to);
|
||||
if (res)
|
||||
Rm(from);
|
||||
else
|
||||
return res;
|
||||
errno = 0;
|
||||
int ret = rename(from.c_str(), to.c_str());
|
||||
if (ret != 0 && (errno == EXDEV || errno == EEXIST))
|
||||
{
|
||||
bool res = Copy(from, to);
|
||||
if (res)
|
||||
Rm(from);
|
||||
else
|
||||
return res;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3954,6 +3954,10 @@ bool Server::listen_internal() {
|
||||
#endif
|
||||
}
|
||||
|
||||
int const size = 1048576;
|
||||
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
|
||||
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
|
||||
|
||||
task_queue->enqueue([this, sock]() { process_and_close_socket(sock); });
|
||||
}
|
||||
|
||||
|
||||
+291
-8
@@ -5,6 +5,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <json-c/json.h>
|
||||
#include <orbis/libkernel.h>
|
||||
#include <orbis/Bgft.h>
|
||||
#include <orbis/AppInstUtil.h>
|
||||
@@ -12,6 +13,21 @@
|
||||
#include <orbis/SystemService.h>
|
||||
#include "clients/webdav.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/smbclient.h"
|
||||
#include "clients/sftpclient.h"
|
||||
#include "clients/ftpclient.h"
|
||||
#include "clients/github.h"
|
||||
#include "clients/nfsclient.h"
|
||||
#include "clients/webdav.h"
|
||||
#include "clients/apache.h"
|
||||
#include "clients/archiveorg.h"
|
||||
#include "clients/iis.h"
|
||||
#include "clients/github.h"
|
||||
#include "clients/myrient.h"
|
||||
#include "clients/nginx.h"
|
||||
#include "clients/npxserve.h"
|
||||
#include "clients/rclone.h"
|
||||
|
||||
#include "server/http_server.h"
|
||||
#include "installer.h"
|
||||
#include "util.h"
|
||||
@@ -22,6 +38,8 @@
|
||||
#include "fs.h"
|
||||
#include "sfo.h"
|
||||
|
||||
#define SERVER_ELF_PATH "/mnt/sandbox/pfsmnt/RMTC00001-app0/daemon/daemon.elf"
|
||||
|
||||
#define BGFT_HEAP_SIZE (1 * 1024 * 1024)
|
||||
|
||||
struct BgProgressCheck
|
||||
@@ -41,6 +59,11 @@ static std::map<std::string, SplitPkgInstallData *> split_pkg_install_data_list;
|
||||
|
||||
namespace INSTALLER
|
||||
{
|
||||
static int FtpCallback(int64_t xfered, void *arg)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Init(void)
|
||||
{
|
||||
int ret;
|
||||
@@ -199,11 +222,53 @@ namespace INSTALLER
|
||||
return title;
|
||||
}
|
||||
|
||||
std::string StoreBgInstallHostData(RemoteSettings *settings, const std::string &path)
|
||||
{
|
||||
std::string hash = Util::UrlHash(settings->server + path + settings->username + settings->password + std::to_string(settings->type));
|
||||
json_object *history_item_obj = json_object_new_object();
|
||||
json_object_object_add(history_item_obj, "hash", json_object_new_string(hash.c_str()));
|
||||
json_object_object_add(history_item_obj, "url", json_object_new_string(settings->server));
|
||||
json_object_object_add(history_item_obj, "path", json_object_new_string(path.c_str()));
|
||||
json_object_object_add(history_item_obj, "username", json_object_new_string(settings->username));
|
||||
json_object_object_add(history_item_obj, "password", json_object_new_string(settings->password));
|
||||
json_object_object_add(history_item_obj, "type", json_object_new_int(settings->type));
|
||||
|
||||
if (settings->type == CLIENT_TYPE_HTTP_SERVER)
|
||||
{
|
||||
json_object_object_add(history_item_obj, "http_server_type", json_object_new_string(settings->http_server_type));
|
||||
}
|
||||
|
||||
const char *params_str = json_object_to_json_string(history_item_obj);
|
||||
|
||||
httplib::Client client = httplib::Client(std::string("http://127.0.0.1:") + std::to_string(http_int_server_port));
|
||||
client.set_connection_timeout(1);
|
||||
|
||||
if (auto res = client.Post("/store_bg_install_data", params_str, "application/json"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
std::string getRemoteUrl(const std::string path, bool encodeUrl)
|
||||
{
|
||||
if (strlen(remote_settings->username) == 0 && strlen(remote_settings->password) == 0 &&
|
||||
(remoteclient->clientType() == CLIENT_TYPE_WEBDAV ||
|
||||
(remoteclient->clientType() == CLIENT_TYPE_HTTP_SERVER && strcmp(remote_settings->http_server_type, HTTP_SERVER_GITHUB) != 0)))
|
||||
if (remote_settings->type == CLIENT_TYPE_HTTP_SERVER && strcmp(remote_settings->http_server_type, HTTP_SERVER_GITHUB) == 0)
|
||||
{
|
||||
GithubClient *tmp_client = (GithubClient*) remoteclient;
|
||||
return tmp_client->GetDownloadUrl(path);
|
||||
}
|
||||
if ( strlen(remote_settings->username) == 0 &&
|
||||
strlen(remote_settings->password) == 0 &&
|
||||
(remote_settings->type == CLIENT_TYPE_WEBDAV ||
|
||||
(remote_settings->type == CLIENT_TYPE_HTTP_SERVER && strcmp(remote_settings->http_server_type, HTTP_SERVER_ARCHIVEORG) == 0)
|
||||
)
|
||||
)
|
||||
{
|
||||
std::string full_url = WebDAVClient::GetHttpUrl(remote_settings->server + path);
|
||||
size_t scheme_pos = full_url.find("://");
|
||||
@@ -222,9 +287,8 @@ namespace INSTALLER
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string encoded_path = httplib::detail::encode_url(path);
|
||||
std::string encoded_site_name = httplib::detail::encode_url(remote_settings->site_name);
|
||||
std::string full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst/" + encoded_site_name + encoded_path;
|
||||
std::string hash = StoreBgInstallHostData(remote_settings, path);
|
||||
std::string full_url = std::string("http://127.0.0.1:") + std::to_string(http_int_server_port) + "/bg_install/" + hash;
|
||||
return full_url;
|
||||
}
|
||||
|
||||
@@ -855,7 +919,7 @@ namespace INSTALLER
|
||||
}
|
||||
|
||||
std::string hash = Util::UrlHash(path);
|
||||
std::string full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/archive_inst/" + hash;
|
||||
std::string full_url = std::string("http://127.0.0.1:") + std::to_string(http_server_port) + "/archive_inst/" + hash;
|
||||
AddArchivePkgInstallData(hash, pkg_data);
|
||||
|
||||
OrbisBgftTaskProgress progress_info;
|
||||
@@ -1042,7 +1106,7 @@ namespace INSTALLER
|
||||
}
|
||||
|
||||
std::string hash = Util::UrlHash(path);
|
||||
std::string full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/split_inst/" + hash;
|
||||
std::string full_url = std::string("http://127.0.0.1:") + std::to_string(http_server_port) + "/split_inst/" + hash;
|
||||
AddSplitPkgInstallData(hash, pkg_data);
|
||||
|
||||
OrbisBgftTaskProgress progress_info;
|
||||
@@ -1171,4 +1235,223 @@ namespace INSTALLER
|
||||
Windows::SetModalMode(false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string EzRemoteServerVersion()
|
||||
{
|
||||
if (!IsPortOpen("127.0.0.1", 6701, 1))
|
||||
return "";
|
||||
|
||||
httplib::Client tmp_client = httplib::Client("http://127.0.0.1:6701");
|
||||
|
||||
tmp_client.set_connection_timeout(1);
|
||||
|
||||
if (auto res = tmp_client.Get("/version"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
return res->body;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
bool IsPortOpen(const char *ip, uint16_t port, int timeout_sec)
|
||||
{
|
||||
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd < 0)
|
||||
return 0;
|
||||
|
||||
// Set socket to non-blocking mode
|
||||
int flags = fcntl(sockfd, F_GETFL, 0);
|
||||
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
inet_pton(AF_INET, ip, &addr.sin_addr);
|
||||
|
||||
// Attempt connection
|
||||
int res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
if (res < 0)
|
||||
{
|
||||
if (errno == EINPROGRESS)
|
||||
{
|
||||
// Wait for connection completion using select()
|
||||
fd_set write_fds;
|
||||
struct timeval timeout;
|
||||
|
||||
FD_ZERO(&write_fds);
|
||||
FD_SET(sockfd, &write_fds);
|
||||
|
||||
timeout.tv_sec = timeout_sec;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
res = select(sockfd + 1, NULL, &write_fds, NULL, &timeout);
|
||||
|
||||
if (res > 0)
|
||||
{
|
||||
// Check if connection succeeded or failed with an error
|
||||
int so_error;
|
||||
socklen_t len = sizeof(so_error);
|
||||
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len);
|
||||
|
||||
if (so_error == 0)
|
||||
{
|
||||
// Port is open! Clean up and return success
|
||||
close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Connected instantly (e.g., local loopback)
|
||||
close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
close(sockfd);
|
||||
return 0; // Port is closed or timed out
|
||||
}
|
||||
|
||||
int StartEzRemoteServer()
|
||||
{
|
||||
char buffer[8192];
|
||||
in_addr_t in_addr;
|
||||
in_addr_t server_addr;
|
||||
int filefd;
|
||||
int sockfd;
|
||||
ssize_t i;
|
||||
ssize_t read_return;
|
||||
struct hostent *hostent;
|
||||
struct sockaddr_in sockaddr_in;
|
||||
unsigned short server_port = 9090;
|
||||
|
||||
if (IsPortOpen("127.0.0.1", 6701, 1))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
filefd = open(SERVER_ELF_PATH, O_RDONLY);
|
||||
if (filefd == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
hostent = gethostbyname("127.0.0.1");
|
||||
if (hostent == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
in_addr = inet_addr(inet_ntoa(*(struct in_addr *)*(hostent->h_addr_list)));
|
||||
if (in_addr == (in_addr_t)-1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sockaddr_in.sin_addr.s_addr = in_addr;
|
||||
sockaddr_in.sin_family = AF_INET;
|
||||
sockaddr_in.sin_port = htons(server_port);
|
||||
|
||||
if (connect(sockfd, (struct sockaddr *)&sockaddr_in, sizeof(sockaddr_in)) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
read_return = read(filefd, buffer, 8192);
|
||||
if (read_return == 0)
|
||||
break;
|
||||
if (read_return == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (write(sockfd, buffer, read_return) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
close(filefd);
|
||||
close(sockfd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void StopEzRemoteServer()
|
||||
{
|
||||
httplib::Client tmp_client = httplib::Client("http://127.0.0.1:6701");
|
||||
tmp_client.Get("/stop");
|
||||
}
|
||||
|
||||
RemoteClient *GetRemoteClient(int site_idx)
|
||||
{
|
||||
RemoteClient *tmp_client = nullptr;
|
||||
RemoteSettings *tmp_settings = &site_settings[sites[site_idx]];
|
||||
|
||||
return GetRemoteClient(tmp_settings);
|
||||
}
|
||||
|
||||
RemoteClient *GetRemoteClient(RemoteSettings *settings)
|
||||
{
|
||||
RemoteClient *tmp_client = nullptr;
|
||||
|
||||
if (settings->type == CLIENT_TYPE_HTTP_SERVER)
|
||||
{
|
||||
if (strcmp(remote_settings->http_server_type, HTTP_SERVER_APACHE) == 0)
|
||||
tmp_client = new ApacheClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_MS_IIS) == 0)
|
||||
tmp_client = new IISClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_NGINX) == 0)
|
||||
tmp_client = new NginxClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_NPX_SERVE) == 0)
|
||||
tmp_client = new NpxServeClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_RCLONE) == 0)
|
||||
tmp_client = new RCloneClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_ARCHIVEORG) == 0)
|
||||
tmp_client = new ArchiveOrgClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_GITHUB) == 0)
|
||||
tmp_client = new GithubClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_MYRIENT) == 0)
|
||||
tmp_client = new MyrientClient();
|
||||
}
|
||||
else if (settings->type == CLIENT_TYPE_WEBDAV)
|
||||
{
|
||||
tmp_client = new WebDAVClient();
|
||||
}
|
||||
else if (settings->type == CLIENT_TYPE_SMB)
|
||||
{
|
||||
tmp_client = new SmbClient();
|
||||
}
|
||||
else if (settings->type == CLIENT_TYPE_SFTP)
|
||||
{
|
||||
tmp_client = new SFTPClient();
|
||||
}
|
||||
else if (settings->type == CLIENT_TYPE_FTP)
|
||||
{
|
||||
tmp_client = new FtpClient();
|
||||
FtpClient *ftp_client = (FtpClient *)tmp_client;
|
||||
ftp_client->SetCallbackXferFunction(FtpCallback);
|
||||
}
|
||||
else if (settings->type == CLIENT_TYPE_NFS)
|
||||
{
|
||||
tmp_client = new NfsClient();
|
||||
}
|
||||
|
||||
tmp_client->Connect(settings->server, settings->username, settings->password, false);
|
||||
|
||||
return tmp_client;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -4,6 +4,7 @@
|
||||
#include "zip_util.h"
|
||||
#include "split_file.h"
|
||||
#include "pthread.h"
|
||||
#include "config.h"
|
||||
|
||||
#define SWAP16(x) \
|
||||
((uint16_t)((((uint16_t)(x)&UINT16_C(0x00FF)) << 8) | \
|
||||
@@ -164,4 +165,11 @@ namespace INSTALLER
|
||||
void AddSplitPkgInstallData(const std::string &hash, SplitPkgInstallData *pkg_data);
|
||||
void RemoveSplitPkgInstallData(const std::string &hash);
|
||||
bool InstallSplitPkg(const std::string &path, SplitPkgInstallData* pkg_data, bool bg = false);
|
||||
}
|
||||
std::string EzRemoteServerVersion();
|
||||
int StartEzRemoteServer();
|
||||
void StopEzRemoteServer();
|
||||
std::string StoreBgInstallHostData(RemoteSettings *remote_settings, const std::string &path);
|
||||
RemoteClient *GetRemoteClient(int site_idx);
|
||||
RemoteClient *GetRemoteClient(RemoteSettings *settings);
|
||||
bool IsPortOpen(const char *ip, uint16_t port, int timeout_sec);
|
||||
}
|
||||
|
||||
+13
-1
@@ -177,6 +177,18 @@ char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = {
|
||||
"Install Via AllDebrid", // STR_ENABLE_ALLDEBRID_MSG
|
||||
"Install Via RealDebrid", // STR_ENABLE_REALDEBRID_MSG
|
||||
"Enable Disk Cache", // STR_ENABLE_DISKCACHE_DESC
|
||||
"Cannot perform operation while activity is in progress", // STR_ACTIVITY_IN_PROGRESS_MSG
|
||||
"ezRemote Direct Package Installer payload is not loaded", // STR_ETAHEN_DPI_ERROR_MSG
|
||||
"Start/Restart Server", // STR_RESTART_SERVER
|
||||
"Stop Server", // STR_STOP_SERVER
|
||||
"Warning", // STR_WARNING
|
||||
"The version of ezRemote Server payload running does not match the required version needed by ezRemote Client.", // STR_WARNING_MSG_1
|
||||
"If you are using Goldhen payload loader, then update the elf that comes with ezRemoteClient package.", // STR_WARNING_MSG_2
|
||||
"You may goto the Global Settings and restart ezRemote Server with the version that came packaged.", // STR_WARNING_MSG_3
|
||||
"Enable background download", // STR_ENABLE_BG_DOWNLOAD
|
||||
"Minimum background file size (bytes)", // STR_BG_DOWNLOAD_MIN_SIZE
|
||||
"Background Download Progress", // STR_BG_DOWNLOAD_PROGRESS
|
||||
"Show Background Download Progress", // STR_SHOW_BG_DOWNLOAD_PROGRESS
|
||||
};
|
||||
|
||||
bool needs_extended_font = false;
|
||||
@@ -297,4 +309,4 @@ namespace Lang
|
||||
sscanf(last_site, "%[^ ] %d", buf, &num);
|
||||
sprintf(display_site, "%s %d", lang_strings[STR_SITE], num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
-3
@@ -170,7 +170,19 @@
|
||||
FUNC(STR_ENABLE_DISK_CACHE) \
|
||||
FUNC(STR_ENABLE_ALLDEBRID_MSG) \
|
||||
FUNC(STR_ENABLE_REALDEBRID_MSG) \
|
||||
FUNC(STR_ENABLE_DISKCACHE_DESC)
|
||||
FUNC(STR_ENABLE_DISKCACHE_DESC) \
|
||||
FUNC(STR_ACTIVITY_IN_PROGRESS_MSG) \
|
||||
FUNC(STR_DPI_NOT_STARTED_ERROR_MSG) \
|
||||
FUNC(STR_RESTART_SERVER) \
|
||||
FUNC(STR_STOP_SERVER) \
|
||||
FUNC(STR_WARNING) \
|
||||
FUNC(STR_WARNING_MSG_1) \
|
||||
FUNC(STR_WARNING_MSG_2) \
|
||||
FUNC(STR_WARNING_MSG_3) \
|
||||
FUNC(STR_ENABLE_BG_DOWNLOAD) \
|
||||
FUNC(STR_BG_DOWNLOAD_MIN_SIZE) \
|
||||
FUNC(STR_BG_DOWNLOAD_PROGRESS) \
|
||||
FUNC(STR_SHOW_BG_DOWNLOAD_PROGRESS) \
|
||||
|
||||
#define GET_VALUE(x) x,
|
||||
#define GET_STRING(x) #x,
|
||||
@@ -180,7 +192,7 @@ enum
|
||||
FOREACH_STR(GET_VALUE)
|
||||
};
|
||||
|
||||
#define LANG_STRINGS_NUM 167
|
||||
#define LANG_STRINGS_NUM 179
|
||||
#define LANG_ID_SIZE 64
|
||||
#define LANG_STR_SIZE 384
|
||||
extern char lang_identifiers[LANG_STRINGS_NUM][LANG_ID_SIZE];
|
||||
@@ -192,4 +204,4 @@ namespace Lang
|
||||
void SetTranslation(int32_t lang_idx);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+7
-2
@@ -294,13 +294,12 @@ int main()
|
||||
if (sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_AUDIOOUT) < 0 || sceAudioOutInit() != 0) return 0;
|
||||
if (sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_NET) < 0 || sceNetInit() != 0) return 0;
|
||||
|
||||
sceNetPoolCreate("simple", NET_HEAP_SIZE, 0);
|
||||
sceNetPoolCreate("ezremote_client", NET_HEAP_SIZE, 0);
|
||||
|
||||
if (INSTALLER::Init() < 0)
|
||||
return 0;
|
||||
|
||||
CONFIG::LoadConfig();
|
||||
HttpServer::Start();
|
||||
|
||||
// Create a window context
|
||||
window = SDL_CreateWindow("main", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, FRAME_WIDTH, FRAME_HEIGHT, 0);
|
||||
@@ -329,6 +328,12 @@ int main()
|
||||
|
||||
atexit(terminate);
|
||||
|
||||
HttpServer::Start();
|
||||
if (INSTALLER::StartEzRemoteServer() < 0)
|
||||
{
|
||||
Util::Notify("Cloud not load ezRemote Server. It is needed for background install and download. Please ensure Goldhen payload server is enabled");
|
||||
}
|
||||
|
||||
GUI::RenderLoop(renderer);
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
|
||||
+22
-15
@@ -45,25 +45,32 @@ static void build_iovec(struct iovec** iov, int* iovlen, const char* name, const
|
||||
|
||||
int mount_large_fs(const char* device, const char* mountpoint, const char* fstype, const char* mode, unsigned int flags)
|
||||
{
|
||||
struct iovec* iov = NULL;
|
||||
int iovlen = 0;
|
||||
struct iovec* iov = NULL;
|
||||
int iovlen = 0;
|
||||
int ret;
|
||||
|
||||
unmount(mountpoint, 0);
|
||||
build_iovec(&iov, &iovlen, "fstype", fstype, -1);
|
||||
build_iovec(&iov, &iovlen, "fspath", mountpoint, -1);
|
||||
build_iovec(&iov, &iovlen, "from", device, -1);
|
||||
build_iovec(&iov, &iovlen, "large", "yes", -1);
|
||||
build_iovec(&iov, &iovlen, "timezone", "static", -1);
|
||||
build_iovec(&iov, &iovlen, "async", "", -1);
|
||||
build_iovec(&iov, &iovlen, "ignoreacl", "", -1);
|
||||
|
||||
build_iovec(&iov, &iovlen, "fstype", fstype, -1);
|
||||
build_iovec(&iov, &iovlen, "fspath", mountpoint, -1);
|
||||
build_iovec(&iov, &iovlen, "from", device, -1);
|
||||
build_iovec(&iov, &iovlen, "large", "yes", -1);
|
||||
build_iovec(&iov, &iovlen, "timezone", "static", -1);
|
||||
build_iovec(&iov, &iovlen, "async", "", -1);
|
||||
build_iovec(&iov, &iovlen, "ignoreacl", "", -1);
|
||||
if (mode) {
|
||||
build_iovec(&iov, &iovlen, "dirmask", mode, -1);
|
||||
build_iovec(&iov, &iovlen, "mask", mode, -1);
|
||||
}
|
||||
|
||||
if (mode) {
|
||||
build_iovec(&iov, &iovlen, "dirmask", mode, -1);
|
||||
build_iovec(&iov, &iovlen, "mask", mode, -1);
|
||||
}
|
||||
ret = nmount(iov, iovlen, flags);
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
}
|
||||
else {
|
||||
}
|
||||
|
||||
return nmount(iov, iovlen, flags);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Variables for (un)jailbreaking
|
||||
|
||||
+216
-44
@@ -47,6 +47,7 @@ static RemoteDownloadData remote_data[100];
|
||||
|
||||
Server *svr;
|
||||
int http_server_port = 8080;
|
||||
int http_int_server_port = 6701;
|
||||
char compressed_file_path[1024];
|
||||
bool web_server_enabled = false;
|
||||
|
||||
@@ -324,7 +325,7 @@ namespace HttpServer
|
||||
}); });
|
||||
|
||||
svr->Post("/__local__/list", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
const char *path;
|
||||
bool onlyFolders = false;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
@@ -369,11 +370,12 @@ namespace HttpServer
|
||||
json_object *results = json_object_new_object();
|
||||
json_object_object_add(results, "result", json_files);
|
||||
const char *results_str = json_object_to_json_string(results);
|
||||
|
||||
res.status = 200;
|
||||
res.set_content(results_str, strlen(results_str), "application/json"); });
|
||||
|
||||
svr->Post("/__local__/rename", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
const char *item;
|
||||
const char *newItemPath;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
@@ -398,7 +400,13 @@ namespace HttpServer
|
||||
return; });
|
||||
|
||||
svr->Post("/__local__/move", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
if (activity_inprogess)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_ACTIVITY_IN_PROGRESS_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
const json_object *items;
|
||||
const char *newPath;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
@@ -452,7 +460,13 @@ namespace HttpServer
|
||||
success(res); });
|
||||
|
||||
svr->Post("/__local__/copy", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
if (activity_inprogess)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_ACTIVITY_IN_PROGRESS_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
const json_object *items;
|
||||
const char *newPath;
|
||||
const char *singleFilename;
|
||||
@@ -526,7 +540,13 @@ namespace HttpServer
|
||||
success(res); });
|
||||
|
||||
svr->Post("/__local__/remove", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
if (activity_inprogess)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_ACTIVITY_IN_PROGRESS_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
json_object *items;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
if (jobj != nullptr)
|
||||
@@ -565,7 +585,13 @@ namespace HttpServer
|
||||
success(res); });
|
||||
|
||||
svr->Post("/__local__/install", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
if (activity_inprogess)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_ACTIVITY_IN_PROGRESS_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
json_object *items;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
if (jobj != nullptr)
|
||||
@@ -598,10 +624,11 @@ namespace HttpServer
|
||||
failed(res, 200, error_msg);
|
||||
}
|
||||
else
|
||||
success(res); });
|
||||
success(res);
|
||||
});
|
||||
|
||||
svr->Post("/__local__/edit", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
const char *item;
|
||||
const char *content;
|
||||
size_t content_len;
|
||||
@@ -634,7 +661,7 @@ namespace HttpServer
|
||||
success(res); });
|
||||
|
||||
svr->Post("/__local__/getContent", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
const char *item;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
if (jobj != nullptr)
|
||||
@@ -656,11 +683,13 @@ namespace HttpServer
|
||||
json_object *result = json_object_new_object();
|
||||
json_object_object_add(result, "result", json_object_new_string(content.data()));
|
||||
const char *result_str = json_object_to_json_string(result);
|
||||
|
||||
res.status = 200;
|
||||
res.set_content(result_str, strlen(result_str), "application/json"); });
|
||||
res.set_content(result_str, strlen(result_str), "application/json");
|
||||
});
|
||||
|
||||
svr->Post("/__local__/createFolder", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
const char *newPath;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
if (jobj != nullptr)
|
||||
@@ -679,13 +708,22 @@ namespace HttpServer
|
||||
}
|
||||
|
||||
FS::MkDirs(newPath);
|
||||
success(res); });
|
||||
success(res);
|
||||
});
|
||||
|
||||
svr->Post("/__local__/permission", [&](const Request &req, Response &res)
|
||||
{ failed(res, 200, "Operation not supported"); });
|
||||
{
|
||||
failed(res, 200, "Operation not supported");
|
||||
});
|
||||
|
||||
svr->Post("/__local__/compress", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
if (activity_inprogess)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_ACTIVITY_IN_PROGRESS_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
json_object *items;
|
||||
const char* destination;
|
||||
const char* compressedFilename;
|
||||
@@ -738,7 +776,13 @@ namespace HttpServer
|
||||
} });
|
||||
|
||||
svr->Post("/__local__/extract", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
if (activity_inprogess)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_ACTIVITY_IN_PROGRESS_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* item;
|
||||
const char* destination;
|
||||
const char* folderName;
|
||||
@@ -777,7 +821,7 @@ namespace HttpServer
|
||||
success(res); });
|
||||
|
||||
svr->Get("/__local__/uploadResumeSize", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
std::string destination = req.get_param_value("destination");
|
||||
std::string filename = req.get_param_value("filename");
|
||||
std::string file_path = destination + "/" + filename;
|
||||
@@ -789,7 +833,7 @@ namespace HttpServer
|
||||
res.set_content(result_str.c_str(), result_str.length(), "application/json"); });
|
||||
|
||||
svr->Post("/__local__/upload", [&](const Request &req, Response &res, const ContentReader &content_reader)
|
||||
{
|
||||
{
|
||||
MultipartFormDataItems items;
|
||||
std::string destination;
|
||||
size_t chunk_size = 0;
|
||||
@@ -859,7 +903,7 @@ namespace HttpServer
|
||||
|
||||
// Download multiple files as ZIP
|
||||
svr->Get("/__local__/downloadMultiple", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
if (req.get_param_value_count("items") == 0 || req.get_param_value_count("toFilename") == 0)
|
||||
{
|
||||
failed(res, 200, "Required items and toFilename parameter missing");
|
||||
@@ -917,7 +961,7 @@ namespace HttpServer
|
||||
|
||||
// Download single file
|
||||
svr->Get("/__local__/downloadFile", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
std::string path = req.get_param_value("path", 0);
|
||||
if (path.empty())
|
||||
{
|
||||
@@ -950,7 +994,7 @@ namespace HttpServer
|
||||
}); });
|
||||
|
||||
svr->Get("/google_auth", [](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
std::string auth_code = req.get_param_value("code");
|
||||
Client client(GOOGLE_OAUTH_HOST);
|
||||
client.set_follow_location(true);
|
||||
@@ -960,7 +1004,7 @@ namespace HttpServer
|
||||
std::string post_data = std::string("code=") + auth_code +
|
||||
"&client_id=" + gg_app.client_id +
|
||||
"&client_secret=" + gg_app.client_secret +
|
||||
"&redirect_uri=http%3A//localhost%3A" + std::to_string(http_server_port) + "/google_auth"
|
||||
"&redirect_uri=http%3A//127.0.0.1%3A" + std::to_string(http_server_port) + "/google_auth"
|
||||
"&grant_type=authorization_code";
|
||||
|
||||
if (auto result = client.Post(url, post_data.c_str(), post_data.length(), "application/x-www-form-urlencoded"))
|
||||
@@ -996,10 +1040,11 @@ namespace HttpServer
|
||||
}
|
||||
login_state = -1;
|
||||
std::string str = std::string(lang_strings[STR_FAIL_GET_TOKEN_MSG]) + " Google";
|
||||
res.set_content(str.c_str(), "text/plain"); });
|
||||
res.set_content(str.c_str(), "text/plain");
|
||||
});
|
||||
|
||||
svr->Get("/rmt_inst/Site (\\d+)(/)(.*)", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
RemoteClient *tmp_client = nullptr;
|
||||
RemoteSettings *tmp_settings;
|
||||
auto site_idx = std::stoi(req.matches[1])-1;
|
||||
@@ -1120,7 +1165,7 @@ namespace HttpServer
|
||||
} });
|
||||
|
||||
svr->Get("/archive_inst/(.*)", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
RemoteClient *tmp_client;
|
||||
RemoteSettings *tmp_settings;
|
||||
std::string hash = req.matches[1];
|
||||
@@ -1175,7 +1220,8 @@ namespace HttpServer
|
||||
[](bool success) {
|
||||
return true;
|
||||
});
|
||||
} });
|
||||
}
|
||||
});
|
||||
|
||||
svr->Get("/split_inst/(.*)", [&](const Request &req, Response &res)
|
||||
{
|
||||
@@ -1240,12 +1286,13 @@ namespace HttpServer
|
||||
} });
|
||||
|
||||
svr->Post("/__local__/install_url", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
std::string url;
|
||||
const char *url_param;
|
||||
bool use_alldebrid = false;
|
||||
bool use_realdebrid = false;
|
||||
bool use_disk_cache = false;
|
||||
bool enable_rpi = false;
|
||||
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
if (jobj != nullptr)
|
||||
@@ -1254,6 +1301,7 @@ namespace HttpServer
|
||||
use_alldebrid = json_object_get_boolean(json_object_object_get(jobj, "use_alldebrid"));
|
||||
use_realdebrid = json_object_get_boolean(json_object_object_get(jobj, "use_realdebrid"));
|
||||
use_disk_cache = json_object_get_boolean(json_object_object_get(jobj, "use_disk_cache"));
|
||||
enable_rpi = json_object_get_boolean(json_object_object_get(jobj, "enable_rpi"));
|
||||
|
||||
if (url_param == nullptr)
|
||||
{
|
||||
@@ -1322,26 +1370,47 @@ namespace HttpServer
|
||||
}
|
||||
baseclient->Head(path, &header, sizeof(pkg_header));
|
||||
|
||||
FileHost::AddCacheDownloadUrl(hash, download_url);
|
||||
std::string title = INSTALLER::GetRemotePkgTitle(baseclient, path, &header);
|
||||
|
||||
if (BE32(header.pkg_magic) == 0x7F434E54)
|
||||
{
|
||||
bytes_to_download = header.pkg_content_size;
|
||||
FileHost::AddCacheDownloadUrl(hash, download_url);
|
||||
std::string title = INSTALLER::GetRemotePkgTitle(baseclient, path, &header);
|
||||
|
||||
if (!use_disk_cache)
|
||||
if (enable_rpi && !use_disk_cache)
|
||||
{
|
||||
std::string remote_install_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst/Site%2099/" + hash;
|
||||
int rc = INSTALLER::InstallRemotePkg(remote_install_url, &header, title, false);
|
||||
if (rc == 0)
|
||||
json_object *history_item_obj = json_object_new_object();
|
||||
json_object_object_add(history_item_obj, "hash", json_object_new_string(hash.c_str()));
|
||||
json_object_object_add(history_item_obj, "url", json_object_new_string(host.c_str()));
|
||||
json_object_object_add(history_item_obj, "path", json_object_new_string(path.c_str()));
|
||||
json_object_object_add(history_item_obj, "username", json_object_new_string(""));
|
||||
json_object_object_add(history_item_obj, "password", json_object_new_string(""));
|
||||
json_object_object_add(history_item_obj, "type", json_object_new_int(CLIENT_TYPE_FILEHOST));
|
||||
|
||||
const char *params_str = json_object_to_json_string(history_item_obj);
|
||||
|
||||
Client tmp_client = Client(std::string("http://127.0.0.1:") + std::to_string(http_int_server_port));
|
||||
|
||||
if (auto resp = tmp_client.Post("/store_bg_install_data", params_str, strlen(params_str), "application/json"))
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_FAIL_INSTALL_FROM_URL_MSG]);
|
||||
activity_inprogess = false;
|
||||
file_transfering = false;
|
||||
Windows::SetModalMode(false);
|
||||
return;
|
||||
if (HTTP_SUCCESS(resp->status))
|
||||
{
|
||||
std::string remote_install_url = std::string("http://localhost:") + std::to_string(http_int_server_port) + "/bg_install/" + hash;
|
||||
int rc = INSTALLER::InstallRemotePkg(remote_install_url, &header, title);
|
||||
activity_inprogess = false;
|
||||
file_transfering = false;
|
||||
Windows::SetModalMode(false);
|
||||
sleep(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
failed(res, 200, "Could not save host data for background install");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
failed(res, 200, "Could not save host data for background install");
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (enable_rpi && use_disk_cache)
|
||||
{
|
||||
SplitPkgInstallData *install_data = (SplitPkgInstallData*) malloc(sizeof(SplitPkgInstallData));
|
||||
memset(install_data, 0, sizeof(SplitPkgInstallData));
|
||||
@@ -1410,17 +1479,120 @@ namespace HttpServer
|
||||
return;
|
||||
}
|
||||
}
|
||||
success(res); });
|
||||
success(res);
|
||||
|
||||
});
|
||||
|
||||
svr->Post("/__local__/download_url", [&](const Request &req, Response &res)
|
||||
{
|
||||
std::string url;
|
||||
std::string dest;
|
||||
const char *url_param;
|
||||
const char *dest_param;
|
||||
bool use_alldebrid = false;
|
||||
bool use_realdebrid = false;
|
||||
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
if (jobj != nullptr)
|
||||
{
|
||||
url_param = json_object_get_string(json_object_object_get(jobj, "url"));
|
||||
dest_param = json_object_get_string(json_object_object_get(jobj, "dest"));
|
||||
use_alldebrid = json_object_get_boolean(json_object_object_get(jobj, "use_alldebrid"));
|
||||
use_realdebrid = json_object_get_boolean(json_object_object_get(jobj, "use_realdebrid"));
|
||||
|
||||
if (url_param == nullptr || dest_param == nullptr)
|
||||
{
|
||||
bad_request(res, "Required url, dest parameter missing");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bad_request(res, "Invalid payload");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((use_alldebrid && strlen(alldebrid_api_key) == 0) || (use_realdebrid && strlen(realdebrid_api_key) == 0))
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_ALLDEBRID_API_KEY_MISSING_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
url = std::string(url_param);
|
||||
FileHost *filehost = FileHost::getFileHost(url, use_alldebrid, use_realdebrid);
|
||||
|
||||
if (!filehost->IsValidUrl())
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_INVALID_URL]);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string download_url = filehost->GetDownloadUrl();
|
||||
if (download_url.empty())
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_CANT_EXTRACT_URL_MSG]);
|
||||
return;
|
||||
}
|
||||
delete(filehost);
|
||||
|
||||
size_t scheme_pos = download_url.find("://");
|
||||
size_t root_pos = download_url.find("/", scheme_pos + 3);
|
||||
std::string host = download_url.substr(0, root_pos);
|
||||
std::string path = download_url.substr(root_pos);
|
||||
int64_t file_size;
|
||||
|
||||
RemoteClient *baseclient = new BaseClient();
|
||||
baseclient->Connect(host, "", "");
|
||||
baseclient->Size(path, &file_size);
|
||||
delete baseclient;
|
||||
|
||||
OrbisTick tick;
|
||||
sceRtcGetCurrentTick(&tick);
|
||||
json_object *params = json_object_new_object();
|
||||
json_object_object_add(params, "type", json_object_new_int(CLIENT_TYPE_FILEHOST));
|
||||
json_object_object_add(params, "url", json_object_new_string(host.c_str()));
|
||||
json_object_object_add(params, "username", json_object_new_string(""));
|
||||
json_object_object_add(params, "password", json_object_new_string(""));
|
||||
json_object_object_add(params, "src_path", json_object_new_string(path.c_str()));
|
||||
json_object_object_add(params, "dest_path", json_object_new_string(dest_param));
|
||||
json_object_object_add(params, "size", json_object_new_uint64(file_size));
|
||||
json_object_object_add(params, "id", json_object_new_uint64(tick.mytick));
|
||||
|
||||
const char *params_str = json_object_to_json_string(params);
|
||||
httplib::Client tmp_client = httplib::Client(std::string("http://127.0.0.1:") + std::to_string(http_int_server_port));
|
||||
|
||||
std::string download_req_url = + "/download_url";
|
||||
if (auto resp = tmp_client.Post(download_req_url, params_str, strlen(params_str), "application/json"))
|
||||
{
|
||||
if (HTTP_SUCCESS(resp->status))
|
||||
{
|
||||
Util::Notify("%s queued for download", path.c_str());
|
||||
success(res);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Util::Notify("Failed to queue %s for download in background", path.c_str());
|
||||
failed(res, 200, "Failed to download");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
failed(res, 200, "Failed to download");
|
||||
});
|
||||
|
||||
svr->Get("/stop", [&](const Request & /*req*/, Response & /*res*/)
|
||||
{ svr->stop(); });
|
||||
{
|
||||
svr->stop();
|
||||
});
|
||||
|
||||
svr->set_error_handler([](const Request & /*req*/, Response &res)
|
||||
{
|
||||
{
|
||||
const char *fmt = "<p>Error Status: <span style='color:red;'>%d</span></p>";
|
||||
char buf[BUFSIZ];
|
||||
snprintf(buf, sizeof(buf), fmt, res.status);
|
||||
res.set_content(buf, "text/html"); });
|
||||
res.set_content(buf, "text/html");
|
||||
});
|
||||
|
||||
/*
|
||||
svr->set_logger([](const Request &req, const Response &res)
|
||||
|
||||
@@ -8,6 +8,7 @@ extern Server *svr;
|
||||
|
||||
static pthread_t http_server_thid;
|
||||
extern int http_server_port;
|
||||
extern int http_int_server_port;
|
||||
extern char compressed_file_path[];
|
||||
extern bool web_server_enabled;
|
||||
|
||||
@@ -18,4 +19,4 @@ namespace HttpServer
|
||||
void Stop();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+54
-15
@@ -24,7 +24,7 @@ SplitFile::~SplitFile()
|
||||
fclose(this->file_blocks[i]->fd);
|
||||
}
|
||||
remove(this->file_blocks[i]->block_file.c_str());
|
||||
free(this->file_blocks[i]);
|
||||
delete this->file_blocks[i];
|
||||
}
|
||||
}
|
||||
sem_destroy(&this->block_ready);
|
||||
@@ -33,8 +33,6 @@ SplitFile::~SplitFile()
|
||||
int SplitFile::Open()
|
||||
{
|
||||
this->block_in_progress = NewBlock();
|
||||
this->block_in_progress->fd = fopen(block_in_progress->block_file.c_str(), "w");
|
||||
|
||||
return (block_in_progress->fd == nullptr);
|
||||
}
|
||||
|
||||
@@ -56,9 +54,16 @@ size_t SplitFile::Read(char *buf, size_t buf_size, size_t offset)
|
||||
while ((block_num >= this->file_blocks.size() && !this->complete) ||
|
||||
(block_num < this->file_blocks.size() && this->file_blocks[block_num]->status == BLOCK_STATUS_NOT_EXISTS))
|
||||
{
|
||||
sem_wait(&this->block_ready);
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_sec += 2;
|
||||
sem_timedwait(&this->block_ready, &ts);
|
||||
}
|
||||
|
||||
// If complete and block_num is past the end, the requested offset is beyond EOF
|
||||
if (block_num >= this->file_blocks.size())
|
||||
return 0;
|
||||
|
||||
block = this->file_blocks[block_num];
|
||||
if (block->status == BLOCK_STATUS_DELETED)
|
||||
{
|
||||
@@ -118,19 +123,26 @@ size_t SplitFile::Read(char *buf, size_t buf_size, size_t offset)
|
||||
block_offset = 0;
|
||||
|
||||
while ((block_num > this->file_blocks.size() - 1 && !this->complete) ||
|
||||
this->file_blocks[block_num]->status == BLOCK_STATUS_NOT_EXISTS)
|
||||
(block_num < this->file_blocks.size() && this->file_blocks[block_num]->status == BLOCK_STATUS_NOT_EXISTS))
|
||||
{
|
||||
sem_wait(&this->block_ready);
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_sec += 2;
|
||||
sem_timedwait(&this->block_ready, &ts);
|
||||
}
|
||||
|
||||
// If complete and block_num is past the end, no more data
|
||||
if (block_num >= this->file_blocks.size())
|
||||
break;
|
||||
|
||||
block = this->file_blocks[block_num];
|
||||
}
|
||||
|
||||
// delete blocks before the first read offset block. Assumuption, that reads are always
|
||||
// forward and won't read previously already read blocks. For safety, keeping only current block and 2 previous blocks
|
||||
for (int j=0; j < first_block_num - 2; j++)
|
||||
for (int j=0; j < first_block_num - 13; j++)
|
||||
{
|
||||
if (this->file_blocks[j]->status == BLOCK_STATUS_CREATED)
|
||||
if (this->file_blocks[j] != nullptr && this->file_blocks[j]->status == BLOCK_STATUS_CREATED)
|
||||
{
|
||||
if (this->file_blocks[j]->fd != nullptr)
|
||||
{
|
||||
@@ -139,22 +151,28 @@ size_t SplitFile::Read(char *buf, size_t buf_size, size_t offset)
|
||||
}
|
||||
this->file_blocks[j]->status = BLOCK_STATUS_DELETED;
|
||||
remove(this->file_blocks[j]->block_file.c_str());
|
||||
delete (this->file_blocks[j]);
|
||||
this->file_blocks[j] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
this->read_offset = offset + total_bytes_read;
|
||||
return total_bytes_read;
|
||||
}
|
||||
|
||||
size_t SplitFile::Write(char *buf, size_t buf_size)
|
||||
ssize_t SplitFile::Write(char *buf, size_t buf_size)
|
||||
{
|
||||
size_t bytes_written;
|
||||
size_t bytes_written = 0;
|
||||
size_t block_space_remaining;
|
||||
size_t bytes_to_write;
|
||||
|
||||
char *p = buf;
|
||||
size_t total_bytes_written = 0;
|
||||
ssize_t total_bytes_written = 0;
|
||||
size_t remaining_to_write = buf_size;
|
||||
|
||||
if (this->IsClosed())
|
||||
return -1;
|
||||
|
||||
while (remaining_to_write > 0 && !this->complete)
|
||||
{
|
||||
block_space_remaining = this->block_size - block_in_progress->size;
|
||||
@@ -186,6 +204,7 @@ size_t SplitFile::Write(char *buf, size_t buf_size)
|
||||
block_in_progress = NewBlock();
|
||||
}
|
||||
}
|
||||
this->write_offset += total_bytes_written;
|
||||
|
||||
return total_bytes_written;
|
||||
}
|
||||
@@ -195,6 +214,8 @@ int SplitFile::Close()
|
||||
if (this->complete)
|
||||
return 0;
|
||||
|
||||
this->complete = true;
|
||||
|
||||
if (block_in_progress->fd != nullptr)
|
||||
{
|
||||
fflush(block_in_progress->fd);
|
||||
@@ -204,9 +225,28 @@ int SplitFile::Close()
|
||||
block_in_progress->status = BLOCK_STATUS_CREATED;
|
||||
block_in_progress->is_last = true;
|
||||
this->file_blocks.push_back(block_in_progress);
|
||||
this->complete = true;
|
||||
sem_post(&this->block_ready);
|
||||
|
||||
// Wait until file is fully read, if file isn't full read
|
||||
// in 5 mins then go ahead and delete all file chunks
|
||||
int retries = 10;
|
||||
size_t prev_read_offset = 0;
|
||||
while (this->read_offset != this->write_offset && retries > 0)
|
||||
{
|
||||
if (prev_read_offset == this->read_offset)
|
||||
retries--;
|
||||
prev_read_offset = this->read_offset;
|
||||
sceKernelUsleep(1000000);
|
||||
}
|
||||
sceKernelUsleep(5000000);
|
||||
|
||||
for (size_t j = 0; j < this->file_blocks.size(); j++)
|
||||
{
|
||||
if (this->file_blocks[j] != nullptr && this->file_blocks[j]->status == BLOCK_STATUS_CREATED)
|
||||
{
|
||||
remove(this->file_blocks[j]->block_file.c_str());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -217,8 +257,7 @@ bool SplitFile::IsClosed()
|
||||
|
||||
FileBlock *SplitFile::NewBlock()
|
||||
{
|
||||
FileBlock *block = (FileBlock *)malloc(sizeof(FileBlock));
|
||||
memset(block, 0, sizeof(FileBlock));
|
||||
FileBlock *block = new FileBlock{};
|
||||
|
||||
block->is_last = false;
|
||||
block->size = 0;
|
||||
@@ -226,4 +265,4 @@ FileBlock *SplitFile::NewBlock()
|
||||
block->fd = fopen(block->block_file.c_str(), "w");
|
||||
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -4,6 +4,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <semaphore.h>
|
||||
#include <pthread.h>
|
||||
|
||||
enum FileBlockStatus
|
||||
@@ -28,15 +29,16 @@ public:
|
||||
SplitFile(const std::string& path, size_t block_size);
|
||||
~SplitFile();
|
||||
size_t Read(char* buf, size_t buf_size, size_t offset);
|
||||
size_t Write(char* buf, size_t buf_size);
|
||||
ssize_t Write(char* buf, size_t buf_size);
|
||||
int Open();
|
||||
int Close();
|
||||
bool IsClosed();
|
||||
|
||||
private:
|
||||
std::vector<FileBlock*> file_blocks;
|
||||
size_t write_offset;
|
||||
size_t write_offset = 0;
|
||||
size_t block_size;
|
||||
size_t read_offset;
|
||||
std::string path;
|
||||
int write_error;
|
||||
bool complete;
|
||||
@@ -46,4 +48,4 @@ private:
|
||||
FileBlock *NewBlock();
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -88,6 +88,13 @@ namespace Util
|
||||
return out;
|
||||
}
|
||||
|
||||
static uint64_t GetTick()
|
||||
{
|
||||
static struct timeval tick;
|
||||
gettimeofday(&tick, NULL);
|
||||
return tick.tv_sec * 1000000 + tick.tv_usec;
|
||||
}
|
||||
|
||||
static inline void Notify(const char *fmt, ...)
|
||||
{
|
||||
OrbisNotificationRequest request;
|
||||
|
||||
+253
-3
@@ -41,9 +41,13 @@ static ime_callback_t ime_cancelled = nullptr;
|
||||
static std::vector<std::string> *ime_multi_field;
|
||||
static char *ime_single_field;
|
||||
static int ime_field_size;
|
||||
static bool show_ezremote_server_warning;
|
||||
|
||||
static char txt_http_server_port[6];
|
||||
static char txt_bg_download_size[32];
|
||||
|
||||
bool is_server_started = false;
|
||||
bool ezremote_server_version_match = true;
|
||||
bool handle_updates = false;
|
||||
int64_t bytes_transfered;
|
||||
int64_t bytes_to_download;
|
||||
@@ -55,6 +59,7 @@ std::set<DirEntry> multi_selected_local_files;
|
||||
std::set<DirEntry> multi_selected_remote_files;
|
||||
std::vector<DirEntry> local_paste_files;
|
||||
std::vector<DirEntry> remote_paste_files;
|
||||
std::vector<DownloadProgress> bg_download_progress;
|
||||
DirEntry selected_local_file;
|
||||
DirEntry selected_remote_file;
|
||||
ACTIONS selected_action;
|
||||
@@ -78,6 +83,8 @@ int favorite_url_idx = 0;
|
||||
char extract_zip_folder[256];
|
||||
char zip_file_path[384];
|
||||
bool show_settings = false;
|
||||
bool show_bg_download_progress = false;
|
||||
uint64_t refresh_bg_download_time;
|
||||
|
||||
// Editor variables
|
||||
std::vector<std::string> edit_buffer;
|
||||
@@ -124,12 +131,16 @@ namespace Windows
|
||||
sprintf(local_filter, "");
|
||||
sprintf(remote_filter, "");
|
||||
sprintf(txt_http_server_port, "%d", http_server_port);
|
||||
sprintf(txt_bg_download_size, "%lu", minimum_backgrond_file_size);
|
||||
dont_prompt_overwrite = false;
|
||||
confirm_transfer_state = -1;
|
||||
dont_prompt_overwrite_cb = false;
|
||||
overwrite_type = OVERWRITE_PROMPT;
|
||||
local_paste_files.clear();
|
||||
remote_paste_files.clear();
|
||||
std::string cur_version = INSTALLER::EzRemoteServerVersion();
|
||||
ezremote_server_version_match = cur_version.empty() || (cur_version.compare(EZREMOTE_SERVER_REQUIRED_VERSION) == 0);
|
||||
show_ezremote_server_warning = !ezremote_server_version_match;
|
||||
|
||||
Actions::RefreshLocalFiles(false);
|
||||
}
|
||||
@@ -484,6 +495,7 @@ namespace Windows
|
||||
if (ImGui::Button(ICON_FA_GEAR, ImVec2(35, 0)))
|
||||
{
|
||||
show_settings = true;
|
||||
is_server_started = !INSTALLER::EzRemoteServerVersion().empty();
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
@@ -895,6 +907,21 @@ namespace Windows
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_D) && !paused)
|
||||
{
|
||||
if (selected_browser & LOCAL_BROWSER)
|
||||
{
|
||||
selected_action = ACTION_REFRESH_LOCAL_FILES;
|
||||
}
|
||||
else if (selected_browser & REMOTE_BROWSER)
|
||||
{
|
||||
if (remoteclient != nullptr && remote_files.size() > 0)
|
||||
{
|
||||
selected_action = ACTION_REFRESH_REMOTE_FILES;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StatusPanel()
|
||||
@@ -1408,7 +1435,10 @@ namespace Windows
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 300);
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5);
|
||||
if (ImGui::Button(lang_strings[STR_CLOSE], ImVec2(100, 0)))
|
||||
|
||||
char id[128];
|
||||
sprintf(id, "%s##prodialog", lang_strings[STR_CLOSE]);
|
||||
if (ImGui::Button(id, ImVec2(100, 0)))
|
||||
{
|
||||
SetModalMode(false);
|
||||
selected_action = ACTION_NONE;
|
||||
@@ -1618,6 +1648,9 @@ namespace Windows
|
||||
|
||||
void ShowEditorDialog()
|
||||
{
|
||||
if (!paused)
|
||||
saved_selected_browser = selected_browser;
|
||||
|
||||
if (editor_inprogress)
|
||||
{
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
@@ -1752,6 +1785,140 @@ namespace Windows
|
||||
}
|
||||
}
|
||||
|
||||
void ShowWarningDialog()
|
||||
{
|
||||
if (show_ezremote_server_warning)
|
||||
{
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
(void)io;
|
||||
ImGuiStyle *style = &ImGui::GetStyle();
|
||||
ImVec4 *colors = style->Colors;
|
||||
|
||||
SetModalMode(true);
|
||||
ImGui::OpenPopup(lang_strings[STR_WARNING]);
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(600, 350));
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(720, 80), ImVec2(720, 500), NULL, NULL);
|
||||
if (ImGui::BeginPopupModal(lang_strings[STR_WARNING], NULL, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
ImVec2 cur_pos = ImGui::GetCursorPos();
|
||||
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + 700);
|
||||
ImGui::Text("%s %s %s", lang_strings[STR_WARNING_MSG_1], lang_strings[STR_WARNING_MSG_2], lang_strings[STR_WARNING_MSG_3]);
|
||||
ImGui::PopTextWrapPos();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 285);
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5);
|
||||
|
||||
char id[128];
|
||||
sprintf(id, "%s##warning", lang_strings[STR_CLOSE]);
|
||||
if (ImGui::Button(id, ImVec2(150, 0)))
|
||||
{
|
||||
show_ezremote_server_warning = false;
|
||||
SetModalMode(false);
|
||||
}
|
||||
|
||||
if (ImGui::IsWindowAppearing())
|
||||
{
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_GamepadFaceRight, false))
|
||||
{
|
||||
show_ezremote_server_warning = false;
|
||||
SetModalMode(false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShowDownloadProgressDialog()
|
||||
{
|
||||
if (show_bg_download_progress)
|
||||
{
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
(void)io;
|
||||
ImGuiStyle *style = &ImGui::GetStyle();
|
||||
ImVec4 *colors = style->Colors;
|
||||
char datetime_str[32];
|
||||
|
||||
SetModalMode(true);
|
||||
ImGui::OpenPopup(lang_strings[STR_BG_DOWNLOAD_PROGRESS]);
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(345, 320));
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(1260, 80), ImVec2(1260, 500), NULL, NULL);
|
||||
if (ImGui::BeginPopupModal(lang_strings[STR_BG_DOWNLOAD_PROGRESS], NULL, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
ImGui::Columns(4, "bg_download_progress##Columns", true);
|
||||
|
||||
for (int j = 0; j < bg_download_progress.size(); j++)
|
||||
{
|
||||
DownloadProgress item = bg_download_progress[j];
|
||||
|
||||
std::tm* ptm = std::localtime(&item.timestamp);
|
||||
// Format: YYYY-MM-DD HH:MM:SS
|
||||
std::strftime(datetime_str, sizeof(datetime_str), "%Y-%m-%d %H:%M", ptm);
|
||||
|
||||
ImGui::SetColumnWidth(-1, 220);
|
||||
ImGui::Text("%s", datetime_str);
|
||||
|
||||
ImGui::NextColumn();
|
||||
ImGui::SetColumnWidth(-1, 740);
|
||||
ImGui::Text("%s", item.path.c_str());
|
||||
|
||||
ImGui::NextColumn();
|
||||
ImGui::SetColumnWidth(-1, 150);
|
||||
ImGui::Text("%s", item.state.c_str());
|
||||
|
||||
ImGui::NextColumn();
|
||||
ImGui::SetColumnWidth(-1, 100);
|
||||
ImGui::Text("%.2f%%", (item.bytes_transfered * 1.0f/item.file_size * 1.0f)*100);
|
||||
|
||||
ImGui::NextColumn();
|
||||
ImGui::Separator();
|
||||
}
|
||||
ImGui::Columns(1);
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 485);
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5);
|
||||
|
||||
char id[128];
|
||||
sprintf(id, "%s##bg_dl_progress", lang_strings[STR_CLOSE]);
|
||||
if (ImGui::Button(id, ImVec2(150, 0)))
|
||||
{
|
||||
show_bg_download_progress = false;
|
||||
SetModalMode(false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
if (ImGui::IsWindowAppearing())
|
||||
{
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_GamepadFaceRight, false))
|
||||
{
|
||||
show_bg_download_progress = false;
|
||||
SetModalMode(false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
|
||||
OrbisTick tick;
|
||||
sceRtcGetCurrentTick(&tick);
|
||||
uint64_t cur_time = tick.mytick;
|
||||
if (cur_time - refresh_bg_download_time > 2000000)
|
||||
{
|
||||
refresh_bg_download_time = cur_time;
|
||||
Actions::GetBackgroundDownloadProgress();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShowSettingsDialog()
|
||||
{
|
||||
if (show_settings)
|
||||
@@ -1765,7 +1932,7 @@ namespace Windows
|
||||
ImGui::OpenPopup(lang_strings[STR_SETTINGS]);
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(1050, 80));
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 80), ImVec2(850, 750), NULL, NULL);
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 80), ImVec2(850, 850), NULL, NULL);
|
||||
if (ImGui::BeginPopupModal(lang_strings[STR_SETTINGS], NULL, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
char id[192];
|
||||
@@ -1803,6 +1970,7 @@ namespace Windows
|
||||
ImGui::SetCursorPosX(805);
|
||||
ImGui::Checkbox("##auto_delete_tmp_pkg", &auto_delete_tmp_pkg);
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
|
||||
ImGui::Text("%s", lang_strings[STR_SHOW_HIDDEN_FILES]);
|
||||
ImGui::SameLine();
|
||||
@@ -1824,7 +1992,36 @@ namespace Windows
|
||||
ime_single_field = temp_folder;
|
||||
ime_field_size = 512;
|
||||
ime_callback = SingleValueImeCallback;
|
||||
Dialog::initImeDialog(lang_strings[STR_COMPRESSED_FILE_PATH], temp_folder, 255, ORBIS_TYPE_BASIC_LATIN, 1050, 80);
|
||||
Dialog::initImeDialog(lang_strings[STR_COMPRESSED_FILE_PATH], temp_folder, 255, ORBIS_TYPE_DEFAULT, 1050, 80);
|
||||
gui_mode = GUI_MODE_IME;
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
|
||||
ImGui::Text("%s", lang_strings[STR_ENABLE_BG_DOWNLOAD]);
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(805);
|
||||
ImGui::Checkbox("##enable_bg_download", &enable_background_download);
|
||||
ImGui::Separator();
|
||||
|
||||
field_size = ImGui::CalcTextSize(lang_strings[STR_BG_DOWNLOAD_MIN_SIZE]);
|
||||
width = field_size.x + 45;
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
|
||||
ImGui::Text("%s", lang_strings[STR_BG_DOWNLOAD_MIN_SIZE]);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 1.0f));
|
||||
sprintf(id, "%s##bg_download_min_size", txt_bg_download_size);
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
|
||||
if (ImGui::Button(id, ImVec2(835-width, 0)))
|
||||
{
|
||||
ResetImeCallbacks();
|
||||
ime_single_field = txt_bg_download_size;
|
||||
ime_field_size = 16;
|
||||
ime_callback = SingleValueImeCallback;
|
||||
ime_after_update = AfterMinBgDlSizeChangeCallback;
|
||||
Dialog::initImeDialog(lang_strings[STR_BG_DOWNLOAD_MIN_SIZE], txt_bg_download_size, 16, ORBIS_TYPE_NUMBER, 1050, 80);
|
||||
gui_mode = GUI_MODE_IME;
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
@@ -1860,6 +2057,7 @@ namespace Windows
|
||||
gui_mode = GUI_MODE_IME;
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
|
||||
ImGui::Text("%s", lang_strings[STR_COMPRESSED_FILE_PATH]);
|
||||
ImGui::SameLine();
|
||||
@@ -1879,6 +2077,33 @@ namespace Windows
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::Separator();
|
||||
|
||||
sprintf(id, "%s##settings", lang_strings[STR_RESTART_SERVER]);
|
||||
if (is_server_started)
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 1.0f, 0.0f, 1.0f)); // Green background
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); // Black Text
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 0.0f, 0.0f, 1.0f)); // Red background
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); // White Text
|
||||
}
|
||||
if (ImGui::Button(id, ImVec2(410, 0)))
|
||||
{
|
||||
Actions::RestartServer();
|
||||
is_server_started = !INSTALLER::EzRemoteServerVersion().empty();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
sprintf(id, "%s##settings", lang_strings[STR_STOP_SERVER]);
|
||||
if (ImGui::Button(id, ImVec2(410, 0)))
|
||||
{
|
||||
INSTALLER::StopEzRemoteServer();
|
||||
is_server_started = !INSTALLER::EzRemoteServerVersion().empty();
|
||||
}
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_ALLDEBRID]);
|
||||
ImGui::Separator();
|
||||
|
||||
@@ -1978,6 +2203,21 @@ namespace Windows
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::Separator();
|
||||
|
||||
sprintf(id, "%s##settings", lang_strings[STR_SHOW_BG_DOWNLOAD_PROGRESS]);
|
||||
if (ImGui::Button(id, ImVec2(835, 0)))
|
||||
{
|
||||
Actions::GetBackgroundDownloadProgress();
|
||||
show_bg_download_progress = true;
|
||||
show_settings = false;
|
||||
OrbisTick tick;
|
||||
sceRtcGetCurrentTick(&tick);
|
||||
refresh_bg_download_time = tick.mytick;
|
||||
SetModalMode(false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
sprintf(id, "%s##settings", lang_strings[STR_CLOSE]);
|
||||
if (ImGui::Button(id, ImVec2(835, 0)))
|
||||
{
|
||||
@@ -2141,6 +2381,8 @@ namespace Windows
|
||||
ShowSettingsDialog();
|
||||
ShowImageDialog();
|
||||
ShowPackageInfoDialog();
|
||||
ShowWarningDialog();
|
||||
ShowDownloadProgressDialog();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
@@ -2662,6 +2904,14 @@ namespace Windows
|
||||
}
|
||||
}
|
||||
|
||||
void AfterMinBgDlSizeChangeCallback(int ime_result)
|
||||
{
|
||||
if (ime_result == IME_DIALOG_RESULT_FINISHED)
|
||||
{
|
||||
minimum_backgrond_file_size = atol(txt_bg_download_size);
|
||||
}
|
||||
}
|
||||
|
||||
void AfterEditorCallback(int ime_result)
|
||||
{
|
||||
if (ime_result == IME_DIALOG_RESULT_FINISHED)
|
||||
|
||||
@@ -24,6 +24,7 @@ extern std::set<DirEntry> multi_selected_local_files;
|
||||
extern std::set<DirEntry> multi_selected_remote_files;
|
||||
extern std::vector<DirEntry> local_paste_files;
|
||||
extern std::vector<DirEntry> remote_paste_files;
|
||||
extern std::vector<DownloadProgress> bg_download_progress;
|
||||
extern ACTIONS paste_action;
|
||||
extern DirEntry selected_local_file;
|
||||
extern DirEntry selected_remote_file;
|
||||
@@ -44,6 +45,8 @@ extern bool file_transfering;
|
||||
extern char extract_zip_folder[];
|
||||
extern char zip_file_path[];
|
||||
extern std::vector<std::string> edit_buffer;
|
||||
extern bool is_server_started;
|
||||
extern bool ezremote_server_version_match;
|
||||
|
||||
static ImVector<ImRect> s_GroupPanelLabelStack;
|
||||
|
||||
@@ -212,6 +215,7 @@ namespace Windows
|
||||
void AfterZipFileCallback(int ime_result);
|
||||
void AferServerChangeCallback(int ime_result);
|
||||
void AfterHttpPortChangeCallback(int ime_result);
|
||||
void AfterMinBgDlSizeChangeCallback(int ime_result);
|
||||
void AfterEditorCallback(int ime_result);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user