-
Notifications
You must be signed in to change notification settings - Fork 142
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Shim SlippiDirectCodes to Rust port.
This changes out the internals of the `SlippiDirectCodes` class, wherein it'll now just silently call over to the Rust side. This keeps the changes minimal for now as we continue to migrate things out. There is a small change here to `FileUtil` to have it return a folder path rather than a file path; the Rust layer will extend that path with whatever it needs (e.g `user.json`). This compiles but has not been fully tested/vetted yet. Building this branch currently requires the corresponding branch from slippi-rust-extensions.
- Loading branch information
1 parent
4f53653
commit e4bdc9d
Showing
5 changed files
with
53 additions
and
244 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,230 +1,41 @@ | ||
#include "SlippiDirectCodes.h" | ||
|
||
#ifdef _WIN32 | ||
#include "AtlBase.h" | ||
#include "AtlConv.h" | ||
#endif | ||
|
||
#include "Common/CommonPaths.h" | ||
#include "Common/FileUtil.h" | ||
#include "Common/Logging/Log.h" | ||
#include "Common/MsgHandler.h" | ||
#include "Common/StringUtil.h" | ||
#include "Common/Thread.h" | ||
|
||
#include "Core/ConfigManager.h" | ||
#include "SlippiRustExtensions.h" | ||
|
||
#include <codecvt> | ||
#include <locale> | ||
#include <time.h> | ||
|
||
#include <json.hpp> | ||
using json = nlohmann::json; | ||
|
||
SlippiDirectCodes::SlippiDirectCodes(std::string fileName) | ||
{ | ||
m_fileName = fileName; | ||
#include "SlippiDirectCodes.h" | ||
|
||
// Prevent additional file reads, if we've already loaded data to memory. | ||
// if (directCodeInfos.empty()) | ||
ReadFile(); | ||
Sort(); | ||
DirectCodeKind mapCode(uint8_t code_kind) { | ||
return code_kind == SlippiDirectCodes::DIRECT ? | ||
DirectCodeKind::DirectCodes : | ||
DirectCodeKind::TeamsCodes; | ||
} | ||
|
||
SlippiDirectCodes::~SlippiDirectCodes() | ||
SlippiDirectCodes::SlippiDirectCodes(uintptr_t rs_exi_device_ptr, uint8_t code_kind) | ||
{ | ||
// Add additional cleanup behavior here? Just added something | ||
// So compiler wouldn't nag. | ||
return; | ||
slprs_exi_device_ptr = rs_exi_device_ptr; | ||
kind = code_kind; | ||
} | ||
|
||
void SlippiDirectCodes::ReadFile() | ||
{ | ||
std::string directCodesFilePath = getCodesFilePath(); | ||
|
||
INFO_LOG(SLIPPI_ONLINE, "Looking for direct codes file at %s", directCodesFilePath.c_str()); | ||
|
||
if (!File::Exists(directCodesFilePath)) | ||
{ | ||
// Attempt to create empty file with array as parent json item. | ||
if (File::CreateFullPath(directCodesFilePath) && File::CreateEmptyFile(directCodesFilePath)) | ||
{ | ||
File::WriteStringToFile("[\n]", directCodesFilePath); | ||
} | ||
else | ||
{ | ||
WARN_LOG(SLIPPI_ONLINE, "Was unable to create %s", directCodesFilePath.c_str()); | ||
} | ||
} | ||
|
||
std::string directCodesFileContents; | ||
File::ReadFileToString(directCodesFilePath, directCodesFileContents); | ||
|
||
directCodeInfos = parseFile(directCodesFileContents); | ||
} | ||
SlippiDirectCodes::~SlippiDirectCodes() {} | ||
|
||
void SlippiDirectCodes::AddOrUpdateCode(std::string code) | ||
{ | ||
WARN_LOG(SLIPPI_ONLINE, "Attempting to add or update direct code: %s", code.c_str()); | ||
|
||
time_t curTime; | ||
time(&curTime); | ||
u8 dateTimeStrLength = sizeof "20171015T095717"; | ||
std::vector<char> dateTimeBuf(dateTimeStrLength); | ||
strftime(&dateTimeBuf[0], dateTimeStrLength, "%Y%m%dT%H%M%S", localtime(&curTime)); | ||
std::string timestamp(&dateTimeBuf[0]); | ||
|
||
bool found = false; | ||
for (auto it = directCodeInfos.begin(); it != directCodeInfos.end(); ++it) | ||
{ | ||
if (it->connectCode == code) | ||
{ | ||
found = true; | ||
it->lastPlayed = timestamp; | ||
} | ||
} | ||
|
||
if (!found) | ||
{ | ||
CodeInfo newDirectCode = {code, timestamp, false}; | ||
directCodeInfos.push_back(newDirectCode); | ||
} | ||
|
||
// TODO: Maybe remove from here? | ||
// Or start a thread that is periodically called, if file writes will happen enough. | ||
WriteFile(); | ||
} | ||
|
||
void SlippiDirectCodes::Sort(u8 sortByProperty) | ||
{ | ||
switch (sortByProperty) | ||
{ | ||
case SORT_BY_TIME: | ||
std::sort(directCodeInfos.begin(), directCodeInfos.end(), | ||
[](const CodeInfo a, const CodeInfo b) -> bool { return a.lastPlayed > b.lastPlayed; }); | ||
break; | ||
|
||
case SORT_BY_NAME: | ||
std::sort(directCodeInfos.begin(), directCodeInfos.end(), | ||
[](const CodeInfo a, const CodeInfo b) -> bool { return a.connectCode < b.connectCode; }); | ||
break; | ||
} | ||
} | ||
|
||
std::string SlippiDirectCodes::Autocomplete(std::string startText) | ||
{ | ||
// Pre-sort direct codes. | ||
Sort(); | ||
|
||
// Find first entry in our sorted vector that starts with the given text. | ||
for (auto it = directCodeInfos.begin(); it != directCodeInfos.end(); it++) | ||
{ | ||
if (it->connectCode.rfind(startText, 0) == 0) | ||
{ | ||
return it->connectCode; | ||
} | ||
} | ||
|
||
return startText; | ||
slprs_user_direct_codes_add_or_update(slprs_exi_device_ptr, mapCode(kind), code.c_str()); | ||
} | ||
|
||
std::string SlippiDirectCodes::get(int index) | ||
{ | ||
Sort(); | ||
|
||
if (index < directCodeInfos.size() && index >= 0) | ||
{ | ||
return directCodeInfos.at(index).connectCode; | ||
} | ||
char *code = slprs_user_direct_codes_get_code_at_index(slprs_exi_device_ptr, mapCode(kind), index); | ||
|
||
// To be safe, just do an extra copy into a full C++ string type - i.e, the ownership | ||
// that we're passing out from behind this method is clear. | ||
std::string connectCode = std::string(code); | ||
|
||
INFO_LOG(SLIPPI_ONLINE, "Out of bounds name entry index %d", index); | ||
// Since the C string was allocated on the Rust side, we need to free it using that allocator. | ||
slprs_user_direct_codes_free_code(code); | ||
|
||
return (index >= directCodeInfos.size()) ? "1" : ""; | ||
return connectCode; | ||
} | ||
|
||
int SlippiDirectCodes::length() | ||
{ | ||
return (int)directCodeInfos.size(); | ||
} | ||
|
||
void SlippiDirectCodes::WriteFile() | ||
{ | ||
std::string directCodesFilePath = getCodesFilePath(); | ||
|
||
// Outer empty array. | ||
json fileData = json::array(); | ||
|
||
// Inner contents. | ||
json directCodeData = json::object(); | ||
|
||
// TODO Define constants for string literals. | ||
for (auto it = directCodeInfos.begin(); it != directCodeInfos.end(); ++it) | ||
{ | ||
directCodeData["connectCode"] = it->connectCode; | ||
directCodeData["lastPlayed"] = it->lastPlayed; | ||
directCodeData["isFavorite"] = it->isFavorite; | ||
|
||
fileData.emplace_back(directCodeData); | ||
} | ||
|
||
File::WriteStringToFile(fileData.dump(), directCodesFilePath); | ||
} | ||
|
||
std::string SlippiDirectCodes::getCodesFilePath() | ||
{ | ||
std::string fileName = m_fileName + ".json"; | ||
|
||
std::string directCodesPath = File::GetUserPath(D_SLIPPI_IDX) + m_fileName; | ||
return directCodesPath; | ||
} | ||
|
||
inline std::string readString(json obj, std::string key) | ||
{ | ||
auto item = obj.find(key); | ||
if (item == obj.end() || item.value().is_null()) | ||
{ | ||
return ""; | ||
} | ||
|
||
return obj[key]; | ||
} | ||
|
||
inline bool readBool(json obj, std::string key) | ||
{ | ||
auto item = obj.find(key); | ||
if (item == obj.end() || item.value().is_null()) | ||
{ | ||
return false; | ||
} | ||
|
||
return obj[key]; | ||
} | ||
|
||
std::vector<SlippiDirectCodes::CodeInfo> SlippiDirectCodes::parseFile(std::string fileContents) | ||
{ | ||
std::vector<SlippiDirectCodes::CodeInfo> directCodes; | ||
|
||
json res = json::parse(fileContents, nullptr, false); | ||
// Unlike the user.json, the encapsulating type should be an array. | ||
if (res.is_discarded() || !res.is_array()) | ||
{ | ||
WARN_LOG(SLIPPI_ONLINE, "Malformed json in direct codes file."); | ||
return directCodes; | ||
} | ||
|
||
// Retrieve all saved direct codes and related info | ||
for (auto it = res.begin(); it != res.end(); ++it) | ||
{ | ||
if (it.value().is_object()) | ||
{ | ||
CodeInfo curDirectCode; | ||
curDirectCode.connectCode = readString(*it, "connectCode"); | ||
curDirectCode.lastPlayed = readString(*it, "lastPlayed"); | ||
curDirectCode.isFavorite = readBool(*it, "favorite"); | ||
|
||
directCodes.push_back(curDirectCode); | ||
} | ||
} | ||
|
||
return directCodes; | ||
return slprs_user_direct_codes_get_length(slprs_exi_device_ptr, mapCode(kind)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,34 @@ | ||
#pragma once | ||
|
||
#include "Common/CommonTypes.h" | ||
#include <atomic> | ||
#include <string> | ||
#include <thread> | ||
#include <vector> | ||
|
||
// This class is currently a shim for the Rust codes interface. We're doing it this way | ||
// to migrate things over without needing to do larger invasive changes. | ||
// | ||
// The remaining methods on here are simply layers that direct the call over to the Rust | ||
// side. A quirk of this is that we're using the EXI device pointer, so this class absolutely | ||
// cannot outlive the EXI device - but we control that and just need to do our due diligence | ||
// when making changes. | ||
class SlippiDirectCodes | ||
{ | ||
public: | ||
static const uint8_t SORT_BY_TIME = 1; | ||
static const uint8_t SORT_BY_FAVORITE = 2; | ||
static const uint8_t SORT_BY_NAME = 3; | ||
// We can't currently expose `SlippiRustExtensions.h` in header files, so | ||
// we export these two types for code clarity and map them in the implementation. | ||
static const uint8_t DIRECT = 0; | ||
static const uint8_t TEAMS = 1; | ||
|
||
struct CodeInfo | ||
{ | ||
std::string connectCode = ""; | ||
std::string lastPlayed = ""; | ||
bool isFavorite = false; | ||
}; | ||
|
||
SlippiDirectCodes(std::string fileName); | ||
SlippiDirectCodes(uintptr_t rs_exi_device_ptr, uint8_t kind); | ||
~SlippiDirectCodes(); | ||
|
||
void ReadFile(); | ||
void AddOrUpdateCode(std::string code); | ||
std::string get(int index); | ||
int length(); | ||
void Sort(u8 sortByProperty = SlippiDirectCodes::SORT_BY_TIME); | ||
std::string Autocomplete(std::string startText); | ||
void AddOrUpdateCode(std::string code); | ||
|
||
protected: | ||
void WriteFile(); | ||
std::string getCodesFilePath(); | ||
std::vector<CodeInfo> parseFile(std::string fileContents); | ||
std::vector<CodeInfo> directCodeInfos; | ||
std::string m_fileName; | ||
}; | ||
// A pointer to a "shadow" EXI Device that lives on the Rust side of things. | ||
// Do *not* do any cleanup of this! The EXI device will handle it. | ||
uintptr_t slprs_exi_device_ptr; | ||
|
||
// An internal marker for what kind of codes we're reading/reporting. | ||
uint8_t kind; | ||
}; |