Compare commits

...

33 Commits

Author SHA1 Message Date
cy33hc 28c046d5a5 disable debug 2026-05-31 11:26:09 -07:00
cy33hc 99099a6b82 update readme 2026-05-31 10:09:58 -07:00
cy33hc c30a8ab70e update message 2026-05-31 02:30:43 -07:00
cy33hc 046083ccf6 bump version 2026-05-31 02:25:54 -07:00
cy33hc 6d36073413 handle proper loading of ezremote server payload 2026-05-31 02:24:31 -07:00
cy33hc b831dd7db4 update code to handle background install and download of file from file hosts 2026-05-30 21:34:56 -07:00
cy33hc 3ba286a016 add ability to use R2 button to refresh files 2026-05-30 19:34:11 -07:00
cy33hc 7395056a75 add bg download function 2026-05-30 13:49:31 -07:00
cy33hc 81a5143f2f first working bg install 2026-05-30 04:08:00 -07:00
cy33hc 432c0020be commit what I have so far 2026-05-19 23:07:59 -07:00
cy33hc fd1b9e5d96 add windows changes 2026-05-18 20:08:44 -07:00
cy33hc a3741a0a6c initial bg install 2026-05-18 20:03:50 -07:00
cy33hc ce71f5af9a fix version 2026-05-02 22:24:18 -07:00
cy33hc cd42afcb6b fix random crash when installing with disk cache or pkgs in zip files 2026-05-02 22:22:20 -07:00
cy33hc b6eaef82fd fix edit files from Edit menu 2026-03-29 17:15:02 -07:00
cy33hc 9d0790fccc minor improvement to cut/paste files 2026-03-27 01:27:02 -07:00
Chee Yee bfe2505efc fix installing pkg via RPI 2025-03-17 00:28:16 -07:00
Chee Yee 749a79d8b9 Merge branch 'master' of github.com:cy33hc/ps4-ezremote-client 2025-03-05 11:53:48 -08:00
Chee Yee c03201c040 update version 2025-03-05 11:53:42 -08:00
cy33hc 7be30e358a Update README.md 2025-03-01 18:43:00 -08:00
cy33hc d58fc0eac2 Update README.md 2025-03-01 18:38:37 -08:00
Chee Yee ed3f8a71c4 increase site slots to 30 2025-03-01 03:35:46 -08:00
Chee Yee 13279b6040 disable rpi for github 2025-03-01 03:27:29 -08:00
Chee Yee eb465356b6 refactor parging github releases 2025-03-01 00:37:34 -08:00
Chee Yee 8602a5353e add support for github repos 2025-02-28 15:44:17 -08:00
Chee Yee 467a459665 implement resume upload to gdrive 2025-02-28 15:33:03 -08:00
Chee Yee b7fe46cb94 support archive.org protected urls 2025-01-11 21:25:55 -08:00
Chee Yee 3bcf136d2a support archive.org protected urls 2025-01-10 21:06:19 -08:00
Chee Yee e5d5ddb8bc support for servers that does not permit NOOP 2025-01-10 21:05:16 -08:00
Chee Yee 3e4b5e3ea2 update to handle Norwegian lang 2024-11-08 22:55:32 -08:00
cy33hc c4889ec160 Merge pull request #32 from xdpirate/master
Add Norwegian translation
2024-11-08 22:33:05 -08:00
xdpirate 3076f4b179 Add Norwegian translation 2024-11-08 11:24:14 +01:00
Chee Yee 93fb338ce0 failed install to display server error message 2024-11-08 00:38:31 -08:00
49 changed files with 2233 additions and 314 deletions
+1
View File
@@ -11,3 +11,4 @@ CTestTestfile.cmake
_deps
.vscode
build
data/daemon
+3
View File
@@ -0,0 +1,3 @@
[submodule "ps4-ezremote-server"]
path = ps4-ezremote-server
url = git@github.com:cy33hc/ps4-ezremote-server.git
+13 -5
View File
@@ -28,6 +28,7 @@ add_executable(ezremote_client
source/clients/archiveorg.cpp
source/clients/ftpclient.cpp
source/clients/gdrive.cpp
source/clients/github.cpp
source/clients/myrient.cpp
source/clients/iis.cpp
source/clients/nginx.cpp
@@ -67,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.30" 32 0)
target_link_libraries(ezremote_client
dbglogger
c
c++
png
@@ -109,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
)
+25 -1
View File
@@ -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.
@@ -87,7 +105,13 @@ To distinguish between FTP, SMB, NFS, WebDAV or HTTP, the URL must be prefix wit
| | | |
|----------|-----------|---|
| ![archive_org_screen1](https://github.com/user-attachments/assets/b129b6cf-b938-4d7c-a3fa-61e1c633c1f6) | ![archive_org_screen2](https://github.com/user-attachments/assets/646106d1-e60b-4b35-b153-3475182df968)| ![image](https://github.com/user-attachments/assets/cad94de8-a694-4ef5-92a8-b87468e30adb) |
- For Myrient repos, entry **https://myrient.erista.me/files** in the server field.
![image](https://github.com/user-attachments/assets/b80e2bec-b8cc-4acc-9ab6-7b0dc4ef20e6)
- Support for browse and download release artifacts from github repos. Under the server just enter the git repo of the homebrew eg https://github.com/cy33hc/ps4-ezremote-client
![image](https://github.com/user-attachments/assets/f8e931ea-f1d1-4af8-aed5-b0dfe661a230)
Tested with following WebDAV server:
- **(Recommeded)** [Dufs](https://github.com/sigoden/dufs) - For hosting your own WebDAV server. (Recommended since this allow anonymous access which is required for Remote Package Install)
- [SFTPgo](https://github.com/drakkan/sftpgo) - For local hosted WebDAV server. Can also be used as a webdav frontend for Cloud Storage like AWS S3, Azure Blob or Google Storage.
+2 -1
View File
@@ -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>
+166
View File
@@ -0,0 +1,166 @@
STR_CONNECTION_SETTINGS=Tilkoblingsinnstillinger
STR_SITE=Side
STR_LOCAL=Lokal
STR_REMOTE=Ekstern
STR_MESSAGES=Meldinger
STR_UPDATE_SOFTWARE=Oppdater programvare
STR_CONNECT=Koble til
STR_DISCONNECT=Koble fra
STR_SEARCH=Søk
STR_REFRESH=Oppdater
STR_SERVER=Tjener
STR_USERNAME=Brukernavn
STR_PASSWORD=Passord
STR_PORT=Port
STR_PASV=Pasv
STR_DIRECTORY=Mappe
STR_FILTER=Filter
STR_YES=Ja
STR_NO=Nei
STR_CANCEL=Avbryt
STR_CONTINUE=Fortsett
STR_CLOSE=Lukk
STR_FOLDER=Mappe
STR_FILE=Fil
STR_TYPE=Type
STR_NAME=Navn
STR_SIZE=Størrelse
STR_DATE=Dato
STR_NEW_FOLDER=Ny mappe
STR_RENAME=Gi nytt navn
STR_DELETE=Slett
STR_UPLOAD=Last opp
STR_DOWNLOAD=Last ned
STR_SELECT_ALL=Marker alle
STR_CLEAR_ALL=Fjern alle
STR_UPLOADING=Laster opp
STR_DOWNLOADING=Laster ned
STR_OVERWRITE=Skriv over
STR_DONT_OVERWRITE=Ikke skriv over
STR_ASK_FOR_CONFIRM=Spør om bekreftelse
STR_DONT_ASK_CONFIRM=Ikke spør om bekreftelse
STR_ALLWAYS_USE_OPTION=Bruk alltid dette valget og ikke spør igjen
STR_ACTIONS=Handlinger
STR_CONFIRM=Bekreft
STR_OVERWRITE_OPTIONS=Overskriv innstillinger
STR_PROPERTIES=Egenskaper
STR_PROGRESS=Framdrift
STR_UPDATES=Oppdateringer
STR_DEL_CONFIRM_MSG=Er du sikker på at du vil slette filen(e)/mappen(e)?
STR_CANCEL_ACTION_MSG=Avbryter. Venter på at siste handling skal fullføres
STR_FAIL_UPLOAD_MSG=Opplasting av fil mislykkes
STR_FAIL_DOWNLOAD_MSG=Nedlasting av fil mislykkes
STR_FAIL_READ_LOCAL_DIR_MSG=Lesing av mappe mislykkes, eller mappen finnes ikke.
STR_CONNECTION_CLOSE_ERR_MSG=426 Tilkobling Lukket.
STR_REMOTE_TERM_CONN_MSG=426 Ekstern Tjener har lukket tilkoblingen.
STR_FAIL_LOGIN_MSG=300 Innlogging Mislykkes. Vennligst sjekk ditt brukernavn og passord.
STR_FAIL_TIMEOUT_MSG=426 Mislykkes. Tilkoblingen timet ut.
STR_FAIL_DEL_DIR_MSG=Sletting av mappe mislykkes
STR_DELETING=Sletter
STR_FAIL_DEL_FILE_MSG=Sletting av fil mislykkes
STR_DELETED=Slettet
STR_LINK=Lenke
STR_SHARE=Del
STR_FAILED=310 Mislykket
STR_FAIL_CREATE_LOCAL_FILE_MSG=310 Oppretting av lokal fil mislykkes
STR_INSTALL=Installér
STR_INSTALLING=Installerer
STR_INSTALL_SUCCESS=Vellykket
STR_INSTALL_FAILED=Mislykket
STR_INSTALL_SKIPPED=Hoppet over
STR_CHECK_HTTP_MSG=Sjekker tilkobling til ekstern HTTP-tjener
STR_FAILED_HTTP_CHECK=Mislykket tilkobling til HTTP-tjener
STR_REMOTE_NOT_HTTP=Ekstern tjener er ikke en HTTP-tjener
STR_INSTALL_FROM_DATA_MSG=Pakke finnes ikke i mappene /data eller /mnt/usbX
STR_ALREADY_INSTALLED_MSG=Pakken er allerede installert
STR_INSTALL_FROM_URL=Installer fra URL
STR_CANNOT_READ_PKG_HDR_MSG=Kunne ikke lese pakkens header
STR_FAVORITE_URLS=Favoritt-URLer
STR_SLOT=Spor
STR_EDIT=Redigér
STR_ONETIME_URL=Engangs-URL
STR_NOT_A_VALID_PACKAGE=Ikke en gyldig pakke
STR_WAIT_FOR_INSTALL_MSG=Venter på at pakke skal bli ferdig å installere
STR_FAIL_INSTALL_TMP_PKG_MSG=Installasjon av PKG-fil mislykkes. Vennligst slett den midlertidlige PKG-filen manuelt
STR_FAIL_TO_OBTAIN_GG_DL_MSG=Kunne ikke hente nedlastings-URL
STR_AUTO_DELETE_TMP_PKG=Automatisk slett midlertidig nedlastet PKG-fil etter installasjon
STR_PROTOCOL_NOT_SUPPORTED=Protokollen er ikke støttet
STR_COULD_NOT_RESOLVE_HOST=Kunne ikke koble til tjenernavnet
STR_EXTRACT=Pakk ut
STR_EXTRACTING=Pakker ut
STR_FAILED_TO_EXTRACT=Utpakking mislykkes
STR_EXTRACT_LOCATION=Utpakkingsbane
STR_COMPRESS=Komprimér
STR_ZIP_FILE_PATH=ZIP-filnavn
STR_COMPRESSING=Komprimerer
STR_ERROR_CREATE_ZIP=Oppretting av ZIP mislykket
STR_UNSUPPORTED_FILE_FORMAT=Arkivformatet er ikke støttet
STR_CUT=Klipp ut
STR_COPY=Kopiér
STR_PASTE=Lim inn
STR_MOVING=Flytter
STR_COPYING=Kopierer
STR_FAIL_MOVE_MSG=Flytting av fil mislykkes
STR_FAIL_COPY_MSG=Kopiering av fil mislykkes
STR_CANT_MOVE_TO_SUBDIR_MSG=Kan ikke flytte overordnet mappe til undermappe
STR_CANT_COPY_TO_SUBDIR_MSG=Kan ikke kopiere overordnet mappe til undermappe
STR_UNSUPPORTED_OPERATION_MSG=Handling ikke støttet
STR_HTTP_PORT=HTTP-port
STR_REINSTALL_CONFIRM_MSG=Innholdet er allerede installert. Vil du fortsette installasjonen
STR_REMOTE_NOT_SUPPORT_MSG=Fjerninstallasjon av pakker er ikke støttet for beskyttede tjenere.
STR_CANNOT_CONNECT_REMOTE_MSG=Ekstern HTTP-tjener kan ikke nås.
STR_DOWNLOAD_INSTALL_MSG=Fjerninstallasjon er ikke mulig. Vil du laste ned pakken og installere den istedet?
STR_CHECKING_REMOTE_SERVER_MSG=Sjekker tjener for fjerninstallasjon av pakke.
STR_ENABLE_RPI=FIP
STR_ENABLE_RPI_FTP_SMB_MSG=Dette valget skrur på fjerninstallasjon av pakke via innebygd Web-tjenerproxy.
STR_ENABLE_RPI_WEBDAV_MSG=Dette valget skrur på fjerninstallasjon av pakke via innebygd Web-tjenerproxy.
STR_FILES=Filer
STR_EDITOR=Redigeringsprogram
STR_SAVE=Lagre
STR_MAX_EDIT_FILE_SIZE_MSG=Kan ikke redigere filer større enn
STR_DELETE_LINE=Slett markert linje
STR_INSERT_LINE=Sett inn under markert linje
STR_MODIFIED=Endret
STR_FAIL_GET_TOKEN_MSG=Kunne ikke hente en tilgangstoken fra
STR_GET_TOKEN_SUCCESS_MSG=Innlogging vellykket. Du kan lukke nettleseren og gå tilbake til applikasjonen
STR_PERM_DRIVE=Se, endre, opprette og slette dine Google Drive-filer
STR_PERM_DRIVE_APPDATA=Se, opprette og slette dens egen konfigurasjonsdata i din Google Drive
STR_PERM_DRIVE_FILE=Se, endre, opprette og slette kun de spesifikke Google Drive-filene du bruker med denne appen
STR_PERM_DRIVE_METADATA=Vise og behandle metadataen til filer i din Google Drive
STR_PERM_DRIVE_METADATA_RO=Se informasjon om dine Google Drive-filer
STR_GOOGLE_LOGIN_FAIL_MSG=Google-innlogging mislykkes
STR_GOOGLE_LOGIN_TIMEOUT_MSG=Google-innlogging timet ut
STR_NEW_FILE=Ny Fil
STR_SETTINGS=Innstillinger
STR_CLIENT_ID=Klient-ID
STR_CLIENT_SECRET=Klienthemmelighet (Client Secret)
STR_GLOBAL=Global
STR_GOOGLE=Google
STR_COPY_LINE=Kopier markert linje
STR_PASTE_LINE=Lim inn i markert linje
STR_SHOW_HIDDEN_FILES=Vis skjulte filer
STR_SET_DEFAULT_DIRECTORY=Sett oppstartsmappe
STR_SET_DEFAULT_DIRECTORY_MSG=har blitt satt som oppstartsmappe
STR_VIEW_IMAGE=Vis bilde
STR_VIEW_PKG_INFO=Pakkeinformasjon
STR_NFS_EXP_PATH_MISSING_MSG=NFS-eksportbane mangler fra URL
STR_FAIL_INIT_NFS_CONTEXT=Initialisering av NFS-kontekst mislykkes
STR_FAIL_MOUNT_NFS_MSG=Montering av NFS-share mislykkes
STR_WEB_SERVER=Web-tjener
STR_ENABLE=Skru på
STR_COMPRESSED_FILE_PATH=Lokasjon for komprimerte filer
STR_COMPRESSED_FILE_PATH_MSG=Lokasjon for komprimerte filer på Web-tjener
STR_ALLDEBRID=AllDebrid
STR_API_KEY=API-nøkkel
STR_CANT_EXTRACT_URL_MSG=Kunne ikke utvinne nedlastings-URL
STR_FAIL_INSTALL_FROM_URL_MSG=Installasjon fra URL mislykkes
STR_INVALID_URL=Ugyldig URL
STR_ALLDEBRID_API_KEY_MISSING_MSG=For å bruke denne funksjonen, må du konfigurere en API-nøkkel i instillingene for ezRemote Client.
STR_LANGUAGE=Språk
STR_TEMP_DIRECTORY=Midlertidig mappe
STR_REALDEBRID=Real-Debrid
STR_BACKGROUND_INSTALL_INPROGRESS=Pakkeinstallasjon kjører i bakrunnen. Ikke lykk denne appen mens installasjonen pågår
STR_ENABLE_DISC_CACHE_MSG=Skru på disk-caching. Kan gjøre fjerninstallasjon av pakker kjappere når tilkoblingen er treg, men lar deg ikke fortsette en avbrutt installasjon
STR_ENABLE_ALLDEBRID_MSG=Installér via AllDebrid
STR_ENABLE_REALDEBRID_MSG=Installér via RealDebrid
STR_ENABLE_DISKCACHE_DESC=Skru på disk-cache
File diff suppressed because one or more lines are too long
Submodule ps4-ezremote-server added at 7644256a3c
+119 -40
View File
@@ -12,6 +12,7 @@
#include "clients/webdav.h"
#include "clients/apache.h"
#include "clients/archiveorg.h"
#include "clients/github.h"
#include "clients/myrient.h"
#include "clients/nginx.h"
#include "clients/npxserve.h"
@@ -489,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;
@@ -525,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);
}
@@ -653,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)
@@ -707,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++;
@@ -727,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);
@@ -744,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);
}
}
}
}
@@ -763,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));
@@ -1157,7 +1173,7 @@ namespace Actions
int ret = tmp_client.Size(path, &bytes_to_download);
if (ret == 0)
{
sprintf(status_message, "%s - %s", lang_strings[STR_FAILED], lang_strings[STR_CANNOT_READ_PKG_HDR_MSG]);
sprintf(status_message, "%s", tmp_client.LastResponse());
tmp_client.Quit();
activity_inprogess = false;
Windows::SetModalMode(false);
@@ -1314,6 +1330,8 @@ namespace Actions
remoteclient = new ArchiveOrgClient();
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_MYRIENT) == 0)
remoteclient = new MyrientClient();
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_GITHUB) == 0)
remoteclient = new GithubClient();
}
else if (strncmp(remote_settings->server, "webdavs://", 10) == 0 || strncmp(remote_settings->server, "webdav://", 9) == 0)
{
@@ -1467,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++)
@@ -1481,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)
{
@@ -1507,6 +1537,11 @@ namespace Actions
}
free(new_path);
}
if (!isCopy && FS::FolderExists(src.path))
{
FS::RmDir(src.path);
}
}
else
{
@@ -1548,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
{
@@ -1892,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
View File
@@ -122,6 +122,8 @@ namespace Actions
void CreateRemoteFile(char *filename);
void *ExtractArchivePkg(void *argp);
void *DownloadSplitPkg(void *argp);
void RestartServer();
void GetBackgroundDownloadProgress();
}
#endif
#endif
+125 -2
View File
@@ -15,7 +15,121 @@ using httplib::Client;
using httplib::Headers;
using httplib::Result;
struct InsensitiveCompare
{
bool operator()(const std::string &a, const std::string &b) const
{
return strcasecmp(a.c_str(), b.c_str()) < 0;
}
};
static std::map<std::string, int> month_map = {{"Jan", 1}, {"Feb", 2}, {"Mar", 3}, {"Apr", 4}, {"May", 5}, {"Jun", 6}, {"Jul", 7}, {"Aug", 8}, {"Sep", 9}, {"Oct", 10}, {"Nov", 11}, {"Dec", 12}};
static std::set<std::string, InsensitiveCompare> ignore_cookie_keys = {"path", "expires", "max-age", "domain", "secure"};
std::string ArchiveOrgClient::GenerateRandomId(const int len)
{
static const char alphanum[] = "0123456789abcdef";
std::string tmp_s;
tmp_s.reserve(len);
for (int i = 0; i < len; ++i) {
tmp_s += alphanum[rand() % (sizeof(alphanum) - 1)];
}
return tmp_s;
}
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("://");
size_t root_pos = url.find("/", scheme_pos + 3);
if (root_pos != std::string::npos)
{
this->host_url = url.substr(0, root_pos);
this->base_path = url.substr(root_pos);
}
client = new httplib::Client(this->host_url);
client->set_keep_alive(true);
client->set_follow_location(true);
client->set_connection_timeout(30);
client->set_read_timeout(30);
client->enable_server_certificate_verification(false);
this->cookies = {
{"donation-identifier", GenerateRandomId(32)},
{"test-cookie", "1"},
{"abtest-identifier", GenerateRandomId(32)}
};
if (username.length() > 0)
return Login(username, password);
else if (!send_ping)
this->connected = true;
else if (Ping())
this->connected = true;
return 1;
}
int ArchiveOrgClient::Login(const std::string &username, const std::string &password)
{
std::string url = std::string("/account/login");
Headers headers = {{ "User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0"}};
SetCookies(headers);
MultipartFormDataItems items = {
{"username", username, "", ""},
{"password", password, "", ""},
{"remember", "true", "", ""},
{"referer", "https://archive.org/", "", ""},
{"login", "true", "", ""},
{"submit_by_js", "true", "", ""}};
if (auto res = client->Post(url, headers, items))
{
if (HTTP_SUCCESS(res->status))
{
if (res->has_header("Set-Cookie"))
{
int cookies_count = res->get_header_value_count("Set-Cookie");
for (int i = 0; i < cookies_count; i++)
{
std::string cookie_str = res->get_header_value("Set-Cookie", i);
std::vector<std::string> cookies = Util::Split(cookie_str, ";");
for (std::vector<std::string>::iterator it = cookies.begin(); it != cookies.end();)
{
std::vector<std::string> cookie = Util::Split(*it, "=");
std::string key = Util::Trim(cookie[0], " ");
if (ignore_cookie_keys.find(key) == ignore_cookie_keys.end())
{
if (cookie.size() > 1)
this->cookies[key] = Util::Trim(cookie[1], " ");
else
this->cookies[key] = "";
}
++it;
}
}
this->connected = true;
return 1;
}
else
{
return 0;
}
}
else
{
return 0;
}
}
else
{
return 0;
}
}
std::vector<DirEntry> ArchiveOrgClient::ListDir(const std::string &path)
{
@@ -23,9 +137,11 @@ std::vector<DirEntry> ArchiveOrgClient::ListDir(const std::string &path)
DirEntry entry;
Util::SetupPreviousFolder(path, &entry);
out.push_back(entry);
Headers headers;
SetCookies(headers);
std::string encoded_path = httplib::detail::encode_url(GetFullPath(path) + "/");
if (auto res = client->Get(encoded_path))
if (auto res = client->Get(encoded_path, headers))
{
lxb_status_t status;
lxb_dom_attr_t *attr;
@@ -130,6 +246,13 @@ std::vector<DirEntry> ArchiveOrgClient::ListDir(const std::string &path)
// td0 contains the <a> tag
td_element = lxb_dom_collection_element(td_collection, 0);
lxb_dom_node_t *a_node = NextChildElement(td_element);
// there is no a_node in protected links
if (a_node == nullptr)
{
lxb_dom_collection_destroy(td_collection, true);
continue;
}
value = lxb_dom_element_local_name(lxb_dom_interface_element(a_node), &value_len);
tmp_string = std::string((const char *)value, value_len);
if (tmp_string.compare("a") != 0)
@@ -236,4 +359,4 @@ std::vector<DirEntry> ArchiveOrgClient::ListDir(const std::string &path)
finish:
return out;
}
}
+6 -1
View File
@@ -11,7 +11,12 @@
class ArchiveOrgClient : public BaseClient
{
public:
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:
int Login(const std::string &username, const std::string &password);
std::string GenerateRandomId(const int len);
};
#endif
#endif
+50 -6
View File
@@ -20,7 +20,27 @@ BaseClient::~BaseClient()
delete client;
};
int BaseClient::Connect(const std::string &url, const std::string &username, const std::string &password)
int BaseClient::SetCookies(Headers &headers)
{
if (this->cookies.size() > 0)
{
std::string cookie;
for (std::map<std::string, std::string>::iterator it = this->cookies.begin(); it != this->cookies.end();)
{
cookie.append(it->first).append("=").append(it->second);
if (std::next(it, 1) != this->cookies.end())
{
cookie.append("; ");
}
++it;
}
headers.emplace("Cookie", cookie);
}
return 1;
}
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("://");
@@ -38,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;
}
@@ -81,7 +105,10 @@ int BaseClient::Rmdir(const std::string &path, bool recursive)
int BaseClient::Size(const std::string &path, int64_t *size)
{
if (auto res = client->Head(GetFullPath(path)))
Headers headers;
SetCookies(headers);
if (auto res = client->Head(GetFullPath(path), headers))
{
if (HTTP_SUCCESS(res->status))
{
@@ -90,10 +117,12 @@ int BaseClient::Size(const std::string &path, int64_t *size)
*size = atoll(content_length.c_str());
return 1;
}
else // Server doesn't support HEAD request. Try get range with 0 bytes and grab size from the response header
else if (res->status == 405)// Server doesn't support HEAD request. Try get range with 0 bytes and grab size from the response header
// example: Content-Range: bytes 0-10/4372785
{
Headers headers = {{"Range", "bytes=0-1"}};
SetCookies(headers);
if (auto range_res = client->Get(GetFullPath(path), headers))
{
if (HTTP_SUCCESS(range_res->status))
@@ -111,6 +140,10 @@ int BaseClient::Size(const std::string &path, int64_t *size)
}
}
}
else
{
sprintf(this->response, "%d - %s", res->status, detail::status_message(res->status));
}
}
else
{
@@ -124,8 +157,10 @@ int BaseClient::Get(const std::string &outputfile, const std::string &path, uint
std::ofstream file_stream(outputfile, std::ios::binary);
bytes_transfered = 0;
sceRtcGetCurrentTick(&prev_tick);
Headers headers;
SetCookies(headers);
if (auto res = client->Get(GetFullPath(path),
if (auto res = client->Get(GetFullPath(path), headers,
[&](const char *data, size_t data_length)
{
file_stream.write(data, data_length);
@@ -145,7 +180,10 @@ int BaseClient::Get(const std::string &outputfile, const std::string &path, uint
int BaseClient::Get(SplitFile *split_file, const std::string &path, uint64_t offset)
{
if (auto res = client->Get(GetFullPath(path),
Headers headers;
SetCookies(headers);
if (auto res = client->Get(GetFullPath(path), headers,
[&](const char *data, size_t data_length)
{
if (!split_file->IsClosed())
@@ -171,6 +209,8 @@ int BaseClient::GetRange(const std::string &path, DataSink &sink, uint64_t size,
char range_header[64];
sprintf(range_header, "bytes=%lu-%lu", offset, offset + size - 1);
Headers headers = {{"Range", range_header}};
SetCookies(headers);
size_t bytes_read = 0;
if (auto res = client->Get(GetFullPath(path), headers,
[&](const char *data, size_t data_length)
@@ -194,6 +234,8 @@ int BaseClient::GetRange(const std::string &path, void *buffer, uint64_t size, u
char range_header[64];
sprintf(range_header, "bytes=%lu-%lu", offset, offset + size - 1);
Headers headers = {{"Range", range_header}};
SetCookies(headers);
size_t bytes_read = 0;
std::vector<char> body;
if (auto res = client->Get(GetFullPath(path), headers,
@@ -253,6 +295,8 @@ int BaseClient::Head(const std::string &path, void *buffer, uint64_t len)
char range_header[64];
sprintf(range_header, "bytes=%lu-%lu", 0L, len - 1);
Headers headers = {{"Range", range_header}};
SetCookies(headers);
size_t bytes_read = 0;
std::vector<char> body;
if (auto res = client->Get(GetFullPath(path), headers,
+5 -2
View File
@@ -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);
@@ -49,11 +49,14 @@ public:
static std::string UnEscape(const std::string &url);
protected:
int SetCookies(httplib::Headers &headers);
httplib::Client *client;
std::string base_path;
std::string host_url;
char response[512];
bool connected = false;
std::map<std::string, std::string> cookies;
};
#endif
#endif
+87 -60
View File
@@ -24,8 +24,6 @@
#define FTP_CLIENT_READ 1
#define FTP_CLIENT_WRITE 2
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
FtpClient::FtpClient()
{
mp_ftphandle = static_cast<ftphandle *>(calloc(1, sizeof(ftphandle)));
@@ -48,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);
@@ -125,7 +123,7 @@ int FtpClient::Connect(const std::string &url, const std::string &user, const st
}
mp_ftphandle->handle = sControl;
if (ReadResponse('2', mp_ftphandle) == 0)
if (ReadResponse("2", mp_ftphandle) == 0)
{
close(mp_ftphandle->handle);
mp_ftphandle->handle = 0;
@@ -142,7 +140,7 @@ int FtpClient::Connect(const std::string &url, const std::string &user, const st
cmd = "USER anonymous";
}
if (!FtpSendCmd(cmd, '3', mp_ftphandle))
if (!FtpSendCmd(cmd, "3", mp_ftphandle))
{
if (mp_ftphandle->ctrl != NULL)
return 1;
@@ -161,7 +159,7 @@ int FtpClient::Connect(const std::string &url, const std::string &user, const st
cmd = "PASS " + pass;
int ret;
if ((ret = FtpSendCmd(cmd, '2', mp_ftphandle)))
if ((ret = FtpSendCmd(cmd, "2", mp_ftphandle)))
{
mp_ftphandle->is_connected = true;
}
@@ -179,7 +177,7 @@ int FtpClient::Connect(const std::string &url, const std::string &user, const st
*
* return 1 if proper response received, 0 otherwise
*/
int FtpClient::FtpSendCmd(const std::string &cmd, char expected_resp, ftphandle *nControl)
int FtpClient::FtpSendCmd(const std::string &cmd, const std::string &expected_resp, ftphandle *nControl)
{
char buf[512];
int x;
@@ -205,7 +203,7 @@ int FtpClient::FtpSendCmd(const std::string &cmd, char expected_resp, ftphandle
* return 0 if first char doesn't match
* return 1 if first char matches
*/
int FtpClient::ReadResponse(char c, ftphandle *nControl)
int FtpClient::ReadResponse(const std::string &c, ftphandle *nControl)
{
char match[5];
@@ -228,7 +226,7 @@ int FtpClient::ReadResponse(char c, ftphandle *nControl)
} while (strncmp(nControl->response, match, 4));
}
if (nControl->response[0] == c)
if (c.find(nControl->response[0]) != std::string::npos)
return 1;
return 0;
}
@@ -368,7 +366,7 @@ int FtpClient::FtpAccess(const std::string &path, accesstype type, transfermode
return 0;
}
sprintf(buf, "TYPE %c", mode);
if (!FtpSendCmd(buf, '2', nControl))
if (!FtpSendCmd(buf, "2", nControl))
return 0;
switch (type)
@@ -477,7 +475,7 @@ int FtpClient::FtpAcceptConnection(ftphandle *nData, ftphandle *nControl)
{
close(nData->handle);
nData->handle = 0;
ReadResponse('2', nControl);
ReadResponse("2", nControl);
rv = 0;
}
@@ -521,7 +519,7 @@ int FtpClient::FtpOpenPasv(ftphandle *nControl, ftphandle **nData, transfermode
memset(&sin, 0, l);
sin.in.sin_family = AF_INET;
if (!FtpSendCmd("PASV", '2', nControl))
if (!FtpSendCmd("PASV", "2", nControl))
return -1;
cp = strchr(nControl->response, '(');
if (cp == NULL)
@@ -542,7 +540,7 @@ int FtpClient::FtpOpenPasv(ftphandle *nControl, ftphandle **nData, transfermode
{
char buf[512];
sprintf(buf, "REST %lld", mp_ftphandle->offset);
if (!FtpSendCmd(buf, '3', nControl))
if (!FtpSendCmd(buf, "3", nControl))
return 0;
}
@@ -592,7 +590,7 @@ int FtpClient::FtpOpenPasv(ftphandle *nControl, ftphandle **nData, transfermode
return -1;
}
if (!ReadResponse('1', nControl))
if (!ReadResponse("1", nControl))
{
close(sData);
return -1;
@@ -717,7 +715,7 @@ int FtpClient::FtpOpenPort(ftphandle *nControl, ftphandle **nData, transfermode
(unsigned char)sin.sa.sa_data[5],
(unsigned char)sin.sa.sa_data[0],
(unsigned char)sin.sa.sa_data[1]);
if (!FtpSendCmd(buf, '2', nControl))
if (!FtpSendCmd(buf, "2", nControl))
{
close(sData);
return -1;
@@ -727,7 +725,7 @@ int FtpClient::FtpOpenPort(ftphandle *nControl, ftphandle **nData, transfermode
{
char buf[512];
sprintf(buf, "REST %lld", mp_ftphandle->offset);
if (!FtpSendCmd(buf, '3', nControl))
if (!FtpSendCmd(buf, "3", nControl))
{
close(sData);
return 0;
@@ -747,7 +745,7 @@ int FtpClient::FtpOpenPort(ftphandle *nControl, ftphandle **nData, transfermode
return -1;
}
if (!FtpSendCmd(cmd, '1', nControl))
if (!FtpSendCmd(cmd, "1", nControl))
{
FtpClose(*nData);
*nData = NULL;
@@ -899,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);
@@ -1045,7 +1044,7 @@ int FtpClient::FtpClose(ftphandle *nData)
ctrl = nData->ctrl;
free(nData);
if (ctrl)
return ReadResponse('2', ctrl);
return ReadResponse("2", ctrl);
return 1;
}
@@ -1061,7 +1060,7 @@ int FtpClient::Quit()
strcpy(mp_ftphandle->response, "error: no anwser from server\n");
return 0;
}
FtpSendCmd("QUIT", '2', mp_ftphandle);
FtpSendCmd("QUIT", "2", mp_ftphandle);
shutdown(mp_ftphandle->handle, SHUT_WR);
struct linger lng = {1, 0};
setsockopt(mp_ftphandle->handle, SOL_SOCKET, SO_LINGER, &lng, sizeof(lng));
@@ -1105,7 +1104,7 @@ int FtpClient::RawRead(void *buf, int max, ftphandle *handle)
int FtpClient::Site(const std::string &cmd)
{
std::string tmp = "SITE " + cmd;
if (!FtpSendCmd(tmp, '2', mp_ftphandle))
if (!FtpSendCmd(tmp, "2", mp_ftphandle))
return 0;
return 1;
}
@@ -1118,7 +1117,7 @@ int FtpClient::Site(const std::string &cmd)
int FtpClient::Raw(const std::string &cmd)
{
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
return 0;
return 1;
}
@@ -1137,7 +1136,7 @@ int FtpClient::SysType(char *buf, int max)
int l = max;
char *b = buf;
char *s;
if (!FtpSendCmd("SYST", '2', mp_ftphandle))
if (!FtpSendCmd("SYST", "2", mp_ftphandle))
return 0;
s = &mp_ftphandle->response[4];
while ((--l) && (*s != ' '))
@@ -1154,7 +1153,7 @@ int FtpClient::SysType(char *buf, int max)
int FtpClient::Mkdir(const std::string &path)
{
std::string cmd = "MKD " + path;
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
return 0;
return 1;
}
@@ -1167,7 +1166,7 @@ int FtpClient::Mkdir(const std::string &path)
int FtpClient::Chdir(const std::string &path)
{
std::string cmd = "CWD " + path;
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
return 0;
return 1;
}
@@ -1179,7 +1178,7 @@ int FtpClient::Chdir(const std::string &path)
*/
int FtpClient::Cdup()
{
if (!FtpSendCmd("CDUP", '2', mp_ftphandle))
if (!FtpSendCmd("CDUP", "2", mp_ftphandle))
return 0;
return 1;
}
@@ -1191,7 +1190,7 @@ int FtpClient::Cdup()
*/
bool FtpClient::Noop()
{
if (!FtpSendCmd("NOOP", '2', mp_ftphandle))
if (!FtpSendCmd("NOOP", "25", mp_ftphandle))
return 0;
return 1;
}
@@ -1209,7 +1208,7 @@ bool FtpClient::Ping()
int FtpClient::Rmdir(const std::string &path)
{
std::string cmd = "RMD " + path;
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
return 0;
return 1;
}
@@ -1272,11 +1271,11 @@ int FtpClient::Size(const std::string &path, int64_t *size)
return 0;
sprintf(cmd, "TYPE %c", FtpClient::transfermode::image);
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
return 0;
sprintf(cmd, "SIZE %s", path.c_str());
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
rv = 0;
else
{
@@ -1408,10 +1407,10 @@ int FtpClient::Put(const std::string &inputfile, const std::string &path, uint64
int FtpClient::Rename(const std::string &src, const std::string &dst)
{
std::string cmd = "RNFR " + src;
if (!FtpSendCmd(cmd, '3', mp_ftphandle))
if (!FtpSendCmd(cmd, "3", mp_ftphandle))
return 0;
cmd = "RNTO " + dst;
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
return 0;
return 1;
@@ -1420,7 +1419,7 @@ int FtpClient::Rename(const std::string &src, const std::string &dst)
int FtpClient::Delete(const std::string &path)
{
std::string cmd = "DELE " + path;
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
return 0;
return 1;
}
@@ -1501,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
@@ -1527,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
@@ -1549,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;
}
@@ -1580,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);
@@ -1621,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
@@ -1641,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
@@ -1652,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;
}
@@ -1662,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;
}
+4 -4
View File
@@ -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);
@@ -114,12 +114,12 @@ private:
char server[128];
int server_port;
int FtpSendCmd(const std::string &cmd, char expected_resp, ftphandle *nControl);
int FtpSendCmd(const std::string &cmd, const std::string &expected_resp, ftphandle *nControl);
ftphandle *RawOpen(const std::string &path, accesstype type, transfermode mode);
int RawClose(ftphandle *handle);
int RawWrite(void *buf, int len, ftphandle *handle);
int RawRead(void *buf, int max, ftphandle *handle);
int ReadResponse(char c, ftphandle *nControl);
int ReadResponse(const std::string &c, ftphandle *nControl);
int Readline(char *buf, int max, ftphandle *nControl);
int Writeline(char *buf, int len, ftphandle *nData);
void ClearHandle();
@@ -137,4 +137,4 @@ private:
int ParseMLSDDirEntry(char *line, DirEntry *dirEntry);
};
#endif
#endif
+175 -14
View File
@@ -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)
{
@@ -431,7 +431,6 @@ int GDriveClient::Update(const std::string &inputfile, const std::string &path)
sceRtcGetCurrentTick(&prev_tick);
std::ifstream file_stream(inputfile, std::ios::binary);
std::string id = GetValue(path_id_map, path);
std::string drive_id = GetDriveId(path);
@@ -442,6 +441,7 @@ int GDriveClient::Update(const std::string &inputfile, const std::string &path)
headers.insert(std::make_pair("X-Upload-Content-Type", "application/octet-stream"));
headers.insert(std::make_pair("X-Upload-Content-Length", std::to_string(bytes_to_download)));
char *buf = new char[GOOGLE_BUF_SIZE];
if (auto res = client->Patch(url))
{
if (HTTP_SUCCESS(res->status))
@@ -457,8 +457,8 @@ int GDriveClient::Update(const std::string &inputfile, const std::string &path)
upload_uri, bytes_to_download,
[&file_stream, &buf](size_t offset, size_t length, DataSink &sink)
{
uint32_t count = 0;
uint32_t bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
uint64_t count = 0;
uint64_t bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
do
{
file_stream.read(buf, bytes_to_transfer);
@@ -471,7 +471,84 @@ int GDriveClient::Update(const std::string &inputfile, const std::string &path)
},
"application/octet-stream"))
{
// success
if (HTTP_SUCCESS(res->status))
{
delete[] buf;
file_stream.close();
return 1;
}
else if (res->status == 503)
{
// retry interrupted uploads
int retries = 5;
while (res->status == 503 && retries > 0)
{
// Send empty PUT request to get resume position
Headers headers;
headers.insert(std::make_pair("Content-Range", "*/*"));
auto resume_res = client->Put(upload_uri, headers, "", 0, "application/octet-stream");
retries--;
if (HTTP_SUCCESS(resume_res->status))
{
delete[] buf;
file_stream.close();
return 1;
}
else if (resume_res->status == 308)
{
std::string range_val = resume_res->get_header_value("Range");
uint64_t resume_offset = std::stol(Util::Split(Util::Split(range_val, "=")[1], "-")[1]);
Headers headers;
headers.insert(std::make_pair("Content-Length", std::to_string(bytes_to_download-resume_offset)));
std::string range_value = "bytes " + std::to_string(resume_offset + 1) + "_" + std::to_string(bytes_to_download-1);
headers.insert(std::make_pair("Content-Range", range_value));
file_stream.seekg(resume_offset+1);
if (res = client->Put(upload_uri, bytes_to_download-resume_offset,
[&file_stream, &buf](size_t offset, size_t length, DataSink &sink)
{
uint64_t count = 0;
uint64_t bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
do
{
file_stream.read(buf, bytes_to_transfer);
if (sink.write(buf, bytes_to_transfer))
{
count += bytes_to_transfer;
bytes_transfered += bytes_to_transfer;
bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
}
else
{
return false;
}
} while (count < length);
return true;
},
"application/octet-stream"))
{
if (HTTP_SUCCESS(res->status))
{
delete[] buf;
file_stream.close();
return 1;
}
}
}
else
{
delete[] buf;
file_stream.close();
return 0;
}
// pause 5s before retrying
sceKernelUsleep(5000000);
}
}
}
else
{
@@ -505,7 +582,6 @@ int GDriveClient::Put(const std::string &inputfile, const std::string &path, uin
sceRtcGetCurrentTick(&prev_tick);
std::ifstream file_stream(inputfile, std::ios::binary);
size_t path_pos = path.find_last_of("/");
std::string parent_dir;
if (path_pos == 0)
@@ -528,7 +604,9 @@ int GDriveClient::Put(const std::string &inputfile, const std::string &path, uin
headers.insert(std::make_pair("X-Upload-Content-Type", "application/octet-stream"));
headers.insert(std::make_pair("X-Upload-Content-Length", std::to_string(bytes_to_download)));
char *buf = new char[GOOGLE_BUF_SIZE];
if (auto res = client->Post(url, headers, post_data.c_str(), post_data.length(), "application/json"))
httplib::Result res;
if (res = client->Post(url, headers, post_data.c_str(), post_data.length(), "application/json"))
{
if (HTTP_SUCCESS(res->status))
{
@@ -543,21 +621,104 @@ int GDriveClient::Put(const std::string &inputfile, const std::string &path, uin
upload_uri, bytes_to_download,
[&file_stream, &buf](size_t offset, size_t length, DataSink &sink)
{
uint32_t count = 0;
uint32_t bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
uint64_t count = 0;
uint64_t bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
do
{
file_stream.read(buf, bytes_to_transfer);
sink.write(buf, bytes_to_transfer);
count += bytes_to_transfer;
bytes_transfered += bytes_to_transfer;
bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
if (sink.write(buf, bytes_to_transfer))
{
count += bytes_to_transfer;
bytes_transfered += bytes_to_transfer;
bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
}
else
{
return false;
}
} while (count < length);
return true;
},
"application/octet-stream"))
{
// success
if (HTTP_SUCCESS(res->status))
{
delete[] buf;
file_stream.close();
return 1;
}
else if (res->status == 503)
{
// retry interrupted uploads
int retries = 5;
while (res->status == 503)
{
// Send empty PUT request to get resume position
Headers headers;
headers.insert(std::make_pair("Content-Range", "*/*"));
retries--;
auto resume_res = client->Put(upload_uri, headers, "", 0, "application/octet-stream");
if (HTTP_SUCCESS(resume_res->status))
{
delete[] buf;
file_stream.close();
return 1;
}
else if (resume_res->status == 308)
{
std::string range_val = resume_res->get_header_value("Range");
uint64_t resume_offset = std::stol(Util::Split(Util::Split(range_val, "=")[1], "-")[1]);
Headers headers;
headers.insert(std::make_pair("Content-Length", std::to_string(bytes_to_download-resume_offset)));
std::string range_value = "bytes " + std::to_string(resume_offset + 1) + "_" + std::to_string(bytes_to_download-1);
headers.insert(std::make_pair("Content-Range", range_value));
file_stream.seekg(resume_offset+1);
if (res = client->Put(upload_uri, bytes_to_download-resume_offset,
[&file_stream, &buf](size_t offset, size_t length, DataSink &sink)
{
uint64_t count = 0;
uint64_t bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
do
{
file_stream.read(buf, bytes_to_transfer);
if (sink.write(buf, bytes_to_transfer))
{
count += bytes_to_transfer;
bytes_transfered += bytes_to_transfer;
bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
}
else
{
return false;
}
} while (count < length);
return true;
},
"application/octet-stream"))
{
if (HTTP_SUCCESS(res->status))
{
delete[] buf;
file_stream.close();
return 1;
}
}
}
else
{
delete[] buf;
file_stream.close();
return 0;
}
// pause 5s before retrying
sceKernelUsleep(5000000);
}
}
}
else
{
+2 -2
View File
@@ -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
+276
View File
@@ -0,0 +1,276 @@
#include <json-c/json.h>
#include <fstream>
#include <algorithm>
#include "common.h"
#include "clients/remote_client.h"
#include "clients/github.h"
#include "lang.h"
#include "util.h"
#include "windows.h"
using httplib::Client;
using httplib::Headers;
using httplib::Result;
int GithubClient::Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping)
{
if (url.find("https://github.com") == std::string::npos)
return 0;
this->host_url = "https://api.github.com";
this->base_path = "/repos" + url.substr(18);
Util::Rtrim(this->base_path, "/");
this->base_path += "/releases";
this->m_download_url = "https://github.com";
client = new httplib::Client(this->host_url);
if (username.length() > 0)
client->set_basic_auth(username, password);
client->set_follow_location(true);
client->set_connection_timeout(10);
client->set_read_timeout(30);
client->enable_server_certificate_verification(false);
m_client.Connect("https://github.com", username, password);
if (!send_ping)
this->connected = true;
else if (Ping())
this->connected = true;
return 1;
}
std::vector<DirEntry> GithubClient::ListDir(const std::string &path)
{
std::vector<DirEntry> out;
DirEntry entry;
Util::SetupPreviousFolder(path, &entry);
out.push_back(entry);
if (!ParseReleases())
return out;
if (path.compare("/") == 0) // return releases as folders
{
for (std::vector<GitRelease>::iterator release = m_releases.begin(); release != m_releases.end();)
{
DirEntry entry;
entry.isDir = true;
entry.selectable = true;
entry.file_size = 0;
snprintf(entry.directory, 512, "%s", "/");
snprintf(entry.name, 256, "%s", release->name.c_str());
snprintf(entry.path, 768, "/%s", release->name.c_str());
snprintf(entry.display_size, 48, "%s", lang_strings[STR_FOLDER]);
entry.modified = release->modified;
out.push_back(entry);
release++;
}
}
else // return assets in the releases matching the path
{
std::string tag_name = path.substr(1);
std::map<std::string, GitAsset> assets = m_assets[tag_name];
for (std::map<std::string, GitAsset>::iterator asset = assets.begin(); asset != assets.end();)
{
DirEntry entry;
memset(&entry, 0, sizeof(DirEntry));
entry.isDir = false;
entry.selectable = true;
snprintf(entry.directory, 512, "%s", path.c_str());
snprintf(entry.name, 256, "%s", asset->second.name.c_str());
snprintf(entry.path, 768, "%s/%s", path.c_str(), asset->second.name.c_str());
entry.file_size = asset->second.size;
entry.modified = asset->second.modified;
DirEntry::SetDisplaySize(&entry);
out.push_back(entry);
asset++;
}
}
return out;
}
int GithubClient::Size(const std::string &path, int64_t *size)
{
if (!ParseReleases())
return 0;
std::vector<std::string> path_parts = Util::Split(path, "/");
if (path_parts.size() != 2)
{
return 0;
}
*size = m_assets[path_parts[0]][path_parts[1]].size;
return 1;
}
int GithubClient::Head(const std::string &path, void *buffer, uint64_t len)
{
if (!ParseReleases())
return 0;
std::vector<std::string> path_parts = Util::Split(path, "/");
if (path_parts.size() != 2)
{
return 0;
}
return m_client.Head(m_assets[path_parts[0]][path_parts[1]].url, buffer, len);
}
int GithubClient::Get(const std::string &outputfile, const std::string &path, uint64_t offset)
{
if (!ParseReleases())
return 0;
std::vector<std::string> path_parts = Util::Split(path, "/");
if (path_parts.size() != 2)
{
return 0;
}
return m_client.Get(outputfile, m_assets[path_parts[0]][path_parts[1]].url, offset);
}
int GithubClient::Get(SplitFile *split_file, const std::string &path, uint64_t offset)
{
if (!ParseReleases())
return 0;
std::vector<std::string> path_parts = Util::Split(path, "/");
if (path_parts.size() != 2)
{
return 0;
}
return m_client.Get(split_file, m_assets[path_parts[0]][path_parts[1]].url, offset);
}
int GithubClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset)
{
if (!ParseReleases())
return 0;
std::vector<std::string> path_parts = Util::Split(path, "/");
if (path_parts.size() != 2)
{
return 0;
}
return m_client.GetRange(m_assets[path_parts[0]][path_parts[1]].url, buffer, size, offset);
}
int GithubClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset)
{
if (!ParseReleases())
return 0;
std::vector<std::string> path_parts = Util::Split(path, "/");
if (path_parts.size() != 2)
{
return 0;
}
return m_client.GetRange(m_assets[path_parts[0]][path_parts[1]].url, sink, size, offset);
}
bool GithubClient::ParseReleases()
{
if (!releases_parsed)
{
if (auto res = client->Get(this->base_path + "?per_page=100&page=1"))
{
if (HTTP_SUCCESS(res->status))
{
json_object *jobj = json_tokener_parse(res->body.c_str());
struct array_list *areleases = json_object_get_array(jobj);
for (size_t release_idx = 0; release_idx < areleases->length; ++release_idx)
{
GitRelease release_entry;
json_object *release = (json_object *)array_list_get_idx(areleases, release_idx);
release_entry.name = std::string(json_object_get_string(json_object_object_get(release, "tag_name")));
std::string date_time = std::string(json_object_get_string(json_object_object_get(release, "published_at")));
auto date_time_array = Util::Split(date_time, "T");
auto date_array = Util::Split(date_time_array[0], "-");
auto time_array = Util::Split(date_time_array[1], ":");
release_entry.modified.year = std::atoi(date_array[0].c_str());
release_entry.modified.month = std::atoi(date_array[1].c_str());
release_entry.modified.day = std::atoi(date_array[2].c_str());
release_entry.modified.hours = std::atoi(time_array[0].c_str());
release_entry.modified.minutes = std::atoi(time_array[1].c_str());
release_entry.modified.seconds = std::atoi(time_array[2].substr(0,2).c_str());
json_object *obj_assets = json_object_object_get(release, "assets");
if (json_object_get_type(obj_assets) == json_type_array)
{
struct array_list *aassets = json_object_get_array(obj_assets);
std::map<std::string, GitAsset> assets;
for (size_t asset_idx = 0; asset_idx < aassets->length; ++asset_idx)
{
GitAsset asset_entry;
json_object *asset = (json_object *)array_list_get_idx(aassets, asset_idx);
asset_entry.name = std::string(json_object_get_string(json_object_object_get(asset, "name")));
asset_entry.size = json_object_get_uint64(json_object_object_get(asset, "size"));
std::string date_time = std::string(json_object_get_string(json_object_object_get(asset, "updated_at")));
asset_entry.url = std::string(json_object_get_string(json_object_object_get(asset, "browser_download_url")));
Util::ReplaceAll(asset_entry.url, "https://github.com", "");
auto date_time_array = Util::Split(date_time, "T");
auto date_array = Util::Split(date_time_array[0], "-");
auto time_array = Util::Split(date_time_array[1], ":");
asset_entry.modified.year = std::atoi(date_array[0].c_str());
asset_entry.modified.month = std::atoi(date_array[1].c_str());
asset_entry.modified.day = std::atoi(date_array[2].c_str());
asset_entry.modified.hours = std::atoi(time_array[0].c_str());
asset_entry.modified.minutes = std::atoi(time_array[1].c_str());
asset_entry.modified.seconds = std::atoi(time_array[2].substr(0,2).c_str());
assets.insert(std::make_pair(asset_entry.name, asset_entry));
}
m_assets.insert(std::make_pair(release_entry.name, assets));
}
m_releases.push_back(release_entry);
}
releases_parsed = true;
return 1;
}
}
return 0;
}
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);
}
+48
View File
@@ -0,0 +1,48 @@
#ifndef EZ_GITHUB_H
#define EZ_GITHUB_H
#include <string>
#include <vector>
#include "http/httplib.h"
#include "clients/remote_client.h"
#include "clients/baseclient.h"
#include "common.h"
class GithubClient : public BaseClient
{
public:
int Connect(const std::string &url, const std::string &username, const std::string &password, 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);
int Get(SplitFile *split_file, const std::string &path, uint64_t offset=0);
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
int Head(const std::string &path, void *buffer, uint64_t len);
std::string GetDownloadUrl(const std::string &path);
private:
struct GitAsset
{
std::string name;
std::string url;
DateTime modified;
uint64_t size;
};
struct GitRelease
{
std::string name;
DateTime modified;
};
std::vector<GitRelease> m_releases;
std::map<std::string, std::map<std::string, GitAsset>> m_assets;
bool releases_parsed = false;
std::string m_download_url;
BaseClient m_client;
bool ParseReleases();
};
#endif
+4 -1
View File
@@ -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);
+33 -9
View File
@@ -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);
+2 -2
View File
@@ -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
+3 -2
View File
@@ -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
+2 -2
View File
@@ -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;
}
}
+2 -2
View File
@@ -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
+87 -41
View File
@@ -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;
+2 -2
View File
@@ -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
+3 -3
View File
@@ -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;
}
}
+2 -2
View File
@@ -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
View File
@@ -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
+16 -4
View File
@@ -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'};
@@ -156,13 +159,14 @@ namespace CONFIG
install_pkg_url.enable_rpi = true;
sites = {"Site 1", "Site 2", "Site 3", "Site 4", "Site 5", "Site 6", "Site 7", "Site 8", "Site 9", "Site 10",
"Site 11", "Site 12", "Site 13", "Site 14", "Site 15", "Site 16", "Site 17", "Site 18", "Site 19", "Site 20"};
"Site 11", "Site 12", "Site 13", "Site 14", "Site 15", "Site 16", "Site 17", "Site 18", "Site 19", "Site 20",
"Site 21", "Site 22", "Site 23", "Site 24", "Site 25", "Site 26", "Site 27", "Site 28", "Site 29", "Site 30"};
langs = { "Default", "Arabic", "Catalan", "Croatian", "Dutch", "English", "Euskera", "French", "Galego", "German", "Greek",
"Hungarian", "Indonesian", "Italiano", "Japanese", "Korean", "Polish", "Portuguese_BR", "Russian", "Romanian", "Ryukyuan", "Spanish", "Turkish",
"Simplified Chinese", "Traditional Chinese", "Thai", "Ukrainian", "Vietnamese"};
"Hungarian", "Indonesian", "Italiano", "Japanese", "Korean", "Norwegian", "Polish", "Portuguese_BR", "Russian",
"Romanian", "Ryukyuan", "Spanish", "Turkish", "Simplified Chinese", "Traditional Chinese", "Thai", "Ukrainian", "Vietnamese"};
http_servers = {HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE, HTTP_SERVER_RCLONE, HTTP_SERVER_ARCHIVEORG, HTTP_SERVER_MYRIENT};
http_servers = {HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE, HTTP_SERVER_RCLONE, HTTP_SERVER_ARCHIVEORG, HTTP_SERVER_MYRIENT, HTTP_SERVER_GITHUB};
text_file_extensions = { ".txt", ".ini", ".log", ".json", ".xml", ".html", ".xhtml", ".conf", ".config" };
image_file_extensions = { ".bmp", ".jpg", ".jpeg", ".png", ".webp" };
@@ -195,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);
@@ -433,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();
+9
View File
@@ -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"
@@ -84,6 +87,9 @@
#define HTTP_SERVER_RCLONE "RClone"
#define HTTP_SERVER_ARCHIVEORG "Archive.org"
#define HTTP_SERVER_MYRIENT "Myrient"
#define HTTP_SERVER_GITHUB "Github"
#define EZREMOTE_SERVER_REQUIRED_VERSION "1.00"
#define MAX_EDIT_FILE_SIZE 32768
@@ -152,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
View File
@@ -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;
}
+4
View File
@@ -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); });
}
+3 -1
View File
@@ -353,7 +353,7 @@ private:
} // namespace detail
using Headers = std::map<std::string, std::string, detail::ci>;
using Headers = std::multimap<std::string, std::string, detail::ci>;
using Params = std::multimap<std::string, std::string>;
using Match = std::smatch;
@@ -1898,6 +1898,8 @@ make_basic_authentication_header(const std::string &username,
namespace detail {
const char *status_message(int status);
std::string encode_query_param(const std::string &value);
std::string encode_url(const std::string &s);
+291 -7
View File
@@ -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,10 +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))
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("://");
@@ -221,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;
}
@@ -854,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;
@@ -1041,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;
@@ -1170,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
View File
@@ -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);
}
+16 -1
View File
@@ -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;
@@ -258,6 +270,9 @@ namespace Lang
case ORBIS_SYSTEM_PARAM_LANG_ROMANIAN:
sprintf(langFile, "%s", "/app0/assets/langs/Romanian.ini");
break;
case ORBIS_SYSTEM_PARAM_LANG_NORWEGIAN:
sprintf(langFile, "%s", "/app0/assets/langs/Norwegian.ini");
break;
default:
sprintf(langFile, "%s", "/app0/assets/langs/English.ini");
break;
@@ -294,4 +309,4 @@ namespace Lang
sscanf(last_site, "%[^ ] %d", buf, &num);
sprintf(display_site, "%s %d", lang_strings[STR_SITE], num);
}
}
}
+15 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
+232 -45
View File
@@ -11,7 +11,9 @@
#include "clients/webdav.h"
#include "clients/apache.h"
#include "clients/archiveorg.h"
#include "clients/github.h"
#include "clients/iis.h"
#include "clients/myrient.h"
#include "clients/nginx.h"
#include "clients/npxserve.h"
#include "clients/rclone.h"
@@ -45,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;
@@ -252,6 +255,10 @@ namespace HttpServer
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_MYRIENT) == 0)
tmp_client = new MyrientClient();
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_GITHUB) == 0)
tmp_client = new GithubClient();
}
if (tmp_client->clientType() != CLIENT_TYPE_GOOGLE)
@@ -318,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());
@@ -363,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());
@@ -392,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());
@@ -446,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;
@@ -520,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)
@@ -559,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)
@@ -592,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;
@@ -628,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)
@@ -650,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)
@@ -673,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;
@@ -732,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;
@@ -771,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;
@@ -783,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;
@@ -853,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");
@@ -911,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())
{
@@ -944,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);
@@ -954,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"))
@@ -990,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;
@@ -1114,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];
@@ -1169,7 +1220,8 @@ namespace HttpServer
[](bool success) {
return true;
});
} });
}
});
svr->Get("/split_inst/(.*)", [&](const Request &req, Response &res)
{
@@ -1234,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)
@@ -1248,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)
{
@@ -1292,7 +1346,7 @@ namespace HttpServer
failed(res, 200, lang_strings[STR_CANT_EXTRACT_URL_MSG]);
activity_inprogess = false;
file_transfering = false;
Windows::SetModalMode(true);
Windows::SetModalMode(false);
return;
}
delete(filehost);
@@ -1305,28 +1359,58 @@ namespace HttpServer
BaseClient *baseclient = new BaseClient();
baseclient->Connect(host, "", "");
if (!baseclient->FileExists(path))
{
failed(res, 200, baseclient->LastResponse());
activity_inprogess = false;
file_transfering = false;
Windows::SetModalMode(false);
return;
}
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(true);
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));
@@ -1395,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)
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
+7
View File
@@ -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;
+257 -3
View File
@@ -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();
}
@@ -2647,6 +2889,10 @@ namespace Windows
{
sprintf(remote_settings->http_server_type, "%s", HTTP_SERVER_MYRIENT);
}
else if (strncasecmp(remote_settings->server, "https://github.com/", 19) == 0)
{
snprintf(remote_settings->http_server_type, 24, "%s", HTTP_SERVER_GITHUB);
}
}
}
@@ -2658,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)
+4
View File
@@ -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);
}