Logicboard lets you run a blob of code or start REPL via WebSockets. A typical use case is an in-browser code editor which can run code in multiple languages.
The diagram below shows the overall architecture. Logicboard internally runs your code/REPL in a separate docker container and interacts with it via a pseudoterminal.
When running REPL, you can simply send a stdin
via websocket and receive the stdout
in response.
This project consists of two parts:
- Frontend: A web app with code editor, built in React
- Backend: A websocket server that executes code, built in Elixir + Phoenix
We prefer asdf to manage runtime versions, please take a look at our .tool-versions for supported versions.
Else, please make sure the following languages are installed:
erlang 26.0
elixir 1.14.5
nodejs 16.13.2
yarn 1.22.19
You also need to install docker
to generate language-specific images.
Please make sure docker
is running, then run:
mix setup
This will:
- Build Docker images for each language
- Fetch project dependencies
- Run
mix phx.server
- Visit http://localhost:4000 to launch the code editor
- A WebSocket server will also be started at:
ws://localhost:4000/socket/websocket
Logicboard provides an API to run code via websocket messages (aka Commands)
When connecting to the websocket server, you need to pass a Session ID, eg:
ws://localhost:4000/socket/websocket?session_id=abcd
Once the connection is established, you can start sending commands to run code or start REPL.
When you ask logicboard to run code, it also needs a few other things:
language
: The programming language to use.files
: A list of files with the code to execute.
The files
parameter is used to create a directory structure for your code, think of it as cloning
your repository.
main
(bool): Indicates this is the main file to run.name
(string): Name of the file/directory.directory
(bool): Whether the file is a directory.content
(string or array): For a regular file, this contains the text content of the file. In case of directories, it will contain other files/directories as children.
Consider the run
command below, this will execute the contents of file main.py
and return the result Hello, world!
via stdout
{
"event": "run",
"payload": {
"language": "python_3",
"files": [{
"main": true,
"name": "main.py",
"directory": false,
"content": "print('Hello, world!')"
}]
}
}
Starts an interactive REPL session
{
"event": "repl",
"payload": {
"language": "python",
"files": [{
"main": true,
"name": "main.py",
"directory": false,
"content": "<base 64 encoded>"
}]
}
}
Sends a stdin input to the repl session
{
"event": "stdin",
"payload": {
"body": "help()"
}
}
Output from repl session or, result of a run
command
{
"event": "stdout",
"payload": {
"body": "help()"
}
}
Stops current execution, or a repl session
{
"event": "kill"
}
Sent by the server when an execution/repl is stopped
{
"event": "stop"
}
Of course you can! Logicboard just needs:
- A Docker image to run
- Command to compile your code
- Command to start REPL (optional)
Create a <lang name>.dockerfile
inside containers
Make sure your docker image has bash
installed during build step.
We also need a user app
with home directory /home/app
2. Update languages.ts
The languages.ts
file used by the web app to display a list of lanugaues
Update the languages.ts
with a few details:
name
: Name of your languageversion
: Language versioncode
: Language code - an identifier for your languagerepel
: A boolean to indicate whether your language supports REPLexample
: A sample code that will be populated in the editor when your language is selectedmain_file
: Name of your main filemessage
: A placeholder message that will be displayed in the output area when your language is slected
The <language>.ex
module in languages directory is used by the bakend for code execution. We'll need the following:
name
: The name of your languageversion
Language versioncontainer_image
: Ths function should return the image tag for your container. Use<your docker file name>:executor
run_command
: The command used to execute code in your main filerepl_command
: The command used to start REPL shell (or nil)
Once done, you also need to update the languages.ex module:
- Add your language module to alias
- Add entry to the @modules map, where the
code
is the language code you specified in section #2 above
Containers are not a sandbox, and aren't safe for running arbitrary code, so please be careful!