Skip to content

Commit 85fe11f

Browse files
committed
unzip binary separately
1 parent ab240e8 commit 85fe11f

File tree

5 files changed

+103
-58
lines changed

5 files changed

+103
-58
lines changed

loader/include/Geode/loader/Dirs.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ namespace geode::dirs {
4444
* Directory where mods' unzipped packages are stored at runtime
4545
*/
4646
GEODE_DLL std::filesystem::path getModRuntimeDir();
47+
/**
48+
* Directory where mods' unzipped binary files are stored
49+
* This is used in order to override existing unzip binaries,
50+
* such as on iOS where signing the binary is required
51+
*/
52+
GEODE_DLL std::filesystem::path getModBinariesDir();
4753
/**
4854
* Directory where mods' config files lie
4955
*/

loader/src/loader/Dirs.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,8 @@ std::filesystem::path dirs::getCrashlogsDir() {
4949

5050
std::filesystem::path dirs::getModPersistentDir() {
5151
return dirs::getSaveDir() / "geode-persistent";
52+
}
53+
54+
std::filesystem::path dirs::getModBinariesDir() {
55+
return dirs::getModRuntimeDir() / "binaries";
5256
}

loader/src/loader/LoaderImpl.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -923,10 +923,44 @@ Result<> Loader::Impl::unzipGeodeFile(ModMetadata metadata) {
923923
std::filesystem::remove(entry.path(), ec);
924924
}
925925

926+
// Check if there is a binary that we need to move over from the unzipped binaries dir
927+
if (this->isPatchless()) {
928+
auto src = dirs::getModBinariesDir() / metadata.getBinaryName();
929+
auto dst = tempDir / metadata.getBinaryName();
930+
if (std::filesystem::exists(src)) {
931+
std::error_code ec;
932+
std::filesystem::rename(src, dst, ec);
933+
if (ec) {
934+
auto message = formatSystemError(ec.value());
935+
return Err(
936+
fmt::format("Failed to move binary from {} to {}: {}", src.string(), dst.string(), message)
937+
);
938+
}
939+
}
940+
}
941+
926942
auto res = file::writeString(datePath, modifiedHash);
927943
if (!res) {
928-
log::warn("Failed to write modified date of geode zip: {}", res.unwrapErr());
944+
log::warn("Failed to write modified date of geode zip, will try to unzip next launch: {}", res.unwrapErr());
945+
}
946+
947+
return Ok();
948+
}
949+
950+
Result<> Loader::Impl::extractBinary(ModMetadata metadata) {
951+
if (!this->isPatchless()) {
952+
// If we are not patchless, there is no need to extract the binary separately
953+
return Ok();
954+
}
955+
956+
// Extract the binary from the .geode file
957+
GEODE_UNWRAP_INTO(auto unzip, file::Unzip::create(metadata.getPath()));
958+
if (!unzip.hasEntry(metadata.getBinaryName())) {
959+
return Err(
960+
fmt::format("Unable to find platform binary under the name \"{}\"", metadata.getBinaryName())
961+
);
929962
}
963+
GEODE_UNWRAP(unzip.extractTo(metadata.getBinaryName(), dirs::getModBinariesDir() / metadata.getBinaryName()));
930964

931965
return Ok();
932966
}

loader/src/loader/LoaderImpl.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ namespace geode {
138138
// called on a separate thread
139139
Result<> unzipGeodeFile(ModMetadata metadata);
140140

141+
Result<> extractBinary(ModMetadata metadata);
142+
141143
bool userTriedToLoadDLLs() const;
142144

143145
void addProblem(LoadProblem const& problem);

loader/src/server/DownloadManager.cpp

Lines changed: 56 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -116,63 +116,7 @@ class ModDownload::Impl final {
116116

117117
m_downloadListener.bind([this, hash = std::move(version.hash), version = std::move(version)](web::WebTask::Event* event) {
118118
if (auto value = event->getValue()) {
119-
if (value->ok()) {
120-
if (auto actualHash = ::calculateHash(value->data()); actualHash != hash) {
121-
log::error("Failed to download {}, hash mismatch ({} != {})", m_id, actualHash, hash);
122-
m_status = DownloadStatusError {
123-
.details = "Hash mismatch, downloaded file did not match what was expected",
124-
};
125-
ModDownloadEvent(m_id).post();
126-
return;
127-
}
128-
129-
bool removingInstalledWasError = false;
130-
std::string id = m_replacesMod.has_value() ? m_replacesMod.value() : m_id;
131-
if (auto mod = Loader::get()->getInstalledMod(id)) {
132-
std::error_code ec;
133-
std::filesystem::remove(mod->getPackagePath(), ec);
134-
if (ec) {
135-
removingInstalledWasError = true;
136-
m_status = DownloadStatusError {
137-
.details = fmt::format("Unable to delete existing .geode package (code {})", ec),
138-
};
139-
}
140-
// Mark mod as updated
141-
ModImpl::getImpl(mod)->m_requestedAction = ModRequestedAction::Update;
142-
}
143-
// If this was an update, delete the old file first
144-
if (!removingInstalledWasError) {
145-
auto geodePath = dirs::getModsDir() / (m_id + ".geode");
146-
auto ok = file::writeBinary(geodePath, value->data());
147-
if (!ok) {
148-
m_status = DownloadStatusError {
149-
.details = ok.unwrapErr(),
150-
};
151-
}
152-
else {
153-
#ifdef GEODE_IS_IOS
154-
auto metadata = ModMetadata::createFromGeodeZip(geodePath);
155-
if (metadata.isErr()) {
156-
m_status = DownloadStatusError {
157-
.details = m_metadata.unwrapErr(),
158-
};
159-
return;
160-
}
161-
auto okUnzip = LoaderImpl::get()->unzipGeodeFile(metadata.unwrap());
162-
if (!okUnzip) {
163-
m_status = DownloadStatusError {
164-
.details = okUnzip.unwrapErr(),
165-
};
166-
return;
167-
}
168-
#endif
169-
m_status = DownloadStatusDone {
170-
.version = version
171-
};
172-
}
173-
}
174-
}
175-
else {
119+
if (!value->ok()) {
176120
auto resp = event->getValue();
177121

178122
if (resp->code() == -1) {
@@ -199,7 +143,60 @@ class ModDownload::Impl final {
199143
if (!extErr.empty()) {
200144
log::error("Extended error info: {}", extErr);
201145
}
146+
goto postdownloadedevent;
202147
}
148+
149+
if (auto actualHash = ::calculateHash(value->data()); actualHash != hash) {
150+
log::error("Failed to download {}, hash mismatch ({} != {})", m_id, actualHash, hash);
151+
m_status = DownloadStatusError {
152+
.details = "Hash mismatch, downloaded file did not match what was expected",
153+
};
154+
goto postdownloadedevent;
155+
}
156+
157+
std::string id = m_replacesMod.has_value() ? m_replacesMod.value() : m_id;
158+
if (auto mod = Loader::get()->getInstalledMod(id)) {
159+
std::error_code ec;
160+
std::filesystem::remove(mod->getPackagePath(), ec);
161+
if (ec) {
162+
m_status = DownloadStatusError {
163+
.details = fmt::format("Unable to delete existing .geode package (code {})", ec),
164+
};
165+
goto postdownloadedevent;
166+
}
167+
// Mark mod as updated
168+
ModImpl::getImpl(mod)->m_requestedAction = ModRequestedAction::Update;
169+
}
170+
171+
// If this was an update, delete the old file first
172+
auto geodePath = dirs::getModsDir() / (m_id + ".geode");
173+
auto ok = file::writeBinary(geodePath, value->data());
174+
if (!ok) {
175+
m_status = DownloadStatusError {
176+
.details = ok.unwrapErr(),
177+
};
178+
goto postdownloadedevent;
179+
}
180+
181+
auto metadata = ModMetadata::createFromGeodeFile(geodePath);
182+
if (metadata.isErr()) {
183+
m_status = DownloadStatusError {
184+
.details = metadata.unwrapErr(),
185+
};
186+
goto postdownloadedevent;
187+
}
188+
189+
auto okBinary = LoaderImpl::get()->extractBinary(metadata.unwrap());
190+
if (!okBinary) {
191+
m_status = DownloadStatusError {
192+
.details = okBinary.unwrapErr(),
193+
};
194+
goto postdownloadedevent;
195+
}
196+
197+
m_status = DownloadStatusDone {
198+
.version = version
199+
};
203200
}
204201
else if (auto progress = event->getProgress()) {
205202
m_status = DownloadStatusDownloading {
@@ -211,6 +208,8 @@ class ModDownload::Impl final {
211208
}
212209
// Throttle events to only once per frame to not cause a
213210
// billion UI updates at once
211+
postdownloadedevent:
212+
214213
if (m_scheduledEventForFrame != CCDirector::get()->getTotalFrames()) {
215214
m_scheduledEventForFrame = CCDirector::get()->getTotalFrames();
216215
Loader::get()->queueInMainThread([id = m_id]() {

0 commit comments

Comments
 (0)