Entwickler baut minimalistischen Gemini-Client fuer den Mini Micro
In Anlehnung an Joe Strouts Multiplayer-Starter fuer den Mini Micro hat ein Entwickler einen einfachen Gemini-Client fuer die Retro-Plattform umgesetzt. Das Projekt beschreibt Schritt fuer Schritt die Umsetzung des Netzwerkprotokolls.

Ich habe vor Kurzem Joe Strouts Artikel ueber einen Multiplayer-Netzwerk-Starter fuer Mini Micro gelesen, und das hat mich an ein Projekt erinnert, das ich letzten Monat abgeschlossen habe. Deshalb dachte ich mir, ich schreibe dieses Projekt aus, in einem aehnlichen Stil wie mein letzter dev.to-Artikel ueber die Portierung von MiniScript auf Cosmopolitan Libc.
Um die paar Absaetze, die ich in meinem letzten Artikel MiniScript gewidmet habe, auf einen kuerzeren zu verdichten: MiniScript wurde 2016 von Joe Strout erfunden und 2017 als neue Anfaengersprache veroeffentlicht, um Kindern das Programmieren beizubringen. MiniScripts Sprachreferenz passt auf eine Seite eines US-Letter-Blatts, und die Referenz fuer Mini Micro, quasi die "Killer-App" von MiniScript, benoetigt nur drei weitere Seiten (wobei die letzte Seite dieses PDFs das Einseitendokument fuer MiniScript selbst ist).
Gemini wiederum beschreibt sich selbst wie folgt:
Gemini ist eine neue Internettechnologie, die eine elektronische Bibliothek miteinander verbundener Textdokumente unterstuetzt. Das ist keine neue Idee, aber sie ist auch nicht veraltet. Sie ist zeitlos und verdient Werkzeuge, die sie als eigenstaendiges Konzept ersten Ranges behandeln und nicht als ueberbleibselhaften Sonderfall. Gemini geht es nicht um Innovation oder Disruption, sondern darum, jenen eine kleine Erholung zu goennen, die das Gefuehl haben, das Internet sei bereits genug disruptiert worden. Wir wollen nicht die Welt veraendern oder andere Technologien zerstoeren. Wir wollen einen leichtgewichtigen Online-Raum schaffen, in dem Dokumente einfach nur Dokumente sind, im Interesse der Privatsphaere, der Aufmerksamkeit und der Bandbreite jedes Lesers.
Eine Anfrage in Gemini besteht aus einer URL gefolgt von einem CRLF, nicht mehr und nicht weniger. Eine Antwort besteht aus einem zweistelligen Statuscode, einer "Meta"-Zeile und dem Antwortkoerper. Es ist bewusst ein sehr einfaches Protokoll; es gibt keine Moeglichkeit, jemanden zu verfolgen, der nicht verfolgt werden moechte (Gemini verwendet TLS-Client-Zertifikate fuer Faelle, in denen ein kontoaehnliches System gewuenscht ist), und keine Moeglichkeit, ein solches System hinzuzufuegen, ohne die Kompatibilitaet mit aelteren Clients zu brechen.
Eine einfache Programmiersprache und ein einfaches Netzwerkprotokoll, das klingt wie eine himmlische Paarung!
Mithilfe eines einfachen Proxy-Servers zusammen mit einem in Mini Micro laufenden Client kann man mit seinem Mini Micro den Gemini-Space durchstoebern. Es gibt einige Einschraenkungen (nur gemtext und Bilder werden korrekt angezeigt, es gibt weder Unterstuetzung fuer Client-Zertifikate noch fuer Server Certificate Pinning), aber es ist genug implementiert, um einen kurzen Streifzug durch den grundlegenden Geminispace zu unternehmen.
Wenn man eine Gemini-URL eingibt oder einem Link folgt, fuehrt Mini Micro die startup.ms aus, also dieselbe Datei, die Mini Micro beim Start ohnehin ausfuehrt. Darin laeuft ein kleines Codefragment, das die URL beim daneben laufenden Proxy-Server anfordert und dann an ein weiteres Skript weiterleitet, das die jeweilige Antwort verarbeitet (es zeigt die Antwort fuer den Status 20 an bzw. Fehlerbildschirme fuer 4x, 5x oder 6x).
Das Gemini-Protokoll ist, wie oben erwaehnt, ein einfaches Protokoll. Es laeuft auf rohen Sockets, die mit TLS verschluesselt sind. Leider bietet Mini Micro keine Unterstuetzung fuer rohe Sockets, geschweige denn dafuer, diese mit TLS zu umhuellen.
Was Mini Micro unterstuetzt, sind synchrone HTTP-Anfragen. Die Loesung ist also einfach: ein einfaches Python-Skript schreiben, das HTTP-Anfragen entgegennimmt und sie in Gemini konvertiert.
Der Proxy, der in weniger als 100 Zeilen Code implementiert ist, parst die Gemini-URL aus dem HTTP-Anfragepfad, fuehrt die Gemini-Anfrage durch und gibt an Mini Micro dann einen binaeren Blob zurueck, der die kanonische URL, die Gemini-Header-Zeile (Status und Meta) sowie den Body der Antwort enthaelt.
Der Grund, warum wir all diese Daten als binaeren Blob zurueckgeben muessen, liegt darin, dass die HTTP-Unterstuetzung von Mini Micro zugegebenermassen recht begrenzt ist. Sie unterstuetzt lediglich das Abrufen einer Ressource von einem entfernten Server, und im Programm erhaelt man entweder die Ressource zurueck (interpretiert, wie Mini Micro es fuer passend haelt) oder null, falls bei der Kommunikation zwischen Mini Micro und dem Server ein Fehler auftrat. Der Proxy gibt daher den binaeren Blob zurueck, den Mini Micro als RawData interpretiert, ein Objekt, das eigens zur Manipulation binaerer Daten geschaffen wurde, und wir koennen die einzelnen Felder daraus selbst herausparsen.
Die chrome://-Seiten loesen tatsaechlich keine Anfrage beim Proxy aus; stattdessen fuehren sie eine kleine MiniScript-Funktion aus, die entweder eine lokale Datei zurueckgibt (im Fall von chrome://homepage/*) oder intern zusaetzliche Logik ausfuehrt (im Fall von chrome://bookmarks/*). So kann die interne Logik gleich bleiben: Es wird immer dieselbe utils.request-Funktion aufgerufen, unabhaengig davon, ob man eine Gemini-URL oder eine chrome://-URL uebergibt, und die Antwort dieser Funktion wird auf dieselbe Weise verarbeitet.
Das hat zudem den sekundaeren Vorteil, dass ein neuer Nutzer nicht sofort auf einen Fehlerbildschirm geworfen wird, wenn er den Proxy nicht laufen laesst, da die Startseite als chrome://-URL implementiert ist.
Ehrlich gesagt, im grossen Ganzen betrachtet, ist es das wahrscheinlich nicht. MiniScript ist ziemlich nischig, und Gemini ist es auch. Aber fuer die Handvoll Menschen, die beides moegen, mich eingeschlossen, ist es schoen, sie kombinieren zu koennen.
Automatisch übersetzt. Das Original auf Englisch ist unten aufklappbar.
Original (Englisch) anzeigen
I recently read Joe Strout's article on a multiplayer network starter for Mini Micro, and it reminded me of a project I finished up last month, so I figured I'd write that project up, in a similar style to my last dev.to article on porting MiniScript to Cosmopolitan Libc.
To make the couple paragraphs I spent on MiniScript in my last article into one shorter one, MiniScript was invented by Joe Strout in 2016 and released in 2017 as a new beginner language for teaching kids how to code. MiniScript's language reference fits on one side of a sheet of US Letter paper and the reference for Mini Micro, the "killer app" of MiniScript so to speak, only takes 3 more pages (the last page of that PDF being the one-pager for MiniScript itself).
Gemini, on the other hand, describes itself as follows:
Gemini is a new internet technology supporting an electronic library of interconnected text documents. That's not a new idea, but it's not old fashioned either. It's timeless, and deserves tools which treat it as a first class concept, not a vestigial corner case. Gemini isn't about innovation or disruption, it's about providing some respite for those who feel the internet has been disrupted enough already. We're not out to change the world or destroy other technologies. We are out to build a lightweight online space where documents are just documents, in the interests of every reader's privacy, attention and bandwidth.
A request in Gemini is a URL followed by a CRLF--nothing more, nothing less. A response is a 2-digit status code, a "meta" line, and then the response body. It's a very simple protocol by design; there are no ways to track someone unless they want to be tracked--Gemini uses TLS client certificates for cases where you'd want to have an account-like system--and no ways to add such a system without breaking compatibility with older clients.
A simple programming language, and a simple network protocol... seems like a match made in heaven!
Using a simple proxy server alongside a client running in Mini Micro, you can browse Gemini space using your Mini Micro. There are some limitations (only gemtext and images are properly displayed, there's no client certificate support nor server certificate pinning), but enough is implemented for a quick browse of basic Geminispace.
When you type in a Gemini URL or follow a link, Mini Micro runs startup.ms -- the same file Mini Micro would naturally run on boot. This runs a small code snippet which requests the URL from the proxy server you run alongside it and then dispatches to another script which handles the specific response (displaying the response for 20, or showing error screens for 4x, 5x, or 6x ).
The Gemini protocol is, as I said above, a simple protocol. It runs on raw sockets encrypted with TLS. Unfortunately, Mini Micro doesn't provide support for raw sockets, let alone wrapping them with TLS.
What Mini Micro does support is synchronous HTTP requests. So the fix is simple: write a simple Python script to take HTTP requests and convert them to Gemini.
The proxy, implemented in less than 100 lines of code, parses the gemini URL from the HTTP request path, makes the Gemini request, and then returns to Mini Micro a binary blob containing the canonical URL, the Gemini header line (status and meta), and the body of the response.
The reason we have to return a binary blob with all of this data is because Mini Micro's HTTP support is admittedly quite limited. All it supports is retrieving some resource from a remote server, and all you get back in your program is either the resource (interpreted as Mini Micro sees fit), or null, if there was some error communicating between Mini Micro and the server. As such, the proxy returns the binary blob, which Mini Micro interprets as a RawData, an object specifically made for manipulating binary data, and we can parse the separate fields from it ourselves.
The chrome:// pages don't actually trigger a request on the proxy; instead, they run a small MiniScript function, which either returns a local file (in the case of chrome://homepage/* ) or does some extra logic internally (in the case of chrome://bookmarks/* ). This lets the internal logic stay the same; the same utils.request function gets called whether you're passing a Gemini URL or a chrome:// URL, and the response from that function gets handled in the same way.
This also has the secondary benefit of not immediately dropping a new user into an error screen if they aren't running the proxy, since the homepage is implemented as a chrome:// URL.
To be honest, in the grand scheme of things, it probably isn't. MiniScript is pretty niche, and so is Gemini. But for the handful of people who like both--like myself--it's neat to be able to combine them.