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