Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'm Bernard, the creator of lunatic. Great to see us back on HN and happy to answer any questions!

We have been busy pushing out a lot of new stuff. Recently we released a web framework [0] for Rust building on top of lunatic, and a live-view library [1] for crating full stack apps in Rust without JS. For now we are staying close to the Phoenix LiveView implementation, where everything is rendered on the backend and just a diff is sent over websockets to the frontend. But a big advantage of Wasm is that it runs in the browser too, so we hope to leverage this part to move some of the logic directly into the browser, like form checking, or offer a way to create offline-first experiences with the backend running as PWA in a service worker.

[0]: https://github.com/lunatic-solutions/submillisecond

[1]: https://github.com/lunatic-solutions/submillisecond-live-vie...



Wow! I really like this project. I have been loving actor systems, and your project brings a lot of interesting concepts together.

I do not have much of anything to say, but I did come up with an idea. One thing that Fuchsia (operating system) does is that parents are able to lock down the permissions when spawning childs. For example, if a child is spawned with no I/O permissions, that child will have all those permissions removed, and any child that spawns from that will have the same restraints.

Could Lunatic support something like this on the far future?

EDIT: I just read the FAQ and looks to be heading that way. Awesome.


Thanks!

You can already do this in lunatic. For example, in the Rust library you can create a configuration (https://docs.rs/lunatic/latest/lunatic/struct.ProcessConfig....) with specific permissions (e.g. no i/o) and then use the spawn_config function to spawn children with it. Children will automatically inherit the configuration from their parents.

Lunatic is also a bit of a meta-system. We expose a lot of the vm stuff directly to the running wasm instances. So you can in a running wasm modules embed other modules or dynamically load them, then spawn processes from them. At the same time you can use the configurations to limit capabilities of this, potentially untrusted, modules.


Neat. Good luck. I'll paste here the request I keep making again and again:

I want to teach something like Tailscale about my contacts, so they are allowed to communicate with my services (through their services).

Then I want to run an app inside a strong sanbox (maybe Lunatic?) that has capability-based APIs to do things kind of like ZeroMQ for sending messages TO THE CONTACTS. I don't want the API to look like a tcp/ip or udp connection. I want the app to think it's sending a message to a contact I've given it permission to talk to, via some interface that Lunatic itself provides.

If this was running in a strong sandbox, I think this would be an awesome way to develop and use simple federated apps. If something like Mastodon existed on top of this, I'd think it would be really secure and much easier to tell people to stand up their own node...

And I want the whole thing to feel like Sandstorm.io, in that self-updating way, with an app store... But Sandstorm.io is like an Oasis... I want a Federation. And I feel like a Rust-language-implemented WebAssembly sandbox that uses CONTACTS (not TCP) and Messaging, over something like Tailscale for connectivity and encryption, and then a Capability model for storing locally, or talking to a DB, or making external HTTP requests depending on the service, etc...

I want a WebAssembly thin client running on my phone... And a WebAssembly server running on my PC at home. And the server at home runs applets that THINK they're running on my phone (like XWindows, basically). Talking to other applets on my server, which talk to other applets on YOUR server, which talk to applets on your phone. I type a message on my phone, lots of Tailscale happens, and you see the message on your phone. And in my head, there's basically no boilerplate in the code I write. It just looks like Contacts and strongly-typed Messages.

That's the thing I keep wanting.


This is a very cool vision but it sounds like a lot of research, and they probably have many lower-hanging fruit to pick before that!


Ooh, LiveView pattern implementors! I have a question -- I've been tinkering with a custom Phoenix LV client in my 'shop time', so I wanted to ask: are you doing your diffs on a string-based representation, like they do in the internal Phoenix LV protocol? Or are you sending the DOM patches?

In the phx protocol, their diffs depend on having split the render into a tree of 'statics', 'dynamics', 'components', and on each change, that structure is patched, and needs to be recursively zipped to a string, parsed into a DOM, and patches computed against the previous DOM.

I've been playing with a new client as a way of understanding it, and it's definitely a certain amount of work! Fortunately computing 'what needs to change to reconcile 2 html-like DOMs' is a project that's been wrapped into libraries a few times in a few languages (phoenix relies on other people having done that too, via the 'morphdom' library in JS, and Dockyard recently open-sourced an ergonomic Rust library I'm using in my client).

