<?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: Zhiwei Ma</title>
    <description>The latest articles on Forem by Zhiwei Ma (@zhiwei_ma_0fc08a668c1eb51).</description>
    <link>https://forem.com/zhiwei_ma_0fc08a668c1eb51</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%2F3729557%2Fb40e929f-193b-449b-9e8e-1ee496e5fe04.jpg</url>
      <title>Forem: Zhiwei Ma</title>
      <link>https://forem.com/zhiwei_ma_0fc08a668c1eb51</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/zhiwei_ma_0fc08a668c1eb51"/>
    <language>en</language>
    <item>
      <title>FluxDown: A Free Download Manager Built with Rust + Flutter</title>
      <dc:creator>Zhiwei Ma</dc:creator>
      <pubDate>Mon, 16 Feb 2026 07:29:40 +0000</pubDate>
      <link>https://forem.com/zhiwei_ma_0fc08a668c1eb51/fluxdown-a-free-download-manager-built-with-rust-flutter-3ace</link>
      <guid>https://forem.com/zhiwei_ma_0fc08a668c1eb51/fluxdown-a-free-download-manager-built-with-rust-flutter-3ace</guid>
      <description>&lt;p&gt;I've been working on a download manager called FluxDown that handles multiple protocols in one app. The backend is written in Rust on top of Tokio, and the GUI uses Flutter with shadcn-style components. It's free, no ads, no accounts required.&lt;/p&gt;

&lt;p&gt;Here's what it does and why I built it this way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Protocol Downloads
&lt;/h2&gt;

&lt;p&gt;Most download managers handle one protocol well and ignore the rest. IDM is great for HTTP but can't do BitTorrent. qBittorrent handles torrents but nothing else. I wanted a single tool that covers everything I actually use day to day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTTP/HTTPS&lt;/strong&gt; with adaptive segmentation (more on this below)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FTP&lt;/strong&gt; with multi-connection parallel downloads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BitTorrent&lt;/strong&gt; via librqbit — magnet links, .torrent files, DHT, UPnP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HLS streaming&lt;/strong&gt; — .m3u8 with AES-128 decryption&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DASH streaming&lt;/strong&gt; — .mpd with quality selection&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Adaptive Segmentation
&lt;/h2&gt;

&lt;p&gt;This is probably the part I'm happiest with. IDM splits every download into 8 segments regardless of file size or connection speed. That works fine in many cases, but it's not optimal.&lt;/p&gt;

&lt;p&gt;FluxDown takes a different approach. Before starting a download, it sends a 512KB probe request to measure your actual bandwidth. Then it calculates the segment count based on three factors: file size, measured bandwidth, and CPU core count.&lt;/p&gt;

&lt;p&gt;The logic works like this: files under 4MB don't get segmented at all — single connection is fine. For larger files, each segment is at least 2MB. The upper bound is 4x your CPU core count (for I/O parallelism), capped at 64. If your bandwidth is below 512KB/s, it scales down to 25% of the recommended count to avoid overloading a slow connection.&lt;/p&gt;

&lt;p&gt;There's also runtime dynamic splitting. When one segment finishes, the idle worker picks up part of the slowest remaining segment. This matters more than you'd expect on connections with variable speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;The download engine is a Rust binary running on Tokio's async runtime. Each download task is an independent tokio task with its own CancellationToken for lifecycle control. The Rust side handles all network I/O and disk writes.&lt;/p&gt;

&lt;p&gt;The GUI is Flutter (Dart), connected to the Rust backend through the Rinf framework using FFI with bincode serialization. This keeps the UI responsive — Dart handles rendering and user interaction, Rust handles the heavy lifting. No shared memory headaches, just message passing.&lt;/p&gt;

&lt;p&gt;For HTTP, I use reqwest with rustls. FTP goes through suppaftp's synchronous API wrapped in spawn_blocking with mpsc channels. BitTorrent uses librqbit with its own multi-threaded runtime, also in spawn_blocking since it internally calls block_on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Browser Extension
&lt;/h2&gt;

