mirror of
https://github.com/HeyPuter/puter.git
synced 2026-05-03 16:10:31 +00:00
dev(extensions): [+] dev-socket
This extensions brings back the dev-socket functionality, which is really important when testing things like broadcast, alarms, events, etc ; it saves a lot of time if you can invoke a command directly to the backend. This is an optional extension that will not be included in production deployments. This is for development purposes only.
This commit is contained in:
@@ -87,3 +87,7 @@ See [events.md](./events.md)
|
||||
## Definitions
|
||||
|
||||
See [definitions.md](./definitions.md)
|
||||
|
||||
## Bundled extensions
|
||||
|
||||
- [dev-console](./dev-console.md) – Dev socket for running backend commands locally (opt-in via `DEVCONSOLE=1`).
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# dev-console extension
|
||||
|
||||
The **dev-console** extension provides a **dev socket** so you can run backend commands on a local Puter instance (e.g. commands registered in [CommandService](../../../src/backend/src/services/CommandService.js)).
|
||||
|
||||
## Enabling
|
||||
|
||||
The extension is **opt-in**. Set the environment variable `DEVCONSOLE=1` when starting Puter. The `npm run dev` script already does this:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
With `DEVCONSOLE=1`, the extension registers a `dev-socket` service that creates a UNIX socket and runs command lines through CommandService.
|
||||
|
||||
## Usage
|
||||
|
||||
See [Backend – dev socket](../../../src/backend/doc/dev_socket.md) for how to connect (e.g. `rlwrap nc -U ./dev.sock`) and run commands like `help`, `logs:indent`, etc.
|
||||
|
||||
## Location
|
||||
|
||||
The extension lives in `extensions/dev-console/`. It only registers the dev-socket service when `DEVCONSOLE=1`; otherwise the extension loads but does nothing, so it does not affect default runs.
|
||||
@@ -1,10 +1,14 @@
|
||||
# Extension System Development Guide]
|
||||
# Extension System Development Guide
|
||||
|
||||
## Where to find documentation
|
||||
|
||||
### Here
|
||||
Documentation for extensions is [here](src/backend/doc/extensions/README.md).
|
||||
|
||||
### Bundled extensions
|
||||
|
||||
- **dev-console** (`extensions/dev-console/`) – Dev socket for running backend commands locally. Opt-in via `DEVCONSOLE=1` (e.g. `npm run dev`). See [Backend – dev socket](src/backend/doc/dev_socket.md).
|
||||
|
||||
### Not Here
|
||||
|
||||
Outdated documentation for extensions is [here](../doc/contributors/extensions/README.md).
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2024-present Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import fs from 'node:fs';
|
||||
import net from 'node:net';
|
||||
import path from 'node:path';
|
||||
|
||||
const SOCKET_NAME = 'dev.sock';
|
||||
const WELCOME = [
|
||||
'Puter dev socket – enter a command (e.g. help) and press Enter.',
|
||||
'Close the connection with Ctrl+C or by typing exit.',
|
||||
'',
|
||||
].join('\n');
|
||||
|
||||
function getSocketDir () {
|
||||
if ( process.env.PUTER_DEV_SOCKET_DIR ) {
|
||||
return process.env.PUTER_DEV_SOCKET_DIR;
|
||||
}
|
||||
const volatileRuntime = path.join(process.cwd(), 'volatile', 'runtime');
|
||||
if ( fs.existsSync(volatileRuntime) ) {
|
||||
return volatileRuntime;
|
||||
}
|
||||
return process.cwd();
|
||||
}
|
||||
|
||||
extension.on('init', async () => {
|
||||
if ( process.env.DEVCONSOLE !== '1' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const commands = extension.import('service:commands');
|
||||
const socketDir = getSocketDir();
|
||||
const socketPath = path.join(socketDir, SOCKET_NAME);
|
||||
|
||||
try {
|
||||
if ( fs.existsSync(socketPath) ) {
|
||||
fs.unlinkSync(socketPath);
|
||||
}
|
||||
fs.mkdirSync(socketDir, { recursive: true });
|
||||
} catch ( err ) {
|
||||
console.warn('dev-socket: could not prepare socket path', socketPath, err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
const server = net.createServer((socket) => {
|
||||
socket.setEncoding('utf8');
|
||||
socket.write(`${WELCOME }\n> `);
|
||||
let buffer = '';
|
||||
socket.on('data', (chunk) => {
|
||||
buffer += chunk;
|
||||
const lines = buffer.split(/\r?\n/);
|
||||
buffer = lines.pop() ?? '';
|
||||
for ( const line of lines ) {
|
||||
const trimmed = line.trim();
|
||||
if ( trimmed === '' ) continue;
|
||||
if ( trimmed.toLowerCase() === 'exit' ) {
|
||||
socket.end();
|
||||
return;
|
||||
}
|
||||
const log = {
|
||||
log: (msg) => {
|
||||
socket.write(`${String(msg) }\n`);
|
||||
},
|
||||
error: (msg) => {
|
||||
socket.write(`${String(msg) }\n`);
|
||||
},
|
||||
};
|
||||
commands.executeRawCommand(trimmed, log).then(() => {
|
||||
socket.write('> ');
|
||||
}).catch((err) => {
|
||||
log.error(err?.message ?? err);
|
||||
socket.write('> ');
|
||||
});
|
||||
}
|
||||
});
|
||||
socket.on('end', () => {
|
||||
});
|
||||
socket.on('error', () => {
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(socketPath, () => {
|
||||
console.log('dev-socket: socket listening at', socketPath);
|
||||
});
|
||||
server.on('error', (err) => {
|
||||
console.warn('dev-socket: socket error', err.message);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "@heyputer/extension-dev-console",
|
||||
"version": "1.0.0",
|
||||
"description": "Dev socket for running backend commands locally (opt-in via DEVCONSOLE=1)",
|
||||
"main": "main.js",
|
||||
"type": "module",
|
||||
"private": true
|
||||
}
|
||||
@@ -1,15 +1,32 @@
|
||||
## Backend - dev socket
|
||||
|
||||
The "dev socket" allows you to interact with Puter's backend by running commands.
|
||||
It's a UNIX socket created in Puter's runtime directory
|
||||
(typically `./volatile/runtime`, or `/var/puter` for production instances).
|
||||
It's a UNIX socket that lets you run commands registered with
|
||||
[CommandService](../../src/services/CommandService.js) (e.g. `help`, `logs:indent`, `params:get`, etc.).
|
||||
|
||||
When in the runtime directory, you can connect to the socket with your tool
|
||||
of choice. For example, using `nc` as well as `rlwrap` to get readline history:
|
||||
### Enabling the dev socket
|
||||
|
||||
The dev socket is provided by the **dev-console extension** and is **opt-in**. To enable it:
|
||||
|
||||
1. Set the environment variable `DEVCONSOLE=1` when starting Puter (e.g. `npm run dev` already does this).
|
||||
2. The extension lives in `extensions/dev-console/` and registers a `dev-socket` service when `DEVCONSOLE=1`.
|
||||
|
||||
### Socket location
|
||||
|
||||
The socket is created in a directory chosen as follows (in order):
|
||||
|
||||
- `PUTER_DEV_SOCKET_DIR` if set
|
||||
- `./volatile/runtime` if it exists (typical local dev)
|
||||
- otherwise the process current working directory
|
||||
|
||||
The socket file is named `dev.sock`.
|
||||
|
||||
### Connecting
|
||||
|
||||
When in that directory, connect with your tool of choice. For example, using `nc` and `rlwrap` for readline history:
|
||||
|
||||
```
|
||||
rlwrap nc -U ./dev.sock
|
||||
```
|
||||
|
||||
If it is successful you will see a message with instructions. At this point
|
||||
you may enter a command. Enter the `help` command to see a list of commands.
|
||||
If it is successful you will see a message with instructions. Enter a command (e.g. `help`) and press Enter.
|
||||
|
||||
@@ -72,6 +72,10 @@ key-value store, and in-memory cache.
|
||||
### Adding Features to Puter
|
||||
- [Implementing Drivers](./pages/drivers.md)
|
||||
|
||||
### Bundled extensions
|
||||
|
||||
- **dev-console** – When `DEVCONSOLE=1` is set (e.g. `npm run dev`), the dev-console extension registers a UNIX socket (`dev.sock`) so you can run backend commands (see [CommandService](../../src/services/CommandService.js)) from a terminal. See [Backend – dev socket](../dev_socket.md).
|
||||
|
||||
## Extensions - Planned Features
|
||||
|
||||
Extensions are under refactor currently. This is the checklist:
|
||||
|
||||
Reference in New Issue
Block a user