examples.html
1 <!doctype html> 2 <html class="no-js" lang="en"> 3 <head><meta charset="utf-8"/> 4 <meta name="viewport" content="width=device-width,initial-scale=1"/> 5 <meta name="color-scheme" content="light dark"><meta name="viewport" content="width=device-width, initial-scale=1" /> 6 <link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Support Reticulum" href="support.html" /><link rel="prev" title="Building Networks" href="networks.html" /> 7 8 <meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/> 9 <title>Code Examples - Reticulum Network Stack 1.0.0 documentation</title> 10 <link rel="stylesheet" type="text/css" href="_static/pygments.css" /> 11 <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" /> 12 <link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> 13 <link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" /> 14 <link rel="stylesheet" type="text/css" href="_static/custom.css" /> 15 16 17 18 19 <style> 20 body { 21 --color-code-background: #f8f8f8; 22 --color-code-foreground: black; 23 24 } 25 @media not print { 26 body[data-theme="dark"] { 27 --color-code-background: #202020; 28 --color-code-foreground: #d0d0d0; 29 --color-background-primary: #202b38; 30 --color-background-secondary: #161f27; 31 --color-foreground-primary: #dbdbdb; 32 --color-foreground-secondary: #a9b1ba; 33 --color-brand-primary: #41adff; 34 --color-background-hover: #161f27; 35 --color-api-name: #ffbe85; 36 --color-api-pre-name: #efae75; 37 38 } 39 @media (prefers-color-scheme: dark) { 40 body:not([data-theme="light"]) { 41 --color-code-background: #202020; 42 --color-code-foreground: #d0d0d0; 43 --color-background-primary: #202b38; 44 --color-background-secondary: #161f27; 45 --color-foreground-primary: #dbdbdb; 46 --color-foreground-secondary: #a9b1ba; 47 --color-brand-primary: #41adff; 48 --color-background-hover: #161f27; 49 --color-api-name: #ffbe85; 50 --color-api-pre-name: #efae75; 51 52 } 53 } 54 } 55 </style></head> 56 <body> 57 58 <script> 59 document.body.dataset.theme = localStorage.getItem("theme") || "auto"; 60 </script> 61 62 63 <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> 64 <symbol id="svg-toc" viewBox="0 0 24 24"> 65 <title>Contents</title> 66 <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 1024 1024"> 67 <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM115.4 518.9L271.7 642c5.8 4.6 14.4.5 14.4-6.9V388.9c0-7.4-8.5-11.5-14.4-6.9L115.4 505.1a8.74 8.74 0 0 0 0 13.8z"/> 68 </svg> 69 </symbol> 70 <symbol id="svg-menu" viewBox="0 0 24 24"> 71 <title>Menu</title> 72 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" 73 stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-menu"> 74 <line x1="3" y1="12" x2="21" y2="12"></line> 75 <line x1="3" y1="6" x2="21" y2="6"></line> 76 <line x1="3" y1="18" x2="21" y2="18"></line> 77 </svg> 78 </symbol> 79 <symbol id="svg-arrow-right" viewBox="0 0 24 24"> 80 <title>Expand</title> 81 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" 82 stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-chevron-right"> 83 <polyline points="9 18 15 12 9 6"></polyline> 84 </svg> 85 </symbol> 86 <symbol id="svg-sun" viewBox="0 0 24 24"> 87 <title>Light mode</title> 88 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" 89 stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="feather-sun"> 90 <circle cx="12" cy="12" r="5"></circle> 91 <line x1="12" y1="1" x2="12" y2="3"></line> 92 <line x1="12" y1="21" x2="12" y2="23"></line> 93 <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> 94 <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> 95 <line x1="1" y1="12" x2="3" y2="12"></line> 96 <line x1="21" y1="12" x2="23" y2="12"></line> 97 <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> 98 <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> 99 </svg> 100 </symbol> 101 <symbol id="svg-moon" viewBox="0 0 24 24"> 102 <title>Dark mode</title> 103 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" 104 stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-moon"> 105 <path stroke="none" d="M0 0h24v24H0z" fill="none" /> 106 <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" /> 107 </svg> 108 </symbol> 109 <symbol id="svg-sun-half" viewBox="0 0 24 24"> 110 <title>Auto light/dark mode</title> 111 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" 112 stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-shadow"> 113 <path stroke="none" d="M0 0h24v24H0z" fill="none"/> 114 <circle cx="12" cy="12" r="9" /> 115 <path d="M13 12h5" /> 116 <path d="M13 15h4" /> 117 <path d="M13 18h1" /> 118 <path d="M13 9h4" /> 119 <path d="M13 6h1" /> 120 </svg> 121 </symbol> 122 </svg> 123 124 <input type="checkbox" class="sidebar-toggle" name="__navigation" id="__navigation"> 125 <input type="checkbox" class="sidebar-toggle" name="__toc" id="__toc"> 126 <label class="overlay sidebar-overlay" for="__navigation"> 127 <div class="visually-hidden">Hide navigation sidebar</div> 128 </label> 129 <label class="overlay toc-overlay" for="__toc"> 130 <div class="visually-hidden">Hide table of contents sidebar</div> 131 </label> 132 133 134 135 <div class="page"> 136 <header class="mobile-header"> 137 <div class="header-left"> 138 <label class="nav-overlay-icon" for="__navigation"> 139 <div class="visually-hidden">Toggle site navigation sidebar</div> 140 <i class="icon"><svg><use href="#svg-menu"></use></svg></i> 141 </label> 142 </div> 143 <div class="header-center"> 144 <a href="index.html"><div class="brand">Reticulum Network Stack 1.0.0 documentation</div></a> 145 </div> 146 <div class="header-right"> 147 <div class="theme-toggle-container theme-toggle-header"> 148 <button class="theme-toggle"> 149 <div class="visually-hidden">Toggle Light / Dark / Auto color theme</div> 150 <svg class="theme-icon-when-auto"><use href="#svg-sun-half"></use></svg> 151 <svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg> 152 <svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg> 153 </button> 154 </div> 155 <label class="toc-overlay-icon toc-header-icon" for="__toc"> 156 <div class="visually-hidden">Toggle table of contents sidebar</div> 157 <i class="icon"><svg><use href="#svg-toc"></use></svg></i> 158 </label> 159 </div> 160 </header> 161 <aside class="sidebar-drawer"> 162 <div class="sidebar-container"> 163 164 <div class="sidebar-sticky"><a class="sidebar-brand centered" href="index.html"> 165 166 <div class="sidebar-logo-container"> 167 <img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/> 168 </div> 169 170 <span class="sidebar-brand-text">Reticulum Network Stack 1.0.0 documentation</span> 171 172 </a><form class="sidebar-search-container" method="get" action="search.html" role="search"> 173 <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search"> 174 <input type="hidden" name="check_keywords" value="yes"> 175 <input type="hidden" name="area" value="default"> 176 </form> 177 <div id="searchbox"></div><div class="sidebar-scroll"><div class="sidebar-tree"> 178 <ul class="current"> 179 <li class="toctree-l1"><a class="reference internal" href="whatis.html">What is Reticulum?</a></li> 180 <li class="toctree-l1"><a class="reference internal" href="gettingstartedfast.html">Getting Started Fast</a></li> 181 <li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a></li> 182 <li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a></li> 183 <li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li> 184 <li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li> 185 <li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li> 186 <li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Code Examples</a></li> 187 <li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li> 188 </ul> 189 <ul> 190 <li class="toctree-l1"><a class="reference internal" href="reference.html">API Reference</a></li> 191 </ul> 192 193 </div> 194 </div> 195 196 </div> 197 198 </div> 199 </aside> 200 <div class="main"> 201 <div class="content"> 202 <div class="article-container"> 203 <a href="#" class="back-to-top muted-link"> 204 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> 205 <path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12z"></path> 206 </svg> 207 <span>Back to top</span> 208 </a> 209 <div class="content-icon-container"> 210 <div class="theme-toggle-container theme-toggle-content"> 211 <button class="theme-toggle"> 212 <div class="visually-hidden">Toggle Light / Dark / Auto color theme</div> 213 <svg class="theme-icon-when-auto"><use href="#svg-sun-half"></use></svg> 214 <svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg> 215 <svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg> 216 </button> 217 </div> 218 <label class="toc-overlay-icon toc-content-icon" for="__toc"> 219 <div class="visually-hidden">Toggle table of contents sidebar</div> 220 <i class="icon"><svg><use href="#svg-toc"></use></svg></i> 221 </label> 222 </div> 223 <article role="main"> 224 <section id="code-examples"> 225 <span id="examples-main"></span><h1>Code Examples<a class="headerlink" href="#code-examples" title="Permalink to this heading">#</a></h1> 226 <p>A number of examples are included in the source distribution of Reticulum. 227 You can use these examples to learn how to write your own programs.</p> 228 <section id="minimal"> 229 <span id="example-minimal"></span><h2>Minimal<a class="headerlink" href="#minimal" title="Permalink to this heading">#</a></h2> 230 <p>The <em>Minimal</em> example demonstrates the bare-minimum setup required to connect to 231 a Reticulum network from your program. In about five lines of code, you will 232 have the Reticulum Network Stack initialised, and ready to pass traffic in your 233 program.</p> 234 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span> 235 <span class="c1"># This RNS example demonstrates a minimal setup, that #</span> 236 <span class="c1"># will start up the Reticulum Network Stack, generate a #</span> 237 <span class="c1"># new destination, and let the user send an announce. #</span> 238 <span class="c1">##########################################################</span> 239 240 <span class="kn">import</span><span class="w"> </span><span class="nn">argparse</span> 241 <span class="kn">import</span><span class="w"> </span><span class="nn">sys</span> 242 <span class="kn">import</span><span class="w"> </span><span class="nn">RNS</span> 243 244 <span class="c1"># Let's define an app name. We'll use this for all</span> 245 <span class="c1"># destinations we create. Since this basic example</span> 246 <span class="c1"># is part of a range of example utilities, we'll put</span> 247 <span class="c1"># them all within the app namespace "example_utilities"</span> 248 <span class="n">APP_NAME</span> <span class="o">=</span> <span class="s2">"example_utilities"</span> 249 250 <span class="c1"># This initialisation is executed when the program is started</span> 251 <span class="k">def</span><span class="w"> </span><span class="nf">program_setup</span><span class="p">(</span><span class="n">configpath</span><span class="p">):</span> 252 <span class="c1"># We must first initialise Reticulum</span> 253 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 254 255 <span class="c1"># Randomly create a new identity for our example</span> 256 <span class="n">identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span> 257 258 <span class="c1"># Using the identity we just created, we create a destination.</span> 259 <span class="c1"># Destinations are endpoints in Reticulum, that can be addressed</span> 260 <span class="c1"># and communicated with. Destinations can also announce their</span> 261 <span class="c1"># existence, which will let the network know they are reachable</span> 262 <span class="c1"># and automatically create paths to them, from anywhere else</span> 263 <span class="c1"># in the network.</span> 264 <span class="n">destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 265 <span class="n">identity</span><span class="p">,</span> 266 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> 267 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 268 <span class="n">APP_NAME</span><span class="p">,</span> 269 <span class="s2">"minimalsample"</span> 270 <span class="p">)</span> 271 272 <span class="c1"># We configure the destination to automatically prove all</span> 273 <span class="c1"># packets addressed to it. By doing this, RNS will automatically</span> 274 <span class="c1"># generate a proof for each incoming packet and transmit it</span> 275 <span class="c1"># back to the sender of that packet. This will let anyone that</span> 276 <span class="c1"># tries to communicate with the destination know whether their</span> 277 <span class="c1"># communication was received correctly.</span> 278 <span class="n">destination</span><span class="o">.</span><span class="n">set_proof_strategy</span><span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">PROVE_ALL</span><span class="p">)</span> 279 280 <span class="c1"># Everything's ready!</span> 281 <span class="c1"># Let's hand over control to the announce loop</span> 282 <span class="n">announceLoop</span><span class="p">(</span><span class="n">destination</span><span class="p">)</span> 283 284 285 <span class="k">def</span><span class="w"> </span><span class="nf">announceLoop</span><span class="p">(</span><span class="n">destination</span><span class="p">):</span> 286 <span class="c1"># Let the user know that everything is ready</span> 287 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 288 <span class="s2">"Minimal example "</span><span class="o">+</span> 289 <span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span> 290 <span class="s2">" running, hit enter to manually send an announce (Ctrl-C to quit)"</span> 291 <span class="p">)</span> 292 293 <span class="c1"># We enter a loop that runs until the users exits.</span> 294 <span class="c1"># If the user hits enter, we will announce our server</span> 295 <span class="c1"># destination on the network, which will let clients</span> 296 <span class="c1"># know how to create messages directed towards it.</span> 297 <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> 298 <span class="n">entered</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 299 <span class="n">destination</span><span class="o">.</span><span class="n">announce</span><span class="p">()</span> 300 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Sent announce from "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">))</span> 301 302 303 <span class="c1">##########################################################</span> 304 <span class="c1">#### Program Startup #####################################</span> 305 <span class="c1">##########################################################</span> 306 307 <span class="c1"># This part of the program gets run at startup,</span> 308 <span class="c1"># and parses input from the user, and then starts</span> 309 <span class="c1"># the desired program mode.</span> 310 <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span> 311 <span class="k">try</span><span class="p">:</span> 312 <span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span> 313 <span class="n">description</span><span class="o">=</span><span class="s2">"Minimal example to start Reticulum and create a destination"</span> 314 <span class="p">)</span> 315 316 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 317 <span class="s2">"--config"</span><span class="p">,</span> 318 <span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span> 319 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 320 <span class="n">help</span><span class="o">=</span><span class="s2">"path to alternative Reticulum config directory"</span><span class="p">,</span> 321 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 322 <span class="p">)</span> 323 324 <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span> 325 326 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span><span class="p">:</span> 327 <span class="n">configarg</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span> 328 <span class="k">else</span><span class="p">:</span> 329 <span class="n">configarg</span> <span class="o">=</span> <span class="kc">None</span> 330 331 <span class="n">program_setup</span><span class="p">(</span><span class="n">configarg</span><span class="p">)</span> 332 333 <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span> 334 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 335 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 336 </pre></div> 337 </div> 338 <p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Minimal.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Minimal.py</a>.</p> 339 </section> 340 <section id="announce"> 341 <span id="example-announce"></span><h2>Announce<a class="headerlink" href="#announce" title="Permalink to this heading">#</a></h2> 342 <p>The <em>Announce</em> example builds upon the previous example by exploring how to 343 announce a destination on the network, and how to let your program receive 344 notifications about announces from relevant destinations.</p> 345 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span> 346 <span class="c1"># This RNS example demonstrates setting up announce #</span> 347 <span class="c1"># callbacks, which will let an application receive a #</span> 348 <span class="c1"># notification when an announce relevant for it arrives #</span> 349 <span class="c1">##########################################################</span> 350 351 <span class="kn">import</span><span class="w"> </span><span class="nn">argparse</span> 352 <span class="kn">import</span><span class="w"> </span><span class="nn">random</span> 353 <span class="kn">import</span><span class="w"> </span><span class="nn">sys</span> 354 <span class="kn">import</span><span class="w"> </span><span class="nn">RNS</span> 355 356 <span class="c1"># Let's define an app name. We'll use this for all</span> 357 <span class="c1"># destinations we create. Since this basic example</span> 358 <span class="c1"># is part of a range of example utilities, we'll put</span> 359 <span class="c1"># them all within the app namespace "example_utilities"</span> 360 <span class="n">APP_NAME</span> <span class="o">=</span> <span class="s2">"example_utilities"</span> 361 362 <span class="c1"># We initialise two lists of strings to use as app_data</span> 363 <span class="n">fruits</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"Peach"</span><span class="p">,</span> <span class="s2">"Quince"</span><span class="p">,</span> <span class="s2">"Date"</span><span class="p">,</span> <span class="s2">"Tangerine"</span><span class="p">,</span> <span class="s2">"Pomelo"</span><span class="p">,</span> <span class="s2">"Carambola"</span><span class="p">,</span> <span class="s2">"Grape"</span><span class="p">]</span> 364 <span class="n">noble_gases</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"Helium"</span><span class="p">,</span> <span class="s2">"Neon"</span><span class="p">,</span> <span class="s2">"Argon"</span><span class="p">,</span> <span class="s2">"Krypton"</span><span class="p">,</span> <span class="s2">"Xenon"</span><span class="p">,</span> <span class="s2">"Radon"</span><span class="p">,</span> <span class="s2">"Oganesson"</span><span class="p">]</span> 365 366 <span class="c1"># This initialisation is executed when the program is started</span> 367 <span class="k">def</span><span class="w"> </span><span class="nf">program_setup</span><span class="p">(</span><span class="n">configpath</span><span class="p">):</span> 368 <span class="c1"># We must first initialise Reticulum</span> 369 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 370 371 <span class="c1"># Randomly create a new identity for our example</span> 372 <span class="n">identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span> 373 374 <span class="c1"># Using the identity we just created, we create two destinations</span> 375 <span class="c1"># in the "example_utilities.announcesample" application space.</span> 376 <span class="c1">#</span> 377 <span class="c1"># Destinations are endpoints in Reticulum, that can be addressed</span> 378 <span class="c1"># and communicated with. Destinations can also announce their</span> 379 <span class="c1"># existence, which will let the network know they are reachable</span> 380 <span class="c1"># and automatically create paths to them, from anywhere else</span> 381 <span class="c1"># in the network.</span> 382 <span class="n">destination_1</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 383 <span class="n">identity</span><span class="p">,</span> 384 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> 385 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 386 <span class="n">APP_NAME</span><span class="p">,</span> 387 <span class="s2">"announcesample"</span><span class="p">,</span> 388 <span class="s2">"fruits"</span> 389 <span class="p">)</span> 390 391 <span class="n">destination_2</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 392 <span class="n">identity</span><span class="p">,</span> 393 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> 394 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 395 <span class="n">APP_NAME</span><span class="p">,</span> 396 <span class="s2">"announcesample"</span><span class="p">,</span> 397 <span class="s2">"noble_gases"</span> 398 <span class="p">)</span> 399 400 <span class="c1"># We configure the destinations to automatically prove all</span> 401 <span class="c1"># packets addressed to it. By doing this, RNS will automatically</span> 402 <span class="c1"># generate a proof for each incoming packet and transmit it</span> 403 <span class="c1"># back to the sender of that packet. This will let anyone that</span> 404 <span class="c1"># tries to communicate with the destination know whether their</span> 405 <span class="c1"># communication was received correctly.</span> 406 <span class="n">destination_1</span><span class="o">.</span><span class="n">set_proof_strategy</span><span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">PROVE_ALL</span><span class="p">)</span> 407 <span class="n">destination_2</span><span class="o">.</span><span class="n">set_proof_strategy</span><span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">PROVE_ALL</span><span class="p">)</span> 408 409 <span class="c1"># We create an announce handler and configure it to only ask for</span> 410 <span class="c1"># announces from "example_utilities.announcesample.fruits".</span> 411 <span class="c1"># Try changing the filter and see what happens.</span> 412 <span class="n">announce_handler</span> <span class="o">=</span> <span class="n">ExampleAnnounceHandler</span><span class="p">(</span> 413 <span class="n">aspect_filter</span><span class="o">=</span><span class="s2">"example_utilities.announcesample.fruits"</span> 414 <span class="p">)</span> 415 416 <span class="c1"># We register the announce handler with Reticulum</span> 417 <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">register_announce_handler</span><span class="p">(</span><span class="n">announce_handler</span><span class="p">)</span> 418 419 <span class="c1"># Everything's ready!</span> 420 <span class="c1"># Let's hand over control to the announce loop</span> 421 <span class="n">announceLoop</span><span class="p">(</span><span class="n">destination_1</span><span class="p">,</span> <span class="n">destination_2</span><span class="p">)</span> 422 423 424 <span class="k">def</span><span class="w"> </span><span class="nf">announceLoop</span><span class="p">(</span><span class="n">destination_1</span><span class="p">,</span> <span class="n">destination_2</span><span class="p">):</span> 425 <span class="c1"># Let the user know that everything is ready</span> 426 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Announce example running, hit enter to manually send an announce (Ctrl-C to quit)"</span><span class="p">)</span> 427 428 <span class="c1"># We enter a loop that runs until the users exits.</span> 429 <span class="c1"># If the user hits enter, we will announce our server</span> 430 <span class="c1"># destination on the network, which will let clients</span> 431 <span class="c1"># know how to create messages directed towards it.</span> 432 <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> 433 <span class="n">entered</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 434 435 <span class="c1"># Randomly select a fruit</span> 436 <span class="n">fruit</span> <span class="o">=</span> <span class="n">fruits</span><span class="p">[</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="nb">len</span><span class="p">(</span><span class="n">fruits</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)]</span> 437 438 <span class="c1"># Send the announce including the app data</span> 439 <span class="n">destination_1</span><span class="o">.</span><span class="n">announce</span><span class="p">(</span><span class="n">app_data</span><span class="o">=</span><span class="n">fruit</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">))</span> 440 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 441 <span class="s2">"Sent announce from "</span><span class="o">+</span> 442 <span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination_1</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span> 443 <span class="s2">" ("</span><span class="o">+</span><span class="n">destination_1</span><span class="o">.</span><span class="n">name</span><span class="o">+</span><span class="s2">")"</span> 444 <span class="p">)</span> 445 446 <span class="c1"># Randomly select a noble gas</span> 447 <span class="n">noble_gas</span> <span class="o">=</span> <span class="n">noble_gases</span><span class="p">[</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="nb">len</span><span class="p">(</span><span class="n">noble_gases</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)]</span> 448 449 <span class="c1"># Send the announce including the app data</span> 450 <span class="n">destination_2</span><span class="o">.</span><span class="n">announce</span><span class="p">(</span><span class="n">app_data</span><span class="o">=</span><span class="n">noble_gas</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">))</span> 451 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 452 <span class="s2">"Sent announce from "</span><span class="o">+</span> 453 <span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination_2</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span> 454 <span class="s2">" ("</span><span class="o">+</span><span class="n">destination_2</span><span class="o">.</span><span class="n">name</span><span class="o">+</span><span class="s2">")"</span> 455 <span class="p">)</span> 456 457 <span class="c1"># We will need to define an announce handler class that</span> 458 <span class="c1"># Reticulum can message when an announce arrives.</span> 459 <span class="k">class</span><span class="w"> </span><span class="nc">ExampleAnnounceHandler</span><span class="p">:</span> 460 <span class="c1"># The initialisation method takes the optional</span> 461 <span class="c1"># aspect_filter argument. If aspect_filter is set to</span> 462 <span class="c1"># None, all announces will be passed to the instance.</span> 463 <span class="c1"># If only some announces are wanted, it can be set to</span> 464 <span class="c1"># an aspect string.</span> 465 <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">aspect_filter</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> 466 <span class="bp">self</span><span class="o">.</span><span class="n">aspect_filter</span> <span class="o">=</span> <span class="n">aspect_filter</span> 467 468 <span class="c1"># This method will be called by Reticulums Transport</span> 469 <span class="c1"># system when an announce arrives that matches the</span> 470 <span class="c1"># configured aspect filter. Filters must be specific,</span> 471 <span class="c1"># and cannot use wildcards.</span> 472 <span class="k">def</span><span class="w"> </span><span class="nf">received_announce</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">destination_hash</span><span class="p">,</span> <span class="n">announced_identity</span><span class="p">,</span> <span class="n">app_data</span><span class="p">):</span> 473 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 474 <span class="s2">"Received an announce from "</span><span class="o">+</span> 475 <span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span> 476 <span class="p">)</span> 477 478 <span class="k">if</span> <span class="n">app_data</span><span class="p">:</span> 479 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 480 <span class="s2">"The announce contained the following app data: "</span><span class="o">+</span> 481 <span class="n">app_data</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span> 482 <span class="p">)</span> 483 484 <span class="c1">##########################################################</span> 485 <span class="c1">#### Program Startup #####################################</span> 486 <span class="c1">##########################################################</span> 487 488 <span class="c1"># This part of the program gets run at startup,</span> 489 <span class="c1"># and parses input from the user, and then starts</span> 490 <span class="c1"># the desired program mode.</span> 491 <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span> 492 <span class="k">try</span><span class="p">:</span> 493 <span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span> 494 <span class="n">description</span><span class="o">=</span><span class="s2">"Reticulum example that demonstrates announces and announce handlers"</span> 495 <span class="p">)</span> 496 497 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 498 <span class="s2">"--config"</span><span class="p">,</span> 499 <span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span> 500 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 501 <span class="n">help</span><span class="o">=</span><span class="s2">"path to alternative Reticulum config directory"</span><span class="p">,</span> 502 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 503 <span class="p">)</span> 504 505 <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span> 506 507 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span><span class="p">:</span> 508 <span class="n">configarg</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span> 509 <span class="k">else</span><span class="p">:</span> 510 <span class="n">configarg</span> <span class="o">=</span> <span class="kc">None</span> 511 512 <span class="n">program_setup</span><span class="p">(</span><span class="n">configarg</span><span class="p">)</span> 513 514 <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span> 515 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 516 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 517 </pre></div> 518 </div> 519 <p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Announce.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Announce.py</a>.</p> 520 </section> 521 <section id="broadcast"> 522 <span id="example-broadcast"></span><h2>Broadcast<a class="headerlink" href="#broadcast" title="Permalink to this heading">#</a></h2> 523 <p>The <em>Broadcast</em> example explores how to transmit plaintext broadcast messages 524 over the network.</p> 525 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span> 526 <span class="c1"># This RNS example demonstrates broadcasting unencrypted #</span> 527 <span class="c1"># information to any listening destinations. #</span> 528 <span class="c1">##########################################################</span> 529 530 <span class="kn">import</span><span class="w"> </span><span class="nn">sys</span> 531 <span class="kn">import</span><span class="w"> </span><span class="nn">argparse</span> 532 <span class="kn">import</span><span class="w"> </span><span class="nn">RNS</span> 533 534 <span class="c1"># Let's define an app name. We'll use this for all</span> 535 <span class="c1"># destinations we create. Since this basic example</span> 536 <span class="c1"># is part of a range of example utilities, we'll put</span> 537 <span class="c1"># them all within the app namespace "example_utilities"</span> 538 <span class="n">APP_NAME</span> <span class="o">=</span> <span class="s2">"example_utilities"</span> 539 540 <span class="c1"># This initialisation is executed when the program is started</span> 541 <span class="k">def</span><span class="w"> </span><span class="nf">program_setup</span><span class="p">(</span><span class="n">configpath</span><span class="p">,</span> <span class="n">channel</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> 542 <span class="c1"># We must first initialise Reticulum</span> 543 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 544 545 <span class="c1"># If the user did not select a "channel" we use</span> 546 <span class="c1"># a default one called "public_information".</span> 547 <span class="c1"># This "channel" is added to the destination name-</span> 548 <span class="c1"># space, so the user can select different broadcast</span> 549 <span class="c1"># channels.</span> 550 <span class="k">if</span> <span class="n">channel</span> <span class="o">==</span> <span class="kc">None</span><span class="p">:</span> 551 <span class="n">channel</span> <span class="o">=</span> <span class="s2">"public_information"</span> 552 553 <span class="c1"># We create a PLAIN destination. This is an uncencrypted endpoint</span> 554 <span class="c1"># that anyone can listen to and send information to.</span> 555 <span class="n">broadcast_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 556 <span class="kc">None</span><span class="p">,</span> 557 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> 558 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">PLAIN</span><span class="p">,</span> 559 <span class="n">APP_NAME</span><span class="p">,</span> 560 <span class="s2">"broadcast"</span><span class="p">,</span> 561 <span class="n">channel</span> 562 <span class="p">)</span> 563 564 <span class="c1"># We specify a callback that will get called every time</span> 565 <span class="c1"># the destination receives data.</span> 566 <span class="n">broadcast_destination</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">packet_callback</span><span class="p">)</span> 567 568 <span class="c1"># Everything's ready!</span> 569 <span class="c1"># Let's hand over control to the main loop</span> 570 <span class="n">broadcastLoop</span><span class="p">(</span><span class="n">broadcast_destination</span><span class="p">)</span> 571 572 <span class="k">def</span><span class="w"> </span><span class="nf">packet_callback</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">packet</span><span class="p">):</span> 573 <span class="c1"># Simply print out the received data</span> 574 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 575 <span class="nb">print</span><span class="p">(</span><span class="s2">"Received data: "</span><span class="o">+</span><span class="n">data</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span><span class="o">+</span><span class="s2">"</span><span class="se">\r\n</span><span class="s2">> "</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">""</span><span class="p">)</span> 576 <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span> 577 578 <span class="k">def</span><span class="w"> </span><span class="nf">broadcastLoop</span><span class="p">(</span><span class="n">destination</span><span class="p">):</span> 579 <span class="c1"># Let the user know that everything is ready</span> 580 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 581 <span class="s2">"Broadcast example "</span><span class="o">+</span> 582 <span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span> 583 <span class="s2">" running, enter text and hit enter to broadcast (Ctrl-C to quit)"</span> 584 <span class="p">)</span> 585 586 <span class="c1"># We enter a loop that runs until the users exits.</span> 587 <span class="c1"># If the user hits enter, we will send the information</span> 588 <span class="c1"># that the user entered into the prompt.</span> 589 <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> 590 <span class="nb">print</span><span class="p">(</span><span class="s2">"> "</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">""</span><span class="p">)</span> 591 <span class="n">entered</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 592 593 <span class="k">if</span> <span class="n">entered</span> <span class="o">!=</span> <span class="s2">""</span><span class="p">:</span> 594 <span class="n">data</span> <span class="o">=</span> <span class="n">entered</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span> 595 <span class="n">packet</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Packet</span><span class="p">(</span><span class="n">destination</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span> 596 <span class="n">packet</span><span class="o">.</span><span class="n">send</span><span class="p">()</span> 597 598 599 600 <span class="c1">##########################################################</span> 601 <span class="c1">#### Program Startup #####################################</span> 602 <span class="c1">##########################################################</span> 603 604 <span class="c1"># This part of the program gets run at startup,</span> 605 <span class="c1"># and parses input from the user, and then starts</span> 606 <span class="c1"># the program.</span> 607 <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span> 608 <span class="k">try</span><span class="p">:</span> 609 <span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span> 610 <span class="n">description</span><span class="o">=</span><span class="s2">"Reticulum example demonstrating sending and receiving broadcasts"</span> 611 <span class="p">)</span> 612 613 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 614 <span class="s2">"--config"</span><span class="p">,</span> 615 <span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span> 616 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 617 <span class="n">help</span><span class="o">=</span><span class="s2">"path to alternative Reticulum config directory"</span><span class="p">,</span> 618 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 619 <span class="p">)</span> 620 621 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 622 <span class="s2">"--channel"</span><span class="p">,</span> 623 <span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span> 624 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 625 <span class="n">help</span><span class="o">=</span><span class="s2">"broadcast channel name"</span><span class="p">,</span> 626 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 627 <span class="p">)</span> 628 629 <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span> 630 631 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span><span class="p">:</span> 632 <span class="n">configarg</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span> 633 <span class="k">else</span><span class="p">:</span> 634 <span class="n">configarg</span> <span class="o">=</span> <span class="kc">None</span> 635 636 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">channel</span><span class="p">:</span> 637 <span class="n">channelarg</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">channel</span> 638 <span class="k">else</span><span class="p">:</span> 639 <span class="n">channelarg</span> <span class="o">=</span> <span class="kc">None</span> 640 641 <span class="n">program_setup</span><span class="p">(</span><span class="n">configarg</span><span class="p">,</span> <span class="n">channelarg</span><span class="p">)</span> 642 643 <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span> 644 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 645 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 646 </pre></div> 647 </div> 648 <p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Broadcast.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Broadcast.py</a>.</p> 649 </section> 650 <section id="echo"> 651 <span id="example-echo"></span><h2>Echo<a class="headerlink" href="#echo" title="Permalink to this heading">#</a></h2> 652 <p>The <em>Echo</em> example demonstrates communication between two destinations using 653 the Packet interface.</p> 654 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span> 655 <span class="c1"># This RNS example demonstrates a simple client/server #</span> 656 <span class="c1"># echo utility. A client can send an echo request to the #</span> 657 <span class="c1"># server, and the server will respond by proving receipt #</span> 658 <span class="c1"># of the packet. #</span> 659 <span class="c1">##########################################################</span> 660 661 <span class="kn">import</span><span class="w"> </span><span class="nn">argparse</span> 662 <span class="kn">import</span><span class="w"> </span><span class="nn">sys</span> 663 <span class="kn">import</span><span class="w"> </span><span class="nn">RNS</span> 664 665 <span class="c1"># Let's define an app name. We'll use this for all</span> 666 <span class="c1"># destinations we create. Since this echo example</span> 667 <span class="c1"># is part of a range of example utilities, we'll put</span> 668 <span class="c1"># them all within the app namespace "example_utilities"</span> 669 <span class="n">APP_NAME</span> <span class="o">=</span> <span class="s2">"example_utilities"</span> 670 671 672 <span class="c1">##########################################################</span> 673 <span class="c1">#### Server Part #########################################</span> 674 <span class="c1">##########################################################</span> 675 676 <span class="c1"># This initialisation is executed when the users chooses</span> 677 <span class="c1"># to run as a server</span> 678 <span class="k">def</span><span class="w"> </span><span class="nf">server</span><span class="p">(</span><span class="n">configpath</span><span class="p">):</span> 679 <span class="k">global</span> <span class="n">reticulum</span> 680 681 <span class="c1"># We must first initialise Reticulum</span> 682 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 683 684 <span class="c1"># Randomly create a new identity for our echo server</span> 685 <span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span> 686 687 <span class="c1"># We create a destination that clients can query. We want</span> 688 <span class="c1"># to be able to verify echo replies to our clients, so we</span> 689 <span class="c1"># create a "single" destination that can receive encrypted</span> 690 <span class="c1"># messages. This way the client can send a request and be</span> 691 <span class="c1"># certain that no-one else than this destination was able</span> 692 <span class="c1"># to read it. </span> 693 <span class="n">echo_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 694 <span class="n">server_identity</span><span class="p">,</span> 695 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> 696 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 697 <span class="n">APP_NAME</span><span class="p">,</span> 698 <span class="s2">"echo"</span><span class="p">,</span> 699 <span class="s2">"request"</span> 700 <span class="p">)</span> 701 702 <span class="c1"># We configure the destination to automatically prove all</span> 703 <span class="c1"># packets addressed to it. By doing this, RNS will automatically</span> 704 <span class="c1"># generate a proof for each incoming packet and transmit it</span> 705 <span class="c1"># back to the sender of that packet.</span> 706 <span class="n">echo_destination</span><span class="o">.</span><span class="n">set_proof_strategy</span><span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">PROVE_ALL</span><span class="p">)</span> 707 708 <span class="c1"># Tell the destination which function in our program to</span> 709 <span class="c1"># run when a packet is received. We do this so we can</span> 710 <span class="c1"># print a log message when the server receives a request</span> 711 <span class="n">echo_destination</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">server_callback</span><span class="p">)</span> 712 713 <span class="c1"># Everything's ready!</span> 714 <span class="c1"># Let's Wait for client requests or user input</span> 715 <span class="n">announceLoop</span><span class="p">(</span><span class="n">echo_destination</span><span class="p">)</span> 716 717 718 <span class="k">def</span><span class="w"> </span><span class="nf">announceLoop</span><span class="p">(</span><span class="n">destination</span><span class="p">):</span> 719 <span class="c1"># Let the user know that everything is ready</span> 720 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 721 <span class="s2">"Echo server "</span><span class="o">+</span> 722 <span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span> 723 <span class="s2">" running, hit enter to manually send an announce (Ctrl-C to quit)"</span> 724 <span class="p">)</span> 725 726 <span class="c1"># We enter a loop that runs until the users exits.</span> 727 <span class="c1"># If the user hits enter, we will announce our server</span> 728 <span class="c1"># destination on the network, which will let clients</span> 729 <span class="c1"># know how to create messages directed towards it.</span> 730 <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> 731 <span class="n">entered</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 732 <span class="n">destination</span><span class="o">.</span><span class="n">announce</span><span class="p">()</span> 733 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Sent announce from "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">))</span> 734 735 736 <span class="k">def</span><span class="w"> </span><span class="nf">server_callback</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">packet</span><span class="p">):</span> 737 <span class="k">global</span> <span class="n">reticulum</span> 738 739 <span class="c1"># Tell the user that we received an echo request, and</span> 740 <span class="c1"># that we are going to send a reply to the requester.</span> 741 <span class="c1"># Sending the proof is handled automatically, since we</span> 742 <span class="c1"># set up the destination to prove all incoming packets.</span> 743 744 <span class="n">reception_stats</span> <span class="o">=</span> <span class="s2">""</span> 745 <span class="k">if</span> <span class="n">reticulum</span><span class="o">.</span><span class="n">is_connected_to_shared_instance</span><span class="p">:</span> 746 <span class="n">reception_rssi</span> <span class="o">=</span> <span class="n">reticulum</span><span class="o">.</span><span class="n">get_packet_rssi</span><span class="p">(</span><span class="n">packet</span><span class="o">.</span><span class="n">packet_hash</span><span class="p">)</span> 747 <span class="n">reception_snr</span> <span class="o">=</span> <span class="n">reticulum</span><span class="o">.</span><span class="n">get_packet_snr</span><span class="p">(</span><span class="n">packet</span><span class="o">.</span><span class="n">packet_hash</span><span class="p">)</span> 748 749 <span class="k">if</span> <span class="n">reception_rssi</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span> 750 <span class="n">reception_stats</span> <span class="o">+=</span> <span class="s2">" [RSSI "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">reception_rssi</span><span class="p">)</span><span class="o">+</span><span class="s2">" dBm]"</span> 751 752 <span class="k">if</span> <span class="n">reception_snr</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span> 753 <span class="n">reception_stats</span> <span class="o">+=</span> <span class="s2">" [SNR "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">reception_snr</span><span class="p">)</span><span class="o">+</span><span class="s2">" dBm]"</span> 754 755 <span class="k">else</span><span class="p">:</span> 756 <span class="k">if</span> <span class="n">packet</span><span class="o">.</span><span class="n">rssi</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span> 757 <span class="n">reception_stats</span> <span class="o">+=</span> <span class="s2">" [RSSI "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">packet</span><span class="o">.</span><span class="n">rssi</span><span class="p">)</span><span class="o">+</span><span class="s2">" dBm]"</span> 758 759 <span class="k">if</span> <span class="n">packet</span><span class="o">.</span><span class="n">snr</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span> 760 <span class="n">reception_stats</span> <span class="o">+=</span> <span class="s2">" [SNR "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">packet</span><span class="o">.</span><span class="n">snr</span><span class="p">)</span><span class="o">+</span><span class="s2">" dB]"</span> 761 762 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Received packet from echo client, proof sent"</span><span class="o">+</span><span class="n">reception_stats</span><span class="p">)</span> 763 764 765 <span class="c1">##########################################################</span> 766 <span class="c1">#### Client Part #########################################</span> 767 <span class="c1">##########################################################</span> 768 769 <span class="c1"># This initialisation is executed when the users chooses</span> 770 <span class="c1"># to run as a client</span> 771 <span class="k">def</span><span class="w"> </span><span class="nf">client</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">,</span> <span class="n">configpath</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> 772 <span class="k">global</span> <span class="n">reticulum</span> 773 774 <span class="c1"># We need a binary representation of the destination</span> 775 <span class="c1"># hash that was entered on the command line</span> 776 <span class="k">try</span><span class="p">:</span> 777 <span class="n">dest_len</span> <span class="o">=</span> <span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">TRUNCATED_HASHLENGTH</span><span class="o">//</span><span class="mi">8</span><span class="p">)</span><span class="o">*</span><span class="mi">2</span> 778 <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> <span class="o">!=</span> <span class="n">dest_len</span><span class="p">:</span> 779 <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span> 780 <span class="s2">"Destination length is invalid, must be </span><span class="si">{hex}</span><span class="s2"> hexadecimal characters (</span><span class="si">{byte}</span><span class="s2"> bytes)."</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">hex</span><span class="o">=</span><span class="n">dest_len</span><span class="p">,</span> <span class="n">byte</span><span class="o">=</span><span class="n">dest_len</span><span class="o">//</span><span class="mi">2</span><span class="p">)</span> 781 <span class="p">)</span> 782 783 <span class="n">destination_hash</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> 784 <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> 785 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!"</span><span class="p">)</span> 786 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="o">+</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span> 787 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 788 789 <span class="c1"># We must first initialise Reticulum</span> 790 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 791 792 <span class="c1"># We override the loglevel to provide feedback when</span> 793 <span class="c1"># an announce is received</span> 794 <span class="k">if</span> <span class="n">RNS</span><span class="o">.</span><span class="n">loglevel</span> <span class="o"><</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_INFO</span><span class="p">:</span> 795 <span class="n">RNS</span><span class="o">.</span><span class="n">loglevel</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_INFO</span> 796 797 <span class="c1"># Tell the user that the client is ready!</span> 798 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 799 <span class="s2">"Echo client ready, hit enter to send echo request to "</span><span class="o">+</span> 800 <span class="n">destination_hexhash</span><span class="o">+</span> 801 <span class="s2">" (Ctrl-C to quit)"</span> 802 <span class="p">)</span> 803 804 <span class="c1"># We enter a loop that runs until the user exits.</span> 805 <span class="c1"># If the user hits enter, we will try to send an</span> 806 <span class="c1"># echo request to the destination specified on the</span> 807 <span class="c1"># command line.</span> 808 <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> 809 <span class="nb">input</span><span class="p">()</span> 810 811 <span class="c1"># Let's first check if RNS knows a path to the destination.</span> 812 <span class="c1"># If it does, we'll load the server identity and create a packet</span> 813 <span class="k">if</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span> 814 815 <span class="c1"># To address the server, we need to know it's public</span> 816 <span class="c1"># key, so we check if Reticulum knows this destination.</span> 817 <span class="c1"># This is done by calling the "recall" method of the</span> 818 <span class="c1"># Identity module. If the destination is known, it will</span> 819 <span class="c1"># return an Identity instance that can be used in</span> 820 <span class="c1"># outgoing destinations.</span> 821 <span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="o">.</span><span class="n">recall</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span> 822 823 <span class="c1"># We got the correct identity instance from the</span> 824 <span class="c1"># recall method, so let's create an outgoing</span> 825 <span class="c1"># destination. We use the naming convention:</span> 826 <span class="c1"># example_utilities.echo.request</span> 827 <span class="c1"># This matches the naming we specified in the</span> 828 <span class="c1"># server part of the code.</span> 829 <span class="n">request_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 830 <span class="n">server_identity</span><span class="p">,</span> 831 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">OUT</span><span class="p">,</span> 832 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 833 <span class="n">APP_NAME</span><span class="p">,</span> 834 <span class="s2">"echo"</span><span class="p">,</span> 835 <span class="s2">"request"</span> 836 <span class="p">)</span> 837 838 <span class="c1"># The destination is ready, so let's create a packet.</span> 839 <span class="c1"># We set the destination to the request_destination</span> 840 <span class="c1"># that was just created, and the only data we add</span> 841 <span class="c1"># is a random hash.</span> 842 <span class="n">echo_request</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Packet</span><span class="p">(</span><span class="n">request_destination</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="o">.</span><span class="n">get_random_hash</span><span class="p">())</span> 843 844 <span class="c1"># Send the packet! If the packet is successfully</span> 845 <span class="c1"># sent, it will return a PacketReceipt instance.</span> 846 <span class="n">packet_receipt</span> <span class="o">=</span> <span class="n">echo_request</span><span class="o">.</span><span class="n">send</span><span class="p">()</span> 847 848 <span class="c1"># If the user specified a timeout, we set this</span> 849 <span class="c1"># timeout on the packet receipt, and configure</span> 850 <span class="c1"># a callback function, that will get called if</span> 851 <span class="c1"># the packet times out.</span> 852 <span class="k">if</span> <span class="n">timeout</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span> 853 <span class="n">packet_receipt</span><span class="o">.</span><span class="n">set_timeout</span><span class="p">(</span><span class="n">timeout</span><span class="p">)</span> 854 <span class="n">packet_receipt</span><span class="o">.</span><span class="n">set_timeout_callback</span><span class="p">(</span><span class="n">packet_timed_out</span><span class="p">)</span> 855 856 <span class="c1"># We can then set a delivery callback on the receipt.</span> 857 <span class="c1"># This will get automatically called when a proof for</span> 858 <span class="c1"># this specific packet is received from the destination.</span> 859 <span class="n">packet_receipt</span><span class="o">.</span><span class="n">set_delivery_callback</span><span class="p">(</span><span class="n">packet_delivered</span><span class="p">)</span> 860 861 <span class="c1"># Tell the user that the echo request was sent</span> 862 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Sent echo request to "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">request_destination</span><span class="o">.</span><span class="n">hash</span><span class="p">))</span> 863 <span class="k">else</span><span class="p">:</span> 864 <span class="c1"># If we do not know this destination, tell the</span> 865 <span class="c1"># user to wait for an announce to arrive.</span> 866 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Destination is not yet known. Requesting path..."</span><span class="p">)</span> 867 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Hit enter to manually retry once an announce is received."</span><span class="p">)</span> 868 <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">request_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span> 869 870 <span class="c1"># This function is called when our reply destination</span> 871 <span class="c1"># receives a proof packet.</span> 872 <span class="k">def</span><span class="w"> </span><span class="nf">packet_delivered</span><span class="p">(</span><span class="n">receipt</span><span class="p">):</span> 873 <span class="k">global</span> <span class="n">reticulum</span> 874 875 <span class="k">if</span> <span class="n">receipt</span><span class="o">.</span><span class="n">status</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">PacketReceipt</span><span class="o">.</span><span class="n">DELIVERED</span><span class="p">:</span> 876 <span class="n">rtt</span> <span class="o">=</span> <span class="n">receipt</span><span class="o">.</span><span class="n">get_rtt</span><span class="p">()</span> 877 <span class="k">if</span> <span class="p">(</span><span class="n">rtt</span> <span class="o">>=</span> <span class="mi">1</span><span class="p">):</span> 878 <span class="n">rtt</span> <span class="o">=</span> <span class="nb">round</span><span class="p">(</span><span class="n">rtt</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span> 879 <span class="n">rttstring</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">rtt</span><span class="p">)</span><span class="o">+</span><span class="s2">" seconds"</span> 880 <span class="k">else</span><span class="p">:</span> 881 <span class="n">rtt</span> <span class="o">=</span> <span class="nb">round</span><span class="p">(</span><span class="n">rtt</span><span class="o">*</span><span class="mi">1000</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span> 882 <span class="n">rttstring</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">rtt</span><span class="p">)</span><span class="o">+</span><span class="s2">" milliseconds"</span> 883 884 <span class="n">reception_stats</span> <span class="o">=</span> <span class="s2">""</span> 885 <span class="k">if</span> <span class="n">reticulum</span><span class="o">.</span><span class="n">is_connected_to_shared_instance</span><span class="p">:</span> 886 <span class="n">reception_rssi</span> <span class="o">=</span> <span class="n">reticulum</span><span class="o">.</span><span class="n">get_packet_rssi</span><span class="p">(</span><span class="n">receipt</span><span class="o">.</span><span class="n">proof_packet</span><span class="o">.</span><span class="n">packet_hash</span><span class="p">)</span> 887 <span class="n">reception_snr</span> <span class="o">=</span> <span class="n">reticulum</span><span class="o">.</span><span class="n">get_packet_snr</span><span class="p">(</span><span class="n">receipt</span><span class="o">.</span><span class="n">proof_packet</span><span class="o">.</span><span class="n">packet_hash</span><span class="p">)</span> 888 889 <span class="k">if</span> <span class="n">reception_rssi</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span> 890 <span class="n">reception_stats</span> <span class="o">+=</span> <span class="s2">" [RSSI "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">reception_rssi</span><span class="p">)</span><span class="o">+</span><span class="s2">" dBm]"</span> 891 892 <span class="k">if</span> <span class="n">reception_snr</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span> 893 <span class="n">reception_stats</span> <span class="o">+=</span> <span class="s2">" [SNR "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">reception_snr</span><span class="p">)</span><span class="o">+</span><span class="s2">" dB]"</span> 894 895 <span class="k">else</span><span class="p">:</span> 896 <span class="k">if</span> <span class="n">receipt</span><span class="o">.</span><span class="n">proof_packet</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span> 897 <span class="k">if</span> <span class="n">receipt</span><span class="o">.</span><span class="n">proof_packet</span><span class="o">.</span><span class="n">rssi</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span> 898 <span class="n">reception_stats</span> <span class="o">+=</span> <span class="s2">" [RSSI "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">receipt</span><span class="o">.</span><span class="n">proof_packet</span><span class="o">.</span><span class="n">rssi</span><span class="p">)</span><span class="o">+</span><span class="s2">" dBm]"</span> 899 900 <span class="k">if</span> <span class="n">receipt</span><span class="o">.</span><span class="n">proof_packet</span><span class="o">.</span><span class="n">snr</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span> 901 <span class="n">reception_stats</span> <span class="o">+=</span> <span class="s2">" [SNR "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">receipt</span><span class="o">.</span><span class="n">proof_packet</span><span class="o">.</span><span class="n">snr</span><span class="p">)</span><span class="o">+</span><span class="s2">" dB]"</span> 902 903 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 904 <span class="s2">"Valid reply received from "</span><span class="o">+</span> 905 <span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">receipt</span><span class="o">.</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span> 906 <span class="s2">", round-trip time is "</span><span class="o">+</span><span class="n">rttstring</span><span class="o">+</span> 907 <span class="n">reception_stats</span> 908 <span class="p">)</span> 909 910 <span class="c1"># This function is called if a packet times out.</span> 911 <span class="k">def</span><span class="w"> </span><span class="nf">packet_timed_out</span><span class="p">(</span><span class="n">receipt</span><span class="p">):</span> 912 <span class="k">if</span> <span class="n">receipt</span><span class="o">.</span><span class="n">status</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">PacketReceipt</span><span class="o">.</span><span class="n">FAILED</span><span class="p">:</span> 913 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Packet "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">receipt</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span><span class="s2">" timed out"</span><span class="p">)</span> 914 915 916 <span class="c1">##########################################################</span> 917 <span class="c1">#### Program Startup #####################################</span> 918 <span class="c1">##########################################################</span> 919 920 <span class="c1"># This part of the program gets run at startup,</span> 921 <span class="c1"># and parses input from the user, and then starts</span> 922 <span class="c1"># the desired program mode.</span> 923 <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span> 924 <span class="k">try</span><span class="p">:</span> 925 <span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"Simple echo server and client utility"</span><span class="p">)</span> 926 927 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 928 <span class="s2">"-s"</span><span class="p">,</span> 929 <span class="s2">"--server"</span><span class="p">,</span> 930 <span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">,</span> 931 <span class="n">help</span><span class="o">=</span><span class="s2">"wait for incoming packets from clients"</span> 932 <span class="p">)</span> 933 934 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 935 <span class="s2">"-t"</span><span class="p">,</span> 936 <span class="s2">"--timeout"</span><span class="p">,</span> 937 <span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span> 938 <span class="n">metavar</span><span class="o">=</span><span class="s2">"s"</span><span class="p">,</span> 939 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 940 <span class="n">help</span><span class="o">=</span><span class="s2">"set a reply timeout in seconds"</span><span class="p">,</span> 941 <span class="nb">type</span><span class="o">=</span><span class="nb">float</span> 942 <span class="p">)</span> 943 944 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--config"</span><span class="p">,</span> 945 <span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span> 946 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 947 <span class="n">help</span><span class="o">=</span><span class="s2">"path to alternative Reticulum config directory"</span><span class="p">,</span> 948 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 949 <span class="p">)</span> 950 951 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 952 <span class="s2">"destination"</span><span class="p">,</span> 953 <span class="n">nargs</span><span class="o">=</span><span class="s2">"?"</span><span class="p">,</span> 954 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 955 <span class="n">help</span><span class="o">=</span><span class="s2">"hexadecimal hash of the server destination"</span><span class="p">,</span> 956 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 957 <span class="p">)</span> 958 959 <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span> 960 961 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">server</span><span class="p">:</span> 962 <span class="n">configarg</span><span class="o">=</span><span class="kc">None</span> 963 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span><span class="p">:</span> 964 <span class="n">configarg</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span> 965 <span class="n">server</span><span class="p">(</span><span class="n">configarg</span><span class="p">)</span> 966 <span class="k">else</span><span class="p">:</span> 967 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span><span class="p">:</span> 968 <span class="n">configarg</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span> 969 <span class="k">else</span><span class="p">:</span> 970 <span class="n">configarg</span> <span class="o">=</span> <span class="kc">None</span> 971 972 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">timeout</span><span class="p">:</span> 973 <span class="n">timeoutarg</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">timeout</span><span class="p">)</span> 974 <span class="k">else</span><span class="p">:</span> 975 <span class="n">timeoutarg</span> <span class="o">=</span> <span class="kc">None</span> 976 977 <span class="k">if</span> <span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span> <span class="o">==</span> <span class="kc">None</span><span class="p">):</span> 978 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 979 <span class="n">parser</span><span class="o">.</span><span class="n">print_help</span><span class="p">()</span> 980 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 981 <span class="k">else</span><span class="p">:</span> 982 <span class="n">client</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span><span class="p">,</span> <span class="n">configarg</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="n">timeoutarg</span><span class="p">)</span> 983 <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span> 984 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 985 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 986 </pre></div> 987 </div> 988 <p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Echo.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Echo.py</a>.</p> 989 </section> 990 <section id="link"> 991 <span id="example-link"></span><h2>Link<a class="headerlink" href="#link" title="Permalink to this heading">#</a></h2> 992 <p>The <em>Link</em> example explores establishing an encrypted link to a remote 993 destination, and passing traffic back and forth over the link.</p> 994 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span> 995 <span class="c1"># This RNS example demonstrates how to set up a link to #</span> 996 <span class="c1"># a destination, and pass data back and forth over it. #</span> 997 <span class="c1">##########################################################</span> 998 999 <span class="kn">import</span><span class="w"> </span><span class="nn">os</span> 1000 <span class="kn">import</span><span class="w"> </span><span class="nn">sys</span> 1001 <span class="kn">import</span><span class="w"> </span><span class="nn">time</span> 1002 <span class="kn">import</span><span class="w"> </span><span class="nn">argparse</span> 1003 <span class="kn">import</span><span class="w"> </span><span class="nn">RNS</span> 1004 1005 <span class="c1"># Let's define an app name. We'll use this for all</span> 1006 <span class="c1"># destinations we create. Since this echo example</span> 1007 <span class="c1"># is part of a range of example utilities, we'll put</span> 1008 <span class="c1"># them all within the app namespace "example_utilities"</span> 1009 <span class="n">APP_NAME</span> <span class="o">=</span> <span class="s2">"example_utilities"</span> 1010 1011 <span class="c1">##########################################################</span> 1012 <span class="c1">#### Server Part #########################################</span> 1013 <span class="c1">##########################################################</span> 1014 1015 <span class="c1"># A reference to the latest client link that connected</span> 1016 <span class="n">latest_client_link</span> <span class="o">=</span> <span class="kc">None</span> 1017 1018 <span class="c1"># This initialisation is executed when the users chooses</span> 1019 <span class="c1"># to run as a server</span> 1020 <span class="k">def</span><span class="w"> </span><span class="nf">server</span><span class="p">(</span><span class="n">configpath</span><span class="p">):</span> 1021 <span class="c1"># We must first initialise Reticulum</span> 1022 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 1023 1024 <span class="c1"># Randomly create a new identity for our link example</span> 1025 <span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span> 1026 1027 <span class="c1"># We create a destination that clients can connect to. We</span> 1028 <span class="c1"># want clients to create links to this destination, so we</span> 1029 <span class="c1"># need to create a "single" destination type.</span> 1030 <span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 1031 <span class="n">server_identity</span><span class="p">,</span> 1032 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> 1033 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 1034 <span class="n">APP_NAME</span><span class="p">,</span> 1035 <span class="s2">"linkexample"</span> 1036 <span class="p">)</span> 1037 1038 <span class="c1"># We configure a function that will get called every time</span> 1039 <span class="c1"># a new client creates a link to this destination.</span> 1040 <span class="n">server_destination</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">client_connected</span><span class="p">)</span> 1041 1042 <span class="c1"># Everything's ready!</span> 1043 <span class="c1"># Let's Wait for client requests or user input</span> 1044 <span class="n">server_loop</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span> 1045 1046 <span class="k">def</span><span class="w"> </span><span class="nf">server_loop</span><span class="p">(</span><span class="n">destination</span><span class="p">):</span> 1047 <span class="c1"># Let the user know that everything is ready</span> 1048 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 1049 <span class="s2">"Link example "</span><span class="o">+</span> 1050 <span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span> 1051 <span class="s2">" running, waiting for a connection."</span> 1052 <span class="p">)</span> 1053 1054 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Hit enter to manually send an announce (Ctrl-C to quit)"</span><span class="p">)</span> 1055 1056 <span class="c1"># We enter a loop that runs until the users exits.</span> 1057 <span class="c1"># If the user hits enter, we will announce our server</span> 1058 <span class="c1"># destination on the network, which will let clients</span> 1059 <span class="c1"># know how to create messages directed towards it.</span> 1060 <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> 1061 <span class="n">entered</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 1062 <span class="n">destination</span><span class="o">.</span><span class="n">announce</span><span class="p">()</span> 1063 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Sent announce from "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">))</span> 1064 1065 <span class="c1"># When a client establishes a link to our server</span> 1066 <span class="c1"># destination, this function will be called with</span> 1067 <span class="c1"># a reference to the link.</span> 1068 <span class="k">def</span><span class="w"> </span><span class="nf">client_connected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 1069 <span class="k">global</span> <span class="n">latest_client_link</span> 1070 1071 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client connected"</span><span class="p">)</span> 1072 <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">client_disconnected</span><span class="p">)</span> 1073 <span class="n">link</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">server_packet_received</span><span class="p">)</span> 1074 <span class="n">latest_client_link</span> <span class="o">=</span> <span class="n">link</span> 1075 1076 <span class="k">def</span><span class="w"> </span><span class="nf">client_disconnected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 1077 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client disconnected"</span><span class="p">)</span> 1078 1079 <span class="k">def</span><span class="w"> </span><span class="nf">server_packet_received</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">packet</span><span class="p">):</span> 1080 <span class="k">global</span> <span class="n">latest_client_link</span> 1081 1082 <span class="c1"># When data is received over any active link,</span> 1083 <span class="c1"># it will all be directed to the last client</span> 1084 <span class="c1"># that connected.</span> 1085 <span class="n">text</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span> 1086 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Received data on the link: "</span><span class="o">+</span><span class="n">text</span><span class="p">)</span> 1087 1088 <span class="n">reply_text</span> <span class="o">=</span> <span class="s2">"I received </span><span class="se">\"</span><span class="s2">"</span><span class="o">+</span><span class="n">text</span><span class="o">+</span><span class="s2">"</span><span class="se">\"</span><span class="s2"> over the link"</span> 1089 <span class="n">reply_data</span> <span class="o">=</span> <span class="n">reply_text</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span> 1090 <span class="n">RNS</span><span class="o">.</span><span class="n">Packet</span><span class="p">(</span><span class="n">latest_client_link</span><span class="p">,</span> <span class="n">reply_data</span><span class="p">)</span><span class="o">.</span><span class="n">send</span><span class="p">()</span> 1091 1092 1093 <span class="c1">##########################################################</span> 1094 <span class="c1">#### Client Part #########################################</span> 1095 <span class="c1">##########################################################</span> 1096 1097 <span class="c1"># A reference to the server link</span> 1098 <span class="n">server_link</span> <span class="o">=</span> <span class="kc">None</span> 1099 1100 <span class="c1"># This initialisation is executed when the users chooses</span> 1101 <span class="c1"># to run as a client</span> 1102 <span class="k">def</span><span class="w"> </span><span class="nf">client</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">,</span> <span class="n">configpath</span><span class="p">):</span> 1103 <span class="c1"># We need a binary representation of the destination</span> 1104 <span class="c1"># hash that was entered on the command line</span> 1105 <span class="k">try</span><span class="p">:</span> 1106 <span class="n">dest_len</span> <span class="o">=</span> <span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">TRUNCATED_HASHLENGTH</span><span class="o">//</span><span class="mi">8</span><span class="p">)</span><span class="o">*</span><span class="mi">2</span> 1107 <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> <span class="o">!=</span> <span class="n">dest_len</span><span class="p">:</span> 1108 <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span> 1109 <span class="s2">"Destination length is invalid, must be </span><span class="si">{hex}</span><span class="s2"> hexadecimal characters (</span><span class="si">{byte}</span><span class="s2"> bytes)."</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">hex</span><span class="o">=</span><span class="n">dest_len</span><span class="p">,</span> <span class="n">byte</span><span class="o">=</span><span class="n">dest_len</span><span class="o">//</span><span class="mi">2</span><span class="p">)</span> 1110 <span class="p">)</span> 1111 1112 <span class="n">destination_hash</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> 1113 <span class="k">except</span><span class="p">:</span> 1114 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span> 1115 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 1116 1117 <span class="c1"># We must first initialise Reticulum</span> 1118 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 1119 1120 <span class="c1"># Check if we know a path to the destination</span> 1121 <span class="k">if</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span> 1122 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Destination is not yet known. Requesting path and waiting for announce to arrive..."</span><span class="p">)</span> 1123 <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">request_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span> 1124 <span class="k">while</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span> 1125 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> 1126 1127 <span class="c1"># Recall the server identity</span> 1128 <span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="o">.</span><span class="n">recall</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span> 1129 1130 <span class="c1"># Inform the user that we'll begin connecting</span> 1131 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Establishing link with server..."</span><span class="p">)</span> 1132 1133 <span class="c1"># When the server identity is known, we set</span> 1134 <span class="c1"># up a destination</span> 1135 <span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 1136 <span class="n">server_identity</span><span class="p">,</span> 1137 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">OUT</span><span class="p">,</span> 1138 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 1139 <span class="n">APP_NAME</span><span class="p">,</span> 1140 <span class="s2">"linkexample"</span> 1141 <span class="p">)</span> 1142 1143 <span class="c1"># And create a link</span> 1144 <span class="n">link</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span> 1145 1146 <span class="c1"># We set a callback that will get executed</span> 1147 <span class="c1"># every time a packet is received over the</span> 1148 <span class="c1"># link</span> 1149 <span class="n">link</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">client_packet_received</span><span class="p">)</span> 1150 1151 <span class="c1"># We'll also set up functions to inform the</span> 1152 <span class="c1"># user when the link is established or closed</span> 1153 <span class="n">link</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">link_established</span><span class="p">)</span> 1154 <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">link_closed</span><span class="p">)</span> 1155 1156 <span class="c1"># Everything is set up, so let's enter a loop</span> 1157 <span class="c1"># for the user to interact with the example</span> 1158 <span class="n">client_loop</span><span class="p">()</span> 1159 1160 <span class="k">def</span><span class="w"> </span><span class="nf">client_loop</span><span class="p">():</span> 1161 <span class="k">global</span> <span class="n">server_link</span> 1162 1163 <span class="c1"># Wait for the link to become active</span> 1164 <span class="k">while</span> <span class="ow">not</span> <span class="n">server_link</span><span class="p">:</span> 1165 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> 1166 1167 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">False</span> 1168 <span class="k">while</span> <span class="ow">not</span> <span class="n">should_quit</span><span class="p">:</span> 1169 <span class="k">try</span><span class="p">:</span> 1170 <span class="nb">print</span><span class="p">(</span><span class="s2">"> "</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">" "</span><span class="p">)</span> 1171 <span class="n">text</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 1172 1173 <span class="c1"># Check if we should quit the example</span> 1174 <span class="k">if</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"quit"</span> <span class="ow">or</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"q"</span> <span class="ow">or</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"exit"</span><span class="p">:</span> 1175 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span> 1176 <span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 1177 1178 <span class="c1"># If not, send the entered text over the link</span> 1179 <span class="k">if</span> <span class="n">text</span> <span class="o">!=</span> <span class="s2">""</span><span class="p">:</span> 1180 <span class="n">data</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span> 1181 <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="o"><=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">MDU</span><span class="p">:</span> 1182 <span class="n">RNS</span><span class="o">.</span><span class="n">Packet</span><span class="p">(</span><span class="n">server_link</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span><span class="o">.</span><span class="n">send</span><span class="p">()</span> 1183 <span class="k">else</span><span class="p">:</span> 1184 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 1185 <span class="s2">"Cannot send this packet, the data size of "</span><span class="o">+</span> 1186 <span class="nb">str</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">))</span><span class="o">+</span><span class="s2">" bytes exceeds the link packet MDU of "</span><span class="o">+</span> 1187 <span class="nb">str</span><span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">MDU</span><span class="p">)</span><span class="o">+</span><span class="s2">" bytes"</span><span class="p">,</span> 1188 <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span> 1189 <span class="p">)</span> 1190 1191 <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> 1192 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Error while sending data over the link: "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span> 1193 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span> 1194 <span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 1195 1196 <span class="c1"># This function is called when a link</span> 1197 <span class="c1"># has been established with the server</span> 1198 <span class="k">def</span><span class="w"> </span><span class="nf">link_established</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 1199 <span class="c1"># We store a reference to the link</span> 1200 <span class="c1"># instance for later use</span> 1201 <span class="k">global</span> <span class="n">server_link</span> 1202 <span class="n">server_link</span> <span class="o">=</span> <span class="n">link</span> 1203 1204 <span class="c1"># Inform the user that the server is</span> 1205 <span class="c1"># connected</span> 1206 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link established with server, enter some text to send, or </span><span class="se">\"</span><span class="s2">quit</span><span class="se">\"</span><span class="s2"> to quit"</span><span class="p">)</span> 1207 1208 <span class="c1"># When a link is closed, we'll inform the</span> 1209 <span class="c1"># user, and exit the program</span> 1210 <span class="k">def</span><span class="w"> </span><span class="nf">link_closed</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 1211 <span class="k">if</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">TIMEOUT</span><span class="p">:</span> 1212 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link timed out, exiting now"</span><span class="p">)</span> 1213 <span class="k">elif</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">DESTINATION_CLOSED</span><span class="p">:</span> 1214 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link was closed by the server, exiting now"</span><span class="p">)</span> 1215 <span class="k">else</span><span class="p">:</span> 1216 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link closed, exiting now"</span><span class="p">)</span> 1217 1218 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span> 1219 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 1220 1221 <span class="c1"># When a packet is received over the link, we</span> 1222 <span class="c1"># simply print out the data.</span> 1223 <span class="k">def</span><span class="w"> </span><span class="nf">client_packet_received</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">packet</span><span class="p">):</span> 1224 <span class="n">text</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span> 1225 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Received data on the link: "</span><span class="o">+</span><span class="n">text</span><span class="p">)</span> 1226 <span class="nb">print</span><span class="p">(</span><span class="s2">"> "</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">" "</span><span class="p">)</span> 1227 <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span> 1228 1229 1230 <span class="c1">##########################################################</span> 1231 <span class="c1">#### Program Startup #####################################</span> 1232 <span class="c1">##########################################################</span> 1233 1234 <span class="c1"># This part of the program runs at startup,</span> 1235 <span class="c1"># and parses input of from the user, and then</span> 1236 <span class="c1"># starts up the desired program mode.</span> 1237 <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span> 1238 <span class="k">try</span><span class="p">:</span> 1239 <span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"Simple link example"</span><span class="p">)</span> 1240 1241 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 1242 <span class="s2">"-s"</span><span class="p">,</span> 1243 <span class="s2">"--server"</span><span class="p">,</span> 1244 <span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">,</span> 1245 <span class="n">help</span><span class="o">=</span><span class="s2">"wait for incoming link requests from clients"</span> 1246 <span class="p">)</span> 1247 1248 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 1249 <span class="s2">"--config"</span><span class="p">,</span> 1250 <span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span> 1251 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 1252 <span class="n">help</span><span class="o">=</span><span class="s2">"path to alternative Reticulum config directory"</span><span class="p">,</span> 1253 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 1254 <span class="p">)</span> 1255 1256 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 1257 <span class="s2">"destination"</span><span class="p">,</span> 1258 <span class="n">nargs</span><span class="o">=</span><span class="s2">"?"</span><span class="p">,</span> 1259 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 1260 <span class="n">help</span><span class="o">=</span><span class="s2">"hexadecimal hash of the server destination"</span><span class="p">,</span> 1261 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 1262 <span class="p">)</span> 1263 1264 <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span> 1265 1266 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span><span class="p">:</span> 1267 <span class="n">configarg</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span> 1268 <span class="k">else</span><span class="p">:</span> 1269 <span class="n">configarg</span> <span class="o">=</span> <span class="kc">None</span> 1270 1271 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">server</span><span class="p">:</span> 1272 <span class="n">server</span><span class="p">(</span><span class="n">configarg</span><span class="p">)</span> 1273 <span class="k">else</span><span class="p">:</span> 1274 <span class="k">if</span> <span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span> <span class="o">==</span> <span class="kc">None</span><span class="p">):</span> 1275 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 1276 <span class="n">parser</span><span class="o">.</span><span class="n">print_help</span><span class="p">()</span> 1277 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 1278 <span class="k">else</span><span class="p">:</span> 1279 <span class="n">client</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span><span class="p">,</span> <span class="n">configarg</span><span class="p">)</span> 1280 1281 <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span> 1282 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 1283 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 1284 </pre></div> 1285 </div> 1286 <p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Link.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Link.py</a>.</p> 1287 </section> 1288 <section id="example-identify"> 1289 <span id="identification"></span><h2>Identification<a class="headerlink" href="#example-identify" title="Permalink to this heading">#</a></h2> 1290 <p>The <em>Identify</em> example explores identifying an intiator of a link, once 1291 the link has been established.</p> 1292 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span> 1293 <span class="c1"># This RNS example demonstrates how to set up a link to #</span> 1294 <span class="c1"># a destination, and identify the initiator to it's peer #</span> 1295 <span class="c1">##########################################################</span> 1296 1297 <span class="kn">import</span><span class="w"> </span><span class="nn">os</span> 1298 <span class="kn">import</span><span class="w"> </span><span class="nn">sys</span> 1299 <span class="kn">import</span><span class="w"> </span><span class="nn">time</span> 1300 <span class="kn">import</span><span class="w"> </span><span class="nn">argparse</span> 1301 <span class="kn">import</span><span class="w"> </span><span class="nn">RNS</span> 1302 1303 <span class="c1"># Let's define an app name. We'll use this for all</span> 1304 <span class="c1"># destinations we create. Since this echo example</span> 1305 <span class="c1"># is part of a range of example utilities, we'll put</span> 1306 <span class="c1"># them all within the app namespace "example_utilities"</span> 1307 <span class="n">APP_NAME</span> <span class="o">=</span> <span class="s2">"example_utilities"</span> 1308 1309 <span class="c1">##########################################################</span> 1310 <span class="c1">#### Server Part #########################################</span> 1311 <span class="c1">##########################################################</span> 1312 1313 <span class="c1"># A reference to the latest client link that connected</span> 1314 <span class="n">latest_client_link</span> <span class="o">=</span> <span class="kc">None</span> 1315 1316 <span class="c1"># This initialisation is executed when the users chooses</span> 1317 <span class="c1"># to run as a server</span> 1318 <span class="k">def</span><span class="w"> </span><span class="nf">server</span><span class="p">(</span><span class="n">configpath</span><span class="p">):</span> 1319 <span class="c1"># We must first initialise Reticulum</span> 1320 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 1321 1322 <span class="c1"># Randomly create a new identity for our link example</span> 1323 <span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span> 1324 1325 <span class="c1"># We create a destination that clients can connect to. We</span> 1326 <span class="c1"># want clients to create links to this destination, so we</span> 1327 <span class="c1"># need to create a "single" destination type.</span> 1328 <span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 1329 <span class="n">server_identity</span><span class="p">,</span> 1330 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> 1331 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 1332 <span class="n">APP_NAME</span><span class="p">,</span> 1333 <span class="s2">"identifyexample"</span> 1334 <span class="p">)</span> 1335 1336 <span class="c1"># We configure a function that will get called every time</span> 1337 <span class="c1"># a new client creates a link to this destination.</span> 1338 <span class="n">server_destination</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">client_connected</span><span class="p">)</span> 1339 1340 <span class="c1"># Everything's ready!</span> 1341 <span class="c1"># Let's Wait for client requests or user input</span> 1342 <span class="n">server_loop</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span> 1343 1344 <span class="k">def</span><span class="w"> </span><span class="nf">server_loop</span><span class="p">(</span><span class="n">destination</span><span class="p">):</span> 1345 <span class="c1"># Let the user know that everything is ready</span> 1346 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 1347 <span class="s2">"Link identification example "</span><span class="o">+</span> 1348 <span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span> 1349 <span class="s2">" running, waiting for a connection."</span> 1350 <span class="p">)</span> 1351 1352 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Hit enter to manually send an announce (Ctrl-C to quit)"</span><span class="p">)</span> 1353 1354 <span class="c1"># We enter a loop that runs until the users exits.</span> 1355 <span class="c1"># If the user hits enter, we will announce our server</span> 1356 <span class="c1"># destination on the network, which will let clients</span> 1357 <span class="c1"># know how to create messages directed towards it.</span> 1358 <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> 1359 <span class="n">entered</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 1360 <span class="n">destination</span><span class="o">.</span><span class="n">announce</span><span class="p">()</span> 1361 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Sent announce from "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">))</span> 1362 1363 <span class="c1"># When a client establishes a link to our server</span> 1364 <span class="c1"># destination, this function will be called with</span> 1365 <span class="c1"># a reference to the link.</span> 1366 <span class="k">def</span><span class="w"> </span><span class="nf">client_connected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 1367 <span class="k">global</span> <span class="n">latest_client_link</span> 1368 1369 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client connected"</span><span class="p">)</span> 1370 <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">client_disconnected</span><span class="p">)</span> 1371 <span class="n">link</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">server_packet_received</span><span class="p">)</span> 1372 <span class="n">link</span><span class="o">.</span><span class="n">set_remote_identified_callback</span><span class="p">(</span><span class="n">remote_identified</span><span class="p">)</span> 1373 <span class="n">latest_client_link</span> <span class="o">=</span> <span class="n">link</span> 1374 1375 <span class="k">def</span><span class="w"> </span><span class="nf">client_disconnected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 1376 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client disconnected"</span><span class="p">)</span> 1377 1378 <span class="k">def</span><span class="w"> </span><span class="nf">remote_identified</span><span class="p">(</span><span class="n">link</span><span class="p">,</span> <span class="n">identity</span><span class="p">):</span> 1379 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Remote identified as: "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">identity</span><span class="p">))</span> 1380 1381 <span class="k">def</span><span class="w"> </span><span class="nf">server_packet_received</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">packet</span><span class="p">):</span> 1382 <span class="k">global</span> <span class="n">latest_client_link</span> 1383 1384 <span class="c1"># Get the originating identity for display</span> 1385 <span class="n">remote_peer</span> <span class="o">=</span> <span class="s2">"unidentified peer"</span> 1386 <span class="k">if</span> <span class="n">packet</span><span class="o">.</span><span class="n">link</span><span class="o">.</span><span class="n">get_remote_identity</span><span class="p">()</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span> 1387 <span class="n">remote_peer</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">packet</span><span class="o">.</span><span class="n">link</span><span class="o">.</span><span class="n">get_remote_identity</span><span class="p">())</span> 1388 1389 <span class="c1"># When data is received over any active link,</span> 1390 <span class="c1"># it will all be directed to the last client</span> 1391 <span class="c1"># that connected.</span> 1392 <span class="n">text</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span> 1393 1394 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Received data from "</span><span class="o">+</span><span class="n">remote_peer</span><span class="o">+</span><span class="s2">": "</span><span class="o">+</span><span class="n">text</span><span class="p">)</span> 1395 1396 <span class="n">reply_text</span> <span class="o">=</span> <span class="s2">"I received </span><span class="se">\"</span><span class="s2">"</span><span class="o">+</span><span class="n">text</span><span class="o">+</span><span class="s2">"</span><span class="se">\"</span><span class="s2"> over the link from "</span><span class="o">+</span><span class="n">remote_peer</span> 1397 <span class="n">reply_data</span> <span class="o">=</span> <span class="n">reply_text</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span> 1398 <span class="n">RNS</span><span class="o">.</span><span class="n">Packet</span><span class="p">(</span><span class="n">latest_client_link</span><span class="p">,</span> <span class="n">reply_data</span><span class="p">)</span><span class="o">.</span><span class="n">send</span><span class="p">()</span> 1399 1400 1401 <span class="c1">##########################################################</span> 1402 <span class="c1">#### Client Part #########################################</span> 1403 <span class="c1">##########################################################</span> 1404 1405 <span class="c1"># A reference to the server link</span> 1406 <span class="n">server_link</span> <span class="o">=</span> <span class="kc">None</span> 1407 1408 <span class="c1"># A reference to the client identity</span> 1409 <span class="n">client_identity</span> <span class="o">=</span> <span class="kc">None</span> 1410 1411 <span class="c1"># This initialisation is executed when the users chooses</span> 1412 <span class="c1"># to run as a client</span> 1413 <span class="k">def</span><span class="w"> </span><span class="nf">client</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">,</span> <span class="n">configpath</span><span class="p">):</span> 1414 <span class="k">global</span> <span class="n">client_identity</span> 1415 <span class="c1"># We need a binary representation of the destination</span> 1416 <span class="c1"># hash that was entered on the command line</span> 1417 <span class="k">try</span><span class="p">:</span> 1418 <span class="n">dest_len</span> <span class="o">=</span> <span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">TRUNCATED_HASHLENGTH</span><span class="o">//</span><span class="mi">8</span><span class="p">)</span><span class="o">*</span><span class="mi">2</span> 1419 <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> <span class="o">!=</span> <span class="n">dest_len</span><span class="p">:</span> 1420 <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span> 1421 <span class="s2">"Destination length is invalid, must be </span><span class="si">{hex}</span><span class="s2"> hexadecimal characters (</span><span class="si">{byte}</span><span class="s2"> bytes)."</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">hex</span><span class="o">=</span><span class="n">dest_len</span><span class="p">,</span> <span class="n">byte</span><span class="o">=</span><span class="n">dest_len</span><span class="o">//</span><span class="mi">2</span><span class="p">)</span> 1422 <span class="p">)</span> 1423 1424 <span class="n">destination_hash</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> 1425 <span class="k">except</span><span class="p">:</span> 1426 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span> 1427 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 1428 1429 <span class="c1"># We must first initialise Reticulum</span> 1430 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 1431 1432 <span class="c1"># Create a new client identity</span> 1433 <span class="n">client_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span> 1434 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 1435 <span class="s2">"Client created new identity "</span><span class="o">+</span> 1436 <span class="nb">str</span><span class="p">(</span><span class="n">client_identity</span><span class="p">)</span> 1437 <span class="p">)</span> 1438 1439 <span class="c1"># Check if we know a path to the destination</span> 1440 <span class="k">if</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span> 1441 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Destination is not yet known. Requesting path and waiting for announce to arrive..."</span><span class="p">)</span> 1442 <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">request_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span> 1443 <span class="k">while</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span> 1444 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> 1445 1446 <span class="c1"># Recall the server identity</span> 1447 <span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="o">.</span><span class="n">recall</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span> 1448 1449 <span class="c1"># Inform the user that we'll begin connecting</span> 1450 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Establishing link with server..."</span><span class="p">)</span> 1451 1452 <span class="c1"># When the server identity is known, we set</span> 1453 <span class="c1"># up a destination</span> 1454 <span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 1455 <span class="n">server_identity</span><span class="p">,</span> 1456 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">OUT</span><span class="p">,</span> 1457 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 1458 <span class="n">APP_NAME</span><span class="p">,</span> 1459 <span class="s2">"identifyexample"</span> 1460 <span class="p">)</span> 1461 1462 <span class="c1"># And create a link</span> 1463 <span class="n">link</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span> 1464 1465 <span class="c1"># We set a callback that will get executed</span> 1466 <span class="c1"># every time a packet is received over the</span> 1467 <span class="c1"># link</span> 1468 <span class="n">link</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">client_packet_received</span><span class="p">)</span> 1469 1470 <span class="c1"># We'll also set up functions to inform the</span> 1471 <span class="c1"># user when the link is established or closed</span> 1472 <span class="n">link</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">link_established</span><span class="p">)</span> 1473 <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">link_closed</span><span class="p">)</span> 1474 1475 <span class="c1"># Everything is set up, so let's enter a loop</span> 1476 <span class="c1"># for the user to interact with the example</span> 1477 <span class="n">client_loop</span><span class="p">()</span> 1478 1479 <span class="k">def</span><span class="w"> </span><span class="nf">client_loop</span><span class="p">():</span> 1480 <span class="k">global</span> <span class="n">server_link</span> 1481 1482 <span class="c1"># Wait for the link to become active</span> 1483 <span class="k">while</span> <span class="ow">not</span> <span class="n">server_link</span><span class="p">:</span> 1484 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> 1485 1486 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">False</span> 1487 <span class="k">while</span> <span class="ow">not</span> <span class="n">should_quit</span><span class="p">:</span> 1488 <span class="k">try</span><span class="p">:</span> 1489 <span class="nb">print</span><span class="p">(</span><span class="s2">"> "</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">" "</span><span class="p">)</span> 1490 <span class="n">text</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 1491 1492 <span class="c1"># Check if we should quit the example</span> 1493 <span class="k">if</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"quit"</span> <span class="ow">or</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"q"</span> <span class="ow">or</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"exit"</span><span class="p">:</span> 1494 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span> 1495 <span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 1496 1497 <span class="c1"># If not, send the entered text over the link</span> 1498 <span class="k">if</span> <span class="n">text</span> <span class="o">!=</span> <span class="s2">""</span><span class="p">:</span> 1499 <span class="n">data</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span> 1500 <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="o"><=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">MDU</span><span class="p">:</span> 1501 <span class="n">RNS</span><span class="o">.</span><span class="n">Packet</span><span class="p">(</span><span class="n">server_link</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span><span class="o">.</span><span class="n">send</span><span class="p">()</span> 1502 <span class="k">else</span><span class="p">:</span> 1503 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 1504 <span class="s2">"Cannot send this packet, the data size of "</span><span class="o">+</span> 1505 <span class="nb">str</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">))</span><span class="o">+</span><span class="s2">" bytes exceeds the link packet MDU of "</span><span class="o">+</span> 1506 <span class="nb">str</span><span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">MDU</span><span class="p">)</span><span class="o">+</span><span class="s2">" bytes"</span><span class="p">,</span> 1507 <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span> 1508 <span class="p">)</span> 1509 1510 <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> 1511 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Error while sending data over the link: "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span> 1512 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span> 1513 <span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 1514 1515 <span class="c1"># This function is called when a link</span> 1516 <span class="c1"># has been established with the server</span> 1517 <span class="k">def</span><span class="w"> </span><span class="nf">link_established</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 1518 <span class="c1"># We store a reference to the link</span> 1519 <span class="c1"># instance for later use</span> 1520 <span class="k">global</span> <span class="n">server_link</span><span class="p">,</span> <span class="n">client_identity</span> 1521 <span class="n">server_link</span> <span class="o">=</span> <span class="n">link</span> 1522 1523 <span class="c1"># Inform the user that the server is</span> 1524 <span class="c1"># connected</span> 1525 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link established with server, identifying to remote peer..."</span><span class="p">)</span> 1526 1527 <span class="n">link</span><span class="o">.</span><span class="n">identify</span><span class="p">(</span><span class="n">client_identity</span><span class="p">)</span> 1528 1529 <span class="c1"># When a link is closed, we'll inform the</span> 1530 <span class="c1"># user, and exit the program</span> 1531 <span class="k">def</span><span class="w"> </span><span class="nf">link_closed</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 1532 <span class="k">if</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">TIMEOUT</span><span class="p">:</span> 1533 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link timed out, exiting now"</span><span class="p">)</span> 1534 <span class="k">elif</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">DESTINATION_CLOSED</span><span class="p">:</span> 1535 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link was closed by the server, exiting now"</span><span class="p">)</span> 1536 <span class="k">else</span><span class="p">:</span> 1537 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link closed, exiting now"</span><span class="p">)</span> 1538 1539 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span> 1540 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 1541 1542 <span class="c1"># When a packet is received over the link, we</span> 1543 <span class="c1"># simply print out the data.</span> 1544 <span class="k">def</span><span class="w"> </span><span class="nf">client_packet_received</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">packet</span><span class="p">):</span> 1545 <span class="n">text</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span> 1546 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Received data on the link: "</span><span class="o">+</span><span class="n">text</span><span class="p">)</span> 1547 <span class="nb">print</span><span class="p">(</span><span class="s2">"> "</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">" "</span><span class="p">)</span> 1548 <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span> 1549 1550 1551 <span class="c1">##########################################################</span> 1552 <span class="c1">#### Program Startup #####################################</span> 1553 <span class="c1">##########################################################</span> 1554 1555 <span class="c1"># This part of the program runs at startup,</span> 1556 <span class="c1"># and parses input of from the user, and then</span> 1557 <span class="c1"># starts up the desired program mode.</span> 1558 <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span> 1559 <span class="k">try</span><span class="p">:</span> 1560 <span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"Simple link example"</span><span class="p">)</span> 1561 1562 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 1563 <span class="s2">"-s"</span><span class="p">,</span> 1564 <span class="s2">"--server"</span><span class="p">,</span> 1565 <span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">,</span> 1566 <span class="n">help</span><span class="o">=</span><span class="s2">"wait for incoming link requests from clients"</span> 1567 <span class="p">)</span> 1568 1569 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 1570 <span class="s2">"--config"</span><span class="p">,</span> 1571 <span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span> 1572 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 1573 <span class="n">help</span><span class="o">=</span><span class="s2">"path to alternative Reticulum config directory"</span><span class="p">,</span> 1574 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 1575 <span class="p">)</span> 1576 1577 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 1578 <span class="s2">"destination"</span><span class="p">,</span> 1579 <span class="n">nargs</span><span class="o">=</span><span class="s2">"?"</span><span class="p">,</span> 1580 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 1581 <span class="n">help</span><span class="o">=</span><span class="s2">"hexadecimal hash of the server destination"</span><span class="p">,</span> 1582 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 1583 <span class="p">)</span> 1584 1585 <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span> 1586 1587 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span><span class="p">:</span> 1588 <span class="n">configarg</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span> 1589 <span class="k">else</span><span class="p">:</span> 1590 <span class="n">configarg</span> <span class="o">=</span> <span class="kc">None</span> 1591 1592 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">server</span><span class="p">:</span> 1593 <span class="n">server</span><span class="p">(</span><span class="n">configarg</span><span class="p">)</span> 1594 <span class="k">else</span><span class="p">:</span> 1595 <span class="k">if</span> <span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span> <span class="o">==</span> <span class="kc">None</span><span class="p">):</span> 1596 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 1597 <span class="n">parser</span><span class="o">.</span><span class="n">print_help</span><span class="p">()</span> 1598 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 1599 <span class="k">else</span><span class="p">:</span> 1600 <span class="n">client</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span><span class="p">,</span> <span class="n">configarg</span><span class="p">)</span> 1601 1602 <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span> 1603 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 1604 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 1605 </pre></div> 1606 </div> 1607 <p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Identify.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Identify.py</a>.</p> 1608 </section> 1609 <section id="requests-responses"> 1610 <span id="example-request"></span><h2>Requests & Responses<a class="headerlink" href="#requests-responses" title="Permalink to this heading">#</a></h2> 1611 <p>The <em>Request</em> example explores sending requests and receiving responses.</p> 1612 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span> 1613 <span class="c1"># This RNS example demonstrates how to perform requests #</span> 1614 <span class="c1"># and receive responses over a link. #</span> 1615 <span class="c1">##########################################################</span> 1616 1617 <span class="kn">import</span><span class="w"> </span><span class="nn">os</span> 1618 <span class="kn">import</span><span class="w"> </span><span class="nn">sys</span> 1619 <span class="kn">import</span><span class="w"> </span><span class="nn">time</span> 1620 <span class="kn">import</span><span class="w"> </span><span class="nn">random</span> 1621 <span class="kn">import</span><span class="w"> </span><span class="nn">argparse</span> 1622 <span class="kn">import</span><span class="w"> </span><span class="nn">RNS</span> 1623 1624 <span class="c1"># Let's define an app name. We'll use this for all</span> 1625 <span class="c1"># destinations we create. Since this echo example</span> 1626 <span class="c1"># is part of a range of example utilities, we'll put</span> 1627 <span class="c1"># them all within the app namespace "example_utilities"</span> 1628 <span class="n">APP_NAME</span> <span class="o">=</span> <span class="s2">"example_utilities"</span> 1629 1630 <span class="c1">##########################################################</span> 1631 <span class="c1">#### Server Part #########################################</span> 1632 <span class="c1">##########################################################</span> 1633 1634 <span class="c1"># A reference to the latest client link that connected</span> 1635 <span class="n">latest_client_link</span> <span class="o">=</span> <span class="kc">None</span> 1636 1637 <span class="k">def</span><span class="w"> </span><span class="nf">random_text_generator</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">request_id</span><span class="p">,</span> <span class="n">link_id</span><span class="p">,</span> <span class="n">remote_identity</span><span class="p">,</span> <span class="n">requested_at</span><span class="p">):</span> 1638 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Generating response to request "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">request_id</span><span class="p">)</span><span class="o">+</span><span class="s2">" on link "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">link_id</span><span class="p">))</span> 1639 <span class="n">texts</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"They looked up"</span><span class="p">,</span> <span class="s2">"On each full moon"</span><span class="p">,</span> <span class="s2">"Becky was upset"</span><span class="p">,</span> <span class="s2">"I’ll stay away from it"</span><span class="p">,</span> <span class="s2">"The pet shop stocks everything"</span><span class="p">]</span> 1640 <span class="k">return</span> <span class="n">texts</span><span class="p">[</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">texts</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)]</span> 1641 1642 <span class="c1"># This initialisation is executed when the users chooses</span> 1643 <span class="c1"># to run as a server</span> 1644 <span class="k">def</span><span class="w"> </span><span class="nf">server</span><span class="p">(</span><span class="n">configpath</span><span class="p">):</span> 1645 <span class="c1"># We must first initialise Reticulum</span> 1646 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 1647 1648 <span class="c1"># Randomly create a new identity for our link example</span> 1649 <span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span> 1650 1651 <span class="c1"># We create a destination that clients can connect to. We</span> 1652 <span class="c1"># want clients to create links to this destination, so we</span> 1653 <span class="c1"># need to create a "single" destination type.</span> 1654 <span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 1655 <span class="n">server_identity</span><span class="p">,</span> 1656 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> 1657 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 1658 <span class="n">APP_NAME</span><span class="p">,</span> 1659 <span class="s2">"requestexample"</span> 1660 <span class="p">)</span> 1661 1662 <span class="c1"># We configure a function that will get called every time</span> 1663 <span class="c1"># a new client creates a link to this destination.</span> 1664 <span class="n">server_destination</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">client_connected</span><span class="p">)</span> 1665 1666 <span class="c1"># We register a request handler for handling incoming</span> 1667 <span class="c1"># requests over any established links.</span> 1668 <span class="n">server_destination</span><span class="o">.</span><span class="n">register_request_handler</span><span class="p">(</span> 1669 <span class="s2">"/random/text"</span><span class="p">,</span> 1670 <span class="n">response_generator</span> <span class="o">=</span> <span class="n">random_text_generator</span><span class="p">,</span> 1671 <span class="n">allow</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">ALLOW_ALL</span> 1672 <span class="p">)</span> 1673 1674 <span class="c1"># Everything's ready!</span> 1675 <span class="c1"># Let's Wait for client requests or user input</span> 1676 <span class="n">server_loop</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span> 1677 1678 <span class="k">def</span><span class="w"> </span><span class="nf">server_loop</span><span class="p">(</span><span class="n">destination</span><span class="p">):</span> 1679 <span class="c1"># Let the user know that everything is ready</span> 1680 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 1681 <span class="s2">"Request example "</span><span class="o">+</span> 1682 <span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span> 1683 <span class="s2">" running, waiting for a connection."</span> 1684 <span class="p">)</span> 1685 1686 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Hit enter to manually send an announce (Ctrl-C to quit)"</span><span class="p">)</span> 1687 1688 <span class="c1"># We enter a loop that runs until the users exits.</span> 1689 <span class="c1"># If the user hits enter, we will announce our server</span> 1690 <span class="c1"># destination on the network, which will let clients</span> 1691 <span class="c1"># know how to create messages directed towards it.</span> 1692 <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> 1693 <span class="n">entered</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 1694 <span class="n">destination</span><span class="o">.</span><span class="n">announce</span><span class="p">()</span> 1695 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Sent announce from "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">))</span> 1696 1697 <span class="c1"># When a client establishes a link to our server</span> 1698 <span class="c1"># destination, this function will be called with</span> 1699 <span class="c1"># a reference to the link.</span> 1700 <span class="k">def</span><span class="w"> </span><span class="nf">client_connected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 1701 <span class="k">global</span> <span class="n">latest_client_link</span> 1702 1703 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client connected"</span><span class="p">)</span> 1704 <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">client_disconnected</span><span class="p">)</span> 1705 <span class="n">latest_client_link</span> <span class="o">=</span> <span class="n">link</span> 1706 1707 <span class="k">def</span><span class="w"> </span><span class="nf">client_disconnected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 1708 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client disconnected"</span><span class="p">)</span> 1709 1710 1711 <span class="c1">##########################################################</span> 1712 <span class="c1">#### Client Part #########################################</span> 1713 <span class="c1">##########################################################</span> 1714 1715 <span class="c1"># A reference to the server link</span> 1716 <span class="n">server_link</span> <span class="o">=</span> <span class="kc">None</span> 1717 1718 <span class="c1"># This initialisation is executed when the users chooses</span> 1719 <span class="c1"># to run as a client</span> 1720 <span class="k">def</span><span class="w"> </span><span class="nf">client</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">,</span> <span class="n">configpath</span><span class="p">):</span> 1721 <span class="c1"># We need a binary representation of the destination</span> 1722 <span class="c1"># hash that was entered on the command line</span> 1723 <span class="k">try</span><span class="p">:</span> 1724 <span class="n">dest_len</span> <span class="o">=</span> <span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">TRUNCATED_HASHLENGTH</span><span class="o">//</span><span class="mi">8</span><span class="p">)</span><span class="o">*</span><span class="mi">2</span> 1725 <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> <span class="o">!=</span> <span class="n">dest_len</span><span class="p">:</span> 1726 <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span> 1727 <span class="s2">"Destination length is invalid, must be </span><span class="si">{hex}</span><span class="s2"> hexadecimal characters (</span><span class="si">{byte}</span><span class="s2"> bytes)."</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">hex</span><span class="o">=</span><span class="n">dest_len</span><span class="p">,</span> <span class="n">byte</span><span class="o">=</span><span class="n">dest_len</span><span class="o">//</span><span class="mi">2</span><span class="p">)</span> 1728 <span class="p">)</span> 1729 1730 <span class="n">destination_hash</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> 1731 <span class="k">except</span><span class="p">:</span> 1732 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span> 1733 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 1734 1735 <span class="c1"># We must first initialise Reticulum</span> 1736 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 1737 1738 <span class="c1"># Check if we know a path to the destination</span> 1739 <span class="k">if</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span> 1740 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Destination is not yet known. Requesting path and waiting for announce to arrive..."</span><span class="p">)</span> 1741 <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">request_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span> 1742 <span class="k">while</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span> 1743 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> 1744 1745 <span class="c1"># Recall the server identity</span> 1746 <span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="o">.</span><span class="n">recall</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span> 1747 1748 <span class="c1"># Inform the user that we'll begin connecting</span> 1749 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Establishing link with server..."</span><span class="p">)</span> 1750 1751 <span class="c1"># When the server identity is known, we set</span> 1752 <span class="c1"># up a destination</span> 1753 <span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 1754 <span class="n">server_identity</span><span class="p">,</span> 1755 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">OUT</span><span class="p">,</span> 1756 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 1757 <span class="n">APP_NAME</span><span class="p">,</span> 1758 <span class="s2">"requestexample"</span> 1759 <span class="p">)</span> 1760 1761 <span class="c1"># And create a link</span> 1762 <span class="n">link</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span> 1763 1764 <span class="c1"># We'll set up functions to inform the</span> 1765 <span class="c1"># user when the link is established or closed</span> 1766 <span class="n">link</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">link_established</span><span class="p">)</span> 1767 <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">link_closed</span><span class="p">)</span> 1768 1769 <span class="c1"># Everything is set up, so let's enter a loop</span> 1770 <span class="c1"># for the user to interact with the example</span> 1771 <span class="n">client_loop</span><span class="p">()</span> 1772 1773 <span class="k">def</span><span class="w"> </span><span class="nf">client_loop</span><span class="p">():</span> 1774 <span class="k">global</span> <span class="n">server_link</span> 1775 1776 <span class="c1"># Wait for the link to become active</span> 1777 <span class="k">while</span> <span class="ow">not</span> <span class="n">server_link</span><span class="p">:</span> 1778 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> 1779 1780 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">False</span> 1781 <span class="k">while</span> <span class="ow">not</span> <span class="n">should_quit</span><span class="p">:</span> 1782 <span class="k">try</span><span class="p">:</span> 1783 <span class="nb">print</span><span class="p">(</span><span class="s2">"> "</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">" "</span><span class="p">)</span> 1784 <span class="n">text</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 1785 1786 <span class="c1"># Check if we should quit the example</span> 1787 <span class="k">if</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"quit"</span> <span class="ow">or</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"q"</span> <span class="ow">or</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"exit"</span><span class="p">:</span> 1788 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span> 1789 <span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 1790 1791 <span class="k">else</span><span class="p">:</span> 1792 <span class="n">server_link</span><span class="o">.</span><span class="n">request</span><span class="p">(</span> 1793 <span class="s2">"/random/text"</span><span class="p">,</span> 1794 <span class="n">data</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> 1795 <span class="n">response_callback</span> <span class="o">=</span> <span class="n">got_response</span><span class="p">,</span> 1796 <span class="n">failed_callback</span> <span class="o">=</span> <span class="n">request_failed</span> 1797 <span class="p">)</span> 1798 1799 1800 <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> 1801 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Error while sending request over the link: "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span> 1802 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span> 1803 <span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 1804 1805 <span class="k">def</span><span class="w"> </span><span class="nf">got_response</span><span class="p">(</span><span class="n">request_receipt</span><span class="p">):</span> 1806 <span class="n">request_id</span> <span class="o">=</span> <span class="n">request_receipt</span><span class="o">.</span><span class="n">request_id</span> 1807 <span class="n">response</span> <span class="o">=</span> <span class="n">request_receipt</span><span class="o">.</span><span class="n">response</span> 1808 1809 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Got response for request "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">request_id</span><span class="p">)</span><span class="o">+</span><span class="s2">": "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">response</span><span class="p">))</span> 1810 1811 <span class="k">def</span><span class="w"> </span><span class="nf">request_received</span><span class="p">(</span><span class="n">request_receipt</span><span class="p">):</span> 1812 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The request "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">request_receipt</span><span class="o">.</span><span class="n">request_id</span><span class="p">)</span><span class="o">+</span><span class="s2">" was received by the remote peer."</span><span class="p">)</span> 1813 1814 <span class="k">def</span><span class="w"> </span><span class="nf">request_failed</span><span class="p">(</span><span class="n">request_receipt</span><span class="p">):</span> 1815 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The request "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">request_receipt</span><span class="o">.</span><span class="n">request_id</span><span class="p">)</span><span class="o">+</span><span class="s2">" failed."</span><span class="p">)</span> 1816 1817 1818 <span class="c1"># This function is called when a link</span> 1819 <span class="c1"># has been established with the server</span> 1820 <span class="k">def</span><span class="w"> </span><span class="nf">link_established</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 1821 <span class="c1"># We store a reference to the link</span> 1822 <span class="c1"># instance for later use</span> 1823 <span class="k">global</span> <span class="n">server_link</span> 1824 <span class="n">server_link</span> <span class="o">=</span> <span class="n">link</span> 1825 1826 <span class="c1"># Inform the user that the server is</span> 1827 <span class="c1"># connected</span> 1828 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link established with server, hit enter to perform a request, or type in </span><span class="se">\"</span><span class="s2">quit</span><span class="se">\"</span><span class="s2"> to quit"</span><span class="p">)</span> 1829 1830 <span class="c1"># When a link is closed, we'll inform the</span> 1831 <span class="c1"># user, and exit the program</span> 1832 <span class="k">def</span><span class="w"> </span><span class="nf">link_closed</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 1833 <span class="k">if</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">TIMEOUT</span><span class="p">:</span> 1834 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link timed out, exiting now"</span><span class="p">)</span> 1835 <span class="k">elif</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">DESTINATION_CLOSED</span><span class="p">:</span> 1836 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link was closed by the server, exiting now"</span><span class="p">)</span> 1837 <span class="k">else</span><span class="p">:</span> 1838 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link closed, exiting now"</span><span class="p">)</span> 1839 1840 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span> 1841 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 1842 1843 1844 <span class="c1">##########################################################</span> 1845 <span class="c1">#### Program Startup #####################################</span> 1846 <span class="c1">##########################################################</span> 1847 1848 <span class="c1"># This part of the program runs at startup,</span> 1849 <span class="c1"># and parses input of from the user, and then</span> 1850 <span class="c1"># starts up the desired program mode.</span> 1851 <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span> 1852 <span class="k">try</span><span class="p">:</span> 1853 <span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"Simple request/response example"</span><span class="p">)</span> 1854 1855 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 1856 <span class="s2">"-s"</span><span class="p">,</span> 1857 <span class="s2">"--server"</span><span class="p">,</span> 1858 <span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">,</span> 1859 <span class="n">help</span><span class="o">=</span><span class="s2">"wait for incoming requests from clients"</span> 1860 <span class="p">)</span> 1861 1862 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 1863 <span class="s2">"--config"</span><span class="p">,</span> 1864 <span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span> 1865 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 1866 <span class="n">help</span><span class="o">=</span><span class="s2">"path to alternative Reticulum config directory"</span><span class="p">,</span> 1867 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 1868 <span class="p">)</span> 1869 1870 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 1871 <span class="s2">"destination"</span><span class="p">,</span> 1872 <span class="n">nargs</span><span class="o">=</span><span class="s2">"?"</span><span class="p">,</span> 1873 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 1874 <span class="n">help</span><span class="o">=</span><span class="s2">"hexadecimal hash of the server destination"</span><span class="p">,</span> 1875 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 1876 <span class="p">)</span> 1877 1878 <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span> 1879 1880 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span><span class="p">:</span> 1881 <span class="n">configarg</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span> 1882 <span class="k">else</span><span class="p">:</span> 1883 <span class="n">configarg</span> <span class="o">=</span> <span class="kc">None</span> 1884 1885 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">server</span><span class="p">:</span> 1886 <span class="n">server</span><span class="p">(</span><span class="n">configarg</span><span class="p">)</span> 1887 <span class="k">else</span><span class="p">:</span> 1888 <span class="k">if</span> <span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span> <span class="o">==</span> <span class="kc">None</span><span class="p">):</span> 1889 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 1890 <span class="n">parser</span><span class="o">.</span><span class="n">print_help</span><span class="p">()</span> 1891 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 1892 <span class="k">else</span><span class="p">:</span> 1893 <span class="n">client</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span><span class="p">,</span> <span class="n">configarg</span><span class="p">)</span> 1894 1895 <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span> 1896 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 1897 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 1898 </pre></div> 1899 </div> 1900 <p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Request.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Request.py</a>.</p> 1901 </section> 1902 <section id="channel"> 1903 <span id="example-channel"></span><h2>Channel<a class="headerlink" href="#channel" title="Permalink to this heading">#</a></h2> 1904 <p>The <em>Channel</em> example explores using a <code class="docutils literal notranslate"><span class="pre">Channel</span></code> to send structured 1905 data between peers of a <code class="docutils literal notranslate"><span class="pre">Link</span></code>.</p> 1906 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span> 1907 <span class="c1"># This RNS example demonstrates how to set up a link to #</span> 1908 <span class="c1"># a destination, and pass structured messages over it #</span> 1909 <span class="c1"># using a channel. #</span> 1910 <span class="c1">##########################################################</span> 1911 1912 <span class="kn">import</span><span class="w"> </span><span class="nn">os</span> 1913 <span class="kn">import</span><span class="w"> </span><span class="nn">sys</span> 1914 <span class="kn">import</span><span class="w"> </span><span class="nn">time</span> 1915 <span class="kn">import</span><span class="w"> </span><span class="nn">argparse</span> 1916 <span class="kn">from</span><span class="w"> </span><span class="nn">datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">datetime</span> 1917 1918 <span class="kn">import</span><span class="w"> </span><span class="nn">RNS</span> 1919 <span class="kn">from</span><span class="w"> </span><span class="nn">RNS.vendor</span><span class="w"> </span><span class="kn">import</span> <span class="n">umsgpack</span> 1920 1921 <span class="c1"># Let's define an app name. We'll use this for all</span> 1922 <span class="c1"># destinations we create. Since this echo example</span> 1923 <span class="c1"># is part of a range of example utilities, we'll put</span> 1924 <span class="c1"># them all within the app namespace "example_utilities"</span> 1925 <span class="n">APP_NAME</span> <span class="o">=</span> <span class="s2">"example_utilities"</span> 1926 1927 <span class="c1">##########################################################</span> 1928 <span class="c1">#### Shared Objects ######################################</span> 1929 <span class="c1">##########################################################</span> 1930 1931 <span class="c1"># Channel data must be structured in a subclass of</span> 1932 <span class="c1"># MessageBase. This ensures that the channel will be able</span> 1933 <span class="c1"># to serialize and deserialize the object and multiplex it</span> 1934 <span class="c1"># with other objects. Both ends of a link will need the</span> 1935 <span class="c1"># same object definitions to be able to communicate over</span> 1936 <span class="c1"># a channel.</span> 1937 <span class="c1">#</span> 1938 <span class="c1"># Note: The objects we wish to use over the channel must</span> 1939 <span class="c1"># be registered with the channel, and each link has a</span> 1940 <span class="c1"># different channel instance. See the client_connected</span> 1941 <span class="c1"># and link_established functions in this example to see</span> 1942 <span class="c1"># how message types are registered.</span> 1943 1944 <span class="c1"># Let's make a simple message class called StringMessage</span> 1945 <span class="c1"># that will convey a string with a timestamp.</span> 1946 1947 <span class="k">class</span><span class="w"> </span><span class="nc">StringMessage</span><span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">MessageBase</span><span class="p">):</span> 1948 <span class="c1"># The MSGTYPE class variable needs to be assigned a</span> 1949 <span class="c1"># 2 byte integer value. This identifier allows the</span> 1950 <span class="c1"># channel to look up your message's constructor when a</span> 1951 <span class="c1"># message arrives over the channel.</span> 1952 <span class="c1">#</span> 1953 <span class="c1"># MSGTYPE must be unique across all message types we</span> 1954 <span class="c1"># register with the channel. MSGTYPEs >= 0xf000 are</span> 1955 <span class="c1"># reserved for the system.</span> 1956 <span class="n">MSGTYPE</span> <span class="o">=</span> <span class="mh">0x0101</span> 1957 1958 <span class="c1"># The constructor of our object must be callable with</span> 1959 <span class="c1"># no arguments. We can have parameters, but they must</span> 1960 <span class="c1"># have a default assignment.</span> 1961 <span class="c1">#</span> 1962 <span class="c1"># This is needed so the channel can create an empty</span> 1963 <span class="c1"># version of our message into which the incoming</span> 1964 <span class="c1"># message can be unpacked.</span> 1965 <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> 1966 <span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="n">data</span> 1967 <span class="bp">self</span><span class="o">.</span><span class="n">timestamp</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> 1968 1969 <span class="c1"># Finally, our message needs to implement functions</span> 1970 <span class="c1"># the channel can call to pack and unpack our message</span> 1971 <span class="c1"># to/from the raw packet payload. We'll use the</span> 1972 <span class="c1"># umsgpack package bundled with RNS. We could also use</span> 1973 <span class="c1"># the struct package bundled with Python if we wanted</span> 1974 <span class="c1"># more control over the structure of the packed bytes.</span> 1975 <span class="c1">#</span> 1976 <span class="c1"># Also note that packed message objects must fit</span> 1977 <span class="c1"># entirely in one packet. The number of bytes</span> 1978 <span class="c1"># available for message payloads can be queried from</span> 1979 <span class="c1"># the channel using the Channel.MDU property. The</span> 1980 <span class="c1"># channel MDU is slightly less than the link MDU due</span> 1981 <span class="c1"># to encoding the message header.</span> 1982 1983 <span class="c1"># The pack function encodes the message contents into</span> 1984 <span class="c1"># a byte stream.</span> 1985 <span class="k">def</span><span class="w"> </span><span class="nf">pack</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bytes</span><span class="p">:</span> 1986 <span class="k">return</span> <span class="n">umsgpack</span><span class="o">.</span><span class="n">packb</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">timestamp</span><span class="p">))</span> 1987 1988 <span class="c1"># And the unpack function decodes a byte stream into</span> 1989 <span class="c1"># the message contents.</span> 1990 <span class="k">def</span><span class="w"> </span><span class="nf">unpack</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">raw</span><span class="p">):</span> 1991 <span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">timestamp</span> <span class="o">=</span> <span class="n">umsgpack</span><span class="o">.</span><span class="n">unpackb</span><span class="p">(</span><span class="n">raw</span><span class="p">)</span> 1992 1993 1994 <span class="c1">##########################################################</span> 1995 <span class="c1">#### Server Part #########################################</span> 1996 <span class="c1">##########################################################</span> 1997 1998 <span class="c1"># A reference to the latest client link that connected</span> 1999 <span class="n">latest_client_link</span> <span class="o">=</span> <span class="kc">None</span> 2000 2001 <span class="c1"># This initialisation is executed when the users chooses</span> 2002 <span class="c1"># to run as a server</span> 2003 <span class="k">def</span><span class="w"> </span><span class="nf">server</span><span class="p">(</span><span class="n">configpath</span><span class="p">):</span> 2004 <span class="c1"># We must first initialise Reticulum</span> 2005 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 2006 2007 <span class="c1"># Randomly create a new identity for our link example</span> 2008 <span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span> 2009 2010 <span class="c1"># We create a destination that clients can connect to. We</span> 2011 <span class="c1"># want clients to create links to this destination, so we</span> 2012 <span class="c1"># need to create a "single" destination type.</span> 2013 <span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 2014 <span class="n">server_identity</span><span class="p">,</span> 2015 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> 2016 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 2017 <span class="n">APP_NAME</span><span class="p">,</span> 2018 <span class="s2">"channelexample"</span> 2019 <span class="p">)</span> 2020 2021 <span class="c1"># We configure a function that will get called every time</span> 2022 <span class="c1"># a new client creates a link to this destination.</span> 2023 <span class="n">server_destination</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">client_connected</span><span class="p">)</span> 2024 2025 <span class="c1"># Everything's ready!</span> 2026 <span class="c1"># Let's Wait for client requests or user input</span> 2027 <span class="n">server_loop</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span> 2028 2029 <span class="k">def</span><span class="w"> </span><span class="nf">server_loop</span><span class="p">(</span><span class="n">destination</span><span class="p">):</span> 2030 <span class="c1"># Let the user know that everything is ready</span> 2031 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 2032 <span class="s2">"Channel example "</span><span class="o">+</span> 2033 <span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span> 2034 <span class="s2">" running, waiting for a connection."</span> 2035 <span class="p">)</span> 2036 2037 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Hit enter to manually send an announce (Ctrl-C to quit)"</span><span class="p">)</span> 2038 2039 <span class="c1"># We enter a loop that runs until the users exits.</span> 2040 <span class="c1"># If the user hits enter, we will announce our server</span> 2041 <span class="c1"># destination on the network, which will let clients</span> 2042 <span class="c1"># know how to create messages directed towards it.</span> 2043 <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> 2044 <span class="n">entered</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 2045 <span class="n">destination</span><span class="o">.</span><span class="n">announce</span><span class="p">()</span> 2046 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Sent announce from "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">))</span> 2047 2048 <span class="c1"># When a client establishes a link to our server</span> 2049 <span class="c1"># destination, this function will be called with</span> 2050 <span class="c1"># a reference to the link.</span> 2051 <span class="k">def</span><span class="w"> </span><span class="nf">client_connected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 2052 <span class="k">global</span> <span class="n">latest_client_link</span> 2053 <span class="n">latest_client_link</span> <span class="o">=</span> <span class="n">link</span> 2054 2055 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client connected"</span><span class="p">)</span> 2056 <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">client_disconnected</span><span class="p">)</span> 2057 2058 <span class="c1"># Register message types and add callback to channel</span> 2059 <span class="n">channel</span> <span class="o">=</span> <span class="n">link</span><span class="o">.</span><span class="n">get_channel</span><span class="p">()</span> 2060 <span class="n">channel</span><span class="o">.</span><span class="n">register_message_type</span><span class="p">(</span><span class="n">StringMessage</span><span class="p">)</span> 2061 <span class="n">channel</span><span class="o">.</span><span class="n">add_message_handler</span><span class="p">(</span><span class="n">server_message_received</span><span class="p">)</span> 2062 2063 <span class="k">def</span><span class="w"> </span><span class="nf">client_disconnected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 2064 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client disconnected"</span><span class="p">)</span> 2065 2066 <span class="k">def</span><span class="w"> </span><span class="nf">server_message_received</span><span class="p">(</span><span class="n">message</span><span class="p">):</span> 2067 <span class="w"> </span><span class="sd">"""</span> 2068 <span class="sd"> A message handler</span> 2069 <span class="sd"> @param message: An instance of a subclass of MessageBase</span> 2070 <span class="sd"> @return: True if message was handled</span> 2071 <span class="sd"> """</span> 2072 <span class="k">global</span> <span class="n">latest_client_link</span> 2073 <span class="c1"># When a message is received over any active link,</span> 2074 <span class="c1"># the replies will all be directed to the last client</span> 2075 <span class="c1"># that connected.</span> 2076 2077 <span class="c1"># In a message handler, any deserializable message</span> 2078 <span class="c1"># that arrives over the link's channel will be passed</span> 2079 <span class="c1"># to all message handlers, unless a preceding handler indicates it</span> 2080 <span class="c1"># has handled the message.</span> 2081 <span class="c1">#</span> 2082 <span class="c1">#</span> 2083 <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">StringMessage</span><span class="p">):</span> 2084 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Received data on the link: "</span> <span class="o">+</span> <span class="n">message</span><span class="o">.</span><span class="n">data</span> <span class="o">+</span> <span class="s2">" (message created at "</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">timestamp</span><span class="p">)</span> <span class="o">+</span> <span class="s2">")"</span><span class="p">)</span> 2085 2086 <span class="n">reply_message</span> <span class="o">=</span> <span class="n">StringMessage</span><span class="p">(</span><span class="s2">"I received </span><span class="se">\"</span><span class="s2">"</span><span class="o">+</span><span class="n">message</span><span class="o">.</span><span class="n">data</span><span class="o">+</span><span class="s2">"</span><span class="se">\"</span><span class="s2"> over the link"</span><span class="p">)</span> 2087 <span class="n">latest_client_link</span><span class="o">.</span><span class="n">get_channel</span><span class="p">()</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">reply_message</span><span class="p">)</span> 2088 2089 <span class="c1"># Incoming messages are sent to each message</span> 2090 <span class="c1"># handler added to the channel, in the order they</span> 2091 <span class="c1"># were added.</span> 2092 <span class="c1"># If any message handler returns True, the message</span> 2093 <span class="c1"># is considered handled and any subsequent</span> 2094 <span class="c1"># handlers are skipped.</span> 2095 <span class="k">return</span> <span class="kc">True</span> 2096 2097 2098 <span class="c1">##########################################################</span> 2099 <span class="c1">#### Client Part #########################################</span> 2100 <span class="c1">##########################################################</span> 2101 2102 <span class="c1"># A reference to the server link</span> 2103 <span class="n">server_link</span> <span class="o">=</span> <span class="kc">None</span> 2104 2105 <span class="c1"># This initialisation is executed when the users chooses</span> 2106 <span class="c1"># to run as a client</span> 2107 <span class="k">def</span><span class="w"> </span><span class="nf">client</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">,</span> <span class="n">configpath</span><span class="p">):</span> 2108 <span class="c1"># We need a binary representation of the destination</span> 2109 <span class="c1"># hash that was entered on the command line</span> 2110 <span class="k">try</span><span class="p">:</span> 2111 <span class="n">dest_len</span> <span class="o">=</span> <span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">TRUNCATED_HASHLENGTH</span><span class="o">//</span><span class="mi">8</span><span class="p">)</span><span class="o">*</span><span class="mi">2</span> 2112 <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> <span class="o">!=</span> <span class="n">dest_len</span><span class="p">:</span> 2113 <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span> 2114 <span class="s2">"Destination length is invalid, must be </span><span class="si">{hex}</span><span class="s2"> hexadecimal characters (</span><span class="si">{byte}</span><span class="s2"> bytes)."</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">hex</span><span class="o">=</span><span class="n">dest_len</span><span class="p">,</span> <span class="n">byte</span><span class="o">=</span><span class="n">dest_len</span><span class="o">//</span><span class="mi">2</span><span class="p">)</span> 2115 <span class="p">)</span> 2116 2117 <span class="n">destination_hash</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> 2118 <span class="k">except</span><span class="p">:</span> 2119 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span> 2120 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 2121 2122 <span class="c1"># We must first initialise Reticulum</span> 2123 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 2124 2125 <span class="c1"># Check if we know a path to the destination</span> 2126 <span class="k">if</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span> 2127 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Destination is not yet known. Requesting path and waiting for announce to arrive..."</span><span class="p">)</span> 2128 <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">request_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span> 2129 <span class="k">while</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span> 2130 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> 2131 2132 <span class="c1"># Recall the server identity</span> 2133 <span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="o">.</span><span class="n">recall</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span> 2134 2135 <span class="c1"># Inform the user that we'll begin connecting</span> 2136 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Establishing link with server..."</span><span class="p">)</span> 2137 2138 <span class="c1"># When the server identity is known, we set</span> 2139 <span class="c1"># up a destination</span> 2140 <span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 2141 <span class="n">server_identity</span><span class="p">,</span> 2142 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">OUT</span><span class="p">,</span> 2143 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 2144 <span class="n">APP_NAME</span><span class="p">,</span> 2145 <span class="s2">"channelexample"</span> 2146 <span class="p">)</span> 2147 2148 <span class="c1"># And create a link</span> 2149 <span class="n">link</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span> 2150 2151 <span class="c1"># We'll also set up functions to inform the</span> 2152 <span class="c1"># user when the link is established or closed</span> 2153 <span class="n">link</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">link_established</span><span class="p">)</span> 2154 <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">link_closed</span><span class="p">)</span> 2155 2156 <span class="c1"># Everything is set up, so let's enter a loop</span> 2157 <span class="c1"># for the user to interact with the example</span> 2158 <span class="n">client_loop</span><span class="p">()</span> 2159 2160 <span class="k">def</span><span class="w"> </span><span class="nf">client_loop</span><span class="p">():</span> 2161 <span class="k">global</span> <span class="n">server_link</span> 2162 2163 <span class="c1"># Wait for the link to become active</span> 2164 <span class="k">while</span> <span class="ow">not</span> <span class="n">server_link</span><span class="p">:</span> 2165 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> 2166 2167 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">False</span> 2168 <span class="k">while</span> <span class="ow">not</span> <span class="n">should_quit</span><span class="p">:</span> 2169 <span class="k">try</span><span class="p">:</span> 2170 <span class="nb">print</span><span class="p">(</span><span class="s2">"> "</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">" "</span><span class="p">)</span> 2171 <span class="n">text</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 2172 2173 <span class="c1"># Check if we should quit the example</span> 2174 <span class="k">if</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"quit"</span> <span class="ow">or</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"q"</span> <span class="ow">or</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"exit"</span><span class="p">:</span> 2175 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span> 2176 <span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 2177 2178 <span class="c1"># If not, send the entered text over the link</span> 2179 <span class="k">if</span> <span class="n">text</span> <span class="o">!=</span> <span class="s2">""</span><span class="p">:</span> 2180 <span class="n">message</span> <span class="o">=</span> <span class="n">StringMessage</span><span class="p">(</span><span class="n">text</span><span class="p">)</span> 2181 <span class="n">packed_size</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">pack</span><span class="p">())</span> 2182 <span class="n">channel</span> <span class="o">=</span> <span class="n">server_link</span><span class="o">.</span><span class="n">get_channel</span><span class="p">()</span> 2183 <span class="k">if</span> <span class="n">channel</span><span class="o">.</span><span class="n">is_ready_to_send</span><span class="p">():</span> 2184 <span class="k">if</span> <span class="n">packed_size</span> <span class="o"><=</span> <span class="n">channel</span><span class="o">.</span><span class="n">mdu</span><span class="p">:</span> 2185 <span class="n">channel</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> 2186 <span class="k">else</span><span class="p">:</span> 2187 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 2188 <span class="s2">"Cannot send this packet, the data size of "</span><span class="o">+</span> 2189 <span class="nb">str</span><span class="p">(</span><span class="n">packed_size</span><span class="p">)</span><span class="o">+</span><span class="s2">" bytes exceeds the link packet MDU of "</span><span class="o">+</span> 2190 <span class="nb">str</span><span class="p">(</span><span class="n">channel</span><span class="o">.</span><span class="n">MDU</span><span class="p">)</span><span class="o">+</span><span class="s2">" bytes"</span><span class="p">,</span> 2191 <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span> 2192 <span class="p">)</span> 2193 <span class="k">else</span><span class="p">:</span> 2194 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Channel is not ready to send, please wait for "</span> <span class="o">+</span> 2195 <span class="s2">"pending messages to complete."</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span> 2196 2197 <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> 2198 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Error while sending data over the link: "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span> 2199 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span> 2200 <span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 2201 2202 <span class="c1"># This function is called when a link</span> 2203 <span class="c1"># has been established with the server</span> 2204 <span class="k">def</span><span class="w"> </span><span class="nf">link_established</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 2205 <span class="c1"># We store a reference to the link</span> 2206 <span class="c1"># instance for later use</span> 2207 <span class="k">global</span> <span class="n">server_link</span> 2208 <span class="n">server_link</span> <span class="o">=</span> <span class="n">link</span> 2209 2210 <span class="c1"># Register messages and add handler to channel</span> 2211 <span class="n">channel</span> <span class="o">=</span> <span class="n">link</span><span class="o">.</span><span class="n">get_channel</span><span class="p">()</span> 2212 <span class="n">channel</span><span class="o">.</span><span class="n">register_message_type</span><span class="p">(</span><span class="n">StringMessage</span><span class="p">)</span> 2213 <span class="n">channel</span><span class="o">.</span><span class="n">add_message_handler</span><span class="p">(</span><span class="n">client_message_received</span><span class="p">)</span> 2214 2215 <span class="c1"># Inform the user that the server is</span> 2216 <span class="c1"># connected</span> 2217 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link established with server, enter some text to send, or </span><span class="se">\"</span><span class="s2">quit</span><span class="se">\"</span><span class="s2"> to quit"</span><span class="p">)</span> 2218 2219 <span class="c1"># When a link is closed, we'll inform the</span> 2220 <span class="c1"># user, and exit the program</span> 2221 <span class="k">def</span><span class="w"> </span><span class="nf">link_closed</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 2222 <span class="k">if</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">TIMEOUT</span><span class="p">:</span> 2223 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link timed out, exiting now"</span><span class="p">)</span> 2224 <span class="k">elif</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">DESTINATION_CLOSED</span><span class="p">:</span> 2225 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link was closed by the server, exiting now"</span><span class="p">)</span> 2226 <span class="k">else</span><span class="p">:</span> 2227 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link closed, exiting now"</span><span class="p">)</span> 2228 2229 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span> 2230 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 2231 2232 <span class="c1"># When a packet is received over the channel, we</span> 2233 <span class="c1"># simply print out the data.</span> 2234 <span class="k">def</span><span class="w"> </span><span class="nf">client_message_received</span><span class="p">(</span><span class="n">message</span><span class="p">):</span> 2235 <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">StringMessage</span><span class="p">):</span> 2236 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Received data on the link: "</span> <span class="o">+</span> <span class="n">message</span><span class="o">.</span><span class="n">data</span> <span class="o">+</span> <span class="s2">" (message created at "</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">timestamp</span><span class="p">)</span> <span class="o">+</span> <span class="s2">")"</span><span class="p">)</span> 2237 <span class="nb">print</span><span class="p">(</span><span class="s2">"> "</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">" "</span><span class="p">)</span> 2238 <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span> 2239 2240 2241 <span class="c1">##########################################################</span> 2242 <span class="c1">#### Program Startup #####################################</span> 2243 <span class="c1">##########################################################</span> 2244 2245 <span class="c1"># This part of the program runs at startup,</span> 2246 <span class="c1"># and parses input of from the user, and then</span> 2247 <span class="c1"># starts up the desired program mode.</span> 2248 <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span> 2249 <span class="k">try</span><span class="p">:</span> 2250 <span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"Simple channel example"</span><span class="p">)</span> 2251 2252 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 2253 <span class="s2">"-s"</span><span class="p">,</span> 2254 <span class="s2">"--server"</span><span class="p">,</span> 2255 <span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">,</span> 2256 <span class="n">help</span><span class="o">=</span><span class="s2">"wait for incoming link requests from clients"</span> 2257 <span class="p">)</span> 2258 2259 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 2260 <span class="s2">"--config"</span><span class="p">,</span> 2261 <span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span> 2262 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 2263 <span class="n">help</span><span class="o">=</span><span class="s2">"path to alternative Reticulum config directory"</span><span class="p">,</span> 2264 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 2265 <span class="p">)</span> 2266 2267 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 2268 <span class="s2">"destination"</span><span class="p">,</span> 2269 <span class="n">nargs</span><span class="o">=</span><span class="s2">"?"</span><span class="p">,</span> 2270 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 2271 <span class="n">help</span><span class="o">=</span><span class="s2">"hexadecimal hash of the server destination"</span><span class="p">,</span> 2272 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 2273 <span class="p">)</span> 2274 2275 <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span> 2276 2277 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span><span class="p">:</span> 2278 <span class="n">configarg</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span> 2279 <span class="k">else</span><span class="p">:</span> 2280 <span class="n">configarg</span> <span class="o">=</span> <span class="kc">None</span> 2281 2282 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">server</span><span class="p">:</span> 2283 <span class="n">server</span><span class="p">(</span><span class="n">configarg</span><span class="p">)</span> 2284 <span class="k">else</span><span class="p">:</span> 2285 <span class="k">if</span> <span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span> <span class="o">==</span> <span class="kc">None</span><span class="p">):</span> 2286 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 2287 <span class="n">parser</span><span class="o">.</span><span class="n">print_help</span><span class="p">()</span> 2288 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 2289 <span class="k">else</span><span class="p">:</span> 2290 <span class="n">client</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span><span class="p">,</span> <span class="n">configarg</span><span class="p">)</span> 2291 2292 <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span> 2293 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 2294 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 2295 </pre></div> 2296 </div> 2297 <p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Channel.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Channel.py</a>.</p> 2298 </section> 2299 <section id="buffer"> 2300 <h2>Buffer<a class="headerlink" href="#buffer" title="Permalink to this heading">#</a></h2> 2301 <p>The <em>Buffer</em> example explores using buffered readers and writers to send 2302 binary data between peers of a <code class="docutils literal notranslate"><span class="pre">Link</span></code>.</p> 2303 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span> 2304 <span class="c1"># This RNS example demonstrates how to set up a link to #</span> 2305 <span class="c1"># a destination, and pass binary data over it using a #</span> 2306 <span class="c1"># channel buffer. #</span> 2307 <span class="c1">##########################################################</span> 2308 <span class="kn">from</span><span class="w"> </span><span class="nn">__future__</span><span class="w"> </span><span class="kn">import</span> <span class="n">annotations</span> 2309 <span class="kn">import</span><span class="w"> </span><span class="nn">os</span> 2310 <span class="kn">import</span><span class="w"> </span><span class="nn">sys</span> 2311 <span class="kn">import</span><span class="w"> </span><span class="nn">time</span> 2312 <span class="kn">import</span><span class="w"> </span><span class="nn">argparse</span> 2313 <span class="kn">from</span><span class="w"> </span><span class="nn">datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">datetime</span> 2314 2315 <span class="kn">import</span><span class="w"> </span><span class="nn">RNS</span> 2316 <span class="kn">from</span><span class="w"> </span><span class="nn">RNS.vendor</span><span class="w"> </span><span class="kn">import</span> <span class="n">umsgpack</span> 2317 2318 <span class="c1"># Let's define an app name. We'll use this for all</span> 2319 <span class="c1"># destinations we create. Since this echo example</span> 2320 <span class="c1"># is part of a range of example utilities, we'll put</span> 2321 <span class="c1"># them all within the app namespace "example_utilities"</span> 2322 <span class="n">APP_NAME</span> <span class="o">=</span> <span class="s2">"example_utilities"</span> 2323 2324 2325 <span class="c1">##########################################################</span> 2326 <span class="c1">#### Server Part #########################################</span> 2327 <span class="c1">##########################################################</span> 2328 2329 <span class="c1"># A reference to the latest client link that connected</span> 2330 <span class="n">latest_client_link</span> <span class="o">=</span> <span class="kc">None</span> 2331 2332 <span class="c1"># A reference to the latest buffer object</span> 2333 <span class="n">latest_buffer</span> <span class="o">=</span> <span class="kc">None</span> 2334 2335 <span class="c1"># This initialisation is executed when the users chooses</span> 2336 <span class="c1"># to run as a server</span> 2337 <span class="k">def</span><span class="w"> </span><span class="nf">server</span><span class="p">(</span><span class="n">configpath</span><span class="p">):</span> 2338 <span class="c1"># We must first initialise Reticulum</span> 2339 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 2340 2341 <span class="c1"># Randomly create a new identity for our example</span> 2342 <span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span> 2343 2344 <span class="c1"># We create a destination that clients can connect to. We</span> 2345 <span class="c1"># want clients to create links to this destination, so we</span> 2346 <span class="c1"># need to create a "single" destination type.</span> 2347 <span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 2348 <span class="n">server_identity</span><span class="p">,</span> 2349 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> 2350 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 2351 <span class="n">APP_NAME</span><span class="p">,</span> 2352 <span class="s2">"bufferexample"</span> 2353 <span class="p">)</span> 2354 2355 <span class="c1"># We configure a function that will get called every time</span> 2356 <span class="c1"># a new client creates a link to this destination.</span> 2357 <span class="n">server_destination</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">client_connected</span><span class="p">)</span> 2358 2359 <span class="c1"># Everything's ready!</span> 2360 <span class="c1"># Let's Wait for client requests or user input</span> 2361 <span class="n">server_loop</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span> 2362 2363 <span class="k">def</span><span class="w"> </span><span class="nf">server_loop</span><span class="p">(</span><span class="n">destination</span><span class="p">):</span> 2364 <span class="c1"># Let the user know that everything is ready</span> 2365 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span> 2366 <span class="s2">"Link buffer example "</span><span class="o">+</span> 2367 <span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span> 2368 <span class="s2">" running, waiting for a connection."</span> 2369 <span class="p">)</span> 2370 2371 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Hit enter to manually send an announce (Ctrl-C to quit)"</span><span class="p">)</span> 2372 2373 <span class="c1"># We enter a loop that runs until the users exits.</span> 2374 <span class="c1"># If the user hits enter, we will announce our server</span> 2375 <span class="c1"># destination on the network, which will let clients</span> 2376 <span class="c1"># know how to create messages directed towards it.</span> 2377 <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> 2378 <span class="n">entered</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 2379 <span class="n">destination</span><span class="o">.</span><span class="n">announce</span><span class="p">()</span> 2380 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Sent announce from "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">))</span> 2381 2382 <span class="c1"># When a client establishes a link to our server</span> 2383 <span class="c1"># destination, this function will be called with</span> 2384 <span class="c1"># a reference to the link.</span> 2385 <span class="k">def</span><span class="w"> </span><span class="nf">client_connected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 2386 <span class="k">global</span> <span class="n">latest_client_link</span><span class="p">,</span> <span class="n">latest_buffer</span> 2387 <span class="n">latest_client_link</span> <span class="o">=</span> <span class="n">link</span> 2388 2389 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client connected"</span><span class="p">)</span> 2390 <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">client_disconnected</span><span class="p">)</span> 2391 2392 <span class="c1"># If a new connection is received, the old reader</span> 2393 <span class="c1"># needs to be disconnected.</span> 2394 <span class="k">if</span> <span class="n">latest_buffer</span><span class="p">:</span> 2395 <span class="n">latest_buffer</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> 2396 2397 2398 <span class="c1"># Create buffer objects.</span> 2399 <span class="c1"># The stream_id parameter to these functions is</span> 2400 <span class="c1"># a bit like a file descriptor, except that it</span> 2401 <span class="c1"># is unique to the *receiver*.</span> 2402 <span class="c1">#</span> 2403 <span class="c1"># In this example, both the reader and the writer</span> 2404 <span class="c1"># use stream_id = 0, but there are actually two</span> 2405 <span class="c1"># separate unidirectional streams flowing in</span> 2406 <span class="c1"># opposite directions.</span> 2407 <span class="c1">#</span> 2408 <span class="n">channel</span> <span class="o">=</span> <span class="n">link</span><span class="o">.</span><span class="n">get_channel</span><span class="p">()</span> 2409 <span class="n">latest_buffer</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Buffer</span><span class="o">.</span><span class="n">create_bidirectional_buffer</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">channel</span><span class="p">,</span> <span class="n">server_buffer_ready</span><span class="p">)</span> 2410 2411 <span class="k">def</span><span class="w"> </span><span class="nf">client_disconnected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 2412 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client disconnected"</span><span class="p">)</span> 2413 2414 <span class="k">def</span><span class="w"> </span><span class="nf">server_buffer_ready</span><span class="p">(</span><span class="n">ready_bytes</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span> 2415 <span class="w"> </span><span class="sd">"""</span> 2416 <span class="sd"> Callback from buffer when buffer has data available</span> 2417 2418 <span class="sd"> :param ready_bytes: The number of bytes ready to read</span> 2419 <span class="sd"> """</span> 2420 <span class="k">global</span> <span class="n">latest_buffer</span> 2421 2422 <span class="n">data</span> <span class="o">=</span> <span class="n">latest_buffer</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">ready_bytes</span><span class="p">)</span> 2423 <span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span> 2424 2425 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Received data over the buffer: "</span> <span class="o">+</span> <span class="n">data</span><span class="p">)</span> 2426 2427 <span class="n">reply_message</span> <span class="o">=</span> <span class="s2">"I received </span><span class="se">\"</span><span class="s2">"</span><span class="o">+</span><span class="n">data</span><span class="o">+</span><span class="s2">"</span><span class="se">\"</span><span class="s2"> over the buffer"</span> 2428 <span class="n">reply_message</span> <span class="o">=</span> <span class="n">reply_message</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span> 2429 <span class="n">latest_buffer</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">reply_message</span><span class="p">)</span> 2430 <span class="n">latest_buffer</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span> 2431 2432 2433 2434 2435 <span class="c1">##########################################################</span> 2436 <span class="c1">#### Client Part #########################################</span> 2437 <span class="c1">##########################################################</span> 2438 2439 <span class="c1"># A reference to the server link</span> 2440 <span class="n">server_link</span> <span class="o">=</span> <span class="kc">None</span> 2441 2442 <span class="c1"># A reference to the buffer object, needed to share the</span> 2443 <span class="c1"># object from the link connected callback to the client</span> 2444 <span class="c1"># loop.</span> 2445 <span class="n">buffer</span> <span class="o">=</span> <span class="kc">None</span> 2446 2447 <span class="c1"># This initialisation is executed when the users chooses</span> 2448 <span class="c1"># to run as a client</span> 2449 <span class="k">def</span><span class="w"> </span><span class="nf">client</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">,</span> <span class="n">configpath</span><span class="p">):</span> 2450 <span class="c1"># We need a binary representation of the destination</span> 2451 <span class="c1"># hash that was entered on the command line</span> 2452 <span class="k">try</span><span class="p">:</span> 2453 <span class="n">dest_len</span> <span class="o">=</span> <span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">TRUNCATED_HASHLENGTH</span><span class="o">//</span><span class="mi">8</span><span class="p">)</span><span class="o">*</span><span class="mi">2</span> 2454 <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> <span class="o">!=</span> <span class="n">dest_len</span><span class="p">:</span> 2455 <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span> 2456 <span class="s2">"Destination length is invalid, must be </span><span class="si">{hex}</span><span class="s2"> hexadecimal characters (</span><span class="si">{byte}</span><span class="s2"> bytes)."</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">hex</span><span class="o">=</span><span class="n">dest_len</span><span class="p">,</span> <span class="n">byte</span><span class="o">=</span><span class="n">dest_len</span><span class="o">//</span><span class="mi">2</span><span class="p">)</span> 2457 <span class="p">)</span> 2458 2459 <span class="n">destination_hash</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> 2460 <span class="k">except</span><span class="p">:</span> 2461 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span> 2462 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 2463 2464 <span class="c1"># We must first initialise Reticulum</span> 2465 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 2466 2467 <span class="c1"># Check if we know a path to the destination</span> 2468 <span class="k">if</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span> 2469 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Destination is not yet known. Requesting path and waiting for announce to arrive..."</span><span class="p">)</span> 2470 <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">request_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span> 2471 <span class="k">while</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span> 2472 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> 2473 2474 <span class="c1"># Recall the server identity</span> 2475 <span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="o">.</span><span class="n">recall</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span> 2476 2477 <span class="c1"># Inform the user that we'll begin connecting</span> 2478 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Establishing link with server..."</span><span class="p">)</span> 2479 2480 <span class="c1"># When the server identity is known, we set</span> 2481 <span class="c1"># up a destination</span> 2482 <span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 2483 <span class="n">server_identity</span><span class="p">,</span> 2484 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">OUT</span><span class="p">,</span> 2485 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 2486 <span class="n">APP_NAME</span><span class="p">,</span> 2487 <span class="s2">"bufferexample"</span> 2488 <span class="p">)</span> 2489 2490 <span class="c1"># And create a link</span> 2491 <span class="n">link</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span> 2492 2493 <span class="c1"># We'll also set up functions to inform the</span> 2494 <span class="c1"># user when the link is established or closed</span> 2495 <span class="n">link</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">link_established</span><span class="p">)</span> 2496 <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">link_closed</span><span class="p">)</span> 2497 2498 <span class="c1"># Everything is set up, so let's enter a loop</span> 2499 <span class="c1"># for the user to interact with the example</span> 2500 <span class="n">client_loop</span><span class="p">()</span> 2501 2502 <span class="k">def</span><span class="w"> </span><span class="nf">client_loop</span><span class="p">():</span> 2503 <span class="k">global</span> <span class="n">server_link</span> 2504 2505 <span class="c1"># Wait for the link to become active</span> 2506 <span class="k">while</span> <span class="ow">not</span> <span class="n">server_link</span><span class="p">:</span> 2507 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> 2508 2509 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">False</span> 2510 <span class="k">while</span> <span class="ow">not</span> <span class="n">should_quit</span><span class="p">:</span> 2511 <span class="k">try</span><span class="p">:</span> 2512 <span class="nb">print</span><span class="p">(</span><span class="s2">"> "</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">" "</span><span class="p">)</span> 2513 <span class="n">text</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 2514 2515 <span class="c1"># Check if we should quit the example</span> 2516 <span class="k">if</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"quit"</span> <span class="ow">or</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"q"</span> <span class="ow">or</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"exit"</span><span class="p">:</span> 2517 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span> 2518 <span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 2519 <span class="k">else</span><span class="p">:</span> 2520 <span class="c1"># Otherwise, encode the text and write it to the buffer.</span> 2521 <span class="n">text</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span> 2522 <span class="n">buffer</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">text</span><span class="p">)</span> 2523 <span class="c1"># Flush the buffer to force the data to be sent.</span> 2524 <span class="n">buffer</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span> 2525 2526 2527 <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> 2528 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Error while sending data over the link buffer: "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span> 2529 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span> 2530 <span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 2531 2532 <span class="c1"># This function is called when a link</span> 2533 <span class="c1"># has been established with the server</span> 2534 <span class="k">def</span><span class="w"> </span><span class="nf">link_established</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 2535 <span class="c1"># We store a reference to the link</span> 2536 <span class="c1"># instance for later use</span> 2537 <span class="k">global</span> <span class="n">server_link</span><span class="p">,</span> <span class="n">buffer</span> 2538 <span class="n">server_link</span> <span class="o">=</span> <span class="n">link</span> 2539 2540 <span class="c1"># Create buffer, see server_client_connected() for</span> 2541 <span class="c1"># more detail about setting up the buffer.</span> 2542 <span class="n">channel</span> <span class="o">=</span> <span class="n">link</span><span class="o">.</span><span class="n">get_channel</span><span class="p">()</span> 2543 <span class="n">buffer</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Buffer</span><span class="o">.</span><span class="n">create_bidirectional_buffer</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">channel</span><span class="p">,</span> <span class="n">client_buffer_ready</span><span class="p">)</span> 2544 2545 <span class="c1"># Inform the user that the server is</span> 2546 <span class="c1"># connected</span> 2547 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link established with server, enter some text to send, or </span><span class="se">\"</span><span class="s2">quit</span><span class="se">\"</span><span class="s2"> to quit"</span><span class="p">)</span> 2548 2549 <span class="c1"># When a link is closed, we'll inform the</span> 2550 <span class="c1"># user, and exit the program</span> 2551 <span class="k">def</span><span class="w"> </span><span class="nf">link_closed</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 2552 <span class="k">if</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">TIMEOUT</span><span class="p">:</span> 2553 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link timed out, exiting now"</span><span class="p">)</span> 2554 <span class="k">elif</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">DESTINATION_CLOSED</span><span class="p">:</span> 2555 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link was closed by the server, exiting now"</span><span class="p">)</span> 2556 <span class="k">else</span><span class="p">:</span> 2557 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link closed, exiting now"</span><span class="p">)</span> 2558 2559 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span> 2560 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 2561 2562 <span class="c1"># When the buffer has new data, read it and write it to the terminal.</span> 2563 <span class="k">def</span><span class="w"> </span><span class="nf">client_buffer_ready</span><span class="p">(</span><span class="n">ready_bytes</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span> 2564 <span class="k">global</span> <span class="n">buffer</span> 2565 <span class="n">data</span> <span class="o">=</span> <span class="n">buffer</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">ready_bytes</span><span class="p">)</span> 2566 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Received data over the link buffer: "</span> <span class="o">+</span> <span class="n">data</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">))</span> 2567 <span class="nb">print</span><span class="p">(</span><span class="s2">"> "</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">" "</span><span class="p">)</span> 2568 <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span> 2569 2570 2571 <span class="c1">##########################################################</span> 2572 <span class="c1">#### Program Startup #####################################</span> 2573 <span class="c1">##########################################################</span> 2574 2575 <span class="c1"># This part of the program runs at startup,</span> 2576 <span class="c1"># and parses input of from the user, and then</span> 2577 <span class="c1"># starts up the desired program mode.</span> 2578 <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span> 2579 <span class="k">try</span><span class="p">:</span> 2580 <span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"Simple buffer example"</span><span class="p">)</span> 2581 2582 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 2583 <span class="s2">"-s"</span><span class="p">,</span> 2584 <span class="s2">"--server"</span><span class="p">,</span> 2585 <span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">,</span> 2586 <span class="n">help</span><span class="o">=</span><span class="s2">"wait for incoming link requests from clients"</span> 2587 <span class="p">)</span> 2588 2589 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 2590 <span class="s2">"--config"</span><span class="p">,</span> 2591 <span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span> 2592 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 2593 <span class="n">help</span><span class="o">=</span><span class="s2">"path to alternative Reticulum config directory"</span><span class="p">,</span> 2594 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 2595 <span class="p">)</span> 2596 2597 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 2598 <span class="s2">"destination"</span><span class="p">,</span> 2599 <span class="n">nargs</span><span class="o">=</span><span class="s2">"?"</span><span class="p">,</span> 2600 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 2601 <span class="n">help</span><span class="o">=</span><span class="s2">"hexadecimal hash of the server destination"</span><span class="p">,</span> 2602 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 2603 <span class="p">)</span> 2604 2605 <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span> 2606 2607 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span><span class="p">:</span> 2608 <span class="n">configarg</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span> 2609 <span class="k">else</span><span class="p">:</span> 2610 <span class="n">configarg</span> <span class="o">=</span> <span class="kc">None</span> 2611 2612 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">server</span><span class="p">:</span> 2613 <span class="n">server</span><span class="p">(</span><span class="n">configarg</span><span class="p">)</span> 2614 <span class="k">else</span><span class="p">:</span> 2615 <span class="k">if</span> <span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span> <span class="o">==</span> <span class="kc">None</span><span class="p">):</span> 2616 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 2617 <span class="n">parser</span><span class="o">.</span><span class="n">print_help</span><span class="p">()</span> 2618 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 2619 <span class="k">else</span><span class="p">:</span> 2620 <span class="n">client</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span><span class="p">,</span> <span class="n">configarg</span><span class="p">)</span> 2621 2622 <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span> 2623 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 2624 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 2625 </pre></div> 2626 </div> 2627 <p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Buffer.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Buffer.py</a>.</p> 2628 </section> 2629 <section id="filetransfer"> 2630 <span id="example-filetransfer"></span><h2>Filetransfer<a class="headerlink" href="#filetransfer" title="Permalink to this heading">#</a></h2> 2631 <p>The <em>Filetransfer</em> example implements a basic file-server program that 2632 allow clients to connect and download files. The program uses the Resource 2633 interface to efficiently pass files of any size over a Reticulum <a class="reference internal" href="reference.html#api-link"><span class="std std-ref">Link</span></a>.</p> 2634 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span> 2635 <span class="c1"># This RNS example demonstrates a simple filetransfer #</span> 2636 <span class="c1"># server and client program. The server will serve a #</span> 2637 <span class="c1"># directory of files, and the clients can list and #</span> 2638 <span class="c1"># download files from the server. #</span> 2639 <span class="c1"># #</span> 2640 <span class="c1"># Please note that using RNS Resources for large file #</span> 2641 <span class="c1"># transfers is not recommended, since compression, #</span> 2642 <span class="c1"># encryption and hashmap sequencing can take a long time #</span> 2643 <span class="c1"># on systems with slow CPUs, which will probably result #</span> 2644 <span class="c1"># in the client timing out before the resource sender #</span> 2645 <span class="c1"># can complete preparing the resource. #</span> 2646 <span class="c1"># #</span> 2647 <span class="c1"># If you need to transfer large files, use the Bundle #</span> 2648 <span class="c1"># class instead, which will automatically slice the data #</span> 2649 <span class="c1"># into chunks suitable for packing as a Resource. #</span> 2650 <span class="c1">##########################################################</span> 2651 2652 <span class="kn">import</span><span class="w"> </span><span class="nn">os</span> 2653 <span class="kn">import</span><span class="w"> </span><span class="nn">sys</span> 2654 <span class="kn">import</span><span class="w"> </span><span class="nn">time</span> 2655 <span class="kn">import</span><span class="w"> </span><span class="nn">threading</span> 2656 <span class="kn">import</span><span class="w"> </span><span class="nn">argparse</span> 2657 <span class="kn">import</span><span class="w"> </span><span class="nn">RNS</span> 2658 <span class="kn">import</span><span class="w"> </span><span class="nn">RNS.vendor.umsgpack</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">umsgpack</span> 2659 2660 <span class="c1"># Let's define an app name. We'll use this for all</span> 2661 <span class="c1"># destinations we create. Since this echo example</span> 2662 <span class="c1"># is part of a range of example utilities, we'll put</span> 2663 <span class="c1"># them all within the app namespace "example_utilities"</span> 2664 <span class="n">APP_NAME</span> <span class="o">=</span> <span class="s2">"example_utilities"</span> 2665 2666 <span class="c1"># We'll also define a default timeout, in seconds</span> 2667 <span class="n">APP_TIMEOUT</span> <span class="o">=</span> <span class="mf">45.0</span> 2668 2669 <span class="c1">##########################################################</span> 2670 <span class="c1">#### Server Part #########################################</span> 2671 <span class="c1">##########################################################</span> 2672 2673 <span class="n">serve_path</span> <span class="o">=</span> <span class="kc">None</span> 2674 2675 <span class="c1"># This initialisation is executed when the users chooses</span> 2676 <span class="c1"># to run as a server</span> 2677 <span class="k">def</span><span class="w"> </span><span class="nf">server</span><span class="p">(</span><span class="n">configpath</span><span class="p">,</span> <span class="n">path</span><span class="p">):</span> 2678 <span class="c1"># We must first initialise Reticulum</span> 2679 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 2680 2681 <span class="c1"># Randomly create a new identity for our file server</span> 2682 <span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span> 2683 2684 <span class="k">global</span> <span class="n">serve_path</span> 2685 <span class="n">serve_path</span> <span class="o">=</span> <span class="n">path</span> 2686 2687 <span class="c1"># We create a destination that clients can connect to. We</span> 2688 <span class="c1"># want clients to create links to this destination, so we</span> 2689 <span class="c1"># need to create a "single" destination type.</span> 2690 <span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 2691 <span class="n">server_identity</span><span class="p">,</span> 2692 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> 2693 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 2694 <span class="n">APP_NAME</span><span class="p">,</span> 2695 <span class="s2">"filetransfer"</span><span class="p">,</span> 2696 <span class="s2">"server"</span> 2697 <span class="p">)</span> 2698 2699 <span class="c1"># We configure a function that will get called every time</span> 2700 <span class="c1"># a new client creates a link to this destination.</span> 2701 <span class="n">server_destination</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">client_connected</span><span class="p">)</span> 2702 2703 <span class="c1"># Everything's ready!</span> 2704 <span class="c1"># Let's Wait for client requests or user input</span> 2705 <span class="n">announceLoop</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span> 2706 2707 <span class="k">def</span><span class="w"> </span><span class="nf">announceLoop</span><span class="p">(</span><span class="n">destination</span><span class="p">):</span> 2708 <span class="c1"># Let the user know that everything is ready</span> 2709 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"File server "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span><span class="s2">" running"</span><span class="p">)</span> 2710 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Hit enter to manually send an announce (Ctrl-C to quit)"</span><span class="p">)</span> 2711 2712 <span class="c1"># We enter a loop that runs until the users exits.</span> 2713 <span class="c1"># If the user hits enter, we will announce our server</span> 2714 <span class="c1"># destination on the network, which will let clients</span> 2715 <span class="c1"># know how to create messages directed towards it.</span> 2716 <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> 2717 <span class="n">entered</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 2718 <span class="n">destination</span><span class="o">.</span><span class="n">announce</span><span class="p">()</span> 2719 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Sent announce from "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">))</span> 2720 2721 <span class="c1"># Here's a convenience function for listing all files</span> 2722 <span class="c1"># in our served directory</span> 2723 <span class="k">def</span><span class="w"> </span><span class="nf">list_files</span><span class="p">():</span> 2724 <span class="c1"># We add all entries from the directory that are</span> 2725 <span class="c1"># actual files, and does not start with "."</span> 2726 <span class="k">global</span> <span class="n">serve_path</span> 2727 <span class="k">return</span> <span class="p">[</span><span class="n">file</span> <span class="k">for</span> <span class="n">file</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">serve_path</span><span class="p">)</span> <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">serve_path</span><span class="p">,</span> <span class="n">file</span><span class="p">))</span> <span class="ow">and</span> <span class="n">file</span><span class="p">[:</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">"."</span><span class="p">]</span> 2728 2729 <span class="c1"># When a client establishes a link to our server</span> 2730 <span class="c1"># destination, this function will be called with</span> 2731 <span class="c1"># a reference to the link. We then send the client</span> 2732 <span class="c1"># a list of files hosted on the server.</span> 2733 <span class="k">def</span><span class="w"> </span><span class="nf">client_connected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 2734 <span class="c1"># Check if the served directory still exists</span> 2735 <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isdir</span><span class="p">(</span><span class="n">serve_path</span><span class="p">):</span> 2736 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client connected, sending file list..."</span><span class="p">)</span> 2737 2738 <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">client_disconnected</span><span class="p">)</span> 2739 2740 <span class="c1"># We pack a list of files for sending in a packet</span> 2741 <span class="n">data</span> <span class="o">=</span> <span class="n">umsgpack</span><span class="o">.</span><span class="n">packb</span><span class="p">(</span><span class="n">list_files</span><span class="p">())</span> 2742 2743 <span class="c1"># Check the size of the packed data</span> 2744 <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="o"><=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">MDU</span><span class="p">:</span> 2745 <span class="c1"># If it fits in one packet, we will just</span> 2746 <span class="c1"># send it as a single packet over the link.</span> 2747 <span class="n">list_packet</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Packet</span><span class="p">(</span><span class="n">link</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span> 2748 <span class="n">list_receipt</span> <span class="o">=</span> <span class="n">list_packet</span><span class="o">.</span><span class="n">send</span><span class="p">()</span> 2749 <span class="n">list_receipt</span><span class="o">.</span><span class="n">set_timeout</span><span class="p">(</span><span class="n">APP_TIMEOUT</span><span class="p">)</span> 2750 <span class="n">list_receipt</span><span class="o">.</span><span class="n">set_delivery_callback</span><span class="p">(</span><span class="n">list_delivered</span><span class="p">)</span> 2751 <span class="n">list_receipt</span><span class="o">.</span><span class="n">set_timeout_callback</span><span class="p">(</span><span class="n">list_timeout</span><span class="p">)</span> 2752 <span class="k">else</span><span class="p">:</span> 2753 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Too many files in served directory!"</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span> 2754 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"You should implement a function to split the filelist over multiple packets."</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span> 2755 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Hint: The client already supports it :)"</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span> 2756 2757 <span class="c1"># After this, we're just going to keep the link</span> 2758 <span class="c1"># open until the client requests a file. We'll</span> 2759 <span class="c1"># configure a function that get's called when</span> 2760 <span class="c1"># the client sends a packet with a file request.</span> 2761 <span class="n">link</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">client_request</span><span class="p">)</span> 2762 <span class="k">else</span><span class="p">:</span> 2763 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client connected, but served path no longer exists!"</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span> 2764 <span class="n">link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 2765 2766 <span class="k">def</span><span class="w"> </span><span class="nf">client_disconnected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 2767 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client disconnected"</span><span class="p">)</span> 2768 2769 <span class="k">def</span><span class="w"> </span><span class="nf">client_request</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">packet</span><span class="p">):</span> 2770 <span class="k">global</span> <span class="n">serve_path</span> 2771 2772 <span class="k">try</span><span class="p">:</span> 2773 <span class="n">filename</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span> 2774 <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> 2775 <span class="n">filename</span> <span class="o">=</span> <span class="kc">None</span> 2776 2777 <span class="k">if</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">list_files</span><span class="p">():</span> 2778 <span class="k">try</span><span class="p">:</span> 2779 <span class="c1"># If we have the requested file, we'll</span> 2780 <span class="c1"># read it and pack it as a resource</span> 2781 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client requested </span><span class="se">\"</span><span class="s2">"</span><span class="o">+</span><span class="n">filename</span><span class="o">+</span><span class="s2">"</span><span class="se">\"</span><span class="s2">"</span><span class="p">)</span> 2782 <span class="n">file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">serve_path</span><span class="p">,</span> <span class="n">filename</span><span class="p">),</span> <span class="s2">"rb"</span><span class="p">)</span> 2783 2784 <span class="n">file_resource</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Resource</span><span class="p">(</span> 2785 <span class="n">file</span><span class="p">,</span> 2786 <span class="n">packet</span><span class="o">.</span><span class="n">link</span><span class="p">,</span> 2787 <span class="n">callback</span><span class="o">=</span><span class="n">resource_sending_concluded</span> 2788 <span class="p">)</span> 2789 2790 <span class="n">file_resource</span><span class="o">.</span><span class="n">filename</span> <span class="o">=</span> <span class="n">filename</span> 2791 <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> 2792 <span class="c1"># If somethign went wrong, we close</span> 2793 <span class="c1"># the link</span> 2794 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Error while reading file </span><span class="se">\"</span><span class="s2">"</span><span class="o">+</span><span class="n">filename</span><span class="o">+</span><span class="s2">"</span><span class="se">\"</span><span class="s2">"</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span> 2795 <span class="n">packet</span><span class="o">.</span><span class="n">link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 2796 <span class="k">raise</span> <span class="n">e</span> 2797 <span class="k">else</span><span class="p">:</span> 2798 <span class="c1"># If we don't have it, we close the link</span> 2799 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client requested an unknown file"</span><span class="p">)</span> 2800 <span class="n">packet</span><span class="o">.</span><span class="n">link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 2801 2802 <span class="c1"># This function is called on the server when a</span> 2803 <span class="c1"># resource transfer concludes.</span> 2804 <span class="k">def</span><span class="w"> </span><span class="nf">resource_sending_concluded</span><span class="p">(</span><span class="n">resource</span><span class="p">):</span> 2805 <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">resource</span><span class="p">,</span> <span class="s2">"filename"</span><span class="p">):</span> 2806 <span class="n">name</span> <span class="o">=</span> <span class="n">resource</span><span class="o">.</span><span class="n">filename</span> 2807 <span class="k">else</span><span class="p">:</span> 2808 <span class="n">name</span> <span class="o">=</span> <span class="s2">"resource"</span> 2809 2810 <span class="k">if</span> <span class="n">resource</span><span class="o">.</span><span class="n">status</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Resource</span><span class="o">.</span><span class="n">COMPLETE</span><span class="p">:</span> 2811 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Done sending </span><span class="se">\"</span><span class="s2">"</span><span class="o">+</span><span class="n">name</span><span class="o">+</span><span class="s2">"</span><span class="se">\"</span><span class="s2"> to client"</span><span class="p">)</span> 2812 <span class="k">elif</span> <span class="n">resource</span><span class="o">.</span><span class="n">status</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Resource</span><span class="o">.</span><span class="n">FAILED</span><span class="p">:</span> 2813 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Sending </span><span class="se">\"</span><span class="s2">"</span><span class="o">+</span><span class="n">name</span><span class="o">+</span><span class="s2">"</span><span class="se">\"</span><span class="s2"> to client failed"</span><span class="p">)</span> 2814 2815 <span class="k">def</span><span class="w"> </span><span class="nf">list_delivered</span><span class="p">(</span><span class="n">receipt</span><span class="p">):</span> 2816 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The file list was received by the client"</span><span class="p">)</span> 2817 2818 <span class="k">def</span><span class="w"> </span><span class="nf">list_timeout</span><span class="p">(</span><span class="n">receipt</span><span class="p">):</span> 2819 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Sending list to client timed out, closing this link"</span><span class="p">)</span> 2820 <span class="n">link</span> <span class="o">=</span> <span class="n">receipt</span><span class="o">.</span><span class="n">destination</span> 2821 <span class="n">link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 2822 2823 <span class="c1">##########################################################</span> 2824 <span class="c1">#### Client Part #########################################</span> 2825 <span class="c1">##########################################################</span> 2826 2827 <span class="c1"># We store a global list of files available on the server</span> 2828 <span class="n">server_files</span> <span class="o">=</span> <span class="p">[]</span> 2829 2830 <span class="c1"># A reference to the server link</span> 2831 <span class="n">server_link</span> <span class="o">=</span> <span class="kc">None</span> 2832 2833 <span class="c1"># And a reference to the current download</span> 2834 <span class="n">current_download</span> <span class="o">=</span> <span class="kc">None</span> 2835 <span class="n">current_filename</span> <span class="o">=</span> <span class="kc">None</span> 2836 2837 <span class="c1"># Variables to store download statistics</span> 2838 <span class="n">download_started</span> <span class="o">=</span> <span class="mi">0</span> 2839 <span class="n">download_finished</span> <span class="o">=</span> <span class="mi">0</span> 2840 <span class="n">download_time</span> <span class="o">=</span> <span class="mi">0</span> 2841 <span class="n">transfer_size</span> <span class="o">=</span> <span class="mi">0</span> 2842 <span class="n">file_size</span> <span class="o">=</span> <span class="mi">0</span> 2843 2844 2845 <span class="c1"># This initialisation is executed when the users chooses</span> 2846 <span class="c1"># to run as a client</span> 2847 <span class="k">def</span><span class="w"> </span><span class="nf">client</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">,</span> <span class="n">configpath</span><span class="p">):</span> 2848 <span class="c1"># We need a binary representation of the destination</span> 2849 <span class="c1"># hash that was entered on the command line</span> 2850 <span class="k">try</span><span class="p">:</span> 2851 <span class="n">dest_len</span> <span class="o">=</span> <span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">TRUNCATED_HASHLENGTH</span><span class="o">//</span><span class="mi">8</span><span class="p">)</span><span class="o">*</span><span class="mi">2</span> 2852 <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> <span class="o">!=</span> <span class="n">dest_len</span><span class="p">:</span> 2853 <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span> 2854 <span class="s2">"Destination length is invalid, must be </span><span class="si">{hex}</span><span class="s2"> hexadecimal characters (</span><span class="si">{byte}</span><span class="s2"> bytes)."</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">hex</span><span class="o">=</span><span class="n">dest_len</span><span class="p">,</span> <span class="n">byte</span><span class="o">=</span><span class="n">dest_len</span><span class="o">//</span><span class="mi">2</span><span class="p">)</span> 2855 <span class="p">)</span> 2856 2857 <span class="n">destination_hash</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> 2858 <span class="k">except</span><span class="p">:</span> 2859 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span> 2860 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 2861 2862 <span class="c1"># We must first initialise Reticulum</span> 2863 <span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span> 2864 2865 2866 <span class="c1"># Check if we know a path to the destination</span> 2867 <span class="k">if</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span> 2868 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Destination is not yet known. Requesting path and waiting for announce to arrive..."</span><span class="p">)</span> 2869 <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">request_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span> 2870 <span class="k">while</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span> 2871 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> 2872 2873 <span class="c1"># Recall the server identity</span> 2874 <span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="o">.</span><span class="n">recall</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span> 2875 2876 <span class="c1"># Inform the user that we'll begin connecting</span> 2877 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Establishing link with server..."</span><span class="p">)</span> 2878 2879 <span class="c1"># When the server identity is known, we set</span> 2880 <span class="c1"># up a destination</span> 2881 <span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span> 2882 <span class="n">server_identity</span><span class="p">,</span> 2883 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">OUT</span><span class="p">,</span> 2884 <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span> 2885 <span class="n">APP_NAME</span><span class="p">,</span> 2886 <span class="s2">"filetransfer"</span><span class="p">,</span> 2887 <span class="s2">"server"</span> 2888 <span class="p">)</span> 2889 2890 <span class="c1"># We also want to automatically prove incoming packets</span> 2891 <span class="n">server_destination</span><span class="o">.</span><span class="n">set_proof_strategy</span><span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">PROVE_ALL</span><span class="p">)</span> 2892 2893 <span class="c1"># And create a link</span> 2894 <span class="n">link</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span> 2895 2896 <span class="c1"># We expect any normal data packets on the link</span> 2897 <span class="c1"># to contain a list of served files, so we set</span> 2898 <span class="c1"># a callback accordingly</span> 2899 <span class="n">link</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">filelist_received</span><span class="p">)</span> 2900 2901 <span class="c1"># We'll also set up functions to inform the</span> 2902 <span class="c1"># user when the link is established or closed</span> 2903 <span class="n">link</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">link_established</span><span class="p">)</span> 2904 <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">link_closed</span><span class="p">)</span> 2905 2906 <span class="c1"># And set the link to automatically begin</span> 2907 <span class="c1"># downloading advertised resources</span> 2908 <span class="n">link</span><span class="o">.</span><span class="n">set_resource_strategy</span><span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">ACCEPT_ALL</span><span class="p">)</span> 2909 <span class="n">link</span><span class="o">.</span><span class="n">set_resource_started_callback</span><span class="p">(</span><span class="n">download_began</span><span class="p">)</span> 2910 <span class="n">link</span><span class="o">.</span><span class="n">set_resource_concluded_callback</span><span class="p">(</span><span class="n">download_concluded</span><span class="p">)</span> 2911 2912 <span class="n">menu</span><span class="p">()</span> 2913 2914 <span class="c1"># Requests the specified file from the server</span> 2915 <span class="k">def</span><span class="w"> </span><span class="nf">download</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span> 2916 <span class="k">global</span> <span class="n">server_link</span><span class="p">,</span> <span class="n">menu_mode</span><span class="p">,</span> <span class="n">current_filename</span><span class="p">,</span> <span class="n">transfer_size</span><span class="p">,</span> <span class="n">download_started</span> 2917 <span class="n">current_filename</span> <span class="o">=</span> <span class="n">filename</span> 2918 <span class="n">download_started</span> <span class="o">=</span> <span class="mi">0</span> 2919 <span class="n">transfer_size</span> <span class="o">=</span> <span class="mi">0</span> 2920 2921 <span class="c1"># We just create a packet containing the</span> 2922 <span class="c1"># requested filename, and send it down the</span> 2923 <span class="c1"># link. We also specify we don't need a</span> 2924 <span class="c1"># packet receipt.</span> 2925 <span class="n">request_packet</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Packet</span><span class="p">(</span><span class="n">server_link</span><span class="p">,</span> <span class="n">filename</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">),</span> <span class="n">create_receipt</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> 2926 <span class="n">request_packet</span><span class="o">.</span><span class="n">send</span><span class="p">()</span> 2927 2928 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 2929 <span class="nb">print</span><span class="p">((</span><span class="s2">"Requested </span><span class="se">\"</span><span class="s2">"</span><span class="o">+</span><span class="n">filename</span><span class="o">+</span><span class="s2">"</span><span class="se">\"</span><span class="s2"> from server, waiting for download to begin..."</span><span class="p">))</span> 2930 <span class="n">menu_mode</span> <span class="o">=</span> <span class="s2">"download_started"</span> 2931 2932 <span class="c1"># This function runs a simple menu for the user</span> 2933 <span class="c1"># to select which files to download, or quit</span> 2934 <span class="n">menu_mode</span> <span class="o">=</span> <span class="kc">None</span> 2935 <span class="k">def</span><span class="w"> </span><span class="nf">menu</span><span class="p">():</span> 2936 <span class="k">global</span> <span class="n">server_files</span><span class="p">,</span> <span class="n">server_link</span> 2937 <span class="c1"># Wait until we have a filelist</span> 2938 <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">server_files</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> 2939 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> 2940 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Ready!"</span><span class="p">)</span> 2941 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span> 2942 2943 <span class="k">global</span> <span class="n">menu_mode</span> 2944 <span class="n">menu_mode</span> <span class="o">=</span> <span class="s2">"main"</span> 2945 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">False</span> 2946 <span class="k">while</span> <span class="p">(</span><span class="ow">not</span> <span class="n">should_quit</span><span class="p">):</span> 2947 <span class="n">print_menu</span><span class="p">()</span> 2948 2949 <span class="k">while</span> <span class="ow">not</span> <span class="n">menu_mode</span> <span class="o">==</span> <span class="s2">"main"</span><span class="p">:</span> 2950 <span class="c1"># Wait</span> 2951 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.25</span><span class="p">)</span> 2952 2953 <span class="n">user_input</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span> 2954 <span class="k">if</span> <span class="n">user_input</span> <span class="o">==</span> <span class="s2">"q"</span> <span class="ow">or</span> <span class="n">user_input</span> <span class="o">==</span> <span class="s2">"quit"</span> <span class="ow">or</span> <span class="n">user_input</span> <span class="o">==</span> <span class="s2">"exit"</span><span class="p">:</span> 2955 <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span> 2956 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 2957 <span class="k">else</span><span class="p">:</span> 2958 <span class="k">if</span> <span class="n">user_input</span> <span class="ow">in</span> <span class="n">server_files</span><span class="p">:</span> 2959 <span class="n">download</span><span class="p">(</span><span class="n">user_input</span><span class="p">)</span> 2960 <span class="k">else</span><span class="p">:</span> 2961 <span class="k">try</span><span class="p">:</span> 2962 <span class="k">if</span> <span class="mi">0</span> <span class="o"><=</span> <span class="nb">int</span><span class="p">(</span><span class="n">user_input</span><span class="p">)</span> <span class="o"><</span> <span class="nb">len</span><span class="p">(</span><span class="n">server_files</span><span class="p">):</span> 2963 <span class="n">download</span><span class="p">(</span><span class="n">server_files</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">user_input</span><span class="p">)])</span> 2964 <span class="k">except</span><span class="p">:</span> 2965 <span class="k">pass</span> 2966 2967 <span class="k">if</span> <span class="n">should_quit</span><span class="p">:</span> 2968 <span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 2969 2970 <span class="c1"># Prints out menus or screens for the</span> 2971 <span class="c1"># various states of the client program.</span> 2972 <span class="c1"># It's simple and quite uninteresting.</span> 2973 <span class="c1"># I won't go into detail here. Just</span> 2974 <span class="c1"># strings basically.</span> 2975 <span class="k">def</span><span class="w"> </span><span class="nf">print_menu</span><span class="p">():</span> 2976 <span class="k">global</span> <span class="n">menu_mode</span><span class="p">,</span> <span class="n">download_time</span><span class="p">,</span> <span class="n">download_started</span><span class="p">,</span> <span class="n">download_finished</span><span class="p">,</span> <span class="n">transfer_size</span><span class="p">,</span> <span class="n">file_size</span> 2977 2978 <span class="k">if</span> <span class="n">menu_mode</span> <span class="o">==</span> <span class="s2">"main"</span><span class="p">:</span> 2979 <span class="n">clear_screen</span><span class="p">()</span> 2980 <span class="n">print_filelist</span><span class="p">()</span> 2981 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 2982 <span class="nb">print</span><span class="p">(</span><span class="s2">"Select a file to download by entering name or number, or q to quit"</span><span class="p">)</span> 2983 <span class="nb">print</span><span class="p">((</span><span class="s2">"> "</span><span class="p">),</span> <span class="n">end</span><span class="o">=</span><span class="s1">' '</span><span class="p">)</span> 2984 <span class="k">elif</span> <span class="n">menu_mode</span> <span class="o">==</span> <span class="s2">"download_started"</span><span class="p">:</span> 2985 <span class="n">download_began</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> 2986 <span class="k">while</span> <span class="n">menu_mode</span> <span class="o">==</span> <span class="s2">"download_started"</span><span class="p">:</span> 2987 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> 2988 <span class="k">if</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">></span> <span class="n">download_began</span><span class="o">+</span><span class="n">APP_TIMEOUT</span><span class="p">:</span> 2989 <span class="nb">print</span><span class="p">(</span><span class="s2">"The download timed out"</span><span class="p">)</span> 2990 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> 2991 <span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 2992 2993 <span class="k">if</span> <span class="n">menu_mode</span> <span class="o">==</span> <span class="s2">"downloading"</span><span class="p">:</span> 2994 <span class="nb">print</span><span class="p">(</span><span class="s2">"Download started"</span><span class="p">)</span> 2995 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 2996 <span class="k">while</span> <span class="n">menu_mode</span> <span class="o">==</span> <span class="s2">"downloading"</span><span class="p">:</span> 2997 <span class="k">global</span> <span class="n">current_download</span> 2998 <span class="n">percent</span> <span class="o">=</span> <span class="nb">round</span><span class="p">(</span><span class="n">current_download</span><span class="o">.</span><span class="n">get_progress</span><span class="p">()</span> <span class="o">*</span> <span class="mf">100.0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> 2999 <span class="nb">print</span><span class="p">((</span><span class="s2">"</span><span class="se">\r</span><span class="s2">Progress: "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">percent</span><span class="p">)</span><span class="o">+</span><span class="s2">" % "</span><span class="p">),</span> <span class="n">end</span><span class="o">=</span><span class="s1">' '</span><span class="p">)</span> 3000 <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span> 3001 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> 3002 3003 <span class="k">if</span> <span class="n">menu_mode</span> <span class="o">==</span> <span class="s2">"save_error"</span><span class="p">:</span> 3004 <span class="nb">print</span><span class="p">((</span><span class="s2">"</span><span class="se">\r</span><span class="s2">Progress: 100.0 %"</span><span class="p">),</span> <span class="n">end</span><span class="o">=</span><span class="s1">' '</span><span class="p">)</span> 3005 <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span> 3006 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 3007 <span class="nb">print</span><span class="p">(</span><span class="s2">"Could not write downloaded file to disk"</span><span class="p">)</span> 3008 <span class="n">current_download</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Resource</span><span class="o">.</span><span class="n">FAILED</span> 3009 <span class="n">menu_mode</span> <span class="o">=</span> <span class="s2">"download_concluded"</span> 3010 3011 <span class="k">if</span> <span class="n">menu_mode</span> <span class="o">==</span> <span class="s2">"download_concluded"</span><span class="p">:</span> 3012 <span class="k">if</span> <span class="n">current_download</span><span class="o">.</span><span class="n">status</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Resource</span><span class="o">.</span><span class="n">COMPLETE</span><span class="p">:</span> 3013 <span class="nb">print</span><span class="p">((</span><span class="s2">"</span><span class="se">\r</span><span class="s2">Progress: 100.0 %"</span><span class="p">),</span> <span class="n">end</span><span class="o">=</span><span class="s1">' '</span><span class="p">)</span> 3014 <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span> 3015 3016 <span class="c1"># Print statistics</span> 3017 <span class="n">hours</span><span class="p">,</span> <span class="n">rem</span> <span class="o">=</span> <span class="nb">divmod</span><span class="p">(</span><span class="n">download_time</span><span class="p">,</span> <span class="mi">3600</span><span class="p">)</span> 3018 <span class="n">minutes</span><span class="p">,</span> <span class="n">seconds</span> <span class="o">=</span> <span class="nb">divmod</span><span class="p">(</span><span class="n">rem</span><span class="p">,</span> <span class="mi">60</span><span class="p">)</span> 3019 <span class="n">timestring</span> <span class="o">=</span> <span class="s2">"</span><span class="si">{:0>2}</span><span class="s2">:</span><span class="si">{:0>2}</span><span class="s2">:</span><span class="si">{:05.2f}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">hours</span><span class="p">),</span><span class="nb">int</span><span class="p">(</span><span class="n">minutes</span><span class="p">),</span><span class="n">seconds</span><span class="p">)</span> 3020 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 3021 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 3022 <span class="nb">print</span><span class="p">(</span><span class="s2">"--- Statistics -----"</span><span class="p">)</span> 3023 <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\t</span><span class="s2">Time taken : "</span><span class="o">+</span><span class="n">timestring</span><span class="p">)</span> 3024 <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\t</span><span class="s2">File size : "</span><span class="o">+</span><span class="n">size_str</span><span class="p">(</span><span class="n">file_size</span><span class="p">))</span> 3025 <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\t</span><span class="s2">Data transferred : "</span><span class="o">+</span><span class="n">size_str</span><span class="p">(</span><span class="n">transfer_size</span><span class="p">))</span> 3026 <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\t</span><span class="s2">Effective rate : "</span><span class="o">+</span><span class="n">size_str</span><span class="p">(</span><span class="n">file_size</span><span class="o">/</span><span class="n">download_time</span><span class="p">,</span> <span class="n">suffix</span><span class="o">=</span><span class="s1">'b'</span><span class="p">)</span><span class="o">+</span><span class="s2">"/s"</span><span class="p">)</span> 3027 <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\t</span><span class="s2">Transfer rate : "</span><span class="o">+</span><span class="n">size_str</span><span class="p">(</span><span class="n">transfer_size</span><span class="o">/</span><span class="n">download_time</span><span class="p">,</span> <span class="n">suffix</span><span class="o">=</span><span class="s1">'b'</span><span class="p">)</span><span class="o">+</span><span class="s2">"/s"</span><span class="p">)</span> 3028 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 3029 <span class="nb">print</span><span class="p">(</span><span class="s2">"The download completed! Press enter to return to the menu."</span><span class="p">)</span> 3030 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 3031 <span class="nb">input</span><span class="p">()</span> 3032 3033 <span class="k">else</span><span class="p">:</span> 3034 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 3035 <span class="nb">print</span><span class="p">(</span><span class="s2">"The download failed! Press enter to return to the menu."</span><span class="p">)</span> 3036 <span class="nb">input</span><span class="p">()</span> 3037 3038 <span class="n">current_download</span> <span class="o">=</span> <span class="kc">None</span> 3039 <span class="n">menu_mode</span> <span class="o">=</span> <span class="s2">"main"</span> 3040 <span class="n">print_menu</span><span class="p">()</span> 3041 3042 <span class="c1"># This function prints out a list of files</span> 3043 <span class="c1"># on the connected server.</span> 3044 <span class="k">def</span><span class="w"> </span><span class="nf">print_filelist</span><span class="p">():</span> 3045 <span class="k">global</span> <span class="n">server_files</span> 3046 <span class="nb">print</span><span class="p">(</span><span class="s2">"Files on server:"</span><span class="p">)</span> 3047 <span class="k">for</span> <span class="n">index</span><span class="p">,</span><span class="n">file</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">server_files</span><span class="p">):</span> 3048 <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\t</span><span class="s2">("</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">index</span><span class="p">)</span><span class="o">+</span><span class="s2">")</span><span class="se">\t</span><span class="s2">"</span><span class="o">+</span><span class="n">file</span><span class="p">)</span> 3049 3050 <span class="k">def</span><span class="w"> </span><span class="nf">filelist_received</span><span class="p">(</span><span class="n">filelist_data</span><span class="p">,</span> <span class="n">packet</span><span class="p">):</span> 3051 <span class="k">global</span> <span class="n">server_files</span><span class="p">,</span> <span class="n">menu_mode</span> 3052 <span class="k">try</span><span class="p">:</span> 3053 <span class="c1"># Unpack the list and extend our</span> 3054 <span class="c1"># local list of available files</span> 3055 <span class="n">filelist</span> <span class="o">=</span> <span class="n">umsgpack</span><span class="o">.</span><span class="n">unpackb</span><span class="p">(</span><span class="n">filelist_data</span><span class="p">)</span> 3056 <span class="k">for</span> <span class="n">file</span> <span class="ow">in</span> <span class="n">filelist</span><span class="p">:</span> 3057 <span class="k">if</span> <span class="ow">not</span> <span class="n">file</span> <span class="ow">in</span> <span class="n">server_files</span><span class="p">:</span> 3058 <span class="n">server_files</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">file</span><span class="p">)</span> 3059 3060 <span class="c1"># If the menu is already visible,</span> 3061 <span class="c1"># we'll update it with what was</span> 3062 <span class="c1"># just received</span> 3063 <span class="k">if</span> <span class="n">menu_mode</span> <span class="o">==</span> <span class="s2">"main"</span><span class="p">:</span> 3064 <span class="n">print_menu</span><span class="p">()</span> 3065 <span class="k">except</span><span class="p">:</span> 3066 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid file list data received, closing link"</span><span class="p">)</span> 3067 <span class="n">packet</span><span class="o">.</span><span class="n">link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> 3068 3069 <span class="c1"># This function is called when a link</span> 3070 <span class="c1"># has been established with the server</span> 3071 <span class="k">def</span><span class="w"> </span><span class="nf">link_established</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 3072 <span class="c1"># We store a reference to the link</span> 3073 <span class="c1"># instance for later use</span> 3074 <span class="k">global</span> <span class="n">server_link</span> 3075 <span class="n">server_link</span> <span class="o">=</span> <span class="n">link</span> 3076 3077 <span class="c1"># Inform the user that the server is</span> 3078 <span class="c1"># connected</span> 3079 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link established with server"</span><span class="p">)</span> 3080 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Waiting for filelist..."</span><span class="p">)</span> 3081 3082 <span class="c1"># And set up a small job to check for</span> 3083 <span class="c1"># a potential timeout in receiving the</span> 3084 <span class="c1"># file list</span> 3085 <span class="n">thread</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">filelist_timeout_job</span><span class="p">,</span> <span class="n">daemon</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> 3086 <span class="n">thread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> 3087 3088 <span class="c1"># This job just sleeps for the specified</span> 3089 <span class="c1"># time, and then checks if the file list</span> 3090 <span class="c1"># was received. If not, the program will</span> 3091 <span class="c1"># exit.</span> 3092 <span class="k">def</span><span class="w"> </span><span class="nf">filelist_timeout_job</span><span class="p">():</span> 3093 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">APP_TIMEOUT</span><span class="p">)</span> 3094 3095 <span class="k">global</span> <span class="n">server_files</span> 3096 <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">server_files</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> 3097 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Timed out waiting for filelist, exiting"</span><span class="p">)</span> 3098 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 3099 3100 3101 <span class="c1"># When a link is closed, we'll inform the</span> 3102 <span class="c1"># user, and exit the program</span> 3103 <span class="k">def</span><span class="w"> </span><span class="nf">link_closed</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> 3104 <span class="k">if</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">TIMEOUT</span><span class="p">:</span> 3105 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link timed out, exiting now"</span><span class="p">)</span> 3106 <span class="k">elif</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">DESTINATION_CLOSED</span><span class="p">:</span> 3107 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link was closed by the server, exiting now"</span><span class="p">)</span> 3108 <span class="k">else</span><span class="p">:</span> 3109 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link closed, exiting now"</span><span class="p">)</span> 3110 3111 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span> 3112 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 3113 3114 <span class="c1"># When RNS detects that the download has</span> 3115 <span class="c1"># started, we'll update our menu state</span> 3116 <span class="c1"># so the user can be shown a progress of</span> 3117 <span class="c1"># the download.</span> 3118 <span class="k">def</span><span class="w"> </span><span class="nf">download_began</span><span class="p">(</span><span class="n">resource</span><span class="p">):</span> 3119 <span class="k">global</span> <span class="n">menu_mode</span><span class="p">,</span> <span class="n">current_download</span><span class="p">,</span> <span class="n">download_started</span><span class="p">,</span> <span class="n">transfer_size</span><span class="p">,</span> <span class="n">file_size</span> 3120 <span class="n">current_download</span> <span class="o">=</span> <span class="n">resource</span> 3121 3122 <span class="k">if</span> <span class="n">download_started</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> 3123 <span class="n">download_started</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> 3124 3125 <span class="n">transfer_size</span> <span class="o">+=</span> <span class="n">resource</span><span class="o">.</span><span class="n">size</span> 3126 <span class="n">file_size</span> <span class="o">=</span> <span class="n">resource</span><span class="o">.</span><span class="n">total_size</span> 3127 3128 <span class="n">menu_mode</span> <span class="o">=</span> <span class="s2">"downloading"</span> 3129 3130 <span class="c1"># When the download concludes, successfully</span> 3131 <span class="c1"># or not, we'll update our menu state and </span> 3132 <span class="c1"># inform the user about how it all went.</span> 3133 <span class="k">def</span><span class="w"> </span><span class="nf">download_concluded</span><span class="p">(</span><span class="n">resource</span><span class="p">):</span> 3134 <span class="k">global</span> <span class="n">menu_mode</span><span class="p">,</span> <span class="n">current_filename</span><span class="p">,</span> <span class="n">download_started</span><span class="p">,</span> <span class="n">download_finished</span><span class="p">,</span> <span class="n">download_time</span> 3135 <span class="n">download_finished</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> 3136 <span class="n">download_time</span> <span class="o">=</span> <span class="n">download_finished</span> <span class="o">-</span> <span class="n">download_started</span> 3137 3138 <span class="n">saved_filename</span> <span class="o">=</span> <span class="n">current_filename</span> 3139 3140 <span class="k">if</span> <span class="n">resource</span><span class="o">.</span><span class="n">status</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Resource</span><span class="o">.</span><span class="n">COMPLETE</span><span class="p">:</span> 3141 <span class="n">counter</span> <span class="o">=</span> <span class="mi">0</span> 3142 <span class="k">while</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">saved_filename</span><span class="p">):</span> 3143 <span class="n">counter</span> <span class="o">+=</span> <span class="mi">1</span> 3144 <span class="n">saved_filename</span> <span class="o">=</span> <span class="n">current_filename</span><span class="o">+</span><span class="s2">"."</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">counter</span><span class="p">)</span> 3145 3146 <span class="k">try</span><span class="p">:</span> 3147 <span class="n">file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">saved_filename</span><span class="p">,</span> <span class="s2">"wb"</span><span class="p">)</span> 3148 <span class="n">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">resource</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">read</span><span class="p">())</span> 3149 <span class="n">file</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> 3150 <span class="n">menu_mode</span> <span class="o">=</span> <span class="s2">"download_concluded"</span> 3151 <span class="k">except</span><span class="p">:</span> 3152 <span class="n">menu_mode</span> <span class="o">=</span> <span class="s2">"save_error"</span> 3153 <span class="k">else</span><span class="p">:</span> 3154 <span class="n">menu_mode</span> <span class="o">=</span> <span class="s2">"download_concluded"</span> 3155 3156 <span class="c1"># A convenience function for printing a human-</span> 3157 <span class="c1"># readable file size</span> 3158 <span class="k">def</span><span class="w"> </span><span class="nf">size_str</span><span class="p">(</span><span class="n">num</span><span class="p">,</span> <span class="n">suffix</span><span class="o">=</span><span class="s1">'B'</span><span class="p">):</span> 3159 <span class="n">units</span> <span class="o">=</span> <span class="p">[</span><span class="s1">''</span><span class="p">,</span><span class="s1">'Ki'</span><span class="p">,</span><span class="s1">'Mi'</span><span class="p">,</span><span class="s1">'Gi'</span><span class="p">,</span><span class="s1">'Ti'</span><span class="p">,</span><span class="s1">'Pi'</span><span class="p">,</span><span class="s1">'Ei'</span><span class="p">,</span><span class="s1">'Zi'</span><span class="p">]</span> 3160 <span class="n">last_unit</span> <span class="o">=</span> <span class="s1">'Yi'</span> 3161 3162 <span class="k">if</span> <span class="n">suffix</span> <span class="o">==</span> <span class="s1">'b'</span><span class="p">:</span> 3163 <span class="n">num</span> <span class="o">*=</span> <span class="mi">8</span> 3164 <span class="n">units</span> <span class="o">=</span> <span class="p">[</span><span class="s1">''</span><span class="p">,</span><span class="s1">'K'</span><span class="p">,</span><span class="s1">'M'</span><span class="p">,</span><span class="s1">'G'</span><span class="p">,</span><span class="s1">'T'</span><span class="p">,</span><span class="s1">'P'</span><span class="p">,</span><span class="s1">'E'</span><span class="p">,</span><span class="s1">'Z'</span><span class="p">]</span> 3165 <span class="n">last_unit</span> <span class="o">=</span> <span class="s1">'Y'</span> 3166 3167 <span class="k">for</span> <span class="n">unit</span> <span class="ow">in</span> <span class="n">units</span><span class="p">:</span> 3168 <span class="k">if</span> <span class="nb">abs</span><span class="p">(</span><span class="n">num</span><span class="p">)</span> <span class="o"><</span> <span class="mf">1024.0</span><span class="p">:</span> 3169 <span class="k">return</span> <span class="s2">"</span><span class="si">%3.2f</span><span class="s2"> </span><span class="si">%s%s</span><span class="s2">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">num</span><span class="p">,</span> <span class="n">unit</span><span class="p">,</span> <span class="n">suffix</span><span class="p">)</span> 3170 <span class="n">num</span> <span class="o">/=</span> <span class="mf">1024.0</span> 3171 <span class="k">return</span> <span class="s2">"</span><span class="si">%.2f</span><span class="s2"> </span><span class="si">%s%s</span><span class="s2">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">num</span><span class="p">,</span> <span class="n">last_unit</span><span class="p">,</span> <span class="n">suffix</span><span class="p">)</span> 3172 3173 <span class="c1"># A convenience function for clearing the screen</span> 3174 <span class="k">def</span><span class="w"> </span><span class="nf">clear_screen</span><span class="p">():</span> 3175 <span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="s1">'cls'</span> <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">name</span><span class="o">==</span><span class="s1">'nt'</span> <span class="k">else</span> <span class="s1">'clear'</span><span class="p">)</span> 3176 3177 <span class="c1">##########################################################</span> 3178 <span class="c1">#### Program Startup #####################################</span> 3179 <span class="c1">##########################################################</span> 3180 3181 <span class="c1"># This part of the program runs at startup,</span> 3182 <span class="c1"># and parses input of from the user, and then</span> 3183 <span class="c1"># starts up the desired program mode.</span> 3184 <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span> 3185 <span class="k">try</span><span class="p">:</span> 3186 <span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span> 3187 <span class="n">description</span><span class="o">=</span><span class="s2">"Simple file transfer server and client utility"</span> 3188 <span class="p">)</span> 3189 3190 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 3191 <span class="s2">"-s"</span><span class="p">,</span> 3192 <span class="s2">"--serve"</span><span class="p">,</span> 3193 <span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span> 3194 <span class="n">metavar</span><span class="o">=</span><span class="s2">"dir"</span><span class="p">,</span> 3195 <span class="n">help</span><span class="o">=</span><span class="s2">"serve a directory of files to clients"</span> 3196 <span class="p">)</span> 3197 3198 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 3199 <span class="s2">"--config"</span><span class="p">,</span> 3200 <span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span> 3201 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 3202 <span class="n">help</span><span class="o">=</span><span class="s2">"path to alternative Reticulum config directory"</span><span class="p">,</span> 3203 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 3204 <span class="p">)</span> 3205 3206 <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span> 3207 <span class="s2">"destination"</span><span class="p">,</span> 3208 <span class="n">nargs</span><span class="o">=</span><span class="s2">"?"</span><span class="p">,</span> 3209 <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> 3210 <span class="n">help</span><span class="o">=</span><span class="s2">"hexadecimal hash of the server destination"</span><span class="p">,</span> 3211 <span class="nb">type</span><span class="o">=</span><span class="nb">str</span> 3212 <span class="p">)</span> 3213 3214 <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span> 3215 3216 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span><span class="p">:</span> 3217 <span class="n">configarg</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span> 3218 <span class="k">else</span><span class="p">:</span> 3219 <span class="n">configarg</span> <span class="o">=</span> <span class="kc">None</span> 3220 3221 <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">serve</span><span class="p">:</span> 3222 <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isdir</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">serve</span><span class="p">):</span> 3223 <span class="n">server</span><span class="p">(</span><span class="n">configarg</span><span class="p">,</span> <span class="n">args</span><span class="o">.</span><span class="n">serve</span><span class="p">)</span> 3224 <span class="k">else</span><span class="p">:</span> 3225 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The specified directory does not exist"</span><span class="p">)</span> 3226 <span class="k">else</span><span class="p">:</span> 3227 <span class="k">if</span> <span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span> <span class="o">==</span> <span class="kc">None</span><span class="p">):</span> 3228 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 3229 <span class="n">parser</span><span class="o">.</span><span class="n">print_help</span><span class="p">()</span> 3230 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 3231 <span class="k">else</span><span class="p">:</span> 3232 <span class="n">client</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span><span class="p">,</span> <span class="n">configarg</span><span class="p">)</span> 3233 3234 <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span> 3235 <span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span> 3236 <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 3237 </pre></div> 3238 </div> 3239 <p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Filetransfer.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Filetransfer.py</a>.</p> 3240 </section> 3241 <section id="custom-interfaces"> 3242 <span id="example-custominterface"></span><h2>Custom Interfaces<a class="headerlink" href="#custom-interfaces" title="Permalink to this heading">#</a></h2> 3243 <p>The <em>ExampleInterface</em> demonstrates creating custom interfaces for Reticulum. 3244 Any number of custom interfaces can be loaded and utilised by Reticulum, and 3245 will be fully on-par with natively included interfaces, including all supported 3246 <a class="reference internal" href="interfaces.html#interfaces-modes"><span class="std std-ref">interface modes</span></a> and <a class="reference internal" href="interfaces.html#interfaces-options"><span class="std std-ref">common configuration options</span></a>.</p> 3247 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># This example illustrates creating a custom interface</span> 3248 <span class="c1"># definition, that can be loaded and used by Reticulum at</span> 3249 <span class="c1"># runtime. Any number of custom interfaces can be created</span> 3250 <span class="c1"># and loaded. To use the interface place it in the folder</span> 3251 <span class="c1"># ~/.reticulum/interfaces, and add an interface entry to</span> 3252 <span class="c1"># your Reticulum configuration file similar to this:</span> 3253 3254 <span class="c1"># [[Example Custom Interface]]</span> 3255 <span class="c1"># type = ExampleInterface</span> 3256 <span class="c1"># enabled = no</span> 3257 <span class="c1"># mode = gateway</span> 3258 <span class="c1"># port = /dev/ttyUSB0</span> 3259 <span class="c1"># speed = 115200</span> 3260 <span class="c1"># databits = 8</span> 3261 <span class="c1"># parity = none</span> 3262 <span class="c1"># stopbits = 1</span> 3263 3264 <span class="kn">from</span><span class="w"> </span><span class="nn">time</span><span class="w"> </span><span class="kn">import</span> <span class="n">sleep</span> 3265 <span class="kn">import</span><span class="w"> </span><span class="nn">sys</span> 3266 <span class="kn">import</span><span class="w"> </span><span class="nn">threading</span> 3267 <span class="kn">import</span><span class="w"> </span><span class="nn">time</span> 3268 3269 <span class="c1"># This HDLC helper class is used by the interface</span> 3270 <span class="c1"># to delimit and packetize data over the physical</span> 3271 <span class="c1"># medium - in this case a serial connection.</span> 3272 <span class="k">class</span><span class="w"> </span><span class="nc">HDLC</span><span class="p">():</span> 3273 <span class="c1"># This example interface packetizes data using</span> 3274 <span class="c1"># simplified HDLC framing, similar to PPP</span> 3275 <span class="n">FLAG</span> <span class="o">=</span> <span class="mh">0x7E</span> 3276 <span class="n">ESC</span> <span class="o">=</span> <span class="mh">0x7D</span> 3277 <span class="n">ESC_MASK</span> <span class="o">=</span> <span class="mh">0x20</span> 3278 3279 <span class="nd">@staticmethod</span> 3280 <span class="k">def</span><span class="w"> </span><span class="nf">escape</span><span class="p">(</span><span class="n">data</span><span class="p">):</span> 3281 <span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="nb">bytes</span><span class="p">([</span><span class="n">HDLC</span><span class="o">.</span><span class="n">ESC</span><span class="p">]),</span> <span class="nb">bytes</span><span class="p">([</span><span class="n">HDLC</span><span class="o">.</span><span class="n">ESC</span><span class="p">,</span> <span class="n">HDLC</span><span class="o">.</span><span class="n">ESC</span><span class="o">^</span><span class="n">HDLC</span><span class="o">.</span><span class="n">ESC_MASK</span><span class="p">]))</span> 3282 <span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="nb">bytes</span><span class="p">([</span><span class="n">HDLC</span><span class="o">.</span><span class="n">FLAG</span><span class="p">]),</span> <span class="nb">bytes</span><span class="p">([</span><span class="n">HDLC</span><span class="o">.</span><span class="n">ESC</span><span class="p">,</span> <span class="n">HDLC</span><span class="o">.</span><span class="n">FLAG</span><span class="o">^</span><span class="n">HDLC</span><span class="o">.</span><span class="n">ESC_MASK</span><span class="p">]))</span> 3283 <span class="k">return</span> <span class="n">data</span> 3284 3285 <span class="c1"># Let's define our custom interface class. It must</span> 3286 <span class="c1"># be a sub-class of the RNS "Interface" class.</span> 3287 <span class="k">class</span><span class="w"> </span><span class="nc">ExampleInterface</span><span class="p">(</span><span class="n">Interface</span><span class="p">):</span> 3288 <span class="c1"># All interface classes must define a default</span> 3289 <span class="c1"># IFAC size, used in IFAC setup when the user</span> 3290 <span class="c1"># has not specified a custom IFAC size. This</span> 3291 <span class="c1"># option is specified in bytes.</span> 3292 <span class="n">DEFAULT_IFAC_SIZE</span> <span class="o">=</span> <span class="mi">8</span> 3293 3294 <span class="c1"># The following properties are local to this</span> 3295 <span class="c1"># particular interface implementation.</span> 3296 <span class="n">owner</span> <span class="o">=</span> <span class="kc">None</span> 3297 <span class="n">port</span> <span class="o">=</span> <span class="kc">None</span> 3298 <span class="n">speed</span> <span class="o">=</span> <span class="kc">None</span> 3299 <span class="n">databits</span> <span class="o">=</span> <span class="kc">None</span> 3300 <span class="n">parity</span> <span class="o">=</span> <span class="kc">None</span> 3301 <span class="n">stopbits</span> <span class="o">=</span> <span class="kc">None</span> 3302 <span class="n">serial</span> <span class="o">=</span> <span class="kc">None</span> 3303 3304 <span class="c1"># All Reticulum interfaces must have an __init__</span> 3305 <span class="c1"># method that takes 2 positional arguments:</span> 3306 <span class="c1"># The owner RNS Transport instance, and a dict</span> 3307 <span class="c1"># of configuration values.</span> 3308 <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">owner</span><span class="p">,</span> <span class="n">configuration</span><span class="p">):</span> 3309 3310 <span class="c1"># The following lines demonstrate handling</span> 3311 <span class="c1"># potential dependencies required for the</span> 3312 <span class="c1"># interface to function correctly.</span> 3313 <span class="kn">import</span><span class="w"> </span><span class="nn">importlib</span> 3314 <span class="k">if</span> <span class="n">importlib</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">find_spec</span><span class="p">(</span><span class="s1">'serial'</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span> 3315 <span class="kn">import</span><span class="w"> </span><span class="nn">serial</span> 3316 <span class="k">else</span><span class="p">:</span> 3317 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Using this interface requires a serial communication module to be installed."</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_CRITICAL</span><span class="p">)</span> 3318 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"You can install one with the command: python3 -m pip install pyserial"</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_CRITICAL</span><span class="p">)</span> 3319 <span class="n">RNS</span><span class="o">.</span><span class="n">panic</span><span class="p">()</span> 3320 3321 <span class="c1"># We start out by initialising the super-class</span> 3322 <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span> 3323 3324 <span class="c1"># To make sure the configuration data is in the</span> 3325 <span class="c1"># correct format, we parse it through the following</span> 3326 <span class="c1"># method on the generic Interface class. This step</span> 3327 <span class="c1"># is required to ensure compatibility on all the</span> 3328 <span class="c1"># platforms that Reticulum supports.</span> 3329 <span class="n">ifconf</span> <span class="o">=</span> <span class="n">Interface</span><span class="o">.</span><span class="n">get_config_obj</span><span class="p">(</span><span class="n">configuration</span><span class="p">)</span> 3330 3331 <span class="c1"># Read the interface name from the configuration</span> 3332 <span class="c1"># and set it on our interface instance.</span> 3333 <span class="n">name</span> <span class="o">=</span> <span class="n">ifconf</span><span class="p">[</span><span class="s2">"name"</span><span class="p">]</span> 3334 <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span> 3335 3336 <span class="c1"># We read configuration parameters from the supplied</span> 3337 <span class="c1"># configuration data, and provide default values in</span> 3338 <span class="c1"># case any are missing.</span> 3339 <span class="n">port</span> <span class="o">=</span> <span class="n">ifconf</span><span class="p">[</span><span class="s2">"port"</span><span class="p">]</span> <span class="k">if</span> <span class="s2">"port"</span> <span class="ow">in</span> <span class="n">ifconf</span> <span class="k">else</span> <span class="kc">None</span> 3340 <span class="n">speed</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">ifconf</span><span class="p">[</span><span class="s2">"speed"</span><span class="p">])</span> <span class="k">if</span> <span class="s2">"speed"</span> <span class="ow">in</span> <span class="n">ifconf</span> <span class="k">else</span> <span class="mi">9600</span> 3341 <span class="n">databits</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">ifconf</span><span class="p">[</span><span class="s2">"databits"</span><span class="p">])</span> <span class="k">if</span> <span class="s2">"databits"</span> <span class="ow">in</span> <span class="n">ifconf</span> <span class="k">else</span> <span class="mi">8</span> 3342 <span class="n">parity</span> <span class="o">=</span> <span class="n">ifconf</span><span class="p">[</span><span class="s2">"parity"</span><span class="p">]</span> <span class="k">if</span> <span class="s2">"parity"</span> <span class="ow">in</span> <span class="n">ifconf</span> <span class="k">else</span> <span class="s2">"N"</span> 3343 <span class="n">stopbits</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">ifconf</span><span class="p">[</span><span class="s2">"stopbits"</span><span class="p">])</span> <span class="k">if</span> <span class="s2">"stopbits"</span> <span class="ow">in</span> <span class="n">ifconf</span> <span class="k">else</span> <span class="mi">1</span> 3344 3345 <span class="c1"># In case no port is specified, we abort setup by</span> 3346 <span class="c1"># raising an exception.</span> 3347 <span class="k">if</span> <span class="n">port</span> <span class="o">==</span> <span class="kc">None</span><span class="p">:</span> 3348 <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">"No port specified for </span><span class="si">{</span><span class="bp">self</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> 3349 3350 <span class="c1"># All interfaces must supply a hardware MTU value</span> 3351 <span class="c1"># to the RNS Transport instance. This value should</span> 3352 <span class="c1"># be the maximum data packet payload size that the</span> 3353 <span class="c1"># underlying medium is capable of handling in all</span> 3354 <span class="c1"># cases without any segmentation.</span> 3355 <span class="bp">self</span><span class="o">.</span><span class="n">HW_MTU</span> <span class="o">=</span> <span class="mi">564</span> 3356 3357 <span class="c1"># We initially set the "online" property to false,</span> 3358 <span class="c1"># since the interface has not actually been fully</span> 3359 <span class="c1"># initialised and connected yet.</span> 3360 <span class="bp">self</span><span class="o">.</span><span class="n">online</span> <span class="o">=</span> <span class="kc">False</span> 3361 3362 <span class="c1"># In this case, we can also set the indicated bit-</span> 3363 <span class="c1"># rate of the interface to the serial port speed.</span> 3364 <span class="bp">self</span><span class="o">.</span><span class="n">bitrate</span> <span class="o">=</span> <span class="n">speed</span> 3365 3366 <span class="c1"># Configure internal properties on the interface</span> 3367 <span class="c1"># according to the supplied configuration.</span> 3368 <span class="bp">self</span><span class="o">.</span><span class="n">pyserial</span> <span class="o">=</span> <span class="n">serial</span> 3369 <span class="bp">self</span><span class="o">.</span><span class="n">serial</span> <span class="o">=</span> <span class="kc">None</span> 3370 <span class="bp">self</span><span class="o">.</span><span class="n">owner</span> <span class="o">=</span> <span class="n">owner</span> 3371 <span class="bp">self</span><span class="o">.</span><span class="n">port</span> <span class="o">=</span> <span class="n">port</span> 3372 <span class="bp">self</span><span class="o">.</span><span class="n">speed</span> <span class="o">=</span> <span class="n">speed</span> 3373 <span class="bp">self</span><span class="o">.</span><span class="n">databits</span> <span class="o">=</span> <span class="n">databits</span> 3374 <span class="bp">self</span><span class="o">.</span><span class="n">parity</span> <span class="o">=</span> <span class="n">serial</span><span class="o">.</span><span class="n">PARITY_NONE</span> 3375 <span class="bp">self</span><span class="o">.</span><span class="n">stopbits</span> <span class="o">=</span> <span class="n">stopbits</span> 3376 <span class="bp">self</span><span class="o">.</span><span class="n">timeout</span> <span class="o">=</span> <span class="mi">100</span> 3377 3378 <span class="k">if</span> <span class="n">parity</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s2">"e"</span> <span class="ow">or</span> <span class="n">parity</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s2">"even"</span><span class="p">:</span> 3379 <span class="bp">self</span><span class="o">.</span><span class="n">parity</span> <span class="o">=</span> <span class="n">serial</span><span class="o">.</span><span class="n">PARITY_EVEN</span> 3380 3381 <span class="k">if</span> <span class="n">parity</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s2">"o"</span> <span class="ow">or</span> <span class="n">parity</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s2">"odd"</span><span class="p">:</span> 3382 <span class="bp">self</span><span class="o">.</span><span class="n">parity</span> <span class="o">=</span> <span class="n">serial</span><span class="o">.</span><span class="n">PARITY_ODD</span> 3383 3384 <span class="c1"># Since all required parameters are now configured,</span> 3385 <span class="c1"># we will try opening the serial port.</span> 3386 <span class="k">try</span><span class="p">:</span> 3387 <span class="bp">self</span><span class="o">.</span><span class="n">open_port</span><span class="p">()</span> 3388 <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> 3389 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Could not open serial port for interface "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="p">),</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span> 3390 <span class="k">raise</span> <span class="n">e</span> 3391 3392 <span class="c1"># If opening the port succeeded, run any post-open</span> 3393 <span class="c1"># configuration required.</span> 3394 <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">serial</span><span class="o">.</span><span class="n">is_open</span><span class="p">:</span> 3395 <span class="bp">self</span><span class="o">.</span><span class="n">configure_device</span><span class="p">()</span> 3396 <span class="k">else</span><span class="p">:</span> 3397 <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s2">"Could not open serial port"</span><span class="p">)</span> 3398 3399 <span class="c1"># Open the serial port with supplied configuration</span> 3400 <span class="c1"># parameters and store a reference to the open port.</span> 3401 <span class="k">def</span><span class="w"> </span><span class="nf">open_port</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> 3402 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Opening serial port "</span><span class="o">+</span><span class="bp">self</span><span class="o">.</span><span class="n">port</span><span class="o">+</span><span class="s2">"..."</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_VERBOSE</span><span class="p">)</span> 3403 <span class="bp">self</span><span class="o">.</span><span class="n">serial</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">pyserial</span><span class="o">.</span><span class="n">Serial</span><span class="p">(</span> 3404 <span class="n">port</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">port</span><span class="p">,</span> 3405 <span class="n">baudrate</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">speed</span><span class="p">,</span> 3406 <span class="n">bytesize</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">databits</span><span class="p">,</span> 3407 <span class="n">parity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">parity</span><span class="p">,</span> 3408 <span class="n">stopbits</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">stopbits</span><span class="p">,</span> 3409 <span class="n">xonxoff</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span> 3410 <span class="n">rtscts</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span> 3411 <span class="n">timeout</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> 3412 <span class="n">inter_byte_timeout</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> 3413 <span class="n">write_timeout</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> 3414 <span class="n">dsrdtr</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span> 3415 <span class="p">)</span> 3416 3417 <span class="c1"># The only thing required after opening the port</span> 3418 <span class="c1"># is to wait a small amount of time for the</span> 3419 <span class="c1"># hardware to initialise and then start a thread</span> 3420 <span class="c1"># that reads any incoming data from the device.</span> 3421 <span class="k">def</span><span class="w"> </span><span class="nf">configure_device</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> 3422 <span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span> 3423 <span class="n">thread</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">read_loop</span><span class="p">)</span> 3424 <span class="n">thread</span><span class="o">.</span><span class="n">daemon</span> <span class="o">=</span> <span class="kc">True</span> 3425 <span class="n">thread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> 3426 <span class="bp">self</span><span class="o">.</span><span class="n">online</span> <span class="o">=</span> <span class="kc">True</span> 3427 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Serial port "</span><span class="o">+</span><span class="bp">self</span><span class="o">.</span><span class="n">port</span><span class="o">+</span><span class="s2">" is now open"</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_VERBOSE</span><span class="p">)</span> 3428 3429 3430 <span class="c1"># This method will be called from our read-loop</span> 3431 <span class="c1"># whenever a full packet has been received over</span> 3432 <span class="c1"># the underlying medium.</span> 3433 <span class="k">def</span><span class="w"> </span><span class="nf">process_incoming</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span> 3434 <span class="c1"># Update our received bytes counter</span> 3435 <span class="bp">self</span><span class="o">.</span><span class="n">rxb</span> <span class="o">+=</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> 3436 3437 <span class="c1"># And send the data packet to the Transport</span> 3438 <span class="c1"># instance for processing.</span> 3439 <span class="bp">self</span><span class="o">.</span><span class="n">owner</span><span class="o">.</span><span class="n">inbound</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span> 3440 3441 <span class="c1"># The running Reticulum Transport instance will</span> 3442 <span class="c1"># call this method on the interface whenever the</span> 3443 <span class="c1"># interface must transmit a packet.</span> 3444 <span class="k">def</span><span class="w"> </span><span class="nf">process_outgoing</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span><span class="n">data</span><span class="p">):</span> 3445 <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">online</span><span class="p">:</span> 3446 <span class="c1"># First, escape and packetize the data</span> 3447 <span class="c1"># according to HDLC framing.</span> 3448 <span class="n">data</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">([</span><span class="n">HDLC</span><span class="o">.</span><span class="n">FLAG</span><span class="p">])</span><span class="o">+</span><span class="n">HDLC</span><span class="o">.</span><span class="n">escape</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="o">+</span><span class="nb">bytes</span><span class="p">([</span><span class="n">HDLC</span><span class="o">.</span><span class="n">FLAG</span><span class="p">])</span> 3449 3450 <span class="c1"># Then write the framed data to the port</span> 3451 <span class="n">written</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">serial</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> 3452 3453 <span class="c1"># Update the transmitted bytes counter</span> 3454 <span class="c1"># and ensure that all data was written</span> 3455 <span class="bp">self</span><span class="o">.</span><span class="n">txb</span> <span class="o">+=</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> 3456 <span class="k">if</span> <span class="n">written</span> <span class="o">!=</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">):</span> 3457 <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s2">"Serial interface only wrote "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">written</span><span class="p">)</span><span class="o">+</span><span class="s2">" bytes of "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)))</span> 3458 3459 <span class="c1"># This read loop runs in a thread and continously</span> 3460 <span class="c1"># receives bytes from the underlying serial port.</span> 3461 <span class="c1"># When a full packet has been received, it will</span> 3462 <span class="c1"># be sent to the process_incoming methed, which</span> 3463 <span class="c1"># will in turn pass it to the Transport instance.</span> 3464 <span class="k">def</span><span class="w"> </span><span class="nf">read_loop</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> 3465 <span class="k">try</span><span class="p">:</span> 3466 <span class="n">in_frame</span> <span class="o">=</span> <span class="kc">False</span> 3467 <span class="n">escape</span> <span class="o">=</span> <span class="kc">False</span> 3468 <span class="n">data_buffer</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">""</span> 3469 <span class="n">last_read_ms</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span><span class="o">*</span><span class="mi">1000</span><span class="p">)</span> 3470 3471 <span class="k">while</span> <span class="bp">self</span><span class="o">.</span><span class="n">serial</span><span class="o">.</span><span class="n">is_open</span><span class="p">:</span> 3472 <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">serial</span><span class="o">.</span><span class="n">in_waiting</span><span class="p">:</span> 3473 <span class="n">byte</span> <span class="o">=</span> <span class="nb">ord</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">serial</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span> 3474 <span class="n">last_read_ms</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span><span class="o">*</span><span class="mi">1000</span><span class="p">)</span> 3475 3476 <span class="k">if</span> <span class="p">(</span><span class="n">in_frame</span> <span class="ow">and</span> <span class="n">byte</span> <span class="o">==</span> <span class="n">HDLC</span><span class="o">.</span><span class="n">FLAG</span><span class="p">):</span> 3477 <span class="n">in_frame</span> <span class="o">=</span> <span class="kc">False</span> 3478 <span class="bp">self</span><span class="o">.</span><span class="n">process_incoming</span><span class="p">(</span><span class="n">data_buffer</span><span class="p">)</span> 3479 <span class="k">elif</span> <span class="p">(</span><span class="n">byte</span> <span class="o">==</span> <span class="n">HDLC</span><span class="o">.</span><span class="n">FLAG</span><span class="p">):</span> 3480 <span class="n">in_frame</span> <span class="o">=</span> <span class="kc">True</span> 3481 <span class="n">data_buffer</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">""</span> 3482 <span class="k">elif</span> <span class="p">(</span><span class="n">in_frame</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">data_buffer</span><span class="p">)</span> <span class="o"><</span> <span class="bp">self</span><span class="o">.</span><span class="n">HW_MTU</span><span class="p">):</span> 3483 <span class="k">if</span> <span class="p">(</span><span class="n">byte</span> <span class="o">==</span> <span class="n">HDLC</span><span class="o">.</span><span class="n">ESC</span><span class="p">):</span> 3484 <span class="n">escape</span> <span class="o">=</span> <span class="kc">True</span> 3485 <span class="k">else</span><span class="p">:</span> 3486 <span class="k">if</span> <span class="p">(</span><span class="n">escape</span><span class="p">):</span> 3487 <span class="k">if</span> <span class="p">(</span><span class="n">byte</span> <span class="o">==</span> <span class="n">HDLC</span><span class="o">.</span><span class="n">FLAG</span> <span class="o">^</span> <span class="n">HDLC</span><span class="o">.</span><span class="n">ESC_MASK</span><span class="p">):</span> 3488 <span class="n">byte</span> <span class="o">=</span> <span class="n">HDLC</span><span class="o">.</span><span class="n">FLAG</span> 3489 <span class="k">if</span> <span class="p">(</span><span class="n">byte</span> <span class="o">==</span> <span class="n">HDLC</span><span class="o">.</span><span class="n">ESC</span> <span class="o">^</span> <span class="n">HDLC</span><span class="o">.</span><span class="n">ESC_MASK</span><span class="p">):</span> 3490 <span class="n">byte</span> <span class="o">=</span> <span class="n">HDLC</span><span class="o">.</span><span class="n">ESC</span> 3491 <span class="n">escape</span> <span class="o">=</span> <span class="kc">False</span> 3492 <span class="n">data_buffer</span> <span class="o">=</span> <span class="n">data_buffer</span><span class="o">+</span><span class="nb">bytes</span><span class="p">([</span><span class="n">byte</span><span class="p">])</span> 3493 3494 <span class="k">else</span><span class="p">:</span> 3495 <span class="n">time_since_last</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span><span class="o">*</span><span class="mi">1000</span><span class="p">)</span> <span class="o">-</span> <span class="n">last_read_ms</span> 3496 <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">data_buffer</span><span class="p">)</span> <span class="o">></span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">time_since_last</span> <span class="o">></span> <span class="bp">self</span><span class="o">.</span><span class="n">timeout</span><span class="p">:</span> 3497 <span class="n">data_buffer</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">""</span> 3498 <span class="n">in_frame</span> <span class="o">=</span> <span class="kc">False</span> 3499 <span class="n">escape</span> <span class="o">=</span> <span class="kc">False</span> 3500 <span class="n">sleep</span><span class="p">(</span><span class="mf">0.08</span><span class="p">)</span> 3501 3502 <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> 3503 <span class="bp">self</span><span class="o">.</span><span class="n">online</span> <span class="o">=</span> <span class="kc">False</span> 3504 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"A serial port error occurred, the contained exception was: "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">),</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span> 3505 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The interface "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">+</span><span class="s2">" experienced an unrecoverable error and is now offline."</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span> 3506 3507 <span class="k">if</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">panic_on_interface_error</span><span class="p">:</span> 3508 <span class="n">RNS</span><span class="o">.</span><span class="n">panic</span><span class="p">()</span> 3509 3510 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Reticulum will attempt to reconnect the interface periodically."</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span> 3511 3512 <span class="bp">self</span><span class="o">.</span><span class="n">online</span> <span class="o">=</span> <span class="kc">False</span> 3513 <span class="bp">self</span><span class="o">.</span><span class="n">serial</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> 3514 <span class="bp">self</span><span class="o">.</span><span class="n">reconnect_port</span><span class="p">()</span> 3515 3516 <span class="c1"># This method handles serial port disconnects.</span> 3517 <span class="k">def</span><span class="w"> </span><span class="nf">reconnect_port</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> 3518 <span class="k">while</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">online</span><span class="p">:</span> 3519 <span class="k">try</span><span class="p">:</span> 3520 <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> 3521 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Attempting to reconnect serial port "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">port</span><span class="p">)</span><span class="o">+</span><span class="s2">" for "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">+</span><span class="s2">"..."</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_VERBOSE</span><span class="p">)</span> 3522 <span class="bp">self</span><span class="o">.</span><span class="n">open_port</span><span class="p">()</span> 3523 <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">serial</span><span class="o">.</span><span class="n">is_open</span><span class="p">:</span> 3524 <span class="bp">self</span><span class="o">.</span><span class="n">configure_device</span><span class="p">()</span> 3525 <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> 3526 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Error while reconnecting port, the contained exception was: "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">),</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span> 3527 3528 <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Reconnected serial port for "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="p">))</span> 3529 3530 <span class="c1"># Signal to Reticulum that this interface should</span> 3531 <span class="c1"># not perform any ingress limiting.</span> 3532 <span class="k">def</span><span class="w"> </span><span class="nf">should_ingress_limit</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> 3533 <span class="k">return</span> <span class="kc">False</span> 3534 3535 <span class="c1"># We must provide a string representation of this</span> 3536 <span class="c1"># interface, that is used whenever the interface</span> 3537 <span class="c1"># is printed in logs or external programs.</span> 3538 <span class="k">def</span><span class="w"> </span><span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> 3539 <span class="k">return</span> <span class="s2">"ExampleInterface["</span><span class="o">+</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="o">+</span><span class="s2">"]"</span> 3540 3541 <span class="c1"># Finally, register the defined interface class as the</span> 3542 <span class="c1"># target class for Reticulum to use as an interface</span> 3543 <span class="n">interface_class</span> <span class="o">=</span> <span class="n">ExampleInterface</span> 3544 </pre></div> 3545 </div> 3546 <p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/ExampleInterface.py">https://github.com/markqvist/Reticulum/blob/master/Examples/ExampleInterface.py</a>.</p> 3547 </section> 3548 </section> 3549 3550 </article> 3551 </div> 3552 <footer> 3553 3554 <div class="related-pages"> 3555 <a class="next-page" href="support.html"> 3556 <div class="page-info"> 3557 <div class="context"> 3558 <span>Next</span> 3559 </div> 3560 <div class="title">Support Reticulum</div> 3561 </div> 3562 <svg class="furo-related-icon"><use href="#svg-arrow-right"></use></svg> 3563 </a> 3564 <a class="prev-page" href="networks.html"> 3565 <svg class="furo-related-icon"><use href="#svg-arrow-right"></use></svg> 3566 <div class="page-info"> 3567 <div class="context"> 3568 <span>Previous</span> 3569 </div> 3570 3571 <div class="title">Building Networks</div> 3572 3573 </div> 3574 </a> 3575 </div> 3576 <div class="bottom-of-page"> 3577 <div class="left-details"> 3578 <div class="copyright"> 3579 Copyright © 2023, Mark Qvist 3580 </div> 3581 Generated with <a href="https://www.sphinx-doc.org/">Sphinx</a> and 3582 <a href="https://github.com/pradyunsg/furo">Furo</a> 3583 3584 </div> 3585 <div class="right-details"> 3586 <div class="icons"> 3587 3588 </div> 3589 </div> 3590 </div> 3591 3592 </footer> 3593 </div> 3594 <aside class="toc-drawer"> 3595 3596 3597 <div class="toc-sticky toc-scroll"> 3598 <div class="toc-title-container"> 3599 <span class="toc-title"> 3600 On this page 3601 </span> 3602 </div> 3603 <div class="toc-tree-container"> 3604 <div class="toc-tree"> 3605 <ul> 3606 <li><a class="reference internal" href="#">Code Examples</a><ul> 3607 <li><a class="reference internal" href="#minimal">Minimal</a></li> 3608 <li><a class="reference internal" href="#announce">Announce</a></li> 3609 <li><a class="reference internal" href="#broadcast">Broadcast</a></li> 3610 <li><a class="reference internal" href="#echo">Echo</a></li> 3611 <li><a class="reference internal" href="#link">Link</a></li> 3612 <li><a class="reference internal" href="#example-identify">Identification</a></li> 3613 <li><a class="reference internal" href="#requests-responses">Requests & Responses</a></li> 3614 <li><a class="reference internal" href="#channel">Channel</a></li> 3615 <li><a class="reference internal" href="#buffer">Buffer</a></li> 3616 <li><a class="reference internal" href="#filetransfer">Filetransfer</a></li> 3617 <li><a class="reference internal" href="#custom-interfaces">Custom Interfaces</a></li> 3618 </ul> 3619 </li> 3620 </ul> 3621 3622 </div> 3623 </div> 3624 </div> 3625 3626 3627 </aside> 3628 </div> 3629 </div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> 3630 <script src="_static/jquery.js"></script> 3631 <script src="_static/underscore.js"></script> 3632 <script src="_static/_sphinx_javascript_frameworks_compat.js"></script> 3633 <script src="_static/doctools.js"></script> 3634 <script src="_static/sphinx_highlight.js"></script> 3635 <script src="_static/scripts/furo.js"></script> 3636 <script src="_static/clipboard.min.js"></script> 3637 <script src="_static/copybutton.js"></script> 3638 </body> 3639 </html>