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