Skip to content

Commit

Permalink
Added updater code and improved zip extraction
Browse files Browse the repository at this point in the history
  • Loading branch information
CompSciOrBust committed Feb 10, 2020
1 parent 641bd7e commit 19fcec6
Show file tree
Hide file tree
Showing 9 changed files with 304 additions and 10 deletions.
5 changes: 4 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "SimpleIniParser"]
path = SimpleIniParser
url = https://github.com/AtlasNX/SimpleIniParser
url = https://github.com/AtlasNX/SimpleIniParser
[submodule "json"]
path = json
url = https://github.com/nlohmann/json
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ DATA := data
INCLUDES := include
APP_AUTHOR := CompSciOrBust
#ROMFS := romfs
APP_VERSION := 0.6.4 Beta
APP_VERSION := 0.7.0

#---------------------------------------------------------------------------------
# options for code generation
Expand All @@ -54,21 +54,21 @@ ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS := -g -Wall -O2 -ffunction-sections \
$(ARCH) $(DEFINES)

CFLAGS += -D__SWITCH__ $(INCLUDE) `sdl2-config --cflags`
CFLAGS += -D__SWITCH__ -DVERSION='"$(APP_VERSION)"' $(INCLUDE) `sdl2-config --cflags`

CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17

ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)

#Stolen from https://github.com/devolution2409/NX-input-recorder/blob/master/Makefile#L63 because SDL_Mixer is hard
LIBS := -lfreetype -lSDL2_mixer -lopusfile -lopus -lmodplug -lmpg123 -lvorbisidec -logg -lSDL2_ttf -lSDL2_gfx -lSDL2_image -lSDL2 -lEGL -lGLESv2 -lglapi -ldrm_nouveau -lwebp -lpng -ljpeg `sdl2-config --libs` `freetype-config --libs` -lnx -lSimpleIniParser -lminizip -lz
LIBS := -lcurl -lz -lmbedtls -lmbedcrypto -lmbedx509 -lnx -lfreetype -lSDL2_mixer -lopusfile -lopus -lmodplug -lmpg123 -lvorbisidec -lc -logg -lSDL2_ttf -lSDL2_gfx -lSDL2_image -lwebp -lpng -ljpeg `sdl2-config --libs` `freetype-config --libs` -lSimpleIniParser -lminizip

#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(LIBNX) $(CURDIR)/SimpleIniParser
LIBDIRS := $(PORTLIBS) $(LIBNX) $(CURDIR)/SimpleIniParser $(CURDIR)/json


#---------------------------------------------------------------------------------
Expand Down
10 changes: 10 additions & 0 deletions include/Networking.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <switch.h>
#include <curl/curl.h>
#include <string>

std::size_t CurlStrWrite(const char* in, std::size_t size, std::size_t num, std::string* out);
std::size_t CurlFileWrite(const char* in, std::size_t size, std::size_t num, FILE* out);
std::string RetrieveContent(std::string URL, std::string MIMEType);
void RetrieveToFile(std::string, std::string);
std::string FormatURL(std::string TextToFormat);
bool HasConnection();
23 changes: 23 additions & 0 deletions include/Updater.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <Utils.h>
#include <nlohmann/json.hpp>
using json = nlohmann::json;

class UpdaterUI : public UIWindow
{
private:
//vars
int State = 0;
bool NewVersion = false;
std::string LatestID;
json GitAPIData;
//functions
bool CheckForNewVersion();
public:
//vars
std::string NroPath = "sdmc:/switch/N-Xplorer.nro";
MenuUI *Menu;
//functions
void DrawUI();
void GetInput();
UpdaterUI();
};
1 change: 1 addition & 0 deletions json
Submodule json added at 973c52
6 changes: 2 additions & 4 deletions source/ExplorerUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,11 +369,9 @@ void ExplorerUI::OpenFile(string Path)
}
else if(FileSuffix == "zip")
{
*WindowState = 4;
*ChosenFile = Path;
*LongOpMessagePtr = "Unzipping " + FileNameList->ListingTextVec.at(FileNameList->SelectedIndex) + ". please wait!";
UnzipFile(Path, DirPath);
*WindowState = 0;
LoadListDirs(DirPath);
*WindowState = 8;
}
}

