@genxis/whmrockstar
Version:
🎸 GenXis WHMRockStar - AI-powered multi-server WHM/cPanel management via Model Context Protocol (MCP). Enhanced with proper MCP stdio protocol support and multi-server management.
249 lines (212 loc) • 7.53 kB
JavaScript
const fs = require('fs');
const path = require('path');
const WHMService = require('./whm-service');
const logger = require('./logger');
class MultiServerManager {
constructor() {
this.servers = new Map();
this.configDir = path.join(process.env.HOME || process.env.USERPROFILE, '.genxis-whmrockstar');
this.serversConfigPath = path.join(this.configDir, 'servers.json');
this.loadServers();
}
loadServers() {
// Ensure config directory exists
if (!fs.existsSync(this.configDir)) {
fs.mkdirSync(this.configDir, { recursive: true });
}
// Load from servers.json
if (fs.existsSync(this.serversConfigPath)) {
try {
const config = JSON.parse(fs.readFileSync(this.serversConfigPath, 'utf8'));
for (const [serverId, serverConfig] of Object.entries(config.servers || {})) {
this.addServer(serverId, serverConfig, false);
}
logger.info(`Loaded ${this.servers.size} server(s) from configuration`);
} catch (error) {
logger.error(`Failed to load servers configuration: ${error.message}`);
}
}
// Load legacy single server config
const legacyConfigPath = path.join(this.configDir, 'config.json');
if (fs.existsSync(legacyConfigPath) && this.servers.size === 0) {
try {
const config = JSON.parse(fs.readFileSync(legacyConfigPath, 'utf8'));
if (config.server && config.apiToken) {
this.addServer('default', {
...config,
name: config.name || `WHM Server (${config.server})`
}, false);
logger.info('Loaded legacy server configuration');
}
} catch (error) {
logger.error(`Failed to load legacy configuration: ${error.message}`);
}
}
// Load from environment variables
if (process.env.WHM_SERVER && process.env.WHM_API_TOKEN && this.servers.size === 0) {
const serverId = process.env.WHM_SERVER_ID || 'env';
this.addServer(serverId, {
server: process.env.WHM_SERVER,
apiToken: process.env.WHM_API_TOKEN,
port: process.env.WHM_PORT || '2087',
name: process.env.WHM_SERVER_NAME || `WHM Server (${process.env.WHM_SERVER})`
}, false);
logger.info('Loaded server configuration from environment variables');
}
}
saveServers() {
try {
const config = {
version: "2.0",
servers: {}
};
for (const [serverId, serverData] of this.servers) {
config.servers[serverId] = {
server: serverData.config.server,
apiToken: serverData.config.apiToken,
port: serverData.config.port || '2087',
name: serverData.config.name,
username: serverData.config.username || 'root',
timeout: serverData.config.timeout || 30000,
enabled: serverData.config.enabled !== false
};
}
fs.writeFileSync(this.serversConfigPath, JSON.stringify(config, null, 2));
logger.info('Server configuration saved');
} catch (error) {
logger.error(`Failed to save server configuration: ${error.message}`);
throw error;
}
}
addServer(serverId, config, save = true) {
try {
// Validate configuration
if (!config.server || !config.apiToken) {
throw new Error('Server IP and API token are required');
}
// Create WHM service instance
const whmService = new WHMService(config);
// Store server configuration
this.servers.set(serverId, {
service: whmService,
config: {
...config,
id: serverId,
enabled: config.enabled !== false
}
});
logger.info(`Added server: ${serverId} (${config.server})`);
if (save) {
this.saveServers();
}
return true;
} catch (error) {
logger.error(`Failed to add server ${serverId}: ${error.message}`);
throw error;
}
}
removeServer(serverId) {
if (!this.servers.has(serverId)) {
throw new Error(`Server '${serverId}' not found`);
}
this.servers.delete(serverId);
logger.info(`Removed server: ${serverId}`);
this.saveServers();
}
updateServer(serverId, updates) {
const serverData = this.servers.get(serverId);
if (!serverData) {
throw new Error(`Server '${serverId}' not found`);
}
// Update configuration
const newConfig = { ...serverData.config, ...updates };
// Create new service instance with updated config
const newService = new WHMService(newConfig);
// Update stored data
this.servers.set(serverId, {
service: newService,
config: newConfig
});
logger.info(`Updated server: ${serverId}`);
this.saveServers();
}
getServer(serverId) {
// If no serverId specified and only one server, return it
if (!serverId && this.servers.size === 1) {
return Array.from(this.servers.values())[0];
}
// If no serverId specified and multiple servers, throw error
if (!serverId && this.servers.size > 1) {
const availableServers = Array.from(this.servers.keys()).join(', ');
throw new Error(`Multiple servers configured. Please specify serverId. Available: ${availableServers}`);
}
// If no serverId specified and no servers, throw error
if (!serverId && this.servers.size === 0) {
throw new Error('No servers configured. Please add a server first.');
}
const serverData = this.servers.get(serverId);
if (!serverData) {
const availableServers = Array.from(this.servers.keys()).join(', ');
throw new Error(`Server '${serverId}' not found. Available servers: ${availableServers}`);
}
if (serverData.config.enabled === false) {
throw new Error(`Server '${serverId}' is disabled`);
}
return serverData;
}
listServers() {
return Array.from(this.servers.entries()).map(([id, { config }]) => ({
id,
name: config.name || `WHM Server (${config.server})`,
server: config.server,
port: config.port || '2087',
enabled: config.enabled !== false,
username: config.username || 'root'
}));
}
async testServer(serverId) {
const { service, config } = this.getServer(serverId);
try {
await service.get('version');
return {
success: true,
server: config.server,
message: 'Connection successful'
};
} catch (error) {
return {
success: false,
server: config.server,
error: error.message
};
}
}
async testAllServers() {
const results = [];
for (const [serverId] of this.servers) {
try {
const result = await this.testServer(serverId);
results.push({ serverId, ...result });
} catch (error) {
results.push({
serverId,
success: false,
error: error.message
});
}
}
return results;
}
getServerCount() {
return this.servers.size;
}
hasServers() {
return this.servers.size > 0;
}
getEnabledServers() {
return Array.from(this.servers.entries())
.filter(([, { config }]) => config.enabled !== false)
.map(([id, data]) => ({ id, ...data }));
}
}
module.exports = MultiServerManager;