Files
CHORUS/target/doc/src/chrs_sync/lib.rs.html

116 lines
13 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `chrs-sync/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="chrs_sync" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../../static.files/storage-82c7156e.js"></script><script defer src="../../static.files/src-script-63605ae7.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">chrs_sync/</div>lib.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="kw">use </span>chrono::Utc;
<a href=#2 id=2 data-nosnippet>2</a><span class="doccomment">/// chrs-sync crate provides synchronization utilities for the CHORUS system.
<a href=#3 id=3 data-nosnippet>3</a>///
<a href=#4 id=4 data-nosnippet>4</a>/// It uses a `Mailbox` for message passing between peers and a Dolt repository
<a href=#5 id=5 data-nosnippet>5</a>/// to track state hashes. The primary abstraction is `SyncManager`, which can
<a href=#6 id=6 data-nosnippet>6</a>/// broadcast the current repository hash to peers and handle incoming sync
<a href=#7 id=7 data-nosnippet>7</a>/// signals.
<a href=#8 id=8 data-nosnippet>8</a></span><span class="kw">use </span>chrs_mail::{Mailbox, Message};
<a href=#9 id=9 data-nosnippet>9</a><span class="kw">use </span>std::path::PathBuf;
<a href=#10 id=10 data-nosnippet>10</a><span class="kw">use </span>std::process::Command;
<a href=#11 id=11 data-nosnippet>11</a><span class="kw">use </span>uuid::Uuid;
<a href=#12 id=12 data-nosnippet>12</a>
<a href=#13 id=13 data-nosnippet>13</a><span class="doccomment">/// Manages synchronization of a Dolt repository across peers.
<a href=#14 id=14 data-nosnippet>14</a>///
<a href=#15 id=15 data-nosnippet>15</a>/// # Fields
<a href=#16 id=16 data-nosnippet>16</a>/// * `mailbox` The `Mailbox` instance used to send and receive messages.
<a href=#17 id=17 data-nosnippet>17</a>/// * `repo_path` Filesystem path to the local Dolt repository.
<a href=#18 id=18 data-nosnippet>18</a>///
<a href=#19 id=19 data-nosnippet>19</a>/// # Rationale
<a href=#20 id=20 data-nosnippet>20</a>/// The CHORUS architecture relies on deterministic state replication. By
<a href=#21 id=21 data-nosnippet>21</a>/// broadcasting the latest commit hash (`sync_signal`) each peer can decide
<a href=#22 id=22 data-nosnippet>22</a>/// whether to pull updates. This struct encapsulates that behaviour, keeping the
<a href=#23 id=23 data-nosnippet>23</a>/// rest of the system agnostic of the underlying VCS commands.
<a href=#24 id=24 data-nosnippet>24</a></span><span class="kw">pub struct </span>SyncManager {
<a href=#25 id=25 data-nosnippet>25</a> mailbox: Mailbox,
<a href=#26 id=26 data-nosnippet>26</a> repo_path: PathBuf,
<a href=#27 id=27 data-nosnippet>27</a>}
<a href=#28 id=28 data-nosnippet>28</a>
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">impl </span>SyncManager {
<a href=#30 id=30 data-nosnippet>30</a> <span class="doccomment">/// Creates a new `SyncManager`.
<a href=#31 id=31 data-nosnippet>31</a> ///
<a href=#32 id=32 data-nosnippet>32</a> /// # Parameters
<a href=#33 id=33 data-nosnippet>33</a> /// * `mailbox` An alreadyopened `Mailbox` for peer communication.
<a href=#34 id=34 data-nosnippet>34</a> /// * `repo_path` Path to the Dolt repository that should be kept in sync.
<a href=#35 id=35 data-nosnippet>35</a> ///
<a href=#36 id=36 data-nosnippet>36</a> /// Returns a fullyinitialised manager ready to broadcast or handle sync
<a href=#37 id=37 data-nosnippet>37</a> /// signals.
<a href=#38 id=38 data-nosnippet>38</a> </span><span class="kw">pub fn </span>new(mailbox: Mailbox, repo_path: PathBuf) -&gt; <span class="self">Self </span>{
<a href=#39 id=39 data-nosnippet>39</a> <span class="self">Self </span>{ mailbox, repo_path }
<a href=#40 id=40 data-nosnippet>40</a> }
<a href=#41 id=41 data-nosnippet>41</a>
<a href=#42 id=42 data-nosnippet>42</a> <span class="doccomment">/// Broadcasts the current repository state to a remote peer.
<a href=#43 id=43 data-nosnippet>43</a> ///
<a href=#44 id=44 data-nosnippet>44</a> /// The method executes `dolt log -n 1 --format %H` to obtain the most recent
<a href=#45 id=45 data-nosnippet>45</a> /// commit hash, constructs a `Message` with topic `"sync_signal"` and sends it
<a href=#46 id=46 data-nosnippet>46</a> /// via the mailbox.
<a href=#47 id=47 data-nosnippet>47</a> ///
<a href=#48 id=48 data-nosnippet>48</a> /// * `from_peer` Identifier of the sender.
<a href=#49 id=49 data-nosnippet>49</a> /// * `to_peer` Identifier of the intended recipient.
<a href=#50 id=50 data-nosnippet>50</a> ///
<a href=#51 id=51 data-nosnippet>51</a> /// # Errors
<a href=#52 id=52 data-nosnippet>52</a> /// Returns any I/O or commandexecution error wrapped in a boxed `dyn
<a href=#53 id=53 data-nosnippet>53</a> /// Error`.
<a href=#54 id=54 data-nosnippet>54</a> </span><span class="kw">pub fn </span>broadcast_state(
<a href=#55 id=55 data-nosnippet>55</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#56 id=56 data-nosnippet>56</a> from_peer: <span class="kw-2">&amp;</span>str,
<a href=#57 id=57 data-nosnippet>57</a> to_peer: <span class="kw-2">&amp;</span>str,
<a href=#58 id=58 data-nosnippet>58</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;(), Box&lt;<span class="kw">dyn </span>std::error::Error&gt;&gt; {
<a href=#59 id=59 data-nosnippet>59</a> <span class="comment">// Get current dolt hash
<a href=#60 id=60 data-nosnippet>60</a> </span><span class="kw">let </span>output = Command::new(<span class="string">"dolt"</span>)
<a href=#61 id=61 data-nosnippet>61</a> .args(<span class="kw-2">&amp;</span>[<span class="string">"log"</span>, <span class="string">"-n"</span>, <span class="string">"1"</span>, <span class="string">"--format"</span>, <span class="string">"%H"</span>])
<a href=#62 id=62 data-nosnippet>62</a> .current_dir(<span class="kw-2">&amp;</span><span class="self">self</span>.repo_path)
<a href=#63 id=63 data-nosnippet>63</a> .output()<span class="question-mark">?</span>;
<a href=#64 id=64 data-nosnippet>64</a>
<a href=#65 id=65 data-nosnippet>65</a> <span class="kw">let </span>current_hash = String::from_utf8_lossy(<span class="kw-2">&amp;</span>output.stdout).trim().to_string();
<a href=#66 id=66 data-nosnippet>66</a>
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw">let </span>msg = Message {
<a href=#68 id=68 data-nosnippet>68</a> id: Uuid::new_v4(),
<a href=#69 id=69 data-nosnippet>69</a> from_peer: from_peer.into(),
<a href=#70 id=70 data-nosnippet>70</a> to_peer: to_peer.into(),
<a href=#71 id=71 data-nosnippet>71</a> topic: <span class="string">"sync_signal"</span>.into(),
<a href=#72 id=72 data-nosnippet>72</a> payload: <span class="macro">serde_json::json!</span>({ <span class="string">"commit_hash"</span>: current_hash }),
<a href=#73 id=73 data-nosnippet>73</a> sent_at: Utc::now(),
<a href=#74 id=74 data-nosnippet>74</a> read_at: <span class="prelude-val">None</span>,
<a href=#75 id=75 data-nosnippet>75</a> };
<a href=#76 id=76 data-nosnippet>76</a>
<a href=#77 id=77 data-nosnippet>77</a> <span class="self">self</span>.mailbox.send(<span class="kw-2">&amp;</span>msg)<span class="question-mark">?</span>;
<a href=#78 id=78 data-nosnippet>78</a> <span class="macro">println!</span>(
<a href=#79 id=79 data-nosnippet>79</a> <span class="string">"Broadcasted sync signal: {} from {}"</span>,
<a href=#80 id=80 data-nosnippet>80</a> current_hash, from_peer
<a href=#81 id=81 data-nosnippet>81</a> );
<a href=#82 id=82 data-nosnippet>82</a> <span class="prelude-val">Ok</span>(())
<a href=#83 id=83 data-nosnippet>83</a> }
<a href=#84 id=84 data-nosnippet>84</a>
<a href=#85 id=85 data-nosnippet>85</a> <span class="doccomment">/// Handles an incoming `sync_signal` message.
<a href=#86 id=86 data-nosnippet>86</a> ///
<a href=#87 id=87 data-nosnippet>87</a> /// If the message topic is not `"sync_signal"` the function returns `Ok(())`
<a href=#88 id=88 data-nosnippet>88</a> /// immediately. Otherwise it extracts the remote commit hash and attempts a
<a href=#89 id=89 data-nosnippet>89</a> /// `dolt pull origin` to bring the local repository uptodate. In a real
<a href=#90 id=90 data-nosnippet>90</a> /// P2P deployment the remote URL would be derived from the sender, but the
<a href=#91 id=91 data-nosnippet>91</a> /// current implementation uses the default remote configuration.
<a href=#92 id=92 data-nosnippet>92</a> ///
<a href=#93 id=93 data-nosnippet>93</a> /// # Errors
<a href=#94 id=94 data-nosnippet>94</a> /// Propagates any command execution failures.
<a href=#95 id=95 data-nosnippet>95</a> </span><span class="kw">pub fn </span>handle_sync_signal(<span class="kw-2">&amp;</span><span class="self">self</span>, msg: <span class="kw-2">&amp;</span>Message) -&gt; <span class="prelude-ty">Result</span>&lt;(), Box&lt;<span class="kw">dyn </span>std::error::Error&gt;&gt; {
<a href=#96 id=96 data-nosnippet>96</a> <span class="kw">if </span>msg.topic != <span class="string">"sync_signal" </span>{
<a href=#97 id=97 data-nosnippet>97</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#98 id=98 data-nosnippet>98</a> }
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">let </span>remote_hash = msg.payload[<span class="string">"commit_hash"</span>].as_str().unwrap_or_default();
<a href=#101 id=101 data-nosnippet>101</a> <span class="macro">println!</span>(<span class="string">"Received sync signal for hash: {}"</span>, remote_hash);
<a href=#102 id=102 data-nosnippet>102</a>
<a href=#103 id=103 data-nosnippet>103</a> <span class="comment">// In a real P2P scenario, we would pull from the remote peer's URL.
<a href=#104 id=104 data-nosnippet>104</a> // For now, we simulate by attempting a 'dolt pull' if a remote is configured.
<a href=#105 id=105 data-nosnippet>105</a> </span><span class="kw">let </span>status = Command::new(<span class="string">"dolt"</span>)
<a href=#106 id=106 data-nosnippet>106</a> .args(<span class="kw-2">&amp;</span>[<span class="string">"pull"</span>, <span class="string">"origin"</span>])
<a href=#107 id=107 data-nosnippet>107</a> .current_dir(<span class="kw-2">&amp;</span><span class="self">self</span>.repo_path)
<a href=#108 id=108 data-nosnippet>108</a> .status()<span class="question-mark">?</span>;
<a href=#109 id=109 data-nosnippet>109</a>
<a href=#110 id=110 data-nosnippet>110</a> <span class="kw">if </span>status.success() {
<a href=#111 id=111 data-nosnippet>111</a> <span class="macro">println!</span>(<span class="string">"Successfully pulled updates for hash: {}"</span>, remote_hash);
<a href=#112 id=112 data-nosnippet>112</a> }
<a href=#113 id=113 data-nosnippet>113</a>
<a href=#114 id=114 data-nosnippet>114</a> <span class="prelude-val">Ok</span>(())
<a href=#115 id=115 data-nosnippet>115</a> }
<a href=#116 id=116 data-nosnippet>116</a>}</code></pre></div></section></main></body></html>