← back to browse
goat command

cpanel

Display hosting information with beautiful circular visual interface

0
views
0
likes
0
installs

Aliases: hosting, server, hostinfo, panel

raw source
const { createCanvas, loadImage, registerFont } = require('canvas');
const fs = require('fs-extra');
const path = require('path');
const os = require('os');

const fontDir = path.join(__dirname, 'assets', 'font');
const cacheDir = path.join(__dirname, 'cache');

registerFont(path.join(fontDir, 'BeVietnamPro-Bold.ttf'), { family: 'BeVietnamPro', weight: 'bold' });
registerFont(path.join(fontDir, 'BeVietnamPro-SemiBold.ttf'), { family: 'BeVietnamPro', weight: '600' });
registerFont(path.join(fontDir, 'BeVietnamPro-Regular.ttf'), { family: 'BeVietnamPro', weight: 'normal' });
registerFont(path.join(fontDir, 'NotoSans-Bold.ttf'), { family: 'NotoSans', weight: 'bold' });
registerFont(path.join(fontDir, 'NotoSans-SemiBold.ttf'), { family: 'NotoSans', weight: '600' });

function formatBytes(bytes, decimals = 2) {
    if (bytes === 0) return '0 B';
    const k = 1024;
    const dm = decimals < 0 ? 0 : decimals;
    const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}

function formatUptime(seconds) {
    const days = Math.floor(seconds / 86400);
    const hours = Math.floor((seconds % 86400) / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
    return `${days}d ${hours}h ${minutes}m`;
}

function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function drawGlowCircle(ctx, x, y, radius, colors, glowColor, glowSize = 30) {
    ctx.save();
    
    for (let i = glowSize; i > 0; i--) {
        const alpha = (1 - i / glowSize) * 0.15;
        ctx.beginPath();
        ctx.arc(x, y, radius + i, 0, Math.PI * 2);
        ctx.fillStyle = glowColor.replace(')', `, ${alpha})`).replace('rgb', 'rgba');
        ctx.fill();
    }
    
    const gradient = ctx.createRadialGradient(x - radius * 0.3, y - radius * 0.3, 0, x, y, radius);
    gradient.addColorStop(0, colors[0]);
    gradient.addColorStop(0.7, colors[1]);
    gradient.addColorStop(1, colors[2] || colors[1]);
    
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, Math.PI * 2);
    ctx.fillStyle = gradient;
    ctx.fill();
    
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, Math.PI * 2);
    ctx.strokeStyle = 'rgba(255,255,255,0.3)';
    ctx.lineWidth = 2;
    ctx.stroke();
    
    ctx.beginPath();
    ctx.arc(x, y, radius - 5, -Math.PI * 0.7, -Math.PI * 0.3);
    const shineGradient = ctx.createLinearGradient(x - radius, y - radius, x, y);
    shineGradient.addColorStop(0, 'rgba(255,255,255,0.4)');
    shineGradient.addColorStop(1, 'rgba(255,255,255,0)');
    ctx.strokeStyle = shineGradient;
    ctx.lineWidth = 3;
    ctx.stroke();
    
    ctx.restore();
}

function drawProgressArc(ctx, x, y, radius, progress, bgColor, fillColor, lineWidth = 8) {
    ctx.save();
    
    ctx.beginPath();
    ctx.arc(x, y, radius, -Math.PI * 0.75, Math.PI * 0.75);
    ctx.strokeStyle = bgColor;
    ctx.lineWidth = lineWidth;
    ctx.lineCap = 'round';
    ctx.stroke();
    
    if (progress > 0) {
        const sweepAngle = (Math.PI * 1.5) * (progress / 100);
        ctx.beginPath();
        ctx.arc(x, y, radius, -Math.PI * 0.75, -Math.PI * 0.75 + sweepAngle);
        ctx.strokeStyle = fillColor;
        ctx.lineWidth = lineWidth;
        ctx.lineCap = 'round';
        ctx.stroke();
    }
    
    ctx.restore();
}

function drawConnectingLine(ctx, x1, y1, x2, y2, color) {
    ctx.save();
    
    const gradient = ctx.createLinearGradient(x1, y1, x2, y2);
    gradient.addColorStop(0, 'rgba(255,255,255,0.05)');
    gradient.addColorStop(0.5, color);
    gradient.addColorStop(1, 'rgba(255,255,255,0.05)');
    
    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.strokeStyle = gradient;
    ctx.lineWidth = 2;
    ctx.stroke();
    
    const dotX = x1 + (x2 - x1) * 0.3;
    const dotY = y1 + (y2 - y1) * 0.3;
    ctx.beginPath();
    ctx.arc(dotX, dotY, 4, 0, Math.PI * 2);
    ctx.fillStyle = color;
    ctx.fill();
    
    ctx.restore();
}

