File size: 2,711 Bytes
05026f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
const Docker = require('dockerode');
const fs = require('fs');

let docker;
try {
    docker = new Docker();
} catch (e) {
    console.warn('Docker not available — container features disabled');
}

async function getOrCreateContainer(projectId, userId, workDir) {
    if (!docker) throw new Error('Docker not available');

    const name = `indus-${projectId}`;

    // Check if already running
    try {
        const container = docker.getContainer(name);
        const info = await container.inspect();
        if (info.State.Running) return container;
        await container.start();
        return container;
    } catch (e) {
        // Container doesn't exist yet
    }

    // Create workspace directory on host
    fs.mkdirSync(workDir, { recursive: true });

    // Create fresh container
    const container = await docker.createContainer({
        Image: 'indus-base:latest',
        name,
        Tty: true,
        OpenStdin: true,
        WorkingDir: '/workspace',
        HostConfig: {
            Memory: 512 * 1024 * 1024,       // 512MB RAM
            MemorySwap: 512 * 1024 * 1024,   // No swap
            CpuQuota: 50000,                 // 50% of one CPU
            NetworkMode: 'bridge',
            Binds: [`${workDir}:/workspace`], // Mount user files
            AutoRemove: false,
        },
    });

    await container.start();
    console.log(`Container created: ${name}`);
    return container;
}

async function stopContainer(projectId) {
    if (!docker) return;
    try {
        const container = docker.getContainer(`indus-${projectId}`);
        await container.stop({ t: 5 });
        console.log(`Container stopped: indus-${projectId}`);
    } catch (e) { }
}

async function removeContainer(projectId) {
    if (!docker) return;
    try {
        const container = docker.getContainer(`indus-${projectId}`);
        await container.remove({ force: true });
        console.log(`Container removed: indus-${projectId}`);
    } catch (e) { }
}

async function execInContainer(projectId, command) {
    if (!docker) throw new Error('Docker not available');

    const container = docker.getContainer(`indus-${projectId}`);
    const exec = await container.exec({
        Cmd: ['bash', '-c', command],
        AttachStdout: true,
        AttachStderr: true,
    });

    const stream = await exec.start({ Detach: false });
    return new Promise((resolve, reject) => {
        let output = '';
        stream.on('data', (chunk) => { output += chunk.toString(); });
        stream.on('end', () => resolve(output));
        stream.on('error', reject);
    });
}

module.exports = {
    getOrCreateContainer,
    stopContainer,
    removeContainer,
    execInContainer,
};