yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
rom_sandbox_manager.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cstdlib>
5
6#include "absl/status/status.h"
7#include "absl/status/statusor.h"
8#include "absl/strings/str_cat.h"
9#include "absl/strings/str_format.h"
10#include "absl/time/time.h"
11#include "util/macro.h"
12
13namespace yaze {
14namespace cli {
15
16namespace {
17
18std::filesystem::path DetermineDefaultRoot() {
19 if (const char* env_root = std::getenv("YAZE_SANDBOX_ROOT")) {
20 return std::filesystem::path(env_root);
21 }
22 std::error_code ec;
23 auto temp_dir = std::filesystem::temp_directory_path(ec);
24 if (ec) {
25 // Fallback to current working directory if temp is unavailable.
26 return std::filesystem::current_path() / "yaze" / "sandboxes";
27 }
28 return temp_dir / "yaze" / "sandboxes";
29}
30
31std::filesystem::path ResolveUniqueDirectory(const std::filesystem::path& root,
32 absl::string_view id) {
33 return root / std::string(id);
34}
35
36} // namespace
37
39 static RomSandboxManager* instance = new RomSandboxManager();
40 return *instance;
41}
42
44 : root_directory_(DetermineDefaultRoot()) {}
45
46void RomSandboxManager::SetRootDirectory(const std::filesystem::path& root) {
47 std::lock_guard<std::mutex> lock(mutex_);
48 root_directory_ = root;
50}
51
52const std::filesystem::path& RomSandboxManager::RootDirectory() const {
53 return root_directory_;
54}
55
57 std::error_code ec;
58 if (!std::filesystem::exists(root_directory_, ec)) {
59 if (!std::filesystem::create_directories(root_directory_, ec) && ec) {
60 return absl::InternalError(
61 absl::StrCat("Failed to create sandbox root at ",
62 root_directory_.string(), ": ", ec.message()));
63 }
64 }
65 return absl::OkStatus();
66}
67
69 absl::Time now = absl::Now();
70 std::string time_component =
71 absl::FormatTime("%Y%m%dT%H%M%S", now, absl::LocalTimeZone());
72 ++sequence_;
73 return absl::StrCat(time_component, "-", sequence_);
74}
75
76absl::StatusOr<RomSandboxManager::SandboxMetadata>
77RomSandboxManager::CreateSandbox(Rom& rom, absl::string_view description) {
78 if (!rom.is_loaded()) {
79 return absl::FailedPreconditionError(
80 "Cannot create sandbox: ROM is not loaded");
81 }
82
83 std::filesystem::path source_path(rom.filename());
84 if (source_path.empty()) {
85 return absl::FailedPreconditionError(
86 "Cannot create sandbox: ROM filename is empty");
87 }
88
89 std::unique_lock<std::mutex> lock(mutex_);
91
92 std::string id = GenerateSandboxIdLocked();
93 std::filesystem::path sandbox_dir =
94 ResolveUniqueDirectory(root_directory_, id);
95 lock.unlock();
96
97 std::error_code ec;
98 if (!std::filesystem::create_directories(sandbox_dir, ec) && ec) {
99 return absl::InternalError(
100 absl::StrCat("Failed to create sandbox directory at ",
101 sandbox_dir.string(), ": ", ec.message()));
102 }
103
104 std::filesystem::path sandbox_rom_path = sandbox_dir / source_path.filename();
105
106 Rom::SaveSettings settings;
107 settings.filename = sandbox_rom_path.string();
108 settings.save_new = false;
109 settings.backup = false;
110
111 absl::Status save_status = rom.SaveToFile(settings);
112 if (!save_status.ok()) {
113 std::error_code cleanup_ec;
114 std::filesystem::remove_all(sandbox_dir, cleanup_ec);
115 return save_status;
116 }
117
118 lock.lock();
120 .id = id,
121 .directory = sandbox_dir,
122 .rom_path = sandbox_rom_path,
123 .source_rom = source_path.string(),
124 .description = std::string(description),
125 .created_at = absl::Now(),
126 };
128
129 return sandboxes_.at(id);
130}
131
132absl::StatusOr<RomSandboxManager::SandboxMetadata>
134 std::lock_guard<std::mutex> lock(mutex_);
135 if (!active_sandbox_id_.has_value()) {
136 return absl::NotFoundError("No active sandbox");
137 }
138 auto it = sandboxes_.find(*active_sandbox_id_);
139 if (it == sandboxes_.end()) {
140 return absl::NotFoundError("Active sandbox metadata missing");
141 }
142 return it->second;
143}
144
145absl::StatusOr<std::filesystem::path> RomSandboxManager::ActiveSandboxRomPath()
146 const {
147 ASSIGN_OR_RETURN(auto meta, ActiveSandbox());
148 return meta.rom_path;
149}
150
151std::vector<RomSandboxManager::SandboxMetadata>
153 std::lock_guard<std::mutex> lock(mutex_);
154 std::vector<SandboxMetadata> list;
155 list.reserve(sandboxes_.size());
156 for (const auto& [_, metadata] : sandboxes_) {
157 list.push_back(metadata);
158 }
159 std::sort(list.begin(), list.end(),
160 [](const SandboxMetadata& a, const SandboxMetadata& b) {
161 return a.created_at < b.created_at;
162 });
163 return list;
164}
165
166absl::Status RomSandboxManager::RemoveSandbox(const std::string& id) {
167 std::lock_guard<std::mutex> lock(mutex_);
168 auto it = sandboxes_.find(id);
169 if (it == sandboxes_.end()) {
170 return absl::NotFoundError("Sandbox not found");
171 }
172 std::error_code ec;
173 std::filesystem::remove_all(it->second.directory, ec);
174 if (ec) {
175 return absl::InternalError(
176 absl::StrCat("Failed to remove sandbox directory: ", ec.message()));
177 }
178 sandboxes_.erase(it);
179 if (active_sandbox_id_.has_value() && *active_sandbox_id_ == id) {
180 active_sandbox_id_.reset();
181 }
182 return absl::OkStatus();
183}
184
186 absl::Duration max_age) {
187 std::vector<std::string> to_remove;
188 {
189 std::lock_guard<std::mutex> lock(mutex_);
190 absl::Time threshold = absl::Now() - max_age;
191 for (const auto& [id, metadata] : sandboxes_) {
192 if (metadata.created_at < threshold) {
193 to_remove.push_back(id);
194 }
195 }
196 }
197
198 int removed = 0;
199 for (const auto& id : to_remove) {
200 absl::Status status = RemoveSandbox(id);
201 if (!status.ok()) {
202 return status;
203 }
204 ++removed;
205 }
206 return removed;
207}
208
209} // namespace cli
210} // namespace yaze
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:24
auto filename() const
Definition rom.h:141
absl::Status SaveToFile(const SaveSettings &settings)
Definition rom.cc:164
bool is_loaded() const
Definition rom.h:128
absl::StatusOr< SandboxMetadata > CreateSandbox(Rom &rom, absl::string_view description)
absl::Status RemoveSandbox(const std::string &id)
void SetRootDirectory(const std::filesystem::path &root)
absl::StatusOr< SandboxMetadata > ActiveSandbox() const
absl::StatusOr< int > CleanupOlderThan(absl::Duration max_age)
std::filesystem::path root_directory_
std::vector< SandboxMetadata > ListSandboxes() const
static RomSandboxManager & Instance()
std::optional< std::string > active_sandbox_id_
absl::StatusOr< std::filesystem::path > ActiveSandboxRomPath() const
const std::filesystem::path & RootDirectory() const
std::unordered_map< std::string, SandboxMetadata > sandboxes_
#define ASSIGN_OR_RETURN(type_variable_name, expression)
Definition macro.h:62
std::filesystem::path ResolveUniqueDirectory(const std::filesystem::path &root, absl::string_view id)
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22
std::string filename
Definition rom.h:29