function drawIcon(ctx, x, y, size, type, color = 'rgba(255,255,255,0.9)') {
    ctx.save();
    ctx.fillStyle = color;
    ctx.strokeStyle = color;
    ctx.lineWidth = 2;
    ctx.lineCap = 'round';
    ctx.lineJoin = 'round';
    
    const scale = size / 24;
    ctx.translate(x - 12 * scale, y - 12 * scale);
    ctx.scale(scale, scale);
    
    switch(type) {
        case 'server':
            ctx.beginPath();
            ctx.roundRect(4, 3, 16, 5, 2);
            ctx.roundRect(4, 10, 16, 5, 2);
            ctx.roundRect(4, 17, 16, 4, 2);
            ctx.stroke();
            ctx.beginPath();
            ctx.arc(7, 5.5, 1, 0, Math.PI * 2);
            ctx.arc(7, 12.5, 1, 0, Math.PI * 2);
            ctx.fill();
            break;
        case 'cpu':
            ctx.strokeRect(6, 6, 12, 12);
            ctx.beginPath();
            const pins = [[9,3,9,6], [12,3,12,6], [15,3,15,6], [9,18,9,21], [12,18,12,21], [15,18,15,21],
                         [3,9,6,9], [3,12,6,12], [3,15,6,15], [18,9,21,9], [18,12,21,12], [18,15,21,15]];
            pins.forEach(([a,b,c,d]) => { ctx.moveTo(a, b); ctx.lineTo(c, d); });
            ctx.stroke();
            ctx.fillRect(9, 9, 6, 6);
            break;
        case 'ram':
            ctx.strokeRect(2, 7, 20, 10);
            ctx.fillRect(5, 10, 3, 4);
            ctx.fillRect(10, 10, 3, 4);
            ctx.fillRect(16, 10, 3, 4);
            break;
        case 'storage':
            ctx.beginPath();
            ctx.ellipse(12, 7, 8, 4, 0, 0, Math.PI * 2);
            ctx.stroke();
            ctx.beginPath();
            ctx.moveTo(4, 7); ctx.lineTo(4, 17);
            ctx.moveTo(20, 7); ctx.lineTo(20, 17);
            ctx.stroke();
            ctx.beginPath();
            ctx.ellipse(12, 17, 8, 4, 0, 0, Math.PI * 2);
            ctx.stroke();
            break;
        case 'bandwidth':
            ctx.beginPath();
            ctx.moveTo(3, 17); ctx.lineTo(8, 11); ctx.lineTo(12, 14); ctx.lineTo(16, 7); ctx.lineTo(21, 10);
            ctx.stroke();
            ctx.beginPath();
            ctx.moveTo(16, 7); ctx.lineTo(21, 7); ctx.lineTo(21, 12);
            ctx.stroke();
            break;
        case 'domain':
            ctx.beginPath();
            ctx.arc(12, 12, 9, 0, Math.PI * 2);
            ctx.stroke();
            ctx.beginPath();
            ctx.ellipse(12, 12, 4, 9, 0, 0, Math.PI * 2);
            ctx.stroke();
            ctx.moveTo(3, 12); ctx.lineTo(21, 12);
            ctx.moveTo(12, 3); ctx.lineTo(12, 21);
            ctx.stroke();
            break;
        case 'ssl':
            ctx.strokeRect(5, 11, 14, 9);
            ctx.beginPath();
            ctx.moveTo(8, 11); ctx.lineTo(8, 8);
            ctx.arc(12, 8, 4, Math.PI, 0);
            ctx.lineTo(16, 11);
            ctx.stroke();
            ctx.beginPath();
            ctx.arc(12, 15, 2, 0, Math.PI * 2);
            ctx.fill();
            break;
        case 'email':
            ctx.strokeRect(2, 5, 20, 14);
            ctx.beginPath();
            ctx.moveTo(2, 5); ctx.lineTo(12, 12); ctx.lineTo(22, 5);
            ctx.stroke();
            break;
        case 'ftp':
            ctx.beginPath();
            ctx.moveTo(12, 4); ctx.lineTo(12, 16);
            ctx.moveTo(7, 9); ctx.lineTo(12, 4); ctx.lineTo(17, 9);
            ctx.stroke();
            ctx.strokeRect(4, 16, 16, 4);
            break;
        case 'database':
            ctx.beginPath();
            ctx.ellipse(12, 6, 7, 3, 0, 0, Math.PI * 2);
            ctx.stroke();
            ctx.beginPath();
            ctx.moveTo(5, 6); ctx.lineTo(5, 18);
            ctx.moveTo(19, 6); ctx.lineTo(19, 18);
            ctx.stroke();
            ctx.beginPath();
            ctx.ellipse(12, 12, 7, 3, 0, Math.PI, 0, true);
            ctx.ellipse(12, 18, 7, 3, 0, 0, Math.PI * 2);
            ctx.stroke();
            break;
        case 'uptime':
            ctx.beginPath();
            ctx.arc(12, 12, 9, 0, Math.PI * 2);
            ctx.stroke();
            ctx.beginPath();
            ctx.moveTo(12, 6); ctx.lineTo(12, 12); ctx.lineTo(17, 15);
            ctx.stroke();
            ctx.beginPath();
            ctx.arc(12, 12, 2, 0, Math.PI * 2);
            ctx.fill();
            break;
        case 'visitors':
            ctx.beginPath();
            ctx.arc(9, 8, 4, 0, Math.PI * 2);
            ctx.stroke();
            ctx.beginPath();
            ctx.moveTo(2, 21); ctx.quadraticCurveTo(9, 14, 16, 21);
            ctx.stroke();
            ctx.beginPath();
            ctx.arc(17, 6, 3, 0, Math.PI * 2);
            ctx.stroke();
            ctx.beginPath();
            ctx.moveTo(12, 18); ctx.quadraticCurveTo(17, 12, 22, 18);
            ctx.stroke();
            break;
        case 'php':
            ctx.font = 'bold 14px BeVietnamPro';
            ctx.textAlign = 'center';
            ctx.fillText('{ }', 12, 16);
            break;
    }
    ctx.restore();
}