Expand Down
87 changes: 87 additions & 0 deletions source/Networking.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//Ripped straight from Amiigo
#include <switch.h>
#include <curl/curl.h>
#include <string>
#include <iostream>
#include <vector>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <chrono>
#include <thread>
#include "Utils.h"

extern int destroyer;
//Stolen from Goldleaf
//Thank you XOR
std::size_t CurlStrWrite(const char* in, std::size_t size, std::size_t num, std::string* out)
{
const size_t totalBytes(size * num);
out->append(in, totalBytes);
return totalBytes;
}

std::size_t CurlFileWrite(const char* in, std::size_t size, std::size_t num, FILE* out)
{
fwrite(in, size, num, out);
return (size * num);
}

std::string RetrieveContent(std::string URL, std::string MIMEType)
{
std::string cnt;
CURL *curl = curl_easy_init();
if(!MIMEType.empty())
{
curl_slist *headerdata = NULL;
headerdata = curl_slist_append(headerdata, ("Content-Type: " + MIMEType).c_str());
headerdata = curl_slist_append(headerdata, ("Accept: " + MIMEType).c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerdata);
}
curl_easy_setopt(curl, CURLOPT_URL, URL.c_str());
curl_easy_setopt(curl, CURLOPT_USERAGENT, "N-Xplorer");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlStrWrite);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &cnt);
curl_easy_perform(curl);
curl_easy_cleanup(curl);
return cnt;
}

void RetrieveToFile(std::string URL, std::string Path)
{
FILE *f = fopen(Path.c_str(), "wb");
if(f)
{
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, URL.c_str());
curl_easy_setopt(curl, CURLOPT_USERAGENT, "N-Xplorer");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlFileWrite);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, f);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
fclose(f);
}

//I made this so even though it's only one two calls it's probably janky.
std::string FormatURL(std::string TextToFormat)
{
CURL *curl = curl_easy_init();
return curl_easy_escape(curl, TextToFormat.c_str(), 0);
}

//More stuff from Xortroll Industries
bool HasConnection()
{
u32 strg = 0;
nifmInitialize(NifmServiceType_User);
nifmGetInternetConnectionStatus(NULL, &strg, NULL);
return (strg > 0);
}
140 changes: 140 additions & 0 deletions source/Updater.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//Based on Amiigo's updater
#include <SDL.h>
#include <Networking.h>
#include <Utils.h>
#include <ExplorerUI.h>
#include <nlohmann/json.hpp>
using json = nlohmann::json;

class UpdaterUI : public UIWindow
{
private:
//vars
int State = 0;
bool NewVersion = false;
std::string LatestID;
json GitAPIData;
//functions
bool CheckForNewVersion();
public:
//vars
std::string NroPath = "sdmc:/switch/N-Xplorer.nro";
MenuUI *Menu;
//functions
void DrawUI();
void GetInput();
UpdaterUI();
};

UpdaterUI::UpdaterUI()
{
nifmInitialize(NifmServiceType_User); //Init nifm for connection stuff
}

void UpdaterUI::DrawUI()
{
Menu->DrawLongOpMessage();
}

