diff --git a/_posts/2024-06-04-playground-for-hare.md b/_posts/2024-06-04-playground-for-hare.md new file mode 100644 index 0000000..cf7871d --- /dev/null +++ b/_posts/2024-06-04-playground-for-hare.md @@ -0,0 +1,135 @@ +--- +permalink: "/{{ year }}/{{ month }}/{{ day }}/playground-for-hare" +title: "A playground for Hare" +published_date: "2024-06-04 22:59:00 +0200" +layout: post.liquid +data: + route: blog +excerpt: | + I built an online for the programming language Hare in Hare. + Why? Because I wanted to do something fun and learn Hare. + How? By using some existing libraries and writing the rest myself. +--- + +I built a thing: + +
+ +### [Hare Playground][playground] + +
+ +And this is what it looks like:[^1] + +![Screenshot of the Hare Playground, the default code example on the left, the out to the right](https://tmp.fnordig.de/blog/2024/hare-playground.png) + +It's an online playground for the [Hare programming language][harelang]. +Code is sent to the server for compilation and execution. +It responds with the standard and error output serialized into JSON, which gets rendered in the output box in the frontend. +This works just the same as [other](https://go.dev/play/) [playgrounds](https://play.rust-lang.org/). + +It's a bit slow and might crash on you, but it works (if it doesn't: reload). + +## Why? + +Because I wanted to do something fun and learn Hare. +Hare is a rather new systems programming language (started in 2020) that's inspired by C, +but promises to do few things better. +The original blog post [Hare's advances compared to C][advances-on-c] has a good overview on that. + +This project gave me the opportunity to explore a couple of areas in Hare, +read through the documentation and the Hare codebase and even fix a few bugs in existing code. + +I might write another more detailed blog post on my impressions. +For now I can say that it was a few fun nights learning and exploring a new language. + +## How? + +The whole codebase is [in the hare-playground repository][hare-playground]. +In about 500 lines of my own code plus 3 external libraries I implemented the webserver part, +including routing and static file serving. +I bet it has memory leaks. + +```c +fn route_request(buf: *io::stream, serv_req: *http::server_request) (void | http_err) = { + let request = &serv_req.request; + switch (request.method) { + case "GET" => + switch (request.target.path) { + case "/" => handle_index(buf, serv_req); + case => + handle_file(buf, serv_req)?; + return; + }; + case "POST" => + switch (request.target.path) { + case "/v1/exec" => handle_exec(buf, serv_req)?; + case => return notfound; + }; + case "OPTIONS" => + handle_cors(serv_req); + return; + case => return notfound; + }; +}; +``` +> The "router" part of the webserver[^2] + +The external libraries I pulled in are: +1. [hare-logfmt] for formatted logging messages (though I only log the minimum). +1. [hare-json] for parsing from and serializing to JSON (unmodified from upstream). +1. [hare-http] for the webserver parts: listening on a socket, parsing HTTP, creating the request and response objects. +I added a couple of commits to fix some issues (available in [my fork](https://git.fnordig.de/jer/hare-http/commits/branch/host-in-uri), I'll upstream them). + +I also wrote a [small wrapper around pthread](https://git.fnordig.de/jer/hare-playground/src/branch/main/vendor/hare-thread/thread/thread.ha), +just so my server can handle more than one request at a time. + +To run the user-submitted Hare code the server launches `hare` in a [bubblewrap][] sandbox. +This should make it somewhat safe to deal with arbitrary input. +The whole thing runs in a VM on [fly.io], +so even if a sandbox escape is possible the worst an attacker can do is break the VM and ruin the playground for others. + +The whole backend even works on macOS (without the sandbox, _do not run in production!_), +thanks to the [Darwin port of Hare](https://github.com/hshq/harelang) (and some of [my own fixes on top](https://github.com/hshq/harelang/compare/master...badboy:harelang:master)). +I wrapped that in a [Nix flake](https://git.fnordig.de/jer/hare-nix) for easy installation. +`nix develop` is all you need in the playground repository. + +The frontend is some basic HTML[^3], a couple of lines of JavaScript and [htmx]. +The code editor is [Codejar], a small one-file editor implementation. +Code highlighting is handled by [highlight.js] +No JavaScript transpiler or bundler needed. +And yes, I use htmx, but still return JSON from the server and add it to the DOM using JavaScript in the right places. +I'd rather not do the whole HTML escape in Hare right now server-side. +Initially I built this using the JavaScript parts of [codapi], +but I ended up rolling it myself using htmx, +as that gives me more freedom placing & styling the button elements and controlling the output. + +## Production when? + +I will keep the playground running on Fly (for now). +I do not plan to work on it much further. +This is after all a playground for me to learn the language a bit and not a more serious long-term project. +The code is open-source ([MPL licensed](https://git.fnordig.de/jer/hare-playground/src/branch/main/COPYING)). + +[playground]: https://hare-exec.fly.dev/ +[harelang]: https://harelang.org/ +[advances-on-c]: https://harelang.org/blog/2021-02-09-hare-advances-on-c/ +[hare-playground]: https://git.fnordig.de/jer/hare-playground +[bubblewrap]: https://github.com/containers/bubblewrap +[fly.io]: https://fly.io/ +[hare-nix]: https://git.fnordig.de/jer/hare-nix +[htmx]: https://htmx.org/ +[codapi]: https://codapi.org/ +[hare-http]: https://git.sr.ht/~sircmpwn/hare-http +[hare-json]: https://git.sr.ht/~sircmpwn/hare-json/ +[hare-logfmt]: https://git.sr.ht/~blainsmith/hare-logfmt +[codejar]: https://medv.io/codejar/ +[highlight.js]: https://highlightjs.org/ + +--- + +_Footnotes:_ + +[^1]: Sorry, no dark mode yet. +[^2]: The syntax highlighter on this site doesn't know about hare, so this code is tagged as C. +[^3]: Thanks to [Dennis](https://overengineer.dev/) for showing me how simple Flexbox is to use.