I am working on a project that should be extensible with plugins. I am not fully sure what would be a good solution to write a plugin extensible project with Rust. I was wondering if some people have experience or ideas about this subject. I have never done something like this before, so any help is appreciated.
- The main program is an executable (Compiled from Rust code), and it exposes a pretty small set of API messages.
- Users should be able to create plugins in any language they like (Not only Rust), so a plugin should be some executable file on the filesystem.
- The plugins system should be cross platform. To be more specific, I want it to work on Linux, Android and Windows.
- The communication between the plugin and the main program has to be secure. (Can not be read or intercepted).
In the first development iteration I wrote sockets interface. This approach is very generic, but the main problem I have with it is that it feels like a system with too many moving parts:
To add a new plugin, the user needs to register a new public key in the main program’s configuration file, then add a private key for the plugin and put it somewhere safe. Finally the user runs the main program, and then runs the plugin. The plugin then connects to the program and authenticates itself using his private key. I I can’t expect a non technical user to go through this process.
My current idea is as follows: The program will contain a configuration file with a list of paths to plugins:
- Plugin1: /path/to/plugin1 + flags?
- Plugin2: /path/to/plugin2 + flags?
When run, the main program will first initialize itself, and then spawn the plugins as processes. To make the communication secure I thought about some ideas:
Socket + secret private key: The main program generates a private key and somehow passes it securely to the plugin. Then the plugin will connect using a socket to the main program. This method saves lots of configuration effort from the user, as described above. However, I couldn’t find a cross platform way to pass the secret private key to the spawned plugin process. I checked some ideas like passing the secret information using command line arguments or environment variables but they seem to be insecure. I also checked the idea of using a temporary file to pass the information, but I am not sure how to use this method securely on all the mentioned platforms (Especially on windows).
Using stdin/stdout: The main program spawns the plugin as a new process, and uses stdin/stdout to communicate with the plugin. When the i/o closes, the plugin closes itself gracefully. I am pretty sure that the stdin/stdout idea works on linux and has reasonable Rust interface (https://doc.rust-lang.org/std/process/struct.Command.html), but I couldn’t understand if this will work on Windows. I’m also not sure if this is expected to work on Android. One more thing I’m not sure about is whether this method is secure for communication.
I like the second idea (stdin/stdout) more at this point, but of course, I might be missing something.
Regarding serialization: I’m using Cap’n proto. This is what I used for the rest of the sockets code, and I thought it should probably work well with any other kind of communication.
If you have some experience with this kind of plugins architecture or have any ideas about what I wrote above I will be very happy to know about it!