UNPKG

@gftdcojp/gftd-cli

Version:

GFTD Schema Management CLI - Drizzle-like schema management for Kafka and ksqlDB

389 lines 14.4 kB
"use strict"; /** * DNS Manager - Local DNS Resolution Management * Automatically manages /etc/hosts file for development domains */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DnsManager = void 0; const fs = __importStar(require("fs-extra")); const path = __importStar(require("node:path")); const os = __importStar(require("node:os")); const node_child_process_1 = require("node:child_process"); const node_util_1 = require("node:util"); const chalk_1 = __importDefault(require("chalk")); const execAsync = (0, node_util_1.promisify)(node_child_process_1.exec); class DnsManager { constructor(domain = 'gftd.ai.dev') { this.domain = domain; this.marker = `# GFTD CLI - ${domain}`; // OS別のhostsファイルパス this.hostsPath = os.platform() === 'win32' ? 'C:\\Windows\\System32\\drivers\\etc\\hosts' : '/etc/hosts'; this.backupPath = path.join(os.homedir(), '.gftd', 'hosts.backup'); } /** * 管理者権限チェック */ async checkPermissions() { try { await fs.access(this.hostsPath, fs.constants.W_OK); return true; } catch { return false; } } /** * sudoで実行可能かチェック */ async checkSudoAccess() { try { await execAsync('sudo -n true'); return true; } catch { return false; } } /** * hostsファイルのバックアップ作成 */ async createBackup() { try { await fs.ensureDir(path.dirname(this.backupPath)); await fs.copy(this.hostsPath, this.backupPath); console.log(chalk_1.default.green('✅ Hosts file backed up')); } catch (error) { console.error(chalk_1.default.red('❌ Failed to create backup:'), error); throw error; } } /** * hostsファイルを読み込み */ async readHosts() { try { return await fs.readFile(this.hostsPath, 'utf-8'); } catch (error) { console.error(chalk_1.default.red('❌ Failed to read hosts file:'), error); throw error; } } /** * hostsファイルに書き込み */ async writeHosts(content) { try { // 管理者権限が必要な場合はsudoを使用 if (!(await this.checkPermissions())) { if (await this.checkSudoAccess()) { const tempPath = path.join(os.tmpdir(), 'gftd-hosts-temp'); await fs.writeFile(tempPath, content); await execAsync(`sudo mv "${tempPath}" "${this.hostsPath}"`); } else { throw new Error('Administrator privileges required to modify hosts file'); } } else { await fs.writeFile(this.hostsPath, content); } console.log(chalk_1.default.green('✅ Hosts file updated')); } catch (error) { console.error(chalk_1.default.red('❌ Failed to write hosts file:'), error); throw error; } } /** * GFTD管理のエントリを取得 */ async getManagedEntries() { const content = await this.readHosts(); const entries = []; const lines = content.split('\n'); let inGftdSection = false; for (const line of lines) { const trimmedLine = line.trim(); if (trimmedLine.startsWith(this.marker)) { inGftdSection = true; continue; } if (inGftdSection) { if (trimmedLine.startsWith('# END GFTD')) { break; } if (trimmedLine && !trimmedLine.startsWith('#')) { const parts = trimmedLine.split(/\s+/); if (parts.length >= 2) { entries.push({ ip: parts[0], hostname: parts[1], comment: parts.slice(2).join(' ') }); } } } } return entries; } /** * DNSエントリを追加 */ async addEntry(hostname, ip = '127.0.0.1', comment) { try { const content = await this.readHosts(); const entries = await this.getManagedEntries(); // 既存エントリをチェック const existingEntry = entries.find(e => e.hostname === hostname); if (existingEntry) { console.log(chalk_1.default.yellow(`⚠️ Entry for ${hostname} already exists`)); return; } // バックアップ作成 await this.createBackup(); // 新しいエントリを追加 const newEntry = { ip, hostname, comment }; const updatedContent = this.insertEntry(content, newEntry); await this.writeHosts(updatedContent); console.log(chalk_1.default.green(`✅ Added DNS entry: ${hostname} -> ${ip}`)); } catch (error) { console.error(chalk_1.default.red('❌ Failed to add DNS entry:'), error); throw error; } } /** * DNSエントリを削除 */ async removeEntry(hostname) { try { const content = await this.readHosts(); const entries = await this.getManagedEntries(); const entryToRemove = entries.find(e => e.hostname === hostname); if (!entryToRemove) { console.log(chalk_1.default.yellow(`⚠️ Entry for ${hostname} not found`)); return; } // バックアップ作成 await this.createBackup(); // エントリを削除 const updatedContent = this.removeEntryFromContent(content, hostname); await this.writeHosts(updatedContent); console.log(chalk_1.default.green(`✅ Removed DNS entry: ${hostname}`)); } catch (error) { console.error(chalk_1.default.red('❌ Failed to remove DNS entry:'), error); throw error; } } /** * 全てのGFTD管理エントリを削除 */ async removeAllEntries() { try { const content = await this.readHosts(); // バックアップ作成 await this.createBackup(); // GFTD管理セクションを削除 const updatedContent = this.removeGftdSection(content); await this.writeHosts(updatedContent); console.log(chalk_1.default.green('✅ Removed all GFTD DNS entries')); } catch (error) { console.error(chalk_1.default.red('❌ Failed to remove DNS entries:'), error); throw error; } } /** * プロジェクト用のDNSエントリを追加 */ async addProjectEntry(subdomain, projectName) { const hostname = `${subdomain}.${this.domain}`; const comment = `# ${projectName}`; await this.addEntry(hostname, '127.0.0.1', comment); } /** * プロジェクト用のDNSエントリを削除 */ async removeProjectEntry(subdomain) { const hostname = `${subdomain}.${this.domain}`; await this.removeEntry(hostname); } /** * 管理状況を表示 */ async showStatus() { try { const entries = await this.getManagedEntries(); console.log(chalk_1.default.blue('🌐 DNS Management Status:')); console.log(''); if (entries.length === 0) { console.log(chalk_1.default.gray(' No DNS entries managed by GFTD')); return; } console.log(chalk_1.default.gray(' Managed DNS entries:')); entries.forEach(entry => { console.log(` ${chalk_1.default.green(entry.hostname)} -> ${entry.ip} ${chalk_1.default.gray(entry.comment || '')}`); }); console.log(''); console.log(chalk_1.default.gray(` Hosts file: ${this.hostsPath}`)); console.log(chalk_1.default.gray(` Backup: ${this.backupPath}`)); } catch (error) { console.error(chalk_1.default.red('❌ Failed to show DNS status:'), error); } } /** * DNS設定の初期化 */ async initialize() { try { // 権限チェック if (!(await this.checkPermissions()) && !(await this.checkSudoAccess())) { console.log(chalk_1.default.yellow('⚠️ Administrator privileges required for DNS management')); console.log(chalk_1.default.gray(' DNS entries will need to be added manually')); return; } // hostsファイルの確認 const content = await this.readHosts(); if (!content.includes(this.marker)) { console.log(chalk_1.default.blue('🔧 Initializing DNS management...')); const updatedContent = this.initializeGftdSection(content); await this.writeHosts(updatedContent); console.log(chalk_1.default.green('✅ DNS management initialized')); } } catch (error) { console.error(chalk_1.default.red('❌ Failed to initialize DNS management:'), error); throw error; } } /** * バックアップから復元 */ async restoreBackup() { try { if (!(await fs.pathExists(this.backupPath))) { console.log(chalk_1.default.yellow('⚠️ No backup found')); return; } await fs.copy(this.backupPath, this.hostsPath); console.log(chalk_1.default.green('✅ Hosts file restored from backup')); } catch (error) { console.error(chalk_1.default.red('❌ Failed to restore backup:'), error); throw error; } } // Private helper methods insertEntry(content, entry) { const lines = content.split('\n'); let insertIndex = -1; // GFTD管理セクションを探す for (let i = 0; i < lines.length; i++) { if (lines[i].trim().startsWith(this.marker)) { // セクションの終了を探す for (let j = i + 1; j < lines.length; j++) { if (lines[j].trim().startsWith('# END GFTD')) { insertIndex = j; break; } } break; } } // セクションが見つからない場合は作成 if (insertIndex === -1) { lines.push(''); lines.push(this.marker); lines.push('# END GFTD'); insertIndex = lines.length - 1; } // エントリを挿入 const entryLine = `${entry.ip} ${entry.hostname} ${entry.comment || ''}`.trim(); lines.splice(insertIndex, 0, entryLine); return lines.join('\n'); } removeEntryFromContent(content, hostname) { const lines = content.split('\n'); const filteredLines = lines.filter(line => { const trimmedLine = line.trim(); return !trimmedLine.includes(hostname) || trimmedLine.startsWith('#'); }); return filteredLines.join('\n'); } removeGftdSection(content) { const lines = content.split('\n'); const filteredLines = []; let inGftdSection = false; for (const line of lines) { const trimmedLine = line.trim(); if (trimmedLine.startsWith(this.marker)) { inGftdSection = true; continue; } if (inGftdSection && trimmedLine.startsWith('# END GFTD')) { inGftdSection = false; continue; } if (!inGftdSection) { filteredLines.push(line); } } return filteredLines.join('\n'); } initializeGftdSection(content) { const lines = content.split('\n'); // 末尾に空行がない場合は追加 if (lines[lines.length - 1].trim() !== '') { lines.push(''); } lines.push(this.marker); lines.push('# Automatically managed by GFTD CLI'); lines.push('# Do not edit this section manually'); lines.push('# END GFTD'); return lines.join('\n'); } } exports.DnsManager = DnsManager; //# sourceMappingURL=dns-manager.js.map