Show HN: I wrote a BitTorrent Client from scratch
193 piyushgupta53 52 6/13/2025, 5:08:05 AM github.com ↗
I picked up programming in late 2023 and been enjoying it now. Wanted to challenge myself and set a stretch goal, so set out to build a bittorrent client.
[0]: kaitai.io
Suggestion: Add a simple usage one liner in the README on how to actually download a .torrent file with it.
Suggestion: Bonus points if you add torrent.ParseFromUrlEveryone should do this for their own spiritual journey.
https://app.codecrafters.io/courses/bittorrent/overview
EDIT: It seems like it was deprecated 10 months ago
https://github.com/golang/go/issues/64622
There are always trade-offs/sacrifices.
The Go team isn't making new versions just for fun. Each version since 1.21 has had improvements. Especially the fix/change to for loop variables in 1.22 is very nice to have, and helps preventing to write bugs.
If there's a reasonable expectation that users will use outdated platforms, it makes sense to support them. If there is no such expectation at all, why would one forego the improvements to the language and tooling.
There's always a price to pay.
[1] https://github.com/piyushgupta53/go-torrent-client/blob/6130...
[2] https://go.dev/doc/modules/gomod-ref#go-notes
This brings me back to college. We did this as our final project for our networking class at Georgia Tech.
I've long lost the code for this, but the lessons learned have lived on :)
Projects like these are great ways to learn new languages too!
So the first step is to figure out if there is an actual spec for the protocol. Well, in the case of Bittorrent there is a spec, but it's kinda... brief. Basically, this is the spec: https://www.bittorrent.org/beps/bep_0003.html
There are some additional extensions here: https://www.bittorrent.org/beps/bep_0000.html
It's very important to break the work up in tiny steps that each give some kind of a result. E.g. I started with parsing .torrent files, for which you have to implement bencoding.
That was interesting, because I downloaded the Arch Linux .torrent and found out it was basically incorrect: it has a url-list key which isn't mentioned in the spec. Then you have to go down a rabbit hole of some research trying to find out what the heck is up with that (turned out to be https://www.bittorrent.org/beps/bep_0019.html). Finally, was able to successfully parse the Debian Linux .torrent file.
Then came implementing the tracker Announce HTTP request and the peer protocol. The peer protocol was tricky, and that's when an experimentation mindset comes in handy. I stripped the announce URL from the Debian torrent and loaded it up in KTorrent, that way it wasn't able to find any peers. I used the "Add peer" option to add my client so I could see what messages it was sending me, and alongside I would implement sending those to KTorrent messages too. A lot of trial and error and debugging.
I have to confess that from time to time I had to ask ChatGPT about some small protocol details because they just didn't show up in the spec. There's also a lot of details that clients have implemented over time but which aren't really documented well. Mostly algorithms for which pieces to download, which peers to choose, how to "choke"/"unchoke", etc, is not well-defined. But web searches help out a lot.
Also an honorable mention to https://wiki.theory.org/Main_Page which has some nice information.
I'm now at a point where I can fully download and upload a torrent with my local KTorrent, so the next steps are to actually get peers from the tracker, and some algorithm to download pieces and store them in a file.
Hope this gives some insights. Let me know if you have specific questions about the process.
Edit: ah, planned feature
My personal favourite is an ImGui wrapper https://github.com/AllenDang/giu
The most featureful is probably unison, although I'm uncertain if anyone uses it outside of their own project (https://gurpscharactersheet.com), meaning documentation will be sparse https://github.com/richardwilkes/unison
Gio uses a different way of thinking about GUIs, used by Tailscale and gotraceui https://gioui.org
Wails is great if you're familiar with development on the web https://wails.io
The GTK4 bindings also look nice https://github.com/diamondburned/gotk4
Cogent Core also looks neat, but I didn't have the time to play with it before I switched over to using the Odin programming language instead of Go https://www.cogentcore.org/core
I personally had nothing but issues with Fyne (especially in regard to performance, across multiple computers and operating systems), but it's probably the most popular option https://fyne.io
Last week I came across these Qt bindings: https://github.com/mappu/miqt
I have no personal experience with it yet, but am excited to try it out.
I’m guessing the main obstacle for me has always been that I’m not sure what the complete list of features is to have a client that will just work for the majority of torrents in the wild. It seems like there are dozens of protocols associated with torrenting and I don’t even know what the full list is much less what each does.
If you're interested, the main Bittorrent spec is actually quite small, you can easily read and understand it in an hour or so: https://www.bittorrent.org/beps/bep_0003.html
There's a lot of stuff "around" Bittorrent, like protocol extensions. But in my experience so far, many clients have different levels of support. E.g. they would try communicating using Protocol Encryption (obfuscation, actually) and if it doesn't work fall back to the regular protocol (if configured in the settings).
If you just want to download a Linux distribution (e.g. Debian) using the .torrent file on their website, it's relatively straight forward. It has just one file, there's a tracker, plenty of peers using the regular protocol, and you could get away not listening for connections when you're behind a NAT.
Naturally when you get into the grey area of content, then you'd need to parse magnet links, use DHT to discover peers, and perhaps you'd want to implement UPnP to try and automatically map a port on your modem. But that is also an iterative process, you can just build out one by one. The more features, the more peers you'll be able to discover and have successful exchanges with.
Magnet and DHT are yet to be added.
Would you like more information about how to identify AI comments? (kidding)
I think it’s a reasonable hypothesis that “I wrote a BitTorrent client from scratch” may be “I produced a BitTorrent client from cursor”.
I've been writing code for 15+ years, this made me laugh my ass off. Comments are great, I don't read comments but I write them for others, especially for open source code. Atoi may be something you and I and a whole bunch of others know but people who don't it's a fine comment. Relax! :)
But, of course, this was vibe coded, so it's unlikely a human actually reviewed it.
You can see here for example: https://github.com/piyushgupta53/go-torrent-client/commit/61...
and some strings coming from crawled resources like: lengthi12345e4 but slightly different tokens (like 25 instead of 35 etc).
Gemini Pro 2.5 even gave me the prompt:
> If you asked me, "Generate Go unit tests for a Bencode decoder function called Decode that takes an io.Reader and returns an interface{} and an error. Cover strings, integers, lists, and dictionaries, including common error cases and nested structures" the output I would strive to produce would look very much like the code you've shown.
> It's a good example of well-written Go tests, and that's the kind of pattern I've learned to recognize and replicate.
and a lot actually matches when you ask from a fresh conversation.
So most likely Cursor + Gemini 2.5 Pro, but I cannot blame, I spend 100% of my time with Claude, and I take ownership of the code.
It's hard to say honestly. I don't call any project AI as it's just too hard to tell. I write lots of comments in my code too so it's hard to call anything AI without a person stating they used it.
Claude is decent for sure, but I always say with AI, learn the math before jumping to a calculator.
Using P2P networks in download-only mode, so called leeching or free-riding, is discouraged.
No comments yet
No comments yet