void UpdaterUI::GetInput()
{
//scan input
bool BPressed = false;
while (SDL_PollEvent(Event))
{
switch (Event->type)
{
//Joycon button down
case SDL_JOYBUTTONDOWN:
{
if (Event->jbutton.which == 0)
{
if(Event->jbutton.button == 1)
{
BPressed = true;
}
}
}
}
}

//Update the message and do logic
switch(State)
{
//Check for connection and update
case 0:
{
if(!HasConnection())
{
Menu->LongOpMessage = "Waiting for connection.";
if(BPressed)
{
*WindowState = 6;
}
}
else
{
Menu->LongOpMessage = "Checking for new version...";
NewVersion = CheckForNewVersion();
State++;
}
}
break;
//Download new zip
case 1:
{
if(NewVersion)
{
Menu->LongOpMessage = "Downloading " + LatestID + ".";
string UpdateFileURL = "https://github.com/CompSciOrBust/N-Xplorer/releases/download/" + LatestID + "/N-Xplorer.zip";
RetrieveToFile(UpdateFileURL, "sdmc:/config/N-Xplorer/update.zip");
UnzipFile("sdmc:/config/N-Xplorer/update.zip", "sdmc:/");
if(NroPath != "sdmc:/switch/N-Xplorer.nro")
{
remove(NroPath.c_str());
rename("sdmc:/switch/N-Xplorer.nro", NroPath.c_str());
*IsDone = 1;
}
}
else
{
Menu->LongOpMessage = "Already on the latest version. Press B to exit.";
if(BPressed)
{
*WindowState = 6;
NewVersion = false;
State = 0;
}
}
}
break;
//Error
case 999:
{
Menu->LongOpMessage = "Error! Is GitHub rate limiting you? Press B to exit";
if(BPressed)
{
*WindowState = 6;
}
}
break;

}
}

bool UpdaterUI::CheckForNewVersion()
{
//Get data from GitHub API
std::string Data = RetrieveContent("https://api.github.com/repos/CompSciOrBust/N-Xplorer/releases", "application/json");
//Get the release tag string from the data
GitAPIData = json::parse(Data);
//Check if GitAPI gave us a release tag otherwise we'll crash
if(Data.length() < 300)
{
State = 999;
return false;
}
LatestID = GitAPIData[0]["tag_name"].get<std::string>();
//Check if we're running the latest version
return (LatestID != VERSION);
}
34 changes: 33 additions & 1 deletion source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <TextUI.h>
#include <ImageUI.h>
#include <Settings.h>
#include <Updater.h>
#include <thread>
#include <mutex>

Expand Down Expand Up @@ -133,11 +134,19 @@ int main(int argc, char* argv[])
SettingsMenu->Explorer = Explorer;
SettingsMenu->ContextMenu = Menu;

//Init the updater
UpdaterUI *Updater = new UpdaterUI();
Updater->Renderer = Renderer;
Updater->Event = &Event;
Updater->WindowState = WindowStatePtr;
Updater->Menu = Menu;
Updater->NroPath = argv[0];

//Load the settings and create ini on first start up
SettingsMenu->CreateNewIni();

//Input loop thread
std::thread InputLoopThread([DonePtr, WindowStatePtr, Explorer, Menu, TextEditor, ImageViewer, SettingsMenu, ExplorerAccessPtr, TextEditorAccessPtr, ImageViewerAccessPtr]()
std::thread InputLoopThread([DonePtr, WindowStatePtr, Explorer, Menu, TextEditor, ImageViewer, SettingsMenu, ExplorerAccessPtr, TextEditorAccessPtr, ImageViewerAccessPtr, Updater]()
{
while(!*DonePtr)
{
Expand Down Expand Up @@ -214,6 +223,21 @@ int main(int argc, char* argv[])
ExplorerAccessPtr->unlock();
}
break;
//Updater input
case 7:
{
Updater->GetInput();
}
break;
//Unzip logic
case 8:
{
*WindowStatePtr = 4;
UnzipFile(*Explorer->ChosenFile, Explorer->DirPath);
*WindowStatePtr = 0;
Explorer->LoadListDirs(Explorer->DirPath);
}
break;
}
}
});
Expand Down Expand Up @@ -284,6 +308,14 @@ int main(int argc, char* argv[])
ExplorerAccess.unlock();
}
break;
//Draw the updater UI
case 7:
{
Explorer->DrawUI();
Updater->DrawUI();
Menu->DrawLongOpMessage();
}
break;
}
//Draw the frame
SDL_RenderPresent(Renderer);
Expand Down

0 comments on commit 19fcec6

Please sign in to comment.