<?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: Hunter LaFaille</title>
    <description>The latest articles on Forem by Hunter LaFaille (@hlafaille).</description>
    <link>https://forem.com/hlafaille</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%2Fuser%2Fprofile_image%2F1322541%2Fb6fa9aaa-c6b9-44e3-bbd0-c0e626a453c6.jpg</url>
      <title>Forem: Hunter LaFaille</title>
      <link>https://forem.com/hlafaille</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/hlafaille"/>
    <language>en</language>
    <item>
      <title>WizardMirror: A lightweight, native alternative to MagicMirror2</title>
      <dc:creator>Hunter LaFaille</dc:creator>
      <pubDate>Wed, 29 Jan 2025 04:52:31 +0000</pubDate>
      <link>https://forem.com/hlafaille/wizardmirror-a-lightweight-native-alternative-to-magicmirror2-o7i</link>
      <guid>https://forem.com/hlafaille/wizardmirror-a-lightweight-native-alternative-to-magicmirror2-o7i</guid>
      <description>&lt;p&gt;Like many this year, learning Zig was part of my goals for the year. I think I've largely accomplished that with a project I'm particularly proud of, even with as little user facing features as it currently has. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Kerosene-Labs/wizardmirror" rel="noopener noreferrer"&gt;https://github.com/Kerosene-Labs/wizardmirror&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;WizardMirror plans to be a lightweight and native re-implementation of the core features of MagicMirror, with none of the Chromium. At its core lies an SDL-based rendering engine written in Zig, a networking stack built on libcurl, and an RSS parser written with libxml2.&lt;/p&gt;

&lt;p&gt;Currently, 90% of the work is going into the engine, getting the foundational pieces operating well enough where we can start drawing widgets (widgets are pre-made, composable components). Right now, we can pull RSS files, parse them, and display them utilizing our &lt;code&gt;rem&lt;/code&gt; based scaling (with rudimentary HiDPI support!).&lt;/p&gt;

&lt;p&gt;I'd love any feedback. I'm sure there's leaks, the caching isn't optimal, but it's cool and I'm proud.&lt;/p&gt;

</description>
      <category>zig</category>
      <category>sdl2</category>
      <category>raspberrypi</category>
      <category>smartmirror</category>
    </item>
    <item>
      <title>Espresso; it's Go time</title>
      <dc:creator>Hunter LaFaille</dc:creator>
      <pubDate>Mon, 30 Sep 2024 23:07:45 +0000</pubDate>
      <link>https://forem.com/hlafaille/espresso-its-go-time-52mj</link>
      <guid>https://forem.com/hlafaille/espresso-its-go-time-52mj</guid>
      <description>&lt;p&gt;I've spent the passed two weeks rewriting my Rust based, no bullshit Java build tool in Go and things progressed much faster. Espresso is faster at runtime and more portable. Espresso also was also recently able to compile and package it's first project, that being my other project Kindling.&lt;/p&gt;

&lt;p&gt;I would love any feedback I can get on Espresso. There's quite a few features that are missing like transient dependency resolution (right now they're declared at the package level but just ignored). The package registry has also changed in philosophy somewhat. Instead of being a simple web API, Espresso registries are now zip archives containing a file structure. This means, if you can host a static zip file, you can host an Espresso registry.&lt;/p&gt;

&lt;p&gt;One more quick thing, Kerosene Labs has also filed Articles of Organization in our home state to become an LLC. :)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Kerosene-Labs/espresso" rel="noopener noreferrer"&gt;https://github.com/Kerosene-Labs/espresso&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/Kerosene-Labs/espresso-registry" rel="noopener noreferrer"&gt;https://github.com/Kerosene-Labs/espresso-registry&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/Kerosene-Labs/kindling" rel="noopener noreferrer"&gt;https://github.com/Kerosene-Labs/kindling&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>go</category>
    </item>
    <item>
      <title>Building a web server with no dependencies in Java</title>
      <dc:creator>Hunter LaFaille</dc:creator>
      <pubDate>Thu, 08 Aug 2024 16:04:51 +0000</pubDate>
      <link>https://forem.com/hlafaille/building-a-web-server-with-no-dependencies-in-java-2okh</link>
      <guid>https://forem.com/hlafaille/building-a-web-server-with-no-dependencies-in-java-2okh</guid>
      <description>&lt;p&gt;I've been working on a hobby project for a few months, an MIT licensed API gateway designed to be independent of any particular vendor. I think it's going quite well, to be honest. As my code base has grown, I've seen opportunity for improvement around the core, that being the HTTP server. Spinning out the core HTTP server into its own micro-framework seemed like a logical solution (and a great learning exercise!).&lt;/p&gt;

