File size: 3,826 Bytes
563b757
 
 
 
 
 
5fa0cf6
 
 
563b757
 
5fa0cf6
 
563b757
 
5fa0cf6
 
 
 
 
 
563b757
 
5fa0cf6
 
563b757
 
 
 
 
 
 
 
5fa0cf6
 
 
563b757
5fa0cf6
563b757
 
 
5fa0cf6
 
 
 
 
563b757
 
 
 
5fa0cf6
 
6f5f964
 
5fa0cf6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
563b757
 
 
5fa0cf6
 
 
 
 
 
563b757
 
 
5fa0cf6
cdcbf0a
 
563b757
 
 
5fa0cf6
 
 
 
 
 
 
563b757
 
 
5fa0cf6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import express, { Request, Response, NextFunction } from 'express';
import { spawn, execSync, ChildProcess } from 'child_process';
import fs from 'fs';
import path from 'path';

interface BotProcess {
    child: ChildProcess;
    tempDir: string;
    startedAt: number;
}
interface Command {
    filename: string;
    content: string;
}
interface RunRequestBody {
    botId: string;
    discordId: string;
    envFile: string;
    zbrJson: string;
    commands: Command[];
    dbBase64: string;
}
interface StopRequestBody {
    botId: string;
    discordId: string;
}

const app = express();
app.use(express.json({ limit: '10mb' }));
const ZBR_SECRET = process.env.ZBR_SECRET;
const processes = new Map<string, BotProcess>();

try {
    const version = execSync('/usr/local/bin/zbr --version').toString().trim();
    const size = execSync('wc -c < /usr/local/bin/zbr').toString().trim();
    console.log('ZBR binary version:', version, '| size:', size, 'bytes');
} catch (e) {
    console.error("Failed to execute ZBR binary:", e);
}

const auth = (req: Request, res: Response, next: NextFunction): void | Response => {
    if (req.path === '/health') return next();
    if (req.headers['x-zbr-secret'] !== ZBR_SECRET) {
        return res.status(401).send('Unauthorized');
    }
    next();
};
app.use(auth);

app.post('/run', (req: Request<{}, any, RunRequestBody>, res: Response) => {
    const { botId, discordId, envFile, zbrJson, commands, dbBase64 } = req.body;
    const key = `${discordId}-${botId}`;
    const userHasRunningBot = Array.from(processes.keys()).some(k => k.startsWith(`${discordId}-`));
    if (userHasRunningBot) return res.status(400).send('You already have a bot running. Stop it before starting another.');
    if (processes.has(key)) return res.status(400).send('Bot already running');
    const tempDir = `/tmp/zbr-${discordId}-${botId}`;
    fs.mkdirSync(tempDir, { recursive: true });
    fs.writeFileSync(path.join(tempDir, '.env'), envFile);
    fs.writeFileSync(path.join(tempDir, 'zbr.json'), zbrJson);
    const commandsDir = path.join(tempDir, 'commands');
    fs.mkdirSync(commandsDir, { recursive: true });
    commands.forEach(cmd => {
        fs.writeFileSync(path.join(commandsDir, cmd.filename), cmd.content);
    });
    fs.writeFileSync(path.join(tempDir, 'zbr.db'), Buffer.from(dbBase64, 'base64'));
    const child = spawn('/usr/local/bin/zbr', [], {
        cwd: tempDir,
        stdio: ['ignore', 'pipe', 'pipe']
    });
    if (child.stdout) {
        child.stdout.on('data', (data) => console.log(data.toString()));
    }
    if (child.stderr) {
        child.stderr.on('data', (data) => console.error(data.toString()));
    }
    processes.set(key, { child, tempDir, startedAt: Date.now() });
    setTimeout(() => {
        if (processes.has(key)) stopBot(key);
    }, 2 * 60 * 60 * 1000);
    res.json({ success: true, status: 'running' });
});

function stopBot(key: string): boolean {
    const proc = processes.get(key);
    if (!proc) return false;
    proc.child.kill();
    fs.rmSync(proc.tempDir, { recursive: true, force: true });
    processes.delete(key);
    return true;
}

app.post('/stop', (req: Request<{}, any, StopRequestBody>, res: Response) => {
    const { botId, discordId } = req.body;
    stopBot(`${discordId}-${botId}`);
    res.json({ success: true, status: 'stopped' });
});

app.get('/status/:discordId/:botId', (req: Request, res: Response) => {
    const { discordId, botId } = req.params;
    const proc = processes.get(`${discordId}-${botId}`);
    if (proc) {
        res.json({ status: 'running', startedAt: proc.startedAt });
    } else {
        res.json({ status: 'stopped' });
    }
});

app.get('/health', (req: Request, res: Response) => res.json({ ok: true }));
app.listen(7860, () => console.log('Server running on port 7860'));