refactoring
Co-authored-by: n.fedorov <mail@nfedorov.dev> Co-committed-by: n.fedorov <mail@nfedorov.dev>
This commit was merged in pull request #1.
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
// Copyright (C) 2024-2026 NXST contributors
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
// Hash and comparison support for AccountUid as map/unordered_map key.
|
||||
namespace std {
|
||||
template <> struct hash<AccountUid> {
|
||||
size_t operator()(const AccountUid& a) const noexcept {
|
||||
return (hash<u64>()(a.uid[0]) ^ (hash<u64>()(a.uid[1]) << 1)) >> 1;
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
inline bool operator==(const AccountUid& x, const AccountUid& y) {
|
||||
return x.uid[0] == y.uid[0] && x.uid[1] == y.uid[1];
|
||||
}
|
||||
|
||||
inline bool operator<(const AccountUid& x, const AccountUid& y) {
|
||||
return x.uid[0] != y.uid[0] ? x.uid[0] < y.uid[0] : x.uid[1] < y.uid[1];
|
||||
}
|
||||
|
||||
struct User {
|
||||
AccountUid id;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
namespace account {
|
||||
Result init();
|
||||
void exit();
|
||||
std::vector<AccountUid> ids();
|
||||
std::string username(AccountUid id);
|
||||
std::string iconPath(AccountUid id);
|
||||
} // namespace account
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
namespace proto {
|
||||
constexpr uint16_t kTcpPort = 8080;
|
||||
constexpr uint16_t kMulticastPort = 8081;
|
||||
constexpr char kMulticastGroup[] = "239.0.0.1";
|
||||
constexpr size_t kBufSize = 65536;
|
||||
constexpr uint32_t kMaxFilename = 4096;
|
||||
constexpr uint32_t kEofSentinel = 0;
|
||||
|
||||
// Wire layout per file:
|
||||
// [filename_len : uint32_t LE] — 0 == end-of-stream
|
||||
// [filename : filename_len bytes]
|
||||
// [file_size : uint64_t LE]
|
||||
// [file_data : file_size bytes]
|
||||
} // namespace proto
|
||||
@@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace nxst {
|
||||
|
||||
template <class T, class E = std::string> class Result {
|
||||
bool ok;
|
||||
alignas(T) alignas(E) unsigned char storage[sizeof(T) > sizeof(E) ? sizeof(T) : sizeof(E)];
|
||||
|
||||
Result() = default;
|
||||
|
||||
public:
|
||||
static Result success(T val) {
|
||||
Result res;
|
||||
res.ok = true;
|
||||
new (res.storage) T(std::move(val));
|
||||
return res;
|
||||
}
|
||||
|
||||
static Result failure(E err) {
|
||||
Result res;
|
||||
res.ok = false;
|
||||
new (res.storage) E(std::move(err));
|
||||
return res;
|
||||
}
|
||||
|
||||
~Result() {
|
||||
if (ok)
|
||||
reinterpret_cast<T*>(storage)->~T();
|
||||
else
|
||||
reinterpret_cast<E*>(storage)->~E();
|
||||
}
|
||||
|
||||
Result(const Result& other) : ok(other.ok) {
|
||||
if (ok)
|
||||
new (storage) T(*reinterpret_cast<const T*>(other.storage));
|
||||
else
|
||||
new (storage) E(*reinterpret_cast<const E*>(other.storage));
|
||||
}
|
||||
|
||||
Result(Result&& other) : ok(other.ok) {
|
||||
if (ok)
|
||||
new (storage) T(std::move(*reinterpret_cast<T*>(other.storage)));
|
||||
else
|
||||
new (storage) E(std::move(*reinterpret_cast<E*>(other.storage)));
|
||||
}
|
||||
|
||||
Result& operator=(const Result&) = delete;
|
||||
|
||||
bool isOk() const noexcept {
|
||||
return ok;
|
||||
}
|
||||
const T& value() const {
|
||||
return *reinterpret_cast<const T*>(storage);
|
||||
}
|
||||
const E& error() const {
|
||||
return *reinterpret_cast<const E*>(storage);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialisation for Result<void>
|
||||
template <class E> class Result<void, E> {
|
||||
bool ok;
|
||||
alignas(E) unsigned char storage[sizeof(E)];
|
||||
|
||||
Result() = default;
|
||||
|
||||
public:
|
||||
static Result success() {
|
||||
Result res;
|
||||
res.ok = true;
|
||||
return res;
|
||||
}
|
||||
|
||||
static Result failure(E err) {
|
||||
Result res;
|
||||
res.ok = false;
|
||||
new (res.storage) E(std::move(err));
|
||||
return res;
|
||||
}
|
||||
|
||||
~Result() {
|
||||
if (!ok)
|
||||
reinterpret_cast<E*>(storage)->~E();
|
||||
}
|
||||
|
||||
Result(const Result& other) : ok(other.ok) {
|
||||
if (!ok)
|
||||
new (storage) E(*reinterpret_cast<const E*>(other.storage));
|
||||
}
|
||||
|
||||
Result(Result&& other) : ok(other.ok) {
|
||||
if (!ok)
|
||||
new (storage) E(std::move(*reinterpret_cast<E*>(other.storage)));
|
||||
}
|
||||
|
||||
Result& operator=(const Result&) = delete;
|
||||
|
||||
bool isOk() const noexcept {
|
||||
return ok;
|
||||
}
|
||||
const E& error() const {
|
||||
return *reinterpret_cast<const E*>(storage);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace nxst
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright (C) 2024-2026 NXST contributors
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
class Title {
|
||||
public:
|
||||
void init(u8 save_data_type, u64 title_id, AccountUid uid, const std::string& name,
|
||||
const std::string& author);
|
||||
|
||||
std::string author() const;
|
||||
std::pair<std::string, std::string> displayName() const;
|
||||
u64 id() const;
|
||||
std::string name() const;
|
||||
std::string path() const;
|
||||
u64 playTimeNanoseconds() const;
|
||||
std::string playTime() const;
|
||||
void playTimeNanoseconds(u64 ns);
|
||||
u32 lastPlayedTimestamp() const;
|
||||
void lastPlayedTimestamp(u32 ts);
|
||||
std::string fullPath(size_t index) const;
|
||||
void refreshDirectories();
|
||||
u64 saveId() const;
|
||||
void saveId(u64 id);
|
||||
std::vector<std::string> saves() const;
|
||||
u8 saveDataType() const;
|
||||
AccountUid userId() const;
|
||||
std::string userName() const;
|
||||
|
||||
private:
|
||||
u64 m_id{0};
|
||||
u64 m_save_id{0};
|
||||
AccountUid m_uid{};
|
||||
std::string m_user_name;
|
||||
std::string m_name;
|
||||
std::string m_safe_name;
|
||||
std::string m_author;
|
||||
std::string m_path;
|
||||
std::vector<std::string> m_saves;
|
||||
std::vector<std::string> m_full_save_paths;
|
||||
u8 m_save_data_type{0};
|
||||
std::pair<std::string, std::string> m_display_name;
|
||||
u64 m_play_time_ns{0};
|
||||
u32 m_last_played_ts{0};
|
||||
};
|
||||
|
||||
bool areTitlesLoaded();
|
||||
void loadTitles();
|
||||
void sortTitles();
|
||||
void rotateSortMode();
|
||||
void getTitle(Title& dst, AccountUid uid, size_t i);
|
||||
size_t getTitleCount(AccountUid uid);
|
||||
void refreshDirectories(u64 id);
|
||||
std::unordered_map<std::string, std::string> getCompleteTitleList();
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
struct TransferState {
|
||||
std::atomic<bool> done{false};
|
||||
std::atomic<bool> cancelled{false};
|
||||
std::atomic<bool> connection_failed{false};
|
||||
std::atomic<uint64_t> bytes_done{0};
|
||||
std::atomic<uint64_t> bytes_total{0};
|
||||
|
||||
std::string status;
|
||||
std::string fail_reason;
|
||||
mutable std::mutex status_mutex;
|
||||
|
||||
void reset() {
|
||||
done = false;
|
||||
cancelled = false;
|
||||
connection_failed = false;
|
||||
bytes_done = 0;
|
||||
bytes_total = 0;
|
||||
fail_reason.clear();
|
||||
std::lock_guard<std::mutex> lock(status_mutex);
|
||||
status.clear();
|
||||
}
|
||||
|
||||
double progress() const {
|
||||
uint64_t t = bytes_total.load();
|
||||
return t ? (double)bytes_done.load() / (double)t * 100.0 : 0.0;
|
||||
}
|
||||
|
||||
std::string getStatus() const {
|
||||
std::lock_guard<std::mutex> lock(status_mutex);
|
||||
return status;
|
||||
}
|
||||
|
||||
void setStatus(const std::string& s) {
|
||||
std::lock_guard<std::mutex> lock(status_mutex);
|
||||
status = s;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (C) 2024-2026 NXST contributors
|
||||
#pragma once
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
void servicesExit();
|
||||
Result servicesInit();
|
||||
void blinkLed(u8 times);
|
||||
|
||||
namespace string_utils {
|
||||
bool containsInvalidChar(const std::string& str);
|
||||
std::string format(const char* fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||
std::string removeForbiddenCharacters(std::string src);
|
||||
std::string UTF16toUTF8(const std::u16string& src);
|
||||
void ltrim(std::string& s);
|
||||
void rtrim(std::string& s);
|
||||
void trim(std::string& s);
|
||||
std::string removeAccents(std::string str);
|
||||
std::string removeNotAscii(std::string str);
|
||||
std::u16string UTF8toUTF16(const char* src);
|
||||
std::string elide(const std::string& s, size_t max_chars);
|
||||
} // namespace string_utils
|
||||
Reference in New Issue
Block a user