&lt;p&gt;Introducing Kindling, the fuel that'll ignite your application. Kindling is based on the standard Java 21 library, with no dependencies. It's designed to be programmable, without using any magic.&lt;/p&gt;

&lt;p&gt;Here's a simple Hello World with Kindling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;io.kerosenelabs.kindling&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.nio.file.Path&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.HashMap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.kerosenelabs.kindling.constant.HttpMethod&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.kerosenelabs.kindling.constant.HttpStatus&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.kerosenelabs.kindling.exception.KindlingException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.kerosenelabs.kindling.handler.RequestHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;KindlingException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nc"&gt;KindlingServer&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KindlingServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// test request handler&lt;/span&gt;
        &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;installRequestHandler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RequestHandler&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="cm"&gt;/**
             * Tell the server what type of request this handler can work with
             */&lt;/span&gt;
            &lt;span class="nd"&gt;@Override&lt;/span&gt;
            &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;accepts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpMethod&lt;/span&gt; &lt;span class="n"&gt;httpMethod&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;KindlingException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;httpMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;

            &lt;span class="cm"&gt;/**
             * Do your business logic here
             */&lt;/span&gt;
            &lt;span class="nd"&gt;@Override&lt;/span&gt;
            &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;HttpResponse&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpRequest&lt;/span&gt; &lt;span class="n"&gt;httpRequest&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;KindlingException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;OK&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                            &lt;span class="o"&gt;{&lt;/span&gt;
                                &lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"text/html"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                            &lt;span class="o"&gt;}&lt;/span&gt;
                        &lt;span class="o"&gt;})&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Hello from Kindling!&amp;lt;/h1&amp;gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;

        &lt;span class="c1"&gt;// serve our server&lt;/span&gt;
        &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;serve&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8443&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mykeystore.p12"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sending a CURL request to the server yields this response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; GET / HTTP/1.1
&amp;gt; Host: localhost:8443
&amp;gt; User-Agent: curl/7.88.1
&amp;gt; Accept: */*
&amp;gt; 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
&amp;lt; HTTP/1.1 200 OK
&amp;lt; Content-Type: text/html
* no chunk, no close, no size. Assume close to signal end
&amp;lt; 
* TLSv1.3 (IN), TLS alert, user canceled (346):
* TLSv1.3 (IN), TLS alert, close notify (256):
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, close notify (256):
&amp;lt;h1&amp;gt;Hello from Kindling!&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...pretty cool, right?&lt;/p&gt;

&lt;p&gt;There's a few bugs, like &lt;code&gt;Content-Length&lt;/code&gt; being missing in the response.&lt;/p&gt;

</description>
      <category>java</category>
      <category>webdev</category>
      <category>http</category>
    </item>
    <item>
      <title>Announcing Espresso; a different kind of Java build tool.</title>
      <dc:creator>Hunter LaFaille</dc:creator>
      <pubDate>Mon, 25 Mar 2024 13:42:56 +0000</pubDate>
      <link>https://forem.com/hlafaille/announcing-espresso-a-different-kind-of-java-build-tool-4k0c</link>
      <guid>https://forem.com/hlafaille/announcing-espresso-a-different-kind-of-java-build-tool-4k0c</guid>
      <description>&lt;p&gt;I've constantly fought Gradle for as long as I've been writing Java. I remember when I first started writing Java, I didn't actually use a build tool (just the built in builder in Eclipse).As I've gotten into the Java world professionally, which means writing more tests, I've realized how god awful Gradle is with it's convoluted plugins that have a needle-in-a-haystack like feel to it. &lt;/p&gt;

&lt;p&gt;I'm confident Gradle has it's place in the world; those organizations who need complicated build processes. The problem is, every code base I've ever worked on could be built by a much simpler tool.&lt;/p&gt;

&lt;p&gt;This is why I built Espresso. Espresso is a build tool for Java (written in Rust) that focuses on simplicity, speed, repeatability and ease of configuration. It's still a huge work in progress (and served as a project for me to finally learn some Rust). Features like including dependencies into the built .jar are missing (although you can fetch them from the Espresso Registry). Espresso is inspired by Cargo and Go.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/hlafaille/espresso" rel="noopener noreferrer"&gt;https://github.com/hlafaille/espresso&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Espresso also does away with using Maven Central, a repository owned by Sonatype, in favor of an open source and transparent approach similar to Nixpkgs and Winget (&lt;a href="https://github.com/hlafaille/espresso-registry" rel="noopener noreferrer"&gt;https://github.com/hlafaille/espresso-registry&lt;/a&gt;).&lt;/p&gt;

</description>
      <category>java</category>
      <category>gradle</category>
      <category>buildtool</category>
      <category>rust</category>
    </item>
  </channel>
</rss>