async function generateCpanelCard(botName = "GOAT BOT") {
    const width = 1600;
    const height = 1200;
    const canvas = createCanvas(width, height);
    const ctx = canvas.getContext('2d');
    const centerX = width / 2;
    const centerY = height / 2;

    const bgGradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, height);
    bgGradient.addColorStop(0, '#1a1a3e');
    bgGradient.addColorStop(0.4, '#0f1628');
    bgGradient.addColorStop(0.7, '#0a0f1a');
    bgGradient.addColorStop(1, '#050810');
    ctx.fillStyle = bgGradient;
    ctx.fillRect(0, 0, width, height);

    ctx.save();
    for (let i = 0; i < 200; i++) {
        const x = Math.random() * width;
        const y = Math.random() * height;
        const size = Math.random() * 2 + 0.5;
        const opacity = Math.random() * 0.6 + 0.2;
        ctx.fillStyle = `rgba(255, 255, 255, ${opacity})`;
        ctx.beginPath();
        ctx.arc(x, y, size, 0, Math.PI * 2);
        ctx.fill();
    }
    ctx.restore();

    ctx.save();
    ctx.strokeStyle = 'rgba(100, 150, 255, 0.03)';
    ctx.lineWidth = 1;
    for (let r = 100; r < Math.max(width, height); r += 80) {
        ctx.beginPath();
        ctx.arc(centerX, centerY, r, 0, Math.PI * 2);
        ctx.stroke();
    }
    ctx.restore();

    const cpuUsage = getRandomInt(15, 45);
    const ramUsage = getRandomInt(30, 65);
    const storageUsed = getRandomInt(20, 70);
    const bandwidthUsed = getRandomInt(40, 85);
    const uptime = os.uptime();
    const totalMem = os.totalmem();
    const freeMem = os.freemem();
    const usedMem = totalMem - freeMem;

    const hostingData = {
        serverStatus: 'Online',
        serverLocation: 'US-East',
        cpuUsage: cpuUsage,
        cpuCores: os.cpus().length,
        ramUsage: ramUsage,
        ramUsed: formatBytes(usedMem),
        storageUsed: storageUsed,
        storageTotal: '50 GB',
        bandwidthUsed: bandwidthUsed,
        domains: getRandomInt(1, 5),
        sslStatus: 'Active',
        emailAccounts: getRandomInt(1, 20),
        ftpAccounts: getRandomInt(1, 5),
        databases: getRandomInt(1, 10),
        uptime: formatUptime(uptime),
        visitors: getRandomInt(100, 5000),
        phpVersion: '8.2'
    };

    const infoCircles = [
        { title: 'SERVER', icon: 'server', value: hostingData.serverStatus, sub: hostingData.serverLocation, colors: ['#34d399', '#10b981', '#059669'], glow: 'rgb(16, 185, 129)' },
        { title: 'CPU', icon: 'cpu', value: `${hostingData.cpuUsage}%`, sub: `${hostingData.cpuCores} Cores`, colors: ['#818cf8', '#6366f1', '#4f46e5'], glow: 'rgb(99, 102, 241)', progress: hostingData.cpuUsage },
        { title: 'RAM', icon: 'ram', value: `${hostingData.ramUsage}%`, sub: hostingData.ramUsed, colors: ['#fbbf24', '#f59e0b', '#d97706'], glow: 'rgb(245, 158, 11)', progress: hostingData.ramUsage },
        { title: 'STORAGE', icon: 'storage', value: `${hostingData.storageUsed}%`, sub: hostingData.storageTotal, colors: ['#f472b6', '#ec4899', '#db2777'], glow: 'rgb(236, 72, 153)', progress: hostingData.storageUsed },
        { title: 'BANDWIDTH', icon: 'bandwidth', value: `${hostingData.bandwidthUsed}%`, sub: '1 TB/mo', colors: ['#2dd4bf', '#14b8a6', '#0d9488'], glow: 'rgb(20, 184, 166)', progress: hostingData.bandwidthUsed },
        { title: 'DOMAINS', icon: 'domain', value: hostingData.domains, sub: 'Active', colors: ['#a78bfa', '#8b5cf6', '#7c3aed'], glow: 'rgb(139, 92, 246)' },
        { title: 'SSL', icon: 'ssl', value: hostingData.sslStatus, sub: 'Secured', colors: ['#4ade80', '#22c55e', '#16a34a'], glow: 'rgb(34, 197, 94)' },
        { title: 'EMAIL', icon: 'email', value: hostingData.emailAccounts, sub: 'Accounts', colors: ['#60a5fa', '#3b82f6', '#2563eb'], glow: 'rgb(59, 130, 246)' },
        { title: 'FTP', icon: 'ftp', value: hostingData.ftpAccounts, sub: 'Accounts', colors: ['#fb7185', '#f43f5e', '#e11d48'], glow: 'rgb(244, 63, 94)' },
        { title: 'DATABASE', icon: 'database', value: hostingData.databases, sub: 'MySQL', colors: ['#38bdf8', '#0ea5e9', '#0284c7'], glow: 'rgb(14, 165, 233)' },
        { title: 'UPTIME', icon: 'uptime', value: hostingData.uptime, sub: '99.9% SLA', colors: ['#a3e635', '#84cc16', '#65a30d'], glow: 'rgb(132, 204, 22)' },
        { title: 'VISITORS', icon: 'visitors', value: hostingData.visitors.toLocaleString(), sub: 'This Month', colors: ['#c084fc', '#a855f7', '#9333ea'], glow: 'rgb(168, 85, 247)' },
    ];

    const outerRadius = 420;
    const circleRadius = 95;

    infoCircles.forEach((circle, index) => {
        const angle = (Math.PI * 2 / 12) * index - Math.PI / 2;
        const x = centerX + Math.cos(angle) * outerRadius;
        const y = centerY + Math.sin(angle) * outerRadius;
        
        const innerEdgeX = centerX + Math.cos(angle) * 160;
        const innerEdgeY = centerY + Math.sin(angle) * 160;
        const outerEdgeX = centerX + Math.cos(angle) * (outerRadius - circleRadius - 10);
        const outerEdgeY = centerY + Math.sin(angle) * (outerRadius - circleRadius - 10);
        
        drawConnectingLine(ctx, innerEdgeX, innerEdgeY, outerEdgeX, outerEdgeY, circle.glow.replace('rgb', 'rgba').replace(')', ', 0.4)'));
    });

    const centerRadius = 150;
    
    ctx.save();
    for (let i = 50; i > 0; i--) {
        const alpha = (1 - i / 50) * 0.2;
        ctx.beginPath();
        ctx.arc(centerX, centerY, centerRadius + i, 0, Math.PI * 2);
        ctx.fillStyle = `rgba(99, 102, 241, ${alpha})`;
        ctx.fill();
    }
    ctx.restore();
    
    const centerGradient = ctx.createRadialGradient(centerX - 40, centerY - 40, 0, centerX, centerY, centerRadius);
    centerGradient.addColorStop(0, '#4f46e5');
    centerGradient.addColorStop(0.5, '#3730a3');
    centerGradient.addColorStop(1, '#1e1b4b');
    
    ctx.beginPath();
    ctx.arc(centerX, centerY, centerRadius, 0, Math.PI * 2);
    ctx.fillStyle = centerGradient;
    ctx.fill();
    
    ctx.beginPath();
    ctx.arc(centerX, centerY, centerRadius, 0, Math.PI * 2);
    ctx.strokeStyle = 'rgba(255,255,255,0.3)';
    ctx.lineWidth = 3;
    ctx.stroke();
    
    ctx.beginPath();
    ctx.arc(centerX, centerY, centerRadius + 10, 0, Math.PI * 2);
    ctx.strokeStyle = 'rgba(99, 102, 241, 0.5)';
    ctx.lineWidth = 2;
    ctx.setLineDash([10, 10]);
    ctx.stroke();
    ctx.setLineDash([]);
    
    ctx.save();
    ctx.fillStyle = '#ffffff';
    ctx.font = 'bold 36px BeVietnamPro';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText('∆', centerX, centerY - 45);
    
    ctx.font = 'bold 32px BeVietnamPro';
    ctx.fillText('NeoKEX AI', centerX, centerY);
    
    ctx.font = '600 16px BeVietnamPro';
    ctx.fillStyle = 'rgba(255,255,255,0.8)';
    ctx.fillText('CONTROL PANEL', centerX, centerY + 35);
    
    ctx.font = '600 14px BeVietnamPro';
    ctx.fillStyle = 'rgba(255,255,255,0.6)';
    ctx.fillText('Hosting Dashboard', centerX, centerY + 60);
    ctx.restore();

    infoCircles.forEach((circle, index) => {
        const angle = (Math.PI * 2 / 12) * index - Math.PI / 2;
        const x = centerX + Math.cos(angle) * outerRadius;
        const y = centerY + Math.sin(angle) * outerRadius;
        
        drawGlowCircle(ctx, x, y, circleRadius, circle.colors, circle.glow, 25);
        
        if (circle.progress !== undefined) {
            drawProgressArc(ctx, x, y, circleRadius + 12, circle.progress, 'rgba(0,0,0,0.3)', '#ffffff', 6);
        }
        
        drawIcon(ctx, x, y - 30, 28, circle.icon);
        
        ctx.save();
        ctx.fillStyle = '#ffffff';
        ctx.font = 'bold 11px BeVietnamPro';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText(circle.title, x, y - 5);
        
        ctx.font = 'bold 24px BeVietnamPro';
        ctx.fillText(String(circle.value), x, y + 22);
        
        ctx.font = '600 12px BeVietnamPro';
        ctx.fillStyle = 'rgba(255,255,255,0.8)';
        ctx.fillText(circle.sub, x, y + 45);
        ctx.restore();
    });

    ctx.save();
    ctx.fillStyle = 'rgba(255,255,255,0.4)';
    ctx.font = '600 14px BeVietnamPro';
    ctx.textAlign = 'center';
    ctx.fillText(`Last Updated: ${new Date().toLocaleString()}`, centerX, height - 40);
    
    ctx.font = '600 12px BeVietnamPro';
    ctx.fillStyle = 'rgba(255,255,255,0.3)';
    ctx.fillText('Real-time Monitoring System', centerX, height - 20);
    ctx.restore();

    return canvas.toBuffer('image/png');
}

