188 lines
3.8 KiB
Markdown
188 lines
3.8 KiB
Markdown
# Plugins
|
|
|
|
VNOX has a plugin system for extending server-side behavior.
|
|
Plugins run on the node, not on the client.
|
|
|
|
---
|
|
|
|
## Supported languages
|
|
|
|
- TypeScript
|
|
- JavaScript
|
|
|
|
---
|
|
|
|
## Runtime
|
|
|
|
**Deno** — chosen as the plugin runtime.
|
|
|
|
Reasons:
|
|
- TypeScript native, no transpile step for plugin authors
|
|
- built-in permissions model — plugins explicitly declare what they need
|
|
- active ecosystem, good Rust embedding via `deno_core`
|
|
|
|
---
|
|
|
|
## API
|
|
|
|
Plugins communicate with the gateway via **WebSocket RPC**.
|
|
The gateway exposes a local WebSocket endpoint that plugins connect to.
|
|
|
|
```
|
|
Plugin process
|
|
│ WebSocket (localhost)
|
|
▼
|
|
Gateway plugin API (localhost:7800)
|
|
```
|
|
|
|
### RPC format
|
|
|
|
```json
|
|
{
|
|
"id": "req-1",
|
|
"method": "channel.send_message",
|
|
"params": {
|
|
"channel_id": "general",
|
|
"content": "Hello from plugin"
|
|
}
|
|
}
|
|
```
|
|
|
|
Response:
|
|
|
|
```json
|
|
{
|
|
"id": "req-1",
|
|
"result": { "message_id": "abc123" }
|
|
}
|
|
```
|
|
|
|
Errors:
|
|
|
|
```json
|
|
{
|
|
"id": "req-1",
|
|
"error": { "code": 403, "message": "permission denied" }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Available methods
|
|
|
|
### Events (subscribe)
|
|
|
|
```typescript
|
|
// Subscribe to all events
|
|
ws.on('message', (event) => {
|
|
const e = JSON.parse(event);
|
|
// e.event, e.data
|
|
});
|
|
```
|
|
|
|
| Event | Payload |
|
|
|-------|---------|
|
|
| `user.join` | `{ user_id, channel_id }` |
|
|
| `user.leave` | `{ user_id, channel_id }` |
|
|
| `message.created` | `{ message_id, channel_id, sender_id, content }` |
|
|
| `voice.speaking` | `{ user_id, channel_id, state }` |
|
|
| `user.muted` | `{ user_id }` |
|
|
|
|
### Commands
|
|
|
|
| Method | Description |
|
|
|--------|-------------|
|
|
| `channel.send_message` | Send a message to a channel |
|
|
| `channel.list` | List all channels |
|
|
| `user.kick` | Kick a user from a channel |
|
|
| `user.mute` | Mute a user (server-side) |
|
|
| `user.ban` | Ban a user by pubkey |
|
|
| `user.get` | Get user info by pubkey |
|
|
| `node.get_stats` | Get node statistics |
|
|
|
|
---
|
|
|
|
## Plugin manifest
|
|
|
|
Each plugin is a directory with a `plugin.json`:
|
|
|
|
```json
|
|
{
|
|
"name": "relay-switcher",
|
|
"version": "0.1.2",
|
|
"author": "raven",
|
|
"description": "Auto-selects the nearest relay node",
|
|
"main": "index.ts",
|
|
"permissions": [
|
|
"node.stats",
|
|
"channel.read"
|
|
]
|
|
}
|
|
```
|
|
|
|
Permissions are declared in the manifest and granted by the node admin.
|
|
A plugin that requests permissions not granted to it will receive `403` on those methods.
|
|
|
|
---
|
|
|
|
## Example plugin
|
|
|
|
A simple moderation bot that deletes messages containing a banned word:
|
|
|
|
```typescript
|
|
// index.ts
|
|
|
|
const ws = new WebSocket("ws://localhost:7800/plugins");
|
|
const BANNED = ["badword"];
|
|
|
|
ws.addEventListener("message", async (event) => {
|
|
const e = JSON.parse(event.data);
|
|
|
|
if (e.event === "message.created") {
|
|
const { message_id, channel_id, content } = e.data;
|
|
const lower = content.toLowerCase();
|
|
|
|
if (BANNED.some(word => lower.includes(word))) {
|
|
await rpc("message.delete", { message_id, channel_id });
|
|
console.log(`Deleted message ${message_id}`);
|
|
}
|
|
}
|
|
});
|
|
|
|
function rpc(method: string, params: object): Promise<any> {
|
|
return new Promise((resolve) => {
|
|
const id = crypto.randomUUID();
|
|
ws.send(JSON.stringify({ id, method, params }));
|
|
ws.addEventListener("message", function handler(e) {
|
|
const res = JSON.parse(e.data);
|
|
if (res.id === id) {
|
|
ws.removeEventListener("message", handler);
|
|
resolve(res.result);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Installing a plugin
|
|
|
|
```bash
|
|
# Copy plugin directory to node's plugin folder
|
|
cp -r my-plugin/ /var/lib/vnox/plugins/
|
|
|
|
# Restart gateway (or use hot-reload if supported)
|
|
systemctl restart vnox-gateway
|
|
```
|
|
|
|
Or via the client: Settings → Plugins → Install → select directory.
|
|
|
|
---
|
|
|
|
## Plugin marketplace
|
|
|
|
A community plugin registry is planned for Phase 3.
|
|
Plugins will be installable directly from the client.
|
|
|
|
Until then, plugins are distributed as source code repositories.
|