Oddbean new post about | logout
 Alright, #nostr / #nostrdev folks, I've got my implementation of multipart NIP-95 files up here:

https://github.com/NfNitLoop/yastr/blob/main/src/server/nip95.rs

(Yes, it's very messy. I just saw all the TODOs which I've already done. 😆)

And I've got a little tool to upload multi-part files here: https://github.com/nfnitloop/nostr-cli/  (The `nt upload` command.)

Since clients might not know how to put together multipart files yet, my relay (wss://www.nfnitloop.com/nostr/) also makes them available via HTTP. For example:

https://www.nfnitloop.com/nostr/files/bee3454df946e79724b0ec972242ba2d2e3a1fc185931a7a45def81a5ffb194c/

There is room for space-saving in the storage implementation. If this takes off I'd want to store the BLOBs in binary instead of Base64. And I'd probably want to dedupe whole files so that we don't end up having to store multiple copies of them if multiple people upload them. BUT, that can come later without changing the public interface.

Before *that*, I want to implement HTTP range requests to show that the blockSize metadata allows a client or server to efficiently fetch bytes from a known offset. That way you could, for example, scrub to a certain position in a video without having to download all the bytes up to that point. 
 And now I’ve added HTTP Range support.

❤️ to the axum-range crate which made this much simpler. (Though I did have to delve deeper into Rust async than I have before. But I was happy to learn more there.)

Here’s a sample video which I saw making the rounds on Mastodon earlier this week:

https://nfnitloop.com/nostr/files/fb8e82bed22cf9c8ee39ef2898970beee6fec7ca9068e1506a061f22f5ec1ae7/

Note that only the first part of the video is fetched. You can jump past that and the server will start loading from the exact point you jump to.

The algorithm the server uses to answer these range requests could also be implemented client-side. (Say, as the Blob interface in the browser.) I’m just not implementing a client. (Yet. 😉)