module.exports = {
    config: {
        name: "cpanel",
        aliases: ["hosting", "server", "hostinfo", "panel"],
        version: "2.0.0",
        author: "Neoaz ゐ",
        countDown: 10,
        role: 0,
        description: "Display hosting information with beautiful circular visual interface",
        category: "utility",
        guide: "{pn}"
    },

    onStart: async function({ message, event }) {
        try {
            message.reaction("⏳", event.messageID);
            
            if (!fs.existsSync(cacheDir)) {
                fs.mkdirpSync(cacheDir);
            }

            const botName = global.GoatBot?.config?.nickNameBot || "GOAT BOT";
            const buffer = await generateCpanelCard(botName);
            const imagePath = path.join(cacheDir, `cpanel_${Date.now()}.png`);
            
            fs.writeFileSync(imagePath, buffer);

            await message.reply({
                body: "📊 𝗛𝗢𝗦𝗧𝗜𝗡𝗚 𝗖𝗢𝗡𝗧𝗥𝗢𝗟 𝗣𝗔𝗡𝗘𝗟",
                attachment: fs.createReadStream(imagePath)
            });

            message.reaction("✅", event.messageID);
            
            setTimeout(() => {
                if (fs.existsSync(imagePath)) {
                    fs.unlinkSync(imagePath);
                }
            }, 5000);

        } catch (error) {
            console.error("CPanel Command Error:", error);
            message.reaction("❌", event.messageID);
            return message.reply("❌ An error occurred while generating the hosting panel. Please try again.");
        }
    }
};
              

View raw file