yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
collaboration_service.cc
Go to the documentation of this file.
2
3#include <chrono>
4#include <thread>
5
6#include "absl/strings/str_format.h"
7
8namespace yaze {
9
10namespace net {
11
13 : rom_(rom),
14 version_mgr_(nullptr),
15 approval_mgr_(nullptr),
16 client_(std::make_unique<WebSocketClient>()),
17 sync_in_progress_(false) {}
18
22
24 const Config& config, RomVersionManager* version_mgr,
25 ProposalApprovalManager* approval_mgr) {
26 config_ = config;
27 version_mgr_ = version_mgr;
28 approval_mgr_ = approval_mgr;
29
30 if (!version_mgr_) {
31 return absl::InvalidArgumentError("version_mgr cannot be null");
32 }
33
34 if (!approval_mgr_) {
35 return absl::InvalidArgumentError("approval_mgr cannot be null");
36 }
37
38 // Set up network event callbacks
39 client_->OnMessage("rom_sync", [this](const nlohmann::json& payload) {
40 OnRomSyncReceived(payload);
41 });
42
43 client_->OnMessage("proposal_shared", [this](const nlohmann::json& payload) {
44 OnProposalReceived(payload);
45 });
46
47 client_->OnMessage(
48 "proposal_vote_received",
49 [this](const nlohmann::json& payload) { OnProposalUpdated(payload); });
50
51 client_->OnMessage("proposal_updated", [this](const nlohmann::json& payload) {
52 OnProposalUpdated(payload);
53 });
54
55 client_->OnMessage(
56 "participant_joined",
57 [this](const nlohmann::json& payload) { OnParticipantJoined(payload); });
58
59 client_->OnMessage("participant_left", [this](const nlohmann::json& payload) {
60 OnParticipantLeft(payload);
61 });
62
63 // Store initial ROM hash
64 if (rom_ && rom_->is_loaded()) {
66 }
67
68 return absl::OkStatus();
69}
70
71absl::Status CollaborationService::Connect(const std::string& host, int port) {
72 return client_->Connect(host, port);
73}
74
76 if (client_->IsConnected()) {
77 client_->Disconnect();
78 }
79}
80
81absl::Status CollaborationService::HostSession(const std::string& session_name,
82 const std::string& username,
83 bool ai_enabled) {
84 if (!client_->IsConnected()) {
85 return absl::FailedPreconditionError("Not connected to server");
86 }
87
88 if (!rom_ || !rom_->is_loaded()) {
89 return absl::FailedPreconditionError("ROM not loaded");
90 }
91
92 // Get current ROM hash
93 std::string rom_hash = version_mgr_->GetCurrentHash();
94
95 // Create initial safe point
96 auto snapshot_result = version_mgr_->CreateSnapshot("Session start", username,
97 true // is_checkpoint
98 );
99
100 if (snapshot_result.ok()) {
101 version_mgr_->MarkAsSafePoint(*snapshot_result);
102 }
103
104 // Host session on server
105 auto session_result =
106 client_->HostSession(session_name, username, rom_hash, ai_enabled);
107
108 if (!session_result.ok()) {
109 return session_result.status();
110 }
111
112 last_sync_hash_ = rom_hash;
113
114 return absl::OkStatus();
115}
116
117absl::Status CollaborationService::JoinSession(const std::string& session_code,
118 const std::string& username) {
119 if (!client_->IsConnected()) {
120 return absl::FailedPreconditionError("Not connected to server");
121 }
122
123 if (!rom_ || !rom_->is_loaded()) {
124 return absl::FailedPreconditionError("ROM not loaded");
125 }
126
127 // Create backup before joining
128 auto snapshot_result =
129 version_mgr_->CreateSnapshot("Before joining session", username, true);
130
131 if (snapshot_result.ok()) {
132 version_mgr_->MarkAsSafePoint(*snapshot_result);
133 }
134
135 // Join session
136 auto session_result = client_->JoinSession(session_code, username);
137
138 if (!session_result.ok()) {
139 return session_result.status();
140 }
141
143
144 return absl::OkStatus();
145}
146
148 if (!client_->InSession()) {
149 return absl::FailedPreconditionError("Not in a session");
150 }
151
152 return client_->LeaveSession();
153}
154
156 const std::string& description, const std::string& username) {
157 if (!client_->InSession()) {
158 return absl::FailedPreconditionError("Not in a session");
159 }
160
161 if (!rom_ || !rom_->is_loaded()) {
162 return absl::FailedPreconditionError("ROM not loaded");
163 }
164
165 // Generate diff from last sync
166 std::string current_hash = version_mgr_->GetCurrentHash();
167 if (current_hash == last_sync_hash_) {
168 return absl::OkStatus(); // No changes to submit
169 }
170
171 std::string diff = GenerateDiff(last_sync_hash_, current_hash);
172
173 // Create proposal data
174 nlohmann::json proposal_data = {{"description", description},
175 {"type", "rom_modification"},
176 {"diff_data", diff},
177 {"from_hash", last_sync_hash_},
178 {"to_hash", current_hash}};
179
180 // Submit to server
181 auto status = client_->ShareProposal(proposal_data, username);
182
183 if (status.ok() && config_.require_approval_for_sync) {
184 // Proposal submitted, waiting for approval
185 // The actual application will happen when approved
186 }
187
188 return status;
189}
190
191absl::Status CollaborationService::ApplyRomSync(const std::string& diff_data,
192 const std::string& rom_hash,
193 const std::string& sender) {
194 if (!rom_ || !rom_->is_loaded()) {
195 return absl::FailedPreconditionError("ROM not loaded");
196 }
197
198 if (sync_in_progress_) {
199 return absl::UnavailableError("Sync already in progress");
200 }
201
202 sync_in_progress_ = true;
203
204 // Create snapshot before applying
206 auto snapshot_result = version_mgr_->CreateSnapshot(
207 absl::StrFormat("Before sync from %s", sender), "system", false);
208
209 if (!snapshot_result.ok()) {
210 sync_in_progress_ = false;
211 return absl::InternalError("Failed to create backup snapshot");
212 }
213 }
214
215 // Apply the diff
216 auto status = ApplyDiff(diff_data);
217
218 if (status.ok()) {
219 last_sync_hash_ = rom_hash;
220 } else {
221 // Rollback on error
223 auto snapshots = version_mgr_->GetSnapshots();
224 if (!snapshots.empty()) {
225 version_mgr_->RestoreSnapshot(snapshots[0].snapshot_id);
226 }
227 }
228 }
229
230 sync_in_progress_ = false;
231 return status;
232}
233
235 const std::string& proposal_id, const nlohmann::json& proposal_data,
236 const std::string& sender) {
237 if (!approval_mgr_) {
238 return absl::FailedPreconditionError("Approval manager not initialized");
239 }
240
241 // Submit to approval manager
243 proposal_id, sender, proposal_data["description"], proposal_data);
244}
245
247 const std::string& proposal_id, bool approved,
248 const std::string& username) {
249 if (!client_->InSession()) {
250 return absl::FailedPreconditionError("Not in a session");
251 }
252
253 // Vote locally
254 auto status = approval_mgr_->VoteOnProposal(proposal_id, username, approved);
255
256 if (!status.ok()) {
257 return status;
258 }
259
260 // Send vote to server
261 return client_->VoteOnProposal(proposal_id, approved, username);
262}
263
265 const std::string& proposal_id) {
266 if (!approval_mgr_->IsProposalApproved(proposal_id)) {
267 return absl::FailedPreconditionError("Proposal not approved");
268 }
269
270 auto proposal_result = approval_mgr_->GetProposalStatus(proposal_id);
271 if (!proposal_result.ok()) {
272 return proposal_result.status();
273 }
274
275 // Apply the proposal (implementation depends on proposal type)
276 // For now, just update status
277 auto status = client_->UpdateProposalStatus(proposal_id, "applied");
278
279 if (status.ok()) {
280 // Create snapshot after applying
282 absl::StrFormat("Applied proposal %s", proposal_id.substr(0, 8)),
283 "system", false);
284 }
285
286 return status;
287}
288
290 return client_->IsConnected();
291}
292
293absl::StatusOr<SessionInfo> CollaborationService::GetSessionInfo() const {
294 return client_->GetSessionInfo();
295}
296
298 config_.auto_sync_enabled = enabled;
299}
300
301// Private callback handlers
302
303void CollaborationService::OnRomSyncReceived(const nlohmann::json& payload) {
304 std::string diff_data = payload["diff_data"];
305 std::string rom_hash = payload["rom_hash"];
306 std::string sender = payload["sender"];
307
308 auto status = ApplyRomSync(diff_data, rom_hash, sender);
309
310 if (!status.ok()) {
311 // Log error or notify user
312 }
313}
314
315void CollaborationService::OnProposalReceived(const nlohmann::json& payload) {
316 std::string proposal_id = payload["proposal_id"];
317 nlohmann::json proposal_data = payload["proposal_data"];
318 std::string sender = payload["sender"];
319
320 HandleIncomingProposal(proposal_id, proposal_data, sender);
321}
322
323void CollaborationService::OnProposalUpdated(const nlohmann::json& payload) {
324 std::string proposal_id = payload["proposal_id"];
325
326 if (payload.contains("status")) {
327 std::string status = payload["status"];
328
329 if (status == "approved" && approval_mgr_) {
330 // Proposal was approved, consider applying it
331 // This would be triggered by the host or based on voting results
332 }
333 }
334
335 if (payload.contains("votes")) {
336 // Vote update received
337 nlohmann::json votes = payload["votes"];
338 // Update local approval manager state
339 }
340}
341
342void CollaborationService::OnParticipantJoined(const nlohmann::json& payload) {
343 std::string username = payload["username"];
344 // Update participant list or notify user
345}
346
347void CollaborationService::OnParticipantLeft(const nlohmann::json& payload) {
348 std::string username = payload["username"];
349 // Update participant list or notify user
350}
351
352// Helper functions
353
354std::string CollaborationService::GenerateDiff(const std::string& from_hash,
355 const std::string& to_hash) {
356 // Simplified diff generation
357 // In production, this would generate a binary diff
358 // For now, just return placeholder
359
360 if (!rom_ || !rom_->is_loaded()) {
361 return "";
362 }
363
364 // TODO: Implement proper binary diff generation
365 // This could use algorithms like bsdiff or a custom format
366
367 return "diff_placeholder";
368}
369
370absl::Status CollaborationService::ApplyDiff(const std::string& diff_data) {
371 if (!rom_ || !rom_->is_loaded()) {
372 return absl::FailedPreconditionError("ROM not loaded");
373 }
374
375 // TODO: Implement proper diff application
376 // For now, just return success
377
378 return absl::OkStatus();
379}
380
383 return false;
384 }
385
386 if (!client_->IsConnected() || !client_->InSession()) {
387 return false;
388 }
389
390 if (sync_in_progress_) {
391 return false;
392 }
393
394 // Check if enough time has passed since last sync
395 // (Implementation would track last sync time)
396
397 return true;
398}
399
400} // namespace net
401
402} // 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
bool is_loaded() const
Definition rom.h:128
std::unique_ptr< WebSocketClient > client_
absl::Status ApplyApprovedProposal(const std::string &proposal_id)
void OnProposalUpdated(const nlohmann::json &payload)
absl::Status VoteOnProposal(const std::string &proposal_id, bool approved, const std::string &username)
absl::Status HandleIncomingProposal(const std::string &proposal_id, const nlohmann::json &proposal_data, const std::string &sender)
absl::Status Initialize(const Config &config, RomVersionManager *version_mgr, ProposalApprovalManager *approval_mgr)
void OnProposalReceived(const nlohmann::json &payload)
void OnRomSyncReceived(const nlohmann::json &payload)
absl::Status ApplyRomSync(const std::string &diff_data, const std::string &rom_hash, const std::string &sender)
absl::StatusOr< SessionInfo > GetSessionInfo() const
absl::Status SubmitChangesAsProposal(const std::string &description, const std::string &username)
ProposalApprovalManager * approval_mgr_
void OnParticipantJoined(const nlohmann::json &payload)
absl::Status Connect(const std::string &host, int port=8765)
absl::Status JoinSession(const std::string &session_code, const std::string &username)
absl::Status ApplyDiff(const std::string &diff_data)
absl::Status HostSession(const std::string &session_name, const std::string &username, bool ai_enabled=true)
void OnParticipantLeft(const nlohmann::json &payload)
std::string GenerateDiff(const std::string &from_hash, const std::string &to_hash)
Manages proposal approval workflow for collaborative sessions.
absl::StatusOr< ApprovalStatus > GetProposalStatus(const std::string &proposal_id) const
absl::Status VoteOnProposal(const std::string &proposal_id, const std::string &username, bool approved)
bool IsProposalApproved(const std::string &proposal_id) const
absl::Status SubmitProposal(const std::string &proposal_id, const std::string &sender, const std::string &description, const nlohmann::json &proposal_data)
Manages ROM versioning, snapshots, and rollback capabilities.
absl::StatusOr< std::string > CreateSnapshot(const std::string &description, const std::string &creator, bool is_checkpoint=false)
absl::Status RestoreSnapshot(const std::string &snapshot_id)
absl::Status MarkAsSafePoint(const std::string &snapshot_id)
std::vector< RomSnapshot > GetSnapshots(bool safe_points_only=false) const
WebSocket client for connecting to yaze-server.