&lt;p&gt;The Chrome MV3 extension (also works on Firefox) has a three-layer interception system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;webRequest API caches download metadata&lt;/li&gt;
&lt;li&gt;downloads.onDeterminingFilename does the main interception&lt;/li&gt;
&lt;li&gt;downloads.onCreated catches anything that slips through&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For streaming detection, it monkey-patches the page's &lt;code&gt;fetch()&lt;/code&gt; and &lt;code&gt;XMLHttpRequest&lt;/code&gt; to catch .m3u8 and .mpd URLs automatically. The extension talks to the desktop client over a local HTTP API on port 19527 — no Native Messaging needed, which makes installation simpler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Details
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Speed limiting&lt;/strong&gt;: Token bucket algorithm with 50ms refill intervals. Smooth curve, not choppy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence&lt;/strong&gt;: All task state goes to SQLite. Resume works after crashes and reboots.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI&lt;/strong&gt;: Dark and light themes, 12 color schemes. System tray, .torrent file association, single-instance enforcement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code quality&lt;/strong&gt;: Rust edition 2024 with strict Clippy lints — deny on unwrap, expect, and wildcard imports. Every error path is handled explicitly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;Windows only for now. No post-download script execution. BT download speed depends on seed availability (nothing I can do about that). SOCKS5 proxy support exists but isn't perfectly stable yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;FluxDown is completely free — no ads, no accounts, no telemetry. All data stays local.&lt;/p&gt;

&lt;p&gt;Website: &lt;a href="https://fluxdown.zerx.dev" rel="noopener noreferrer"&gt;fluxdown.zerx.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd appreciate any feedback on the architecture decisions or feature requests.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>flutter</category>
      <category>showdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Building a GPU-Accelerated Terminal Emulator with Rust and GPUI</title>
      <dc:creator>Zhiwei Ma</dc:creator>
      <pubDate>Sat, 24 Jan 2026 05:40:42 +0000</pubDate>
      <link>https://forem.com/zhiwei_ma_0fc08a668c1eb51/building-a-gpu-accelerated-terminal-emulator-with-rust-and-gpui-4103</link>
      <guid>https://forem.com/zhiwei_ma_0fc08a668c1eb51/building-a-gpu-accelerated-terminal-emulator-with-rust-and-gpui-4103</guid>
      <description>&lt;p&gt;I've been working on a terminal emulator project called &lt;strong&gt;zTerm&lt;/strong&gt; in my spare time, and wanted to share some lessons learned along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Terminal emulation&lt;/strong&gt;: Built on top of &lt;code&gt;alacritty_terminal&lt;/code&gt; - no need to reinvent the wheel for VT parsing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI Framework&lt;/strong&gt;: GPUI, the same framework that powers the Zed editor, with GPU-accelerated rendering&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Component library&lt;/strong&gt;: gpui-component from Longbridge&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I chose GPUI because I was curious about what makes Zed's rendering so smooth. Wanted to see if I could achieve similar results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges I Faced
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cross-Platform PTY
&lt;/h3&gt;

&lt;p&gt;The differences between Windows ConPTY and Unix PTY were bigger than expected. Signal handling and process lifecycle management took significant debugging time.&lt;/p&gt;

&lt;h3&gt;
  
  
  IME Support
&lt;/h3&gt;

&lt;p&gt;Supporting Chinese/Japanese/Korean input methods was tricky. Cursor positioning, candidate window placement, and composition state handling all behave differently across platforms. GPUI's documentation is sparse here, so I ended up reading Zed's source code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rendering Performance
&lt;/h3&gt;

&lt;p&gt;Initially, I was triggering a render on every PTY event. Running &lt;code&gt;cat&lt;/code&gt; on a large file would freeze the terminal. Adding a 4ms batching interval to coalesce multiple events before rendering made a huge difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current Status
&lt;/h2&gt;

&lt;p&gt;Basic functionality works: multi-tab support, scroll history, mouse selection, and keyboard shortcuts. Split panes are in progress, and theming is planned.&lt;/p&gt;

&lt;p&gt;The code is still rough around the edges. If you have experience with GPUI or terminal emulators, feedback and PRs are welcome.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/zerx-lab/zTerm" rel="noopener noreferrer"&gt;https://github.com/zerx-lab/zTerm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Built with Rust. No pre-built releases yet - you'll need to compile from source if you want to try it out.&lt;/p&gt;

</description>
      <category>cli</category>
      <category>rust</category>
      <category>showdev</category>
      <category>ui</category>
    </item>
  </channel>
</rss>
