<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: localhost.run</title>
    <description>The latest articles on Forem by localhost.run (@localhost-run).</description>
    <link>https://forem.com/localhost-run</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F8113%2F1f83d1b8-b21f-4306-bbe8-38420c811b82.png</url>
      <title>Forem: localhost.run</title>
      <link>https://forem.com/localhost-run</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/localhost-run"/>
    <language>en</language>
    <item>
      <title>Mocking with Rust</title>
      <dc:creator>Tom</dc:creator>
      <pubDate>Tue, 02 Jan 2024 17:02:18 +0000</pubDate>
      <link>https://forem.com/localhost-run/mocking-with-rust-32a2</link>
      <guid>https://forem.com/localhost-run/mocking-with-rust-32a2</guid>
      <description>&lt;p&gt;I've got something cooking that i've written in Rust and I recently discovered a neat trick to test it.&lt;/p&gt;

&lt;p&gt;Coming from python, mocks are a thing i often reach for. I find it really neat that I can throw an api from a package in a test harness so easily, same as how I'd do with a HTTP api in an integration test.&lt;/p&gt;

&lt;p&gt;Something external I often mock is time. That's not some deep nihilist philosophy, i mean literally if there's a delay i'll mock out stuff that waits, sleep, etc so that my tests can prove the delayed behaviour instantly.&lt;/p&gt;

&lt;p&gt;In the Rust thing I'm working on I faced this exact issue, specifically a timeout on a socket.&lt;br&gt;
I have a check on an &lt;code&gt;Instant&lt;/code&gt;, is .&lt;code&gt;elapsed()&lt;/code&gt; greater than a &lt;code&gt;Duration&lt;/code&gt;, and if it is I drop the socket from the hashmap it's stored in and it gets closed.&lt;/p&gt;

&lt;p&gt;But I don't want my tests to wait the actual time, I want to be able to manipulate that time.&lt;/p&gt;

&lt;p&gt;In python I would move the external world of the time api around the timeout internal to my function, but in Rust I can use an impl inside my tests to flip that and just move my timeout internal to my struct around the external world. check this out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;WaitingPlace&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;last_switch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Instant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;switch_every&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;is_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;WaitingPlace&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;switch_every&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;last_switch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;Instant&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;switch_every&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;is_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;do_stuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.flip_check&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"is_on: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.is_on&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;flip_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.last_switch&lt;/span&gt;&lt;span class="nf"&gt;.elapsed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.switch_every&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.last_switch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Instant&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.is_on&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.is_on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;#[cfg(test)]&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;test_time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;WaitingPlace&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;WaitingPlace&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;// &amp;lt;- here's the magic where I reach into the struct and change the time&lt;/span&gt;
            &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;move_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_switch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Instant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.last_switch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;last_switch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;wp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;WaitingPlace&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wp&lt;/span&gt;&lt;span class="py"&gt;.is_on&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;wp&lt;/span&gt;&lt;span class="nf"&gt;.do_stuff&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wp&lt;/span&gt;&lt;span class="py"&gt;.is_on&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;wp&lt;/span&gt;&lt;span class="nf"&gt;.move_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Instant&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;wp&lt;/span&gt;&lt;span class="nf"&gt;.do_stuff&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wp&lt;/span&gt;&lt;span class="py"&gt;.is_on&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it's effectively a window onto the internals of my WaitingPlace struct that only exists in my tests. pretty neat i reckon. Maybe this is super obvious to you seasoned rust devs, or maybe i've created an abomination that no one wants to see. Either way i thought it was neat.&lt;/p&gt;

&lt;p&gt;If you know a better way of doing this let me know.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>beginners</category>
    </item>
    <item>
      <title>hello (dev.to) world</title>
      <dc:creator>Tom</dc:creator>
      <pubDate>Tue, 02 Jan 2024 16:42:28 +0000</pubDate>
      <link>https://forem.com/localhost-run/hello-devto-world-4ppd</link>
      <guid>https://forem.com/localhost-run/hello-devto-world-4ppd</guid>
      <description>&lt;h1&gt;
  
  
  Why am I here?
&lt;/h1&gt;

&lt;p&gt;My name is Tom and I have a problem that I want to talk to you about.&lt;/p&gt;

&lt;p&gt;Many years ago I built &lt;a href="https://localhost.run"&gt;localhost.run&lt;/a&gt; to help me write webhooks and accidentally got a bunch of users on it. Since then I've been launching and building and changing and re-launching over and over in an attempt to make it into my day job. Each time something has gotten in the way.&lt;/p&gt;

&lt;p&gt;Today I'm trying something different.&lt;/p&gt;

&lt;h1&gt;
  
  
  What am I talking about?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://localhost.run"&gt;localhost.run&lt;/a&gt; puts your localhost webapp on the internet.&lt;/p&gt;

&lt;p&gt;If you've got a web app knocking about that you don't mind putting on the internet for a minute, fire it up now on port 8080.&lt;br&gt;
If not then find a directory that doesn't have anything secret in it and start either a python (&lt;code&gt;python -m http.server 8080&lt;/code&gt;) or node (&lt;code&gt;npx http-server -p 8080&lt;/code&gt;) webserver, then run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -R 80:localhost:8080 nokey@localhost.run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll get an internet accessible URL back that anyone on the internet can connect to to see your webapp.&lt;/p&gt;

&lt;p&gt;Simple right?&lt;/p&gt;

&lt;p&gt;But building stuff is easy, it's all the stuff that isn't building that is difficult.&lt;/p&gt;

&lt;h1&gt;
  
  
  How will I (try to) solve my problem?
&lt;/h1&gt;

&lt;p&gt;I'm fortunate that life has allowed this to be my side project, but that's not guaranteed sustainable, I need it to become a business that I can fully focus on for that. All the building i've done has only taken it this small distance by luck.&lt;/p&gt;

&lt;p&gt;So instead of again rebuilding it to be faster or fixing stuff in the frontend or moving stuff around in the backend to be more scalable, I'm going to talk about it with all of you.&lt;/p&gt;

&lt;p&gt;There's still work to do, so a lot of this will be technical details about how i've built and will build not just localhost.run but also stuff around it.&lt;/p&gt;

&lt;p&gt;But I also want to talk about my journey towards figuring out how to build a business around it, so there will be a lot of that too. Be warned tho, I know how to build software, but have no idea how to build a business, so don't treat both as equally as authoritative ;)&lt;/p&gt;

&lt;p&gt;My hope is that if I externalise this stuff it will give me a signal that i'm moving forward instead of just moving around.&lt;/p&gt;

&lt;p&gt;I've got a bunch of stuff planned, some of that in the technical space is astro.build and rust, two things i've recently gotten into, and i've also got an article brewing about how to move gigiabits per second thru a python socket proxy if you're into that kind of thing, so subscribe if you want to hear about these ;)&lt;/p&gt;

&lt;p&gt;If you happen by this article please do respond back if you've got any suggestions for me or anything you'd like to know about localhost.run.&lt;/p&gt;

&lt;p&gt;edit: first tech article of many done: &lt;a href="https://dev.to/localhost-run/mocking-with-rust-32a2"&gt;mocking with rust&lt;/a&gt;&lt;/p&gt;

</description>
      <category>saas</category>
      <category>startup</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
