Alternate Playground Implementation
The Rust Playground is a web application that allows you to run Rust programs via your browser. It is invaluable to provide an introduction to Rust without needing to install anything at all. It also allows existing Rust users to perform quick experiments and share code with each other.
Because the Playground accepts code from arbitrary users and the code is compiled, executed, and returns results, the Playground needs to be hardened against malicious users.
Because it is a web application, users expect to be able to use it from any modern web-capable device and have it respond in a reasonable amount of time.
These constraints present an interesting challenge to explore, and recently I reimplemented the Playground from scratch.
What prompted you to try reimplementing play.rust-lang.org?
I’m a heavy user of the Playground as a part of my contributions to
the rust
tag on Stack Overflow. As you might guess, a lot of
the questions are asked by newcomers to Rust, so they aren’t familiar
with normal Rust formatting styles, such as those enforced by
rustfmt.
To provide a uniform experience for all the future readers of those questions and answers, I reformat the questions where the style isn’t an integral part of the problem being asked about. This usually means copying the code, pasting it into the Playground, and then clicking Format.
Unfortunately, rustfmt had to be disabled a few weeks ago. Looking into the source to see if I could help bring it back proved to be a bit daunting, as I wasn’t familiar with the sandboxing technology being used at the time, playpen. Additionally, the backend server was written in Python instead of Rust and the frontend was JavaScript without a framework.
I set out with the goal to reimplement the Playground using Docker, Iron, and React.
Since I started, the official Playground has switched to Docker, the server was re-written in Rust, and rustfmt was re-enabled, but I ended up making different choices and enhancements along the way that I’d like to talk about.
What are the advantages and disadvantages of using your Playground over the official one?
The primary advantage of the alternate Playground is the enhancement I made of including crates: the top 100 crates on crates.io are available to be used. This is very important for a language like Rust that encourages placing things into crates, especially for features that other languages might include in a standard library, like random number generation.
Another advantage is my addition of Clippy, an amazing collection of lints that can help catch mistakes and encourages idiomatic Rust. This has proven to be quite useful when I answer questions on Code Review.
There’s also some UI niceties. The text editor can be configured to be a simple text input field; this is more accessible and also works better on mobile devices. Additionally, you can toggle between multiple forms of output, allowing you to view the LLVM IR and assembly output without having to recompile, for example.
There’s also a few disadvantages. The official Playground has support for communicating with it through IRC! This is not a feature that I make much use of, so I didn’t bother porting it over. However, the underlying sandboxing code should be amenable to be exposed through multiple avenues, including IRC.
Other features that I haven’t ported from the official Playground include viewing the MIR of the program and syntax highlighting of the output, including linking to the error documentation and jumping to the offending line for errors. These are great features!
The alternate Playground also runs on much wimpier hardware. At the moment, it’s running on a single EC2 t2.micro instance - also known as the free tier.
What problems did you run into, and how did you end up solving them?
Even for such a new and small project, there were some interesting problems.
Nanosecond-precision filesystem timestamps have bitten me twice, once for Iron and once for Cargo. The filesystem on OS X (HFS+) ignores fractional seconds, and the Docker AUFS filesystem keeps fractional seconds while the container is running, but truncates them between layers. This causes Iron to not properly cache certain static files and Cargo to rebuild crates unnecessarily. The Iron issue was solved by a fork and the Cargo issue was solved by manipulating some cache files.
Like a lot of Rust users, I’m using serde to serialize to and from JSON. This means I really want to use the macro support afforded by a nightly compiler, but a few times I was unable to compile because my nightly and serde had drifted out of sync. While it’s easy to fix with a tool like rustup, it still means I have to wait a few minutes. This was solved by switching to a build script.
Compiling Clippy uses a lot of memory, and the 1 GiB of memory that the free EC2 instance has isn’t enough. This one had me stumped for a few hours until I went to sleep. The next morning I woke up and remembered that swap memory existed. This was solved by adding any swap space at all;
One day I checked the Playground and everything was simply stuck. Investigating further, I found that all the disk space was gone, at which point I learned that one shouldn’t run Docker with the loopback device in production.
And like any good webapp, there has been the usual wresting with HTML and CSS to get exactly what I wanted. Since I’m only worried about supporting newer versions of browsers, this hasn’t been overwhelmingly painful.
Is your Playground secure from abuse?
It’s intended to be, but I’m not a security specialist. Anyone who is interested is highly encouraged to take a look at the code.
When you run a program, the following limits are applied:
-
The network is disabled. You shouldn’t be able to use this as part of a DDOS.
-
The running time and the memory of the program are limited. This is to avoid charges for running the site and to prevent a DOS to other Playground users.
-
The amount of disk space is limited, in a sense. There’s a small loopback device where temporary files are written to, but this is shared among all concurrent users. A malicious user could fill this up, but it should be cleaned up after each request.
The Playground is not currently served over HTTPS, so programs and output are sent in plaintext and could be read by employers or the like.
Are you planning on submitting any of your changes upstream to the official Playground?
My original plan was to produce a Playground that could potentially replace the official one with a newer technology stack. Although both Playgrounds now use mostly the same stack, they have different code bases, so it would be more complicated than just submitting a pull request.
However, I believe that this can actually have a positive outcome. Healthy competition between two great implementations should create a better experience for everyone, and both Playgrounds can always share ideas and techniques with each other.
What are your future plans for your Playground?
There’s no concrete roadmap; I’ve been working on features that are useful to myself or that I can clearly see benefitting a large group of other people. Features that distinguish the alternate Playground from the official one are also good ideas.
Check out the issues list for a complete set, but a quick highlight of possible avenues:
-
A more distinct UI. Since it’s unlikely that this Playground will replace the official Playground, it would probably be a good idea to modify the UI to avoid any confusion between the two.
-
Improve performance. Before adding crates, compilation took about 600 milliseconds of network time, but that’s now crept up to a little over a second. There’s potential for improvement when you aren’t using every possible crate.
-
Add client-side caching. Because performance has previously been very good, there wasn’t much need to have extra layers of caching. However, Redux should make this pretty straight-forward to implement.
-
MIR output and output highlighting. As mentioned above, these are features from the official Playground that I miss.
-
Revisions to the crate process. I picked the top 100 crates because it was a nice, round number. I fully expect to get requests for “please add crate ‘foo’”. It’d be nice to have some more robust process for including crates.
If you have any questions, comments, feedback, or would like to contribute in any way, I’d certainly welcome it. File an issue or contact me on Twitter - @JakeGoulding.
This web application is an example of a type of project that Integer 32 could build for you. If that sounds interesting, please contact us to see how we can work together. Your business might be the one that allows us to upgrade the Playground beyond the free tier!