So -- it's a lot of client work, but it optimizes for bandwidth. Cool.

But I've wondered if there could be any benefit to optimizing for granularity of patches, and simpler clients -- by sending 'just the patches', ie the list of DOM operations that cause the desired end state. My intuition is that the bandwidth 'cost' would be prohibitive, because the list of patches required to perform the morph could be quite large for a change that appears small in 'what string has changed' terms. (maybe harder to debug, too? lots of trade-offs)

I just don't have the energy to try it that way too, hehe, on the off chance that my intuition is off base and it'd actually help improve things (simpler clients, and maybe the bandwidth hit wouldn't be too bad?); it'd require deep server changes as well, when up until now I've only been writing a client. So I was curious what approach y'all are taking.

Prior/related art in the Rust space: I know there's a non-Phoenix liveview project, 'dioxus', with a generic DOM liveview implementation that several clients have been created for, by making a state machine that operates on that list of generated Patches; however I don't know what that one sends, whether DOM patches directly, or Phx-style diffs that need to go phxDiff -> zippedUpString -> dom -> morphPatches -> applyToDom.


We take the Phoenix approach of splitting the DOM into static and dynamic parts. In fact, we even re-use the pheonix.js library on the frontend, so we just implement the backend part that speaks the same protocol as Phoenix.

I don't think that sending DOM patches directly would have a significant higher bandwidth cost, but it would have higher "implementation" cost for us. That's why we choose to just use an existing "battle tested" library.


Oh, hey that's great! So in your case, you're re-using the Phoenix client, and thus the Phoenix protocol lives on so as not to break that. Makes sense.

Thanks for the answer -- the current SDUI renaissance is a beautiful thing. Cheers :)

Didn't mean to distract from the main discussion either -- pre-emption is something that more people should want, I think, so y'all making it the default for WASM stuff feels super valuable. And surely the sandboxing is really valuable to some people too. (But day-to-day I probably won't use Lunatic, whereas LiveView-based SDUI is my current shop-time project).


I have implemented a VDOM in Ruby which I use to send patches to the browser. It works really well.

I'm currently playing around with signals as in SolidJS. That would result in more granular updates, but it's not as easy to implement.


Cool -- not to pry, but I'd be interested in looking at that if it's public somewhere! Could update my intuition.


Sure! https://github.com/mayu-live/framework

There's lots of things to do until it's useful for anything real, and some parts are quite messy, but I think it's a pretty good approach.


I'm curious about this part:

> This allows it to decide on a per process basis what syscalls are going to be forwarded to the operating systems.

1. Which system calls are being referred to here?

2. Does Lunatic follow WASI's capability-based filesystem access?


1. You can limit almost anything, file system usage (fopen, write, ...), networking i/o, how much memory can be used, message sending, the capability of spawning child processes, etc.

2. Yes


How are you going to implement hot reloading, or when can we expect it to be ready?


Hot reloading is always a pit tricky. The programming model needs to explicitly support it. In lunatic it will consist of 2 parts:

1. Stuff inside the vm that lets you keep the process id and message queue, but replaces the code running.

2. Higher level libraries that allows you to preserve state when the code is reloaded and potentially do state modification so that the newly loaded code can continue operating on the existing state.

This is fairly similar to how Erlang does it and I think it's a good approach for most use cases.


Has anyone written an OTP library on top of it?


We expose some OTP constructs in the lunatic Rust library directly, like supervisors (https://docs.rs/lunatic/0.12.1/lunatic/supervisor/trait.Supe...), gen_server (https://docs.rs/lunatic/0.12.1/lunatic/process/trait.Abstrac...) and others.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: