<?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>DEV Community: Sylvan Franklin</title>
    <description>The latest articles on DEV Community by Sylvan Franklin (@sylvanfranklin).</description>
    <link>https://dev.to/sylvanfranklin</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%2F2498319%2F195b53f9-4430-4f8f-8305-01072f1d25c9.png</url>
      <title>DEV Community: Sylvan Franklin</title>
      <link>https://dev.to/sylvanfranklin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sylvanfranklin"/>
    <language>en</language>
    <item>
      <title>Daemons on macOS with Rust</title>
      <dc:creator>Sylvan Franklin</dc:creator>
      <pubDate>Fri, 29 Nov 2024 19:56:56 +0000</pubDate>
      <link>https://dev.to/sylvanfranklin/daemons-on-macos-with-rust-188a</link>
      <guid>https://dev.to/sylvanfranklin/daemons-on-macos-with-rust-188a</guid>
      <description>&lt;h1&gt;
  
  
  Overview and background
&lt;/h1&gt;

&lt;p&gt;Creating a background service / daemon on macOS can be quite confusing. The native service that macOS ships with is called &lt;code&gt;launchCTL&lt;/code&gt;, and it is not very intuitive at all to figure out. Each service has several different states that it can be in (enabled, disabled, not enabled, bootstrapped). I was writing a Rust daemon called &lt;a href="https://github.com/sylvanfranklin/srhd" rel="noopener noreferrer"&gt;srhd&lt;/a&gt;, and I found the process nightmarish. I created a Rust crate to make the process much simpler for anyone who faces this problem in the future. &lt;/p&gt;

&lt;h2&gt;
  
  
  This guide
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Will walk through creating an example daemon with &lt;code&gt;launchctl&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;Walk through how macOS handles daemons.&lt;/li&gt;
&lt;li&gt;Bamboozle you into staring my project on github.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Example Project
&lt;/h1&gt;

&lt;p&gt;Create a new cargo binary project with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo init &lt;span class="nt"&gt;--bin&lt;/span&gt; daemon_example
&lt;span class="nb"&gt;cd &lt;/span&gt;daemon_example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add launchctl crate&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo add launchctl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the project in your default editor, I recommend nvim. Go to the main file&lt;br&gt;
and create a new Service instance, this will allow us to use a binary as a&lt;br&gt;
service. I'll assume that if you're reading this tutorial you already have a&lt;br&gt;
binary in mind.&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;fn&lt;/span&gt; &lt;span class="nf"&gt;main&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="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Service&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="s"&gt;"com.&amp;lt;owner&amp;gt;.&amp;lt;binary&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;PathBuf&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/bin/ls"&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;Now we can use any of the following commands on this object&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;fn&lt;/span&gt; &lt;span class="nf"&gt;main&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="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Service&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="s"&gt;"com.&amp;lt;owner&amp;gt;.&amp;lt;binary&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;PathBuf&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/bin/ls"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="nf"&gt;.start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
    &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="nf"&gt;.stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
    &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="nf"&gt;.restart&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&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;Keep in mind that launchctl will not create a plist file for you. This file can be created with another crate that some rando wrote a while ago, but I would just use a format string since a crate is overkill in my opinion. Visit the github &lt;a href="https://github.com/sylvanfranklin/launchctl" rel="noopener noreferrer"&gt;repo&lt;/a&gt; for more information about the properties that these plist files can have.&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;fn&lt;/span&gt; &lt;span class="nf"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nn"&gt;launchctl&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;plist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="s"&gt;"&amp;lt;?xml version=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;1.0&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt; encoding=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;UTF-8&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;?&amp;gt;
&amp;lt;!DOCTYPE plist PUBLIC &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;-//Apple Computer//DTD PLIST 1.0//EN&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;http://www.apple.com/DTDs/PropertyList-1.0.dtd&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;
&amp;lt;plist version=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;1.0&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;
&amp;lt;dict&amp;gt;
    &amp;lt;key&amp;gt;Label&amp;lt;/key&amp;gt;
    &amp;lt;string&amp;gt;{}&amp;lt;/string&amp;gt;
    &amp;lt;key&amp;gt;ProgramArguments&amp;lt;/key&amp;gt;
    &amp;lt;array&amp;gt;
        &amp;lt;string&amp;gt;{}&amp;lt;/string&amp;gt;
    &amp;lt;/array&amp;gt;
    &amp;lt;key&amp;gt;RunAtLoad&amp;lt;/key&amp;gt;
    &amp;lt;true/&amp;gt;
        &amp;lt;key&amp;gt;KeepAlive&amp;lt;/key&amp;gt;
    &amp;lt;dict&amp;gt;
        &amp;lt;key&amp;gt;SuccessfulExit&amp;lt;/key&amp;gt;
         &amp;lt;false/&amp;gt;
         &amp;lt;key&amp;gt;Crashed&amp;lt;/key&amp;gt;
         &amp;lt;true/&amp;gt;
    &amp;lt;/dict&amp;gt;
    &amp;lt;key&amp;gt;StandardOutPath&amp;lt;/key&amp;gt;
    &amp;lt;string&amp;gt;/tmp/srhd_sylvanfranklin.out.log&amp;lt;/string&amp;gt;
    &amp;lt;key&amp;gt;StandardErrorPath&amp;lt;/key&amp;gt;
    &amp;lt;string&amp;gt;/tmp/srhd_sylvanfranklin.err.log&amp;lt;/string&amp;gt;
    &amp;lt;key&amp;gt;ProcessType&amp;lt;/key&amp;gt;
    &amp;lt;string&amp;gt;Interactive&amp;lt;/string&amp;gt;
    &amp;lt;key&amp;gt;Nice&amp;lt;/key&amp;gt;
    &amp;lt;integer&amp;gt;-20&amp;lt;/integer&amp;gt;
&amp;lt;/dict&amp;gt;
&amp;lt;/plist&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ctl&lt;/span&gt;&lt;span class="py"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ctl&lt;/span&gt;&lt;span class="py"&gt;.bin_path&lt;/span&gt;&lt;span class="nf"&gt;.to_str&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctl&lt;/span&gt;&lt;span class="py"&gt;.plist_path&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;plist&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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;main&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="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Service&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="s"&gt;"com.&amp;lt;owner&amp;gt;.&amp;lt;binary&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;PathBuf&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/bin/ls"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nf"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="nf"&gt;.start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&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;Run the project, and you should have a thing attached the OS. You should see a notification telling you that a new login item has been added. If you wish to remove it, simply delete the plist file and use the &lt;code&gt;.stop()&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo run 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  I'm lowkey not gonna explain launchctl
&lt;/h1&gt;

&lt;p&gt;I mean the macOS native one. It's just super confusing, and I'm tired of writing this guide. Just look at the docs, or reach out to me on github and I'll help you out. Cheers and what not.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>SRHD - Simple Rust HotKey Daemon</title>
      <dc:creator>Sylvan Franklin</dc:creator>
      <pubDate>Fri, 29 Nov 2024 01:40:05 +0000</pubDate>
      <link>https://dev.to/sylvanfranklin/srhd-simple-rust-hotkey-daemon-ib4</link>
      <guid>https://dev.to/sylvanfranklin/srhd-simple-rust-hotkey-daemon-ib4</guid>
      <description>&lt;h1&gt;
  
  
  SRHD
&lt;/h1&gt;

&lt;p&gt;I wrote a very minimal little Rust library (for macOS, for now), that listens to keys, and let's you run any kind of shell script. It is exactly like skhd if you have heard of that only in Rust. I like skhd but just wanted a version with a toml config. You can view the source right here and maybe give a star, help a brotha out: &lt;a href="https://github.com/SylvanFranklin/srhd" rel="noopener noreferrer"&gt;https://github.com/SylvanFranklin/srhd&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Docs are included on the repo but here is a config example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# srhd.toml&lt;/span&gt;
&lt;span class="nn"&gt;[[binding]]&lt;/span&gt;
&lt;span class="py"&gt;key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"a"&lt;/span&gt;
&lt;span class="py"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"open /Applications/Firefox.app"&lt;/span&gt; &lt;span class="c"&gt;# or any arbitrary shell script&lt;/span&gt;
&lt;span class="py"&gt;mods&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"option"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"shift"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nn"&gt;[[binding]]&lt;/span&gt;
&lt;span class="py"&gt;key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"equals"&lt;/span&gt;
&lt;span class="py"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"echo 'hello from srhd'"&lt;/span&gt;
&lt;span class="py"&gt;mods&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"control"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"fn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"capslock"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
  </channel>